All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.cmu.tetradapp.knowledge_editor.OtherGroupsEditor Maven / Gradle / Ivy

The newest version!
///////////////////////////////////////////////////////////////////////////////
// For information as to what this class does, see the Javadoc, below.       //
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,       //
// 2007, 2008, 2009, 2010, 2014, 2015, 2022 by Peter Spirtes, Richard        //
// Scheines, Joseph Ramsey, and Clark Glymour.                               //
//                                                                           //
// This program is free software; you can redistribute it and/or modify      //
// it under the terms of the GNU General Public License as published by      //
// the Free Software Foundation; either version 2 of the License, or         //
// (at your option) any later version.                                       //
//                                                                           //
// This program is distributed in the hope that it will be useful,           //
// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
// GNU General Public License for more details.                              //
//                                                                           //
// You should have received a copy of the GNU General Public License         //
// along with this program; if not, write to the Free Software               //
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA //
///////////////////////////////////////////////////////////////////////////////
package edu.cmu.tetradapp.knowledge_editor;

import edu.cmu.tetrad.data.Knowledge;
import edu.cmu.tetrad.data.KnowledgeGroup;
import edu.cmu.tetradapp.workbench.LayoutUtils;

import javax.swing.*;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.MatteBorder;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.*;
import java.util.List;
import java.util.*;

/**
 * Edits fobiddings or requirings of groups of node to other groups of nodes.
 *
 * @author Tyler Gibson
 */
class OtherGroupsEditor extends JPanel {

    /**
     * The knowledge that is being edited.
     */
    private final Knowledge knowledge;

    /**
     * The variables in the graph.
     */
    private final List variables;

