/* * Copyright (c) 2010, SQL Power Group Inc. * * This file is part of SQL Power Library. * * SQL Power Library 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. * * SQL Power Library 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, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.swingui.object; import java.awt.Color; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; import net.miginfocom.swing.MigLayout; import org.apache.commons.collections.map.MultiValueMap; import org.apache.log4j.Logger; import ca.sqlpower.object.SPVariableHelper; import ca.sqlpower.swingui.DataEntryPanel; /** * This calss displays a panel to pick and insert a variable. * @author Luc Boudreau */ public class VariablesPanel implements DataEntryPanel { private final JPanel panel; private String currentPickedVariable = ""; private String currentDefValue = ""; private final SPVariableHelper variableHelper; private final JLabel pickerLabel; private final JTextField varNameText; private final JButton varPicker; private final JLabel varDefaultLabel; private final JTextField varDefaultText; private final JLabel varEditLabel; private final JTextField varEditText; private final JLabel previewLabel; private final JLabel varPreviewLabel1; private final JLabel varPreviewLabel2; private boolean stuffToInsert = true; private final VariableInserter action; private final JLabel optionsLabel; private final JLabel namespaceLabel; private final JCheckBox namespaceBox; private final JLabel generalLabel; private static final Logger logger = Logger.getLogger(VariablesPanel.class); public VariablesPanel( SPVariableHelper variableHelper, VariableInserter action) { this(variableHelper,action,""); } /** * Default constructor for the variables panel. * @param variableHelper A helper that will be used in order to * resolve discover and resolve variables. * @param action An implementation of {@link VariableInserter} that * gets called once the variable has been created. This action will be executed * on the Swing Event Dispatch Thread. * @param varDefinition The default variable definition string. */ public VariablesPanel( SPVariableHelper variableHelper, VariableInserter action, String varDefinition) { this.variableHelper = variableHelper; this.action = action; this.generalLabel = new JLabel("General"); this.generalLabel.setFont(this.generalLabel.getFont().deriveFont(Font.BOLD)); this.pickerLabel = new JLabel("Pick a variable"); this.varNameText = new JTextField(); this.varNameText.setEditable(false); this.varNameText.addMouseListener(new MouseListener() { public void mouseReleased(MouseEvent e) { } public void mousePressed(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseClicked(MouseEvent e) { ShowPickerAction act = new ShowPickerAction(); act.actionPerformed(null); } }); this.varPicker = new JButton(new ShowPickerAction()); this.optionsLabel = new JLabel("Options"); this.optionsLabel.setFont(this.optionsLabel.getFont().deriveFont(Font.BOLD)); this.varDefaultLabel = new JLabel("Default value"); this.varDefaultText = new JTextField(); this.varDefaultText.addKeyListener(new KeyListener() { public void keyTyped(KeyEvent e) { SwingUtilities.invokeLater(new Runnable() { public void run() { currentDefValue = varDefaultText.getText(); updateGUI(); } }); } public void keyReleased(KeyEvent e) { } public void keyPressed(KeyEvent e) { } }); this.varEditLabel = new JLabel("Customization"); this.varEditText = new JTextField(); this.varEditText.addKeyListener(new KeyListener() { public void keyTyped(KeyEvent e) { SwingUtilities.invokeLater(new Runnable() { public void run() { int carPos = varEditText.getCaretPosition(); String text = varEditText.getText().replace("$", "").replace("{", "").replace("}", ""); currentPickedVariable = SPVariableHelper.stripDefaultValue(text); if (currentPickedVariable==null) { currentPickedVariable = ""; } currentDefValue = SPVariableHelper.getDefaultValue(text); if (currentDefValue==null) { currentDefValue = ""; } if (SPVariableHelper.getNamespace(text) == null) { namespaceBox.setSelected(false); } else { namespaceBox.setSelected(true); } updateGUI(); try { varEditText.setCaretPosition(carPos); } catch (IllegalArgumentException e) { varEditText.setCaretPosition(carPos-1); } } }); } public void keyReleased(KeyEvent e) { } public void keyPressed(KeyEvent e) { } }); this.namespaceLabel = new JLabel("Constrain to namespace"); this.namespaceBox = new JCheckBox(""); if (SPVariableHelper.getNamespace(varDefinition) != null || "".equals(varDefinition)) { this.namespaceBox.setSelected(true); } else { this.namespaceBox.setSelected(false); } this.namespaceBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { updateGUI(); } }); this.previewLabel = new JLabel("Preview"); this.previewLabel.setFont(this.previewLabel.getFont().deriveFont(Font.BOLD)); this.varPreviewLabel1 = new JLabel("Current value is"); this.varPreviewLabel1.setForeground(Color.GRAY); this.varPreviewLabel2 = new JLabel(); this.varPreviewLabel2.setForeground(Color.GRAY); this.panel = new JPanel(new MigLayout()); this.panel.add(this.generalLabel, "growx, span, wrap"); this.panel.add(new JLabel(" "), "wmin 20, wmax 20"); this.panel.add(this.pickerLabel); this.panel.add(this.varNameText, "growx, wmin 275, wmax 275, gapright 0"); this.panel.add(this.varPicker, "wmax 20, hmax 20, wrap, gapleft 0"); this.panel.add(this.optionsLabel, "growx, span, wrap"); this.panel.add(new JLabel(" "), "wmin 20, wmax 20"); this.panel.add(this.varDefaultLabel); this.panel.add(this.varDefaultText, "span, wrap, wmin 300, wmax 300"); this.panel.add(new JLabel(" "), "wmin 20, wmax 20"); this.panel.add(namespaceLabel); this.panel.add(namespaceBox, "span, wrap"); this.panel.add(new JLabel(" "), "wmin 20, wmax 20"); this.panel.add(this.varEditLabel); this.panel.add(this.varEditText, "span, wmin 300, wmax 300, wrap"); this.panel.add(this.previewLabel, "growx, span, wrap"); this.panel.add(new JLabel(" "), "wmin 20, wmax 20"); this.panel.add(this.varPreviewLabel1); this.panel.add(this.varPreviewLabel2, "span, growx"); this.currentPickedVariable = varDefinition; updateGUI(); } private void updateGUI() { String text = "${"; if (this.namespaceBox.isSelected()) { text += currentPickedVariable; } else { text += SPVariableHelper.getKey(currentPickedVariable); } if (!currentDefValue.trim().equals("")) { text += SPVariableHelper.DEFAULT_VALUE_DELIMITER; text += currentDefValue; } text += "}"; this.varNameText.setText(currentPickedVariable); this.varDefaultText.setText(currentDefValue); this.varEditText.setText(text); Object resolvedValue = variableHelper.resolve(currentPickedVariable, currentDefValue == null ? "null" : currentDefValue); this.varPreviewLabel2.setText(resolvedValue == null ? "null" : resolvedValue.toString()); } private final class ShowPickerAction extends AbstractAction { public ShowPickerAction() { super("..."); } public void actionPerformed(ActionEvent e) { showVarsPicker(); } } private final class InsertVariableAction extends AbstractAction { private final String var; public InsertVariableAction(String label, String var) { super(label); this.var = var; } public void actionPerformed(ActionEvent e) { currentPickedVariable = var; updateGUI(); } } public boolean applyChanges() { final String variable = varEditText.getText(); SwingUtilities.invokeLater(new Runnable() { public void run() { action.insert(variable); } }); this.stuffToInsert = false; return true; } public void discardChanges() { this.stuffToInsert = false; } public JComponent getPanel() { return this.panel; } public boolean hasUnsavedChanges() { return this.stuffToInsert; } @SuppressWarnings("unchecked") private void showVarsPicker() { final MultiValueMap namespaces = this.variableHelper.getNamespaces(); List<String> sortedNames = new ArrayList<String>(namespaces.keySet().size()); sortedNames.addAll(namespaces.keySet()); Collections.sort(sortedNames, new Comparator<String>() { public int compare(String o1, String o2) { if (o1 == null) { return -1; } if (o2 == null) { return 1; } return o1.compareTo(o2); }; }); final JPopupMenu menu = new JPopupMenu(); for (final String name : sortedNames) { final JMenu subMenu = new JMenu(name); menu.add(subMenu); subMenu.addMenuListener(new MenuListener() { private Timer timer; public void menuSelected(MenuEvent e) { subMenu.removeAll(); subMenu.add(new PleaseWaitAction()); ActionListener menuPopulator = new ActionListener() { public void actionPerformed(ActionEvent e) { if (subMenu.isPopupMenuVisible()) { subMenu.removeAll(); for (Object namespaceO : namespaces.getCollection(name)) { String namespace = (String)namespaceO; logger.debug("Resolving variables for namespace ".concat(namespace)); int nbItems = 0; for (String key : variableHelper.keySet(namespace)) { subMenu.add(new InsertVariableAction(SPVariableHelper.getKey((String)key), (String)key)); nbItems++; } if (nbItems==0) { subMenu.add(new DummyAction()); logger.debug("No variables found."); } } subMenu.revalidate(); subMenu.getPopupMenu().pack(); } } }; timer = new Timer(700, menuPopulator); timer.setRepeats(false); timer.start(); } public void menuDeselected(MenuEvent e) { timer.stop(); } public void menuCanceled(MenuEvent e) { timer.stop(); } }); } menu.show(varNameText, 0, varNameText.getHeight()); } private final class DummyAction extends AbstractAction { public DummyAction() { super("No variables available"); this.setEnabled(false); } public void actionPerformed(ActionEvent e) { } } private final class PleaseWaitAction extends AbstractAction { public PleaseWaitAction() { super("Please wait..."); this.setEnabled(false); } public void actionPerformed(ActionEvent e) { } } // public static void main(String[] args) { // SwingUtilities.invokeLater(new Runnable() { // public void run() { // try { // // JFrame f = new JFrame("TEST PANEL"); // JPanel outerPanel = new JPanel(new BorderLayout()); // outerPanel.setBorder(BorderFactory.createLineBorder(Color.BLUE)); // // MockSPObject root = new MockSPObject("root"); // root.setResolver(new SPSimpleVariableResolver(root, root.getUUID(), root.getName())); // root.begin("Begin tree building..."); // MockSPObject node1 = new MockSPObject("node1"); // MockSPObject node2 = new MockSPObject("node2"); // MockSPObject node3 = new MockSPObject("node3"); // root.addChild(node1, 0); // root.addChild(node2, 1); // node2.addChild(node3, 0); // root.commit(); // // node1.getVariableResolver().store("key1", "value1"); // node2.getVariableResolver().store("key2", "value2"); // node3.getVariableResolver().store("key3", "value3"); // node3.getVariableResolver().store("key4", "value4"); // // SPVariableHelper helper = new SPVariableHelper(node3); // // VariablesPanel panel = new VariablesPanel(helper, new VariableInserter() { // public void insert(String variable) { // } // }); // // // outerPanel.add(panel.getPanel(), BorderLayout.CENTER); // f.setContentPane(outerPanel); // f.pack(); // f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // f.setVisible(true); // // } catch (Exception ex) { // throw new RuntimeException(ex); // } // } // }); // } // // private static class MockSPObject extends AbstractSPObject implements SPVariableResolverProvider { // private List<SPObject> children = new ArrayList<SPObject>(); // private SPSimpleVariableResolver resolver = null; // public MockSPObject(String name) { // this.setName(name); // } // @Override // public void setParent(SPObject parent) { // super.setParent(parent); // this.resolver = new SPSimpleVariableResolver(this, this.getUUID(), this.getName()); // } // public void setResolver(SPSimpleVariableResolver resolver) { // this.resolver = resolver; // } // protected boolean removeChildImpl(SPObject child) { // return this.children.remove(child); // } // public boolean allowsChildren() { // return true; // } // public int childPositionOffset(Class<? extends SPObject> childType) { // return 0; // } // public List<? extends SPObject> getChildren() { // return this.children; // } // public List<? extends SPObject> getDependencies() { // return Collections.emptyList(); // } // public void removeDependency(SPObject dependency) { // return; // } // public SPSimpleVariableResolver getVariableResolver() { // return this.resolver; // } // @Override // protected void addChildImpl(SPObject child, int index) { // this.children.add(child); // } // public List<Class<? extends SPObject>> getAllowedChildTypes() { // List<Class<? extends SPObject>> types = new ArrayList<Class <? extends SPObject>>(); // types.add(SPObject.class); // return types; // } // } }