package org.openpnp.vision.pipeline.ui; import java.awt.BorderLayout; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.DropMode; import javax.swing.JButton; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.JToolBar; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import org.openpnp.gui.components.ClassSelectionDialog; import org.openpnp.gui.support.Helpers; import org.openpnp.gui.support.Icons; import org.openpnp.gui.support.MessageBoxes; import org.openpnp.vision.pipeline.CvStage; import com.l2fprod.common.propertysheet.Property; import com.l2fprod.common.propertysheet.PropertySheetPanel; public class PipelinePanel extends JPanel { private final CvPipelineEditor editor; private JTable stagesTable; private StagesTableModel stagesTableModel; private PropertySheetPanel propertySheetPanel; public PipelinePanel(CvPipelineEditor editor) { this.editor = editor; propertySheetPanel = new PropertySheetPanel(); setLayout(new BorderLayout(0, 0)); JSplitPane splitPane = new JSplitPane(); add(splitPane, BorderLayout.CENTER); splitPane.setContinuousLayout(true); splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); JToolBar toolbar = new JToolBar(); add(toolbar, BorderLayout.NORTH); JButton refreshButton = new JButton(refreshAction); refreshButton.setHideActionText(true); toolbar.add(refreshButton); JButton btnAdd = new JButton(newStageAction); btnAdd.setHideActionText(true); toolbar.add(btnAdd); JButton btnRemove = new JButton(deleteStageAction); btnRemove.setHideActionText(true); toolbar.add(btnRemove); toolbar.addSeparator(); JButton copyButton = new JButton(copyAction); copyButton.setHideActionText(true); toolbar.add(copyButton); JButton pasteButton = new JButton(pasteAction); pasteButton.setHideActionText(true); toolbar.add(pasteButton); stagesTable = new JTable(stagesTableModel = new StagesTableModel(editor.getPipeline())); stagesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); stagesTable.setDragEnabled(true); stagesTable.setDropMode(DropMode.INSERT_ROWS); stagesTable.setTransferHandler(new TableRowTransferHandler(stagesTable)); stagesTable.getColumnModel().getColumn(0).setPreferredWidth(50); stagesTable.getColumnModel().getColumn(1).setPreferredWidth(50); stagesTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); JScrollPane scrollPane = new JScrollPane(stagesTable); splitPane.setRightComponent(propertySheetPanel); splitPane.setLeftComponent(scrollPane); // Listen for changes to the selection of the table and update the properties for the // selected stage. stagesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } CvStage stage = getSelectedStage(); editor.stageSelected(stage); if (stage == null) { propertySheetPanel.setProperties(new Property[] {}); } else { try { propertySheetPanel.setBeanInfo(stage.getBeanInfo()); propertySheetPanel.readFromObject(stage); } catch (Exception ex) { ex.printStackTrace(); } } } }); // Listen for changes to the structure of the table (adding or removing rows) and process // the pipeline to update the results. stagesTable.getModel().addTableModelListener(new TableModelListener() { @Override public void tableChanged(TableModelEvent e) { editor.process(); } }); // Listen for editing events in the stages table and process the pipeline to update the // results. stagesTable.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent e) { if ("tableCellEditor".equals(e.getPropertyName())) { if (!propertySheetPanel.getTable().isEditing()) { // editing has ended for a cell, save the values editor.process(); } } } }); // Set the divider location after it's added to the view addHierarchyListener(new HierarchyListener() { @Override public void hierarchyChanged(HierarchyEvent e) { splitPane.setDividerLocation(0.5); } }); // Listen for editing events in the properties and process the pipeline to update the // results. propertySheetPanel.getTable().addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent e) { if ("tableCellEditor".equals(e.getPropertyName())) { if (!propertySheetPanel.getTable().isEditing()) { // editing has ended for a cell, save the values propertySheetPanel.writeToObject(getSelectedStage()); editor.process(); } } } }); } public CvStage getSelectedStage() { int index = stagesTable.getSelectedRow(); if (index == -1) { return null; } else { index = stagesTable.convertRowIndexToModel(index); return stagesTableModel.getStage(index); } } public Action newStageAction = new AbstractAction() { { putValue(SMALL_ICON, Icons.add); putValue(NAME, "New Stage..."); putValue(SHORT_DESCRIPTION, "Create a new stage."); } @Override public void actionPerformed(ActionEvent arg0) { List<Class<? extends CvStage>> stageClasses = new ArrayList<>(editor.getStageClasses()); stageClasses.sort(new Comparator<Class<? extends CvStage>>() { @Override public int compare(Class<? extends CvStage> o1, Class<? extends CvStage> o2) { return o1.getSimpleName().toLowerCase() .compareTo(o2.getSimpleName().toLowerCase()); } }); ClassSelectionDialog<CvStage> dialog = new ClassSelectionDialog<>( JOptionPane.getFrameForComponent(PipelinePanel.this), "New Stage", "Please select a stage implemention from the list below.", stageClasses); dialog.setVisible(true); Class<? extends CvStage> stageClass = dialog.getSelectedClass(); if (stageClass == null) { return; } try { CvStage stage = stageClass.newInstance(); editor.getPipeline().add(stage); stagesTableModel.refresh(); Helpers.selectLastTableRow(stagesTable); editor.process(); } catch (Exception e) { MessageBoxes.errorBox(JOptionPane.getFrameForComponent(PipelinePanel.this), "Error", e); } } }; public Action deleteStageAction = new AbstractAction() { { putValue(SMALL_ICON, Icons.delete); putValue(NAME, "Delete Stage..."); putValue(SHORT_DESCRIPTION, "Delete the selected stage."); } @Override public void actionPerformed(ActionEvent arg0) { CvStage stage = getSelectedStage(); editor.getPipeline().remove(stage); stagesTableModel.refresh(); editor.process(); } }; public final Action copyAction = new AbstractAction() { { putValue(SMALL_ICON, Icons.copy); putValue(NAME, "Copy Pipeline to Clipboard"); putValue(SHORT_DESCRIPTION, "Copy the pipeline to the clipboard in text format."); } @Override public void actionPerformed(ActionEvent arg0) { try { StringSelection stringSelection = new StringSelection(editor.getPipeline().toXmlString()); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(stringSelection, null); } catch (Exception e) { MessageBoxes.errorBox(getTopLevelAncestor(), "Copy Failed", e); } } }; public final Action pasteAction = new AbstractAction() { { putValue(SMALL_ICON, Icons.paste); putValue(NAME, "Create Pipeline from Clipboard"); putValue(SHORT_DESCRIPTION, "Create a new pipeline from a definition on the clipboard."); } @Override public void actionPerformed(ActionEvent arg0) { try { Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); String s = (String) clipboard.getData(DataFlavor.stringFlavor); editor.getPipeline().fromXmlString(s); stagesTableModel.refresh(); Helpers.selectLastTableRow(stagesTable); editor.process(); } catch (Exception e) { MessageBoxes.errorBox(getTopLevelAncestor(), "Paste Failed", e); } } }; public final Action refreshAction = new AbstractAction() { { putValue(SMALL_ICON, Icons.refresh); putValue(NAME, ""); putValue(SHORT_DESCRIPTION, ""); } @Override public void actionPerformed(ActionEvent arg0) { editor.process(); } }; }