    /**
     * 

Constructor for OtherGroupsEditor.

* * @param knowledge a {@link edu.cmu.tetrad.data.Knowledge} object * @param vars a {@link java.util.List} object */ public OtherGroupsEditor(Knowledge knowledge, List vars) { if (knowledge == null) { throw new NullPointerException("The given knowledge must not be null"); } if (vars == null) { throw new NullPointerException("The given list of variables must not be null"); } this.knowledge = knowledge; this.variables = new ArrayList<>(vars); this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); setBorder(new EmptyBorder(5, 5, 5, 5)); this.add(buildComponent()); // this.add(Box.createVerticalGlue()); } /** * Sorts the elemenets of a default list model */ private static void sort(DefaultListModel model) { Object[] elements = model.toArray(); Arrays.sort(elements); model.clear(); for (Object element : elements) { model.addElement(element); } } private static Set getElementsInModel(DefaultListModel model) { Set elements = new HashSet<>(); for (int i = 0; i < model.getSize(); i++) { elements.add((String) model.getElementAt(i)); } return elements; } private static boolean modelContains(Object o, DefaultListModel model) { for (int i = 0; i < model.getSize(); i++) { if (o.equals(model.getElementAt(i))) { return true; } } return false; } //===================== Private Methods ============================// private Box buildComponent() { Box vBox = Box.createVerticalBox(); VariableDragList varList = new VariableDragList(this.variables); varList.setBorder(null); JScrollPane pane = new JScrollPane(varList); pane.setPreferredSize(new Dimension(500, 50)); vBox.add(pane); JButton addForbidden = new JButton("Add New Forbidden Group"); addForbidden.addActionListener(e -> { KnowledgeGroup targetKnowledgeGroup = new KnowledgeGroup(KnowledgeGroup.FORBIDDEN); OtherGroupsEditor.this.knowledge.addKnowledgeGroup(targetKnowledgeGroup); rebuild(); }); JButton addRequired = new JButton("Add New Required Group"); addRequired.addActionListener(e -> { KnowledgeGroup targetKnowledgeGroup = new KnowledgeGroup(KnowledgeGroup.REQUIRED); OtherGroupsEditor.this.knowledge.addKnowledgeGroup(targetKnowledgeGroup); rebuild(); }); Box buttons = Box.createHorizontalBox(); buttons.add(addForbidden); buttons.add(Box.createHorizontalStrut(5)); buttons.add(addRequired); buttons.add(Box.createHorizontalGlue()); vBox.add(Box.createVerticalStrut(5)); vBox.add(buttons); vBox.add(Box.createVerticalStrut(5)); Box groupBoxes = Box.createVerticalBox(); List groups = this.knowledge.getKnowledgeGroups(); for (int i = 0; i < groups.size(); i++) { groupBoxes.add(buildGroupBox(i, groups.get(i))); } groupBoxes.add(Box.createVerticalGlue()); JScrollPane pane2 = new JScrollPane(groupBoxes); pane2.setPreferredSize(new Dimension(500, 400)); vBox.add(pane2); vBox.add(LayoutUtils.leftAlignJLabel(new JLabel("Use shift key to select multiple items."))); return vBox; } /** * Builds a group box using the given knowledge group (if null a default instance is returned). * * @return - A required/forbidden work area. */ private Box buildGroupBox(int index, KnowledgeGroup group) { Box vBox = Box.createVerticalBox(); vBox.setBorder(new EmptyBorder(10, 10, 10, 10)); Box labelBox = Box.createHorizontalBox(); String title; // Only add this forbidden checkbox for required group - Zhou JButton forbiddenButton = new JButton("Generate forbidden group"); forbiddenButton.setFont(forbiddenButton.getFont().deriveFont(11f)); forbiddenButton.setMargin(new Insets(3, 4, 3, 4)); // Enable/disable the button Set fromGroup = group.getFromVariables(); Set toGroup = group.getToVariables(); // Don't allow to create forbidden group from this required group if // no variables in the from or to boxes - Zhou forbiddenButton.setEnabled(!fromGroup.isEmpty() && !toGroup.isEmpty()); // Add skinny hand forbiddenButton.addActionListener((e) -> { Set toForbiddenGroup = new HashSet<>(); this.variables.forEach(var -> { if (!fromGroup.contains(var) && !toGroup.contains(var)) { toForbiddenGroup.add(var); } }); KnowledgeGroup targetKnowledgeGroup = new KnowledgeGroup(KnowledgeGroup.FORBIDDEN, fromGroup, toForbiddenGroup); this.knowledge.addKnowledgeGroup(targetKnowledgeGroup); rebuild(); }); if (group.getType() == KnowledgeGroup.FORBIDDEN) { title = "Forbidden Group"; } else { title = "Required Group"; } JButton remove = new JButton("Remove"); remove.setFont(remove.getFont().deriveFont(11f)); remove.setMargin(new Insets(3, 4, 3, 4)); remove.addActionListener(e -> { OtherGroupsEditor.this.knowledge.removeKnowledgeGroup(index); rebuild(); }); labelBox.add(new JLabel(title)); // Only add this forbidden button for required group - Zhou if (group.getType() == KnowledgeGroup.REQUIRED) { labelBox.add(Box.createHorizontalGlue()); labelBox.add(forbiddenButton); } labelBox.add(Box.createHorizontalGlue()); labelBox.add(remove); vBox.add(labelBox); vBox.add(Box.createVerticalStrut(2)); Box box = Box.createHorizontalBox(); GroupVariableDragList fromList = new GroupVariableDragList(index, true); GroupVariableDragList toList = new GroupVariableDragList(index, false); JScrollPane pane1 = new JScrollPane(fromList); pane1.setPreferredSize(new Dimension(180, 50)); JScrollPane pane2 = new JScrollPane(toList); pane2.setPreferredSize(new Dimension(180, 50)); box.add(pane1); box.add(new Arrow()); box.add(pane2); vBox.add(box); return vBox; } /** * Rebuilds the components */ private void rebuild() { this.removeAll(); this.add(buildComponent()); revalidate(); repaint(); } //========================== Inner classes =====================================// /** * Renders an arrow from the left to right. */ private static class Arrow extends JPanel { private final Color color; public Arrow() { Color b = Color.BLACK; this.color = new Color(b.getRed(), b.getGreen(), b.getBlue(), 150); this.setMinimumSize(new Dimension(22, 22)); } public void paintComponent(Graphics g) { Dimension size = getSize(); // if too small, just don't draw if (size.width < 21 || size.height < 21) { return; } int mid = size.height / 2; g.setColor(this.color); int end = size.width - 15; g.fillRect(5, mid, end - 5, 2); g.fillPolygon(new int[]{end, end + 10, end}, new int[]{mid + 10, mid, mid - 10}, 3); } } /** * Renderer for variables. */ private static class VariableRenderer extends DefaultListCellRenderer { private final Color fillColor = new Color(153, 204, 204); private final Color selectedFillColor = new Color(255, 204, 102); public VariableRenderer() { this.setOpaque(true); setHorizontalAlignment(SwingConstants.CENTER); setBorder(new CompoundBorder( new MatteBorder(2, 2, 2, 2, Color.WHITE), new LineBorder(Color.BLACK))); } public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { setText(" " + value + " "); if (isSelected) { setForeground(Color.BLACK); setBackground(this.selectedFillColor); } else { setForeground(Color.BLACK); setBackground(this.fillColor); } return this; } } /** * A list that allows the user to move variables from it to others. The variables are not deleted when moved. */ private static class VariableDragList extends JList implements DragGestureListener, DropTargetListener { public VariableDragList(List items) { setLayoutOrientation(JList.HORIZONTAL_WRAP); setVisibleRowCount(0); this.setCellRenderer(new VariableRenderer()); new DropTarget(this, DnDConstants.ACTION_MOVE, this, true); DragSource dragSource = DragSource.getDefaultDragSource(); dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this); setModel(new DefaultListModel()); for (Object item : items) { ((DefaultListModel) getModel()).addElement(item); } } public void dragGestureRecognized(DragGestureEvent dragGestureEvent) { if (getSelectedIndex() == -1) { return; } List list = getSelectedValuesList(); if (list == null) { getToolkit().beep(); } else { ListTransferable transferable = new ListTransferable(list); dragGestureEvent.startDrag(DragSource.DefaultMoveDrop, transferable); } } public void drop(DropTargetDropEvent dtde) { dtde.getDropTargetContext().dropComplete(true); } public void dragEnter(DropTargetDragEvent dtde) { } public void dragOver(DropTargetDragEvent dtde) { } public void dropActionChanged(DropTargetDragEvent dtde) { } public void dragExit(DropTargetEvent dte) { } } private class GroupVariableDragList extends JList implements DropTargetListener, DragSourceListener, DragGestureListener { /** * Index of the group that is being edited. */ private final int index; /** * States that whether this if the "from" side or the "to" side (true=from, false=to). */ private final boolean from; public GroupVariableDragList(int index, boolean from) { this.index = index; this.from = from; setLayoutOrientation(JList.HORIZONTAL_WRAP); setVisibleRowCount(0); this.setCellRenderer(new VariableRenderer()); new DropTarget(this, DnDConstants.ACTION_MOVE, this, true); DragSource dragSource = DragSource.getDefaultDragSource(); dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this); setModel(new DefaultListModel()); KnowledgeGroup group = OtherGroupsEditor.this.knowledge.getKnowledgeGroups().get(index); Set vars = from ? group.getFromVariables() : group.getToVariables(); for (Object item : vars) { ((DefaultListModel) getModel()).addElement(item); } } public void drop(DropTargetDropEvent dtde) { try { Transferable tr = dtde.getTransferable(); DataFlavor flavor = tr.getTransferDataFlavors()[0]; DefaultListModel model = (DefaultListModel) getModel(); boolean added = false; for (Object var : (List) tr.getTransferData(flavor)) { if (!OtherGroupsEditor.modelContains(var, model) && !opposingContains((String) var)) { model.addElement(var); added = true; } } // nothing was added so drop is incomplete. if (!added) { dtde.getDropTargetContext().dropComplete(false); return; } OtherGroupsEditor.sort(model); KnowledgeGroup group = OtherGroupsEditor.this.knowledge.getKnowledgeGroups().get(this.index); KnowledgeGroup g; if (this.from) { g = new KnowledgeGroup(group.getType(), OtherGroupsEditor.getElementsInModel(model), group.getToVariables()); } else { g = new KnowledgeGroup(group.getType(), group.getFromVariables(), OtherGroupsEditor.getElementsInModel(model)); } try { OtherGroupsEditor.this.knowledge.setKnowledgeGroup(this.index, g); dtde.getDropTargetContext().dropComplete(true); rebuild(); // Zhou added this to reflect the update } catch (IllegalArgumentException ex) { JOptionPane.showMessageDialog(OtherGroupsEditor.this, ex.getMessage()); // rebuild so the old values are resorted. rebuild(); dtde.getDropTargetContext().dropComplete(false); } } catch (Exception ex) { ex.printStackTrace(); } } public void dragDropEnd(DragSourceDropEvent dsde) { if (dsde.getDropSuccess()) { Transferable t = dsde.getDragSourceContext().getTransferable(); try { List list = (List) t.getTransferData(ListTransferable.DATA_FLAVOR); DefaultListModel model = (DefaultListModel) getModel(); for (Object o : list) { model.removeElement(o); } KnowledgeGroup group = OtherGroupsEditor.this.knowledge.getKnowledgeGroups().get(this.index); KnowledgeGroup g; if (this.from) { g = new KnowledgeGroup(group.getType(), OtherGroupsEditor.getElementsInModel(model), group.getToVariables()); } else { g = new KnowledgeGroup(group.getType(), group.getFromVariables(), OtherGroupsEditor.getElementsInModel(model)); } try { OtherGroupsEditor.this.knowledge.setKnowledgeGroup(this.index, g); rebuild(); // Zhou added this to reflect the update } catch (IllegalArgumentException ex) { JOptionPane.showMessageDialog(OtherGroupsEditor.this, ex.getMessage()); // rebuild so the old values are resorted. rebuild(); } } catch (Exception ex) { ex.printStackTrace(); } } } public void dragGestureRecognized(DragGestureEvent dge) { if (getSelectedIndex() == -1) { return; } List list = getSelectedValuesList(); if (list == null) { getToolkit().beep(); } else { ListTransferable transferable = new ListTransferable(list); dge.startDrag(DragSource.DefaultMoveDrop, transferable, this); } } private boolean opposingContains(String o) { KnowledgeGroup group = OtherGroupsEditor.this.knowledge.getKnowledgeGroups().get(this.index); Set opposite = this.from ? group.getToVariables() : group.getFromVariables(); return opposite.contains(o); } // ===================== Not implemented ====================// public void dragEnter(DropTargetDragEvent dtde) { } public void dragOver(DropTargetDragEvent dtde) { } public void dropActionChanged(DropTargetDragEvent dtde) { } public void dragExit(DropTargetEvent dte) { } public void dragEnter(DragSourceDragEvent dsde) { } public void dragOver(DragSourceDragEvent dsde) { } public void dropActionChanged(DragSourceDragEvent dsde) { } public void dragExit(DragSourceEvent dse) { } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy