/* * Copyright (C) 2011 Jason von Nieda <jason@vonnieda.org> * * This file is package of OpenPnP. * * OpenPnP 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 3 of the * License, or (at your option) any later version. * * OpenPnP 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 OpenPnP. If not, see * <http://www.gnu.org/licenses/>. * * For more information about OpenPnP visit http://openpnp.org */ package org.openpnp.gui; import java.awt.BorderLayout; import java.awt.Frame; 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.ComponentAdapter; import java.awt.event.ComponentEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import java.util.prefs.Preferences; import java.util.regex.PatternSyntaxException; import java.util.stream.Collectors; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.JToolBar; import javax.swing.ListSelectionModel; import javax.swing.RowFilter; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.TableRowSorter; import org.openpnp.gui.components.AutoSelectTextTable; import org.openpnp.gui.components.CameraView; import org.openpnp.gui.support.ActionGroup; import org.openpnp.gui.support.Helpers; import org.openpnp.gui.support.Icons; import org.openpnp.gui.support.MessageBoxes; import org.openpnp.gui.tablemodel.PackagesTableModel; import org.openpnp.model.Configuration; import org.openpnp.model.Package; import org.openpnp.model.Part; import org.openpnp.spi.Camera; import org.pmw.tinylog.Logger; import org.simpleframework.xml.Serializer; @SuppressWarnings("serial") public class PackagesPanel extends JPanel { private static final String PREF_DIVIDER_POSITION = "PackagesPanel.dividerPosition"; private static final int PREF_DIVIDER_POSITION_DEF = -1; private Preferences prefs = Preferences.userNodeForPackage(PackagesPanel.class); final private Configuration configuration; final private Frame frame; private PackagesTableModel tableModel; private TableRowSorter<PackagesTableModel> tableSorter; private JTextField searchTextField; private JTable table; private ActionGroup singleSelectionActionGroup; private ActionGroup multiSelectionActionGroup; public PackagesPanel(Configuration configuration, Frame frame) { this.configuration = configuration; this.frame = frame; singleSelectionActionGroup = new ActionGroup(deletePackageAction, copyPackageToClipboardAction); singleSelectionActionGroup.setEnabled(false); multiSelectionActionGroup = new ActionGroup(deletePackageAction); multiSelectionActionGroup.setEnabled(false); setLayout(new BorderLayout(0, 0)); tableModel = new PackagesTableModel(configuration); tableSorter = new TableRowSorter<>(tableModel); JPanel toolbarAndSearch = new JPanel(); add(toolbarAndSearch, BorderLayout.NORTH); toolbarAndSearch.setLayout(new BorderLayout(0, 0)); JToolBar toolBar = new JToolBar(); toolBar.setFloatable(false); toolbarAndSearch.add(toolBar); JPanel panel_1 = new JPanel(); toolbarAndSearch.add(panel_1, BorderLayout.EAST); JLabel lblSearch = new JLabel("Search"); panel_1.add(lblSearch); searchTextField = new JTextField(); searchTextField.getDocument().addDocumentListener(new DocumentListener() { @Override public void removeUpdate(DocumentEvent e) { search(); } @Override public void insertUpdate(DocumentEvent e) { search(); } @Override public void changedUpdate(DocumentEvent e) { search(); } }); panel_1.add(searchTextField); searchTextField.setColumns(15); JSplitPane splitPane = new JSplitPane(); splitPane.setContinuousLayout(true); splitPane .setDividerLocation(prefs.getInt(PREF_DIVIDER_POSITION, PREF_DIVIDER_POSITION_DEF)); splitPane.addPropertyChangeListener("dividerLocation", new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { prefs.putInt(PREF_DIVIDER_POSITION, splitPane.getDividerLocation()); } }); add(splitPane, BorderLayout.CENTER); JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); JPanel footprintPanel = new JPanel(); footprintPanel.setLayout(new BorderLayout()); tabbedPane.add("Footprint", new JScrollPane(footprintPanel)); table = new AutoSelectTextTable(tableModel); table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } List<Package> selections = getSelections(); if (selections.size() > 1) { singleSelectionActionGroup.setEnabled(false); multiSelectionActionGroup.setEnabled(true); } else { multiSelectionActionGroup.setEnabled(false); singleSelectionActionGroup.setEnabled(!selections.isEmpty()); } Package pkg = getSelection(); footprintPanel.removeAll(); if (pkg != null) { footprintPanel.add(new FootprintPanel(pkg.getFootprint()), BorderLayout.CENTER); } revalidate(); repaint(); } }); table.setRowSorter(tableSorter); splitPane.setLeftComponent(new JScrollPane(table)); splitPane.setRightComponent(tabbedPane); toolBar.add(newPackageAction); toolBar.add(deletePackageAction); toolBar.addSeparator(); toolBar.add(copyPackageToClipboardAction); toolBar.add(pastePackageToClipboardAction); addComponentListener(new ComponentAdapter() { @Override public void componentHidden(ComponentEvent e) { try { Camera camera = Configuration.get().getMachine().getDefaultHead().getDefaultCamera(); CameraView cameraView = MainFrame.get().getCameraViews().getCameraView(camera); if (cameraView == null) { return; } cameraView.removeReticle(FootprintPanel.class.getName()); } catch (Exception e1) { } } }); } private Package getSelection() { List<Package> selections = getSelections(); if (selections.size() != 1) { return null; } return selections.get(0); } private List<Package> getSelections() { List<Package> selections = new ArrayList<>(); for (int selectedRow : table.getSelectedRows()) { selectedRow = table.convertRowIndexToModel(selectedRow); selections.add(tableModel.getPackage(selectedRow)); } return selections; } private void search() { RowFilter<PackagesTableModel, Object> rf = null; // If current expression doesn't parse, don't update. try { rf = RowFilter.regexFilter("(?i)" + searchTextField.getText().trim()); } catch (PatternSyntaxException e) { Logger.warn("Search failed", e); return; } tableSorter.setRowFilter(rf); } public final Action newPackageAction = new AbstractAction() { { putValue(SMALL_ICON, Icons.add); putValue(NAME, "New Package..."); putValue(SHORT_DESCRIPTION, "Create a new package, specifying it's ID."); } @Override public void actionPerformed(ActionEvent arg0) { String id; while ((id = JOptionPane.showInputDialog(frame, "Please enter an ID for the new package.")) != null) { if (configuration.getPackage(id) != null) { MessageBoxes.errorBox(frame, "Error", "Package ID " + id + " already exists."); continue; } Package this_package = new Package(id); configuration.addPackage(this_package); tableModel.fireTableDataChanged(); Helpers.selectLastTableRow(table); break; } } }; public final Action deletePackageAction = new AbstractAction() { { putValue(SMALL_ICON, Icons.delete); putValue(NAME, "Delete Package"); putValue(SHORT_DESCRIPTION, "Delete the currently selected package."); } @Override public void actionPerformed(ActionEvent arg0) { // Check to make sure there are no parts using this package. List<Package> selections = getSelections(); for (Package pkg : selections) { for (Part part : Configuration.get().getParts()) { if (part.getPackage() == pkg) { MessageBoxes.errorBox(getTopLevelAncestor(), "Error", getSelection().getId() + " cannot be deleted. It is used by " + part.getId()); return; } } } List<String> ids = selections.stream().map(Package::getId).collect(Collectors.toList()); String formattedIds; if (ids.size() <= 3) { formattedIds = String.join(", ", ids); } else { formattedIds = String.join(", ", ids.subList(0, 3)) + ", and " + (ids.size() - 3) + " others"; } int ret = JOptionPane.showConfirmDialog(getTopLevelAncestor(), "Are you sure you want to delete " + formattedIds + "?", "Delete " + selections.size() + " packages?", JOptionPane.YES_NO_OPTION); if (ret == JOptionPane.YES_OPTION) { for (Package pkg : selections) { Configuration.get().removePackage(pkg); } } } }; public final Action copyPackageToClipboardAction = new AbstractAction() { { putValue(SMALL_ICON, Icons.copy); putValue(NAME, "Copy Package to Clipboard"); putValue(SHORT_DESCRIPTION, "Copy the currently selected package to the clipboard in text format."); } @Override public void actionPerformed(ActionEvent arg0) { Package pkg = getSelection(); if (pkg == null) { return; } try { Serializer s = Configuration.get().createSerializer(); StringWriter w = new StringWriter(); s.write(pkg, w); StringSelection stringSelection = new StringSelection(w.toString()); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(stringSelection, null); } catch (Exception e) { MessageBoxes.errorBox(getTopLevelAncestor(), "Copy Failed", e); } } }; public final Action pastePackageToClipboardAction = new AbstractAction() { { putValue(SMALL_ICON, Icons.paste); putValue(NAME, "Create Package from Clipboard"); putValue(SHORT_DESCRIPTION, "Create a new package from a definition on the clipboard."); } @Override public void actionPerformed(ActionEvent arg0) { try { Serializer ser = Configuration.get().createSerializer(); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); String s = (String) clipboard.getData(DataFlavor.stringFlavor); StringReader r = new StringReader(s); Package pkg = ser.read(Package.class, s); for (int i = 0;; i++) { if (Configuration.get().getPackage(pkg.getId() + "-" + i) == null) { pkg.setId(pkg.getId() + "-" + i); Configuration.get().addPackage(pkg); break; } } tableModel.fireTableDataChanged(); Helpers.selectLastTableRow(table); } catch (Exception e) { MessageBoxes.errorBox(getTopLevelAncestor(), "Paste Failed", e); } } }; }