View Javadoc

1   /*
2    * Copyright (c) 1998-2004 The Jgroup Team.
3    *
4    * This program is free software; you can redistribute it and/or modify
5    * it under the terms of the GNU Lesser General Public License version 2 as
6    * published by the Free Software Foundation.
7    *
8    * This program is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   * GNU Lesser General Public License for more details.
12   *
13   * You should have received a copy of the GNU Lesser General Public License
14   * along with this program; if not, write to the Free Software
15   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16   *
17   */
18  
19  package jgroup.experiment.gui.views.helpers;
20  
21  import java.awt.Color;
22  import java.awt.GridBagConstraints;
23  import java.awt.GridBagLayout;
24  import java.awt.event.ActionEvent;
25  import java.awt.event.ActionListener;
26  import java.util.Enumeration;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.Map;
30  
31  import javax.swing.BorderFactory;
32  import javax.swing.JButton;
33  import javax.swing.JComboBox;
34  import javax.swing.JLabel;
35  import javax.swing.JOptionPane;
36  import javax.swing.JPanel;
37  import javax.swing.JScrollPane;
38  import javax.swing.JTextField;
39  import javax.swing.JTree;
40  import javax.swing.ScrollPaneConstants;
41  import javax.swing.event.TreeSelectionEvent;
42  import javax.swing.event.TreeSelectionListener;
43  import javax.swing.tree.DefaultMutableTreeNode;
44  import javax.swing.tree.DefaultTreeModel;
45  import javax.swing.tree.TreePath;
46  import javax.swing.tree.TreeSelectionModel;
47  
48  import jgroup.relacs.config.ExperimentConfig;
49  
50  import org.w3c.dom.Document;
51  import org.w3c.dom.Element;
52  
53  /**
54   * @author Bjarte Svaeren
55   */
56  public class PropertiesPanelManager implements PanelManager
57  {
58    ////////////////////////////////////////////////////////////////////////////////////////////
59    // GUI fields
60    ////////////////////////////////////////////////////////////////////////////////////////////
61  
62    // The panel to managed:
63    private JPanel                 propertiesPanel = null;
64    
65    // Components of propertiesPanel:
66    private JPanel                 inputPanel;
67    private JTree                  propertiesTree;
68    private DefaultMutableTreeNode rootNode;
69    private DefaultTreeModel       treeModel;
70    private JScrollPane            propertiesScroller;
71    
72    // Components of inputPanel:
73    private JPanel                 textPanel;
74    private JPanel                 buttonPanel;
75  
76    // Components of textPanel:
77    private JLabel                 nameLabel;
78    private JLabel                 valueLabel;
79    private JLabel                 referenceLabel;
80    private JTextField             nameField;
81    private JTextField             valueField;
82    private JComboBox              referenceCombo;
83  
84    // Components of buttonPanel:  
85    private JButton                changeButton;
86    private JButton                addButton;
87    private JButton                removeButton;
88    private JButton                clearButton;
89    
90  
91    ////////////////////////////////////////////////////////////////////////////////////////////
92    // Data fields
93    ////////////////////////////////////////////////////////////////////////////////////////////
94  
95    // String containing the script
96    private String script;
97    
98    // HashMap containing the properties
99    private HashMap properties;
100    
101   
102   ////////////////////////////////////////////////////////////////////////////////////////////
103   // Constructor
104   ////////////////////////////////////////////////////////////////////////////////////////////
105 
106   public PropertiesPanelManager(JPanel parentPanel) 
107   {
108     propertiesPanel = parentPanel;
109     properties = new HashMap();
110   }
111 
112 
113   ////////////////////////////////////////////////////////////////////////////////////////////
114   // Implemented methods from interface PanelManager
115   ////////////////////////////////////////////////////////////////////////////////////////////
116 
117   /* (non-Javadoc)
118    * @see jgroup.experiment.gui.views.helpers.PanelManager#makePanel()
119    */
120   public void makePanel()
121   {
122     initComponents();
123     addListeners();
124     addComponents();
125   }
126 
127 
128   /* (non-Javadoc)
129    * @see jgroup.experiment.gui.views.helpers.PanelManager#updatePanel(jgroup.relacs.config.ExperimentConfig)
130    */
131   public void updatePanel(ExperimentConfig expConfig)
132   {
133     properties = (HashMap) expConfig.getProperties();
134     
135     int index = 0;
136     for (Iterator iter = properties.entrySet().iterator(); iter.hasNext();) {
137       Map.Entry propertyEntry = (Map.Entry) iter.next();
138       String    propertyName  = (String) propertyEntry.getKey(); 
139       String    propertyValue = (String) propertyEntry.getValue();
140       
141       DefaultMutableTreeNode propertyNode
142                            = new DefaultMutableTreeNode(propertyName + " : "
143                                                       + propertyValue, false);
144       treeModel.insertNodeInto(propertyNode, rootNode, index++);
145       
146       // Add the property to the reference combo box        
147       referenceCombo.addItem("${" + propertyName + "}");
148       
149       // Clear the value field
150       valueField.setText("");         
151     }
152   }
153 
154 
155   /* (non-Javadoc)
156    * @see jgroup.experiment.gui.views.helpers.PanelManager#setParentPanel(javax.swing.JPanel)
157    */
158   public void setParentPanel(JPanel panel)
159   {
160     if(propertiesPanel == null)
161       throw new IllegalArgumentException("JPanel hostPanel has already been set");
162       
163     propertiesPanel = panel;
164   }
165 
166 
167   /* (non-Javadoc)
168    * @see jgroup.experiment.gui.views.helpers.PanelManager#clear()
169    */
170   public void clear()
171   {
172     rootNode.removeAllChildren();
173     treeModel.reload();
174     properties.clear();
175     referenceCombo.removeAllItems();
176     nameField.setText("");
177     valueField.setText("");
178   }
179   
180   
181   public void save(Element parentElement, Document document)
182   {
183     DefaultMutableTreeNode rootNode
184                          = (DefaultMutableTreeNode) treeModel.getRoot();
185 
186     // Iterate through the properties and append them to the DOM    
187     for(Enumeration e = rootNode.children(); e.hasMoreElements();) {
188       DefaultMutableTreeNode propertyNode
189                            = (DefaultMutableTreeNode) e.nextElement();
190 
191       String nodeTitle   = (String) propertyNode.getUserObject();
192       int    index       = nodeTitle.indexOf(" : ");
193       String nodeName    = "";
194       String nodeValue   = "";
195 
196       if(index != -1) {
197         nodeName  = nodeTitle.substring(0, index);
198         nodeValue = nodeTitle.substring(index + 3, nodeTitle.length());
199       } else {
200         nodeName  = nodeTitle;
201       }
202 
203       // Append the property element, and set key and value
204       Element propertyElement = document.createElement("Property");
205       propertyElement.setAttribute("key", nodeName);
206       if(nodeValue != null && nodeValue.length() > 0)
207         propertyElement.setAttribute("value", nodeValue);
208       parentElement.appendChild(propertyElement);
209     }
210   }
211 
212   
213   ////////////////////////////////////////////////////////////////////////////////////////////
214   // Private methods
215   ////////////////////////////////////////////////////////////////////////////////////////////
216   
217   private void initComponents()
218   {
219     propertiesPanel.setBorder(BorderFactory.createCompoundBorder(
220                               BorderFactory.createEtchedBorder(),
221                               BorderFactory.createEmptyBorder(5,5,5,5)));                           
222 
223     inputPanel          = new JPanel(new GridBagLayout());
224     textPanel           = new JPanel(new GridBagLayout());
225     buttonPanel         = new JPanel(new GridBagLayout());
226     textPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,20));
227     buttonPanel.setBorder(BorderFactory.createEmptyBorder(10,20,10,10));
228 
229     referenceLabel      = new JLabel("References:");
230     referenceCombo      = new ScrollableComboBox();
231     // Set the width of the combobox using example text
232     referenceCombo.setPrototypeDisplayValue("this.is.a.property");
233         
234     nameLabel           = new JLabel("Property name:");
235     valueLabel          = new JLabel("Property value");
236     nameField           = new JTextField(40);
237     valueField          = new JTextField(40);
238             
239     changeButton        = new JButton("Change");
240     addButton           = new JButton("Add");
241     removeButton        = new JButton("Remove");
242     clearButton         = new JButton("Clear");
243     
244     rootNode            = new DefaultMutableTreeNode("Global properties");
245     treeModel           = new DefaultTreeModel(rootNode);
246     propertiesTree      = new JTree(treeModel);
247     propertiesScroller  = new JScrollPane(propertiesTree);
248     propertiesScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
249     propertiesScroller.setBorder(BorderFactory.createCompoundBorder(
250                                  BorderFactory.createTitledBorder(
251                                  BorderFactory.createEmptyBorder(),
252                                  "Global properties:"),
253                                  BorderFactory.createCompoundBorder(
254                                  BorderFactory.createLineBorder(Color.BLACK,2),
255                                  BorderFactory.createEtchedBorder())));
256                                    
257     treeModel.setAsksAllowsChildren(true);
258     propertiesTree.getSelectionModel().setSelectionMode
259                     (TreeSelectionModel.SINGLE_TREE_SELECTION);
260   }
261   
262   
263   private void addListeners()
264   {
265     addButtonListeners();
266     addTreeListener();
267     addComboListener();
268     // Select the root node by default
269     propertiesTree.setSelectionPath(new TreePath(rootNode));
270   }
271 
272 
273   private void addComponents()
274   {
275     GridBagConstraints gbc = new GridBagConstraints();
276 
277     gbc.gridx     = 0;
278     gbc.fill      = GridBagConstraints.BOTH;
279     textPanel.add(nameLabel, gbc);
280     textPanel.add(nameField, gbc);
281     textPanel.add(valueLabel, gbc);
282     textPanel.add(valueField, gbc);
283     textPanel.add(referenceLabel, gbc);
284     textPanel.add(referenceCombo, gbc);
285     
286     gbc.gridx     = GridBagConstraints.RELATIVE;
287     gbc.fill      = GridBagConstraints.HORIZONTAL;
288     gbc.gridwidth = GridBagConstraints.REMAINDER;
289     buttonPanel.add(changeButton, gbc);
290     buttonPanel.add(removeButton, gbc);
291     buttonPanel.add(clearButton, gbc);
292     buttonPanel.add(addButton, gbc);
293     
294     gbc.fill      = GridBagConstraints.BOTH;
295     gbc.gridwidth = GridBagConstraints.RELATIVE;
296     inputPanel.add(textPanel, gbc);
297     gbc.gridwidth = GridBagConstraints.REMAINDER;
298     inputPanel.add(buttonPanel, gbc);
299     
300     gbc.weightx   = 0.1;
301     gbc.gridwidth = GridBagConstraints.RELATIVE;        
302     propertiesPanel.add(inputPanel, gbc);    
303     gbc.weightx   = 0.68;
304     gbc.weighty   = 0.1;
305     gbc.gridwidth = GridBagConstraints.REMAINDER;
306     propertiesPanel.add(propertiesScroller, gbc);
307   }
308   
309   
310   private void addButtonListeners()
311   {
312     addButton.addActionListener(new ActionListener() {
313       public void actionPerformed(ActionEvent e) {       
314         String name  = nameField.getText();
315         String value = valueField.getText();
316         
317         if(name == null || name.length() == 0) {
318           JOptionPane.showMessageDialog(propertiesPanel.getTopLevelAncestor(),
319                                         "The property must\n"
320                                        +"have a name.",
321                                         "Missing parameter",
322                                         JOptionPane.INFORMATION_MESSAGE);
323           return;          
324         } else if(value == null || value.length() == 0) {
325           JOptionPane.showMessageDialog(propertiesPanel.getTopLevelAncestor(),
326                                         "The property must\n"
327                                        +"have a value.",
328                                         "Missing parameter",
329                                         JOptionPane.INFORMATION_MESSAGE);
330           return;          
331         } else if(properties.containsKey(name)) {
332           JOptionPane.showMessageDialog(propertiesPanel.getTopLevelAncestor(),
333                                         "A property with the name\n"
334                                       + "\"" + name + "\"\n"
335                                       + "already exists.\n",
336                                         "Missing parameter",
337                                         JOptionPane.INFORMATION_MESSAGE);
338           return;
339         }
340 
341         // Add the property to the properties map and the
342         // reference combo box        
343         properties.put(name, value);
344         referenceCombo.addItem("${" + name + "}");
345                         
346         // Then add the property to the tree
347         DefaultMutableTreeNode newNode 
348                       = new DefaultMutableTreeNode(name + " : " + value, false);                               
349         DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)
350                       propertiesTree.getLastSelectedPathComponent();
351 
352         if(selectedNode == null) {
353           treeModel.insertNodeInto(newNode, rootNode, 
354                                    treeModel.getChildCount(rootNode));        
355         } else if(selectedNode.isRoot()) {
356           treeModel.insertNodeInto(newNode, rootNode, 0);                  
357         } else {
358           treeModel.insertNodeInto(newNode, rootNode,
359                                    treeModel.getIndexOfChild(rootNode, selectedNode) + 1);        
360         }
361         
362         treeModel.reload();
363       }
364     });
365     
366     removeButton.addActionListener(new ActionListener() {
367       public void actionPerformed(ActionEvent e) {
368         DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)
369                                propertiesTree.getLastSelectedPathComponent();
370 
371         // Remove the property from the tree, the properties map
372         // and the reference combo box        
373         if(selectedNode != null && !selectedNode.isRoot()) {
374           treeModel.removeNodeFromParent(selectedNode);
375           String name = (String) selectedNode.getUserObject();
376           properties.remove(name);
377           referenceCombo.removeItem("${" + name + "}");
378         }
379       }
380     });
381     
382     clearButton.addActionListener(new ActionListener() {
383       public void actionPerformed(ActionEvent e) {
384         clear();
385       }
386     });
387     
388     changeButton.addActionListener(new ActionListener() {
389       public void actionPerformed(ActionEvent e) {                               
390         DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)
391                                propertiesTree.getLastSelectedPathComponent();
392         String nodeTitle = (String) selectedNode.getUserObject();
393         String oldName   = nodeTitle.substring(0, nodeTitle.indexOf(" :"));
394         String name      = nameField.getText();
395         String value     = valueField.getText();
396         
397         if(name == null || name.length() == 0) {
398           JOptionPane.showMessageDialog(propertiesPanel.getTopLevelAncestor(),
399                                         "The property must\n"
400                                        +"have a name.",
401                                         "Missing parameter",
402                                         JOptionPane.INFORMATION_MESSAGE);
403           return;          
404         } else if(value == null || value.length() == 0) {
405           JOptionPane.showMessageDialog(propertiesPanel.getTopLevelAncestor(),
406                                         "The property must\n"
407                                        +"have a value.",
408                                         "Missing parameter",
409                                         JOptionPane.INFORMATION_MESSAGE);
410           return;
411         } else if(properties.containsKey(name)) {
412           if(!name.equals(oldName)) {
413             JOptionPane.showMessageDialog(propertiesPanel.getTopLevelAncestor(),
414                                           "A property with the name\n"
415                                         + "\"" + name + "\"\n"
416                                         + "already exists.\n"
417                                         + "Use the Change button to\n"
418                                         + "change the value of the property.",
419                                           "Missing parameter",
420                                           JOptionPane.INFORMATION_MESSAGE);
421             return;
422           }
423         }
424 
425         // Create a node with the new name and value
426         DefaultMutableTreeNode newNode
427                              = new DefaultMutableTreeNode(name + " : "
428                                                         + value, false);
429         // Find the index of the node to be replaced
430         int index = rootNode.getIndex(selectedNode);
431         // Remove the old node and insert the new node
432         rootNode.remove(index);
433         rootNode.insert(newNode, index);
434         properties.remove(oldName);
435         properties.put(name, value);
436         treeModel.reload();
437       }
438     });
439   }
440   
441   
442   private void addTreeListener()
443   {
444     propertiesTree.addTreeSelectionListener(new TreeSelectionListener() {
445       public void valueChanged(TreeSelectionEvent e) {
446         DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)
447                                propertiesTree.getLastSelectedPathComponent();
448                                
449         if(selectedNode == null) {
450           addButton.setEnabled(false);
451           changeButton.setEnabled(false);
452           removeButton.setEnabled(false);
453           clearButton.setEnabled(false);
454           return;          
455         }
456 
457         if(selectedNode.getChildCount() == 0)
458           clearButton.setEnabled(false);
459         else
460           clearButton.setEnabled(true);
461 
462         // If the selected node is the root node,
463         // disable the change and remove buttons.
464         if(selectedNode.isRoot()) {
465           addButton.setEnabled(true);
466           changeButton.setEnabled(false);
467           removeButton.setEnabled(false);
468         } else {
469           // If the node is not the root node, enable buttons
470           // and display property information        
471           addButton.setEnabled(false);
472           changeButton.setEnabled(true);
473           removeButton.setEnabled(true);
474           displayProperty(selectedNode);
475         }
476       }
477     });
478   }
479   
480   
481   private void addComboListener()
482   {
483     // Set the value field to the value of the selected reference
484     referenceCombo.addActionListener(new ActionListener() {
485       public void actionPerformed(ActionEvent e) {
486         if(referenceCombo.getSelectedIndex() != -1) {
487           String reference = (String) referenceCombo.getSelectedItem();
488           // Add the reference in the value field, and give focus to the field
489           valueField.setText(valueField.getText() + reference);
490           valueField.requestFocus();
491         }
492       }
493     });
494   }
495   
496   
497   private void displayProperty(DefaultMutableTreeNode selectedNode)
498   {
499     // Separate property name and value and display them
500     String nodeTitle     = (String) selectedNode.getUserObject();
501     int index = nodeTitle.indexOf(" : ");
502     String propertyName  = nodeTitle.substring(0, index);
503     String propertyValue = nodeTitle.substring(index + 3, nodeTitle.length());
504     
505     nameField.setText(propertyName);
506     valueField.setText( propertyValue.equals("?") ? "" : propertyValue ); 
507   }
508 }