001: package net.suberic.util.gui.propedit;
002:
003: import javax.swing.*;
004: import net.suberic.util.*;
005: import java.awt.CardLayout;
006: import javax.swing.event.*;
007: import java.util.*;
008: import javax.swing.*;
009:
010: /**
011: * This class will make an editor for a list of elements, where each of
012: * the elements has a set of subproperties.
013: *
014: * Configuration is as follows:
015: *
016: * Foo.propertyType=Multi -- shows this is a property editor for an
017: * attribute with multiple values.
018: *
019: * Foo.editableFields=bar:baz -- shows which subfields are to be edited
020: *
021: *
022: * So if your Foo property equals "fooOne:fooTwo", then you'll end up with
023: * a MultiPropertyEditor that has an entry for fooOne and fooTwo, along with
024: * ways to add and delete these properties.
025: *
026: * If your Foo.editableFields=bar:baz, then your editor screen for, say,
027: * fooOne will have two entries, one for Foo.fooOne.bar, and the other for
028: * Foo.fooOne.baz. These editors will use Foo.editableFields.bar and
029: * Foo.editableFields.baz for templates.
030: *
031: */
032:
033: public class MultiEditorPane extends CompositeSwingPropertyEditor
034: implements ListSelectionListener {
035:
036: JList optionList;
037: JPanel entryPanel;
038: JLabel label;
039: boolean changed = false;
040: Vector removeValues = new Vector();
041: DefaultListModel optionListModel;
042: Vector templates;
043: Box optionBox;
044: List buttonList;
045:
046: Hashtable originalPanels = new Hashtable();
047: Hashtable currentPanels = new Hashtable();
048:
049: /**
050: * This configures this editor with the following values.
051: *
052: * @param propertyName The property to be edited.
053: * @param template The property that will define the layout of the
054: * editor.
055: * @param manager The PropertyEditorManager that will manage the
056: * changes.
057: * @param isEnabled Whether or not this editor is enabled by default.
058: */
059: public void configureEditor(String propertyName, String template,
060: PropertyEditorManager newManager, boolean isEnabled) {
061: property = propertyName;
062: manager = newManager;
063: editorTemplate = template;
064: originalValue = manager.getProperty(property, "");
065:
066: if (manager.getProperty(
067: editorTemplate + "._useTemplateForValue", "false")
068: .equalsIgnoreCase("true")) {
069: originalValue = manager.getProperty(editorTemplate, "");
070: } else {
071: originalValue = manager.getProperty(property, "");
072: }
073:
074: // set the default label.
075:
076: label = createLabel();
077:
078: // create the current list of edited items. so if this is a User list,
079: // these values might be 'allen', 'deborah', 'marc', 'jessica', etc.
080:
081: Vector optionVector = createEditedList(originalValue);
082:
083: optionListModel = new DefaultListModel();
084:
085: for (int i = 0; i < optionVector.size(); i++) {
086: optionListModel.addElement(optionVector.elementAt(i));
087: }
088:
089: optionList = new JList(optionListModel);
090:
091: optionBox = createOptionBox(label, optionList);
092: this .add(optionBox);
093:
094: // now create the list of subproperties to be edited.
095:
096: template = editorTemplate + ".editableFields";
097:
098: Vector templateNames = createEditedList(manager.getProperty(
099: template, ""));
100:
101: templates = new Vector();
102: for (int i = 0; i < templateNames.size(); i++) {
103: templates.add(new String(template + "."
104: + (String) templateNames.get(i)));
105: }
106:
107: editors = new Vector();
108:
109: // create entryPanels (the panels which show the subproperties
110: // of each item in the optionList) for each option.
111:
112: entryPanel = createEntryPanel(optionVector, true);
113:
114: if (manager.getProperty(template + "._useScrollPane", "false")
115: .equalsIgnoreCase("true")) {
116: JScrollPane jsp = new JScrollPane(entryPanel);
117: java.awt.Dimension size = jsp.getPreferredSize();
118: size.height = Math.min(size.height, 300);
119: size.width = Math.min(size.width, 475);
120: jsp.setPreferredSize(size);
121: this .add(jsp);
122: valueComponent = jsp;
123: } else {
124: this .add(entryPanel);
125: valueComponent = entryPanel;
126: }
127:
128: labelComponent = optionBox;
129:
130: this .setEnabled(isEnabled);
131:
132: manager.registerPropertyEditor(property, this );
133: }
134:
135: /**
136: * Creates the list of edited items.
137: */
138: private Vector createEditedList(String origValue) {
139: Vector items = new Vector();
140: StringTokenizer tokens;
141:
142: tokens = new StringTokenizer(origValue, ":");
143:
144: for (int i = 0; tokens.hasMoreTokens(); i++) {
145: items.add(tokens.nextToken());
146: }
147: return items;
148: }
149:
150: /**
151: * Creates the option box.
152: */
153: private Box createOptionBox(JLabel label, JList itemList) {
154: Box optBox = new Box(BoxLayout.Y_AXIS);
155: optBox.add(label);
156:
157: optionList.addListSelectionListener(this );
158: JScrollPane listScrollPane = new JScrollPane(optionList);
159: optBox.add(listScrollPane);
160:
161: if (!manager.getProperty(property + "._fixed", "false")
162: .equalsIgnoreCase("true"))
163: optBox.add(createButtonBox());
164:
165: return optBox;
166: }
167:
168: /**
169: * This creates a panel for each option. It uses a CardLayout.
170: *
171: * Note that this is also the section of code which determines which
172: * subproperties are to be edited.
173: */
174: private JPanel createEntryPanel(Vector itemList, boolean original) {
175: JPanel entryPanel = new JPanel(new CardLayout());
176:
177: String rootProp;
178: Vector propList;
179: Vector templateList;
180:
181: // create the default
182:
183: int i = itemList.size();
184:
185: rootProp = new String(property + "._default");
186:
187: SwingPropertyEditor pep = createEditorPane(rootProp,
188: editorTemplate + ".editableFields");
189: pep.setEnabled(false);
190:
191: if (original == true) {
192: originalPanels.put("___default", pep);
193: }
194:
195: currentPanels.put("___default", pep);
196: editors.add(pep);
197:
198: entryPanel.add("___default", pep);
199: CardLayout entryLayout = (CardLayout) entryPanel.getLayout();
200: entryLayout.show(entryPanel, "___default");
201:
202: return entryPanel;
203: }
204:
205: /**
206: * Creates the box which holds the "Add" and "Remove" buttons.
207: */
208: private Box createButtonBox() {
209: buttonList = new ArrayList();
210: Box buttonBox = new Box(BoxLayout.X_AXIS);
211:
212: buttonBox.add(createButton("Add", new AbstractAction() {
213: public void actionPerformed(java.awt.event.ActionEvent e) {
214: addNewValue(getNewValueName());
215: }
216: }, true));
217:
218: buttonBox.add(createButton("Remove", new AbstractAction() {
219: public void actionPerformed(java.awt.event.ActionEvent e) {
220: removeSelectedValue();
221: }
222: }, false));
223:
224: /*
225: buttonBox.add(createButton("Rename", new AbstractAction() {
226: public void actionPerformed(java.awt.event.ActionEvent e) {
227: editSelectedValue();
228: }
229: }, false));
230: */
231:
232: return buttonBox;
233: }
234:
235: /**
236: * Creates a Button for the ButtonBox with the appropriate label and
237: * Action.
238: */
239: private JButton createButton(String label, Action e,
240: boolean isDefault) {
241: JButton this Button;
242:
243: this Button = new JButton(manager.getProperty("label." + label,
244: label));
245: String mnemonic = manager.getProperty("label." + label
246: + ".mnemonic", "");
247: if (!mnemonic.equals(""))
248: this Button.setMnemonic(mnemonic.charAt(0));
249:
250: this Button.setSelected(isDefault);
251:
252: this Button.addActionListener(e);
253:
254: buttonList.add(this Button);
255: return this Button;
256: }
257:
258: /**
259: * Called when the selected value changed. Should result in the
260: * entryPane changing.
261: */
262: public void valueChanged(ListSelectionEvent e) {
263:
264: boolean resize = false;
265: CardLayout entryLayout = (CardLayout) entryPanel.getLayout();
266:
267: String selectedId = (String) ((JList) e.getSource())
268: .getSelectedValue();
269:
270: if (selectedId != null) {
271: Object newSelected = currentPanels.get(selectedId);
272: if (newSelected == null) {
273: String rootProp = new String(property + "."
274: + selectedId);
275: SwingPropertyEditor sep = createEditorPane(rootProp,
276: editorTemplate + ".editableFields");
277:
278: // save reference to new pane in hash table
279: currentPanels.put(selectedId, sep);
280: editors.add(sep);
281:
282: entryPanel.add(selectedId, sep);
283: resize = true;
284: }
285: entryLayout.show(entryPanel, selectedId);
286: } else
287: entryLayout.show(entryPanel, "___default");
288:
289: if (resize)
290: doResize();
291: }
292:
293: /**
294: * Adds a new value to the edited List.
295: */
296: public void addNewValue(String newValueName) {
297: if (newValueName == null || newValueName.length() == 0)
298: return;
299:
300: try {
301: // get what will be the new value.
302: String newValueString = getStringFromList(optionListModel);
303: newValueString = newValueString + "." + newValueName;
304: firePropertyChangingEvent(newValueString);
305:
306: String rootProp = new String(property + "." + newValueName);
307:
308: SwingPropertyEditor pep = createEditorPane(rootProp,
309: editorTemplate + ".editableFields");
310:
311: optionListModel.addElement(newValueName);
312:
313: entryPanel.add(newValueName, pep);
314:
315: getOptionList().setSelectedValue(newValueName, true);
316:
317: this .setChanged(true);
318:
319: firePropertyChangedEvent(getStringFromList(optionListModel));
320:
321: } catch (PropertyValueVetoException pvve) {
322: manager.getFactory().showError(
323: this ,
324: "Error adding value " + newValueName + " to "
325: + label.getText() + ": "
326: + pvve.getReason());
327: }
328: }
329:
330: /**
331: * Removes the currently selected value from the edited List.
332: */
333: public void removeSelectedValue() {
334:
335: String selValue = (String) getOptionList().getSelectedValue();
336: if (selValue == null)
337: return;
338:
339: try {
340: DefaultListModel tmpListModel = new DefaultListModel();
341: for (int i = 0; i < optionListModel.size(); i++) {
342: tmpListModel.addElement(optionListModel.get(i));
343: }
344:
345: tmpListModel.removeElement(selValue);
346: firePropertyChangingEvent(getStringFromList(tmpListModel));
347:
348: String rootProp = new String(property
349: .concat("." + selValue));
350: PropertyEditorUI removedUI = (PropertyEditorUI) currentPanels
351: .get(selValue);
352: if (removedUI != null) {
353: editors.remove(removedUI);
354: java.util.Properties removedProperties = removedUI
355: .getValue();
356: java.util.Enumeration keys = removedProperties.keys();
357: while (keys.hasMoreElements()) {
358: String currentKey = (String) keys.nextElement();
359: removeValues.add(currentKey);
360: }
361:
362: currentPanels.remove(selValue);
363: }
364:
365: optionListModel.removeElement(selValue);
366: firePropertyChangedEvent(getStringFromList(tmpListModel));
367:
368: this .setChanged(true);
369: } catch (PropertyValueVetoException pvve) {
370: manager.getFactory().showError(
371: this ,
372: "Error removing value " + selValue + " from "
373: + label.getText() + ": "
374: + pvve.getReason());
375: }
376:
377: }
378:
379: /**
380: * Edits the currently selected value.
381: */
382: public void editSelectedValue() {
383: }
384:
385: /**
386: * Puts up a dialog to get a name for the new value.
387: */
388: public String getNewValueName() {
389: boolean goodValue = false;
390: boolean matchFound = false;
391:
392: String newName = null;
393: newName = manager.getFactory().showInputDialog(
394: this ,
395: manager.getProperty("MultiEditorPane.renameProperty",
396: "Enter new name."));
397:
398: while (goodValue == false) {
399: matchFound = false;
400: if (newName != null) {
401: for (int i = 0; i < optionListModel.getSize()
402: && matchFound == false; i++) {
403: if (((String) optionListModel.getElementAt(i))
404: .equals(newName))
405: matchFound = true;
406:
407: }
408:
409: if (matchFound == false)
410: goodValue = true;
411: else
412: newName = manager
413: .getFactory()
414: .showInputDialog(
415: this ,
416: manager
417: .getProperty(
418: "MultiEditorPane.error.duplicateName",
419: "Name already exists:")
420: + " "
421: + newName
422: + "\n"
423: + manager
424: .getProperty(
425: "MultiEditorPane.renameProperty",
426: "Enter new name."));
427: } else {
428: goodValue = true;
429: }
430: }
431:
432: return newName;
433: }
434:
435: /**
436: * This renames the selected property.
437: */
438: public void renameProperty(String oldName, String newName) {
439: /*
440: newName = getNewValueName();
441: if (newName != null) {
442: CompositeEditorPane oldPane = (CompositeEditorPane)currentPanels.get(oldName);
443: if (oldPane != null) {
444:
445: String rootProp =new String(property.concat("." + newName));
446:
447: CompositeEditorPane pep = new CompositeEditorPane(manager, rootProp, editorTemplate);;
448: java.util.Properties oldProps = oldPane.getValue();
449: }
450: }
451: */
452: }
453:
454: /**
455: * This produces a string for the given JList.
456: */
457: public String getStringFromList(DefaultListModel dlm) {
458:
459: String retVal;
460: if (dlm.getSize() < 1)
461: return "";
462: else
463: retVal = new String((String) dlm.getElementAt(0));
464:
465: for (int i = 1; i < dlm.getSize(); i++) {
466: retVal = retVal.concat(":" + (String) dlm.getElementAt(i));
467: }
468:
469: return retVal;
470: }
471:
472: /**
473: * Sets the value for this MultiEditorPane.
474: */
475: public void setValue() throws PropertyValueVetoException {
476: if (isEnabled()) {
477:
478: for (int i = 0; i < removeValues.size(); i++)
479: manager.removeProperty((String) removeValues
480: .elementAt(i));
481:
482: removeValues = new Vector();
483:
484: super .setValue();
485:
486: if (isChanged()) {
487: if (debug) {
488: System.out
489: .println("setting property. property is "
490: + property
491: + "; getStringFromList is "
492: + getStringFromList(optionListModel));
493: }
494: manager.setProperty(property,
495: getStringFromList(optionListModel));
496: }
497: }
498: }
499:
500: /**
501: * Resets the default values.
502: */
503: public void resetDefaultValue() throws PropertyValueVetoException {
504:
505: removeValues = new Vector();
506:
507: if (isChanged()) {
508: firePropertyChangingEvent(originalValue);
509: optionListModel.removeAllElements();
510: entryPanel.removeAll();
511:
512: java.util.Enumeration en = originalPanels.keys();
513:
514: while (en.hasMoreElements()) {
515: String key = (String) en.nextElement();
516: entryPanel.add(key, (JPanel) originalPanels.get(key));
517: }
518: firePropertyChangedEvent(originalValue);
519: }
520:
521: java.awt.Component[] components = entryPanel.getComponents();
522: for (int i = 0; i < components.length; i++) {
523: ((CompositeEditorPane) components[i]).resetDefaultValue();
524: }
525: }
526:
527: /**
528: * Returns the currently edited values as a Properties object.
529: */
530: public java.util.Properties getValue() {
531: java.util.Properties currentRetValue = super .getValue();
532: currentRetValue.setProperty(property,
533: getStringFromList(optionListModel));
534: return currentRetValue;
535: }
536:
537: /**
538: * Returns whether or not the top-level edited values of this EditorPane
539: * have changed.
540: */
541: public boolean isChanged() {
542: return changed;
543: }
544:
545: /**
546: * Sets whether or not the top-level edited values of this EditorPane
547: * have changed.
548: */
549: public void setChanged(boolean newChanged) {
550: changed = newChanged;
551: }
552:
553: /**
554: * Returns the optionList.
555: */
556: public JList getOptionList() {
557: return optionList;
558: }
559:
560: /**
561: * Returns the entryPanel.
562: */
563: public JPanel getEntryPanel() {
564: return entryPanel;
565: }
566:
567: /**
568: * Creates an editor.
569: */
570: public SwingPropertyEditor createEditorPane(String subProperty,
571: String subTemplate) {
572: return (SwingPropertyEditor) manager.getFactory().createEditor(
573: subProperty, subTemplate, "Composite", manager, true);
574: }
575:
576: /**
577: * Sets this enabled or disabled.
578: */
579: public void setEnabled(boolean newValue) {
580:
581: optionList.setEnabled(newValue);
582: for (int i = 0; i < buttonList.size(); i++) {
583: ((JButton) buttonList.get(i)).setEnabled(newValue);
584: }
585:
586: Object defaultEditor = originalPanels.get("___default");
587: for (int i = 0; i < editors.size(); i++) {
588: PropertyEditorUI current = (PropertyEditorUI) editors
589: .get(i);
590: if (current != defaultEditor) {
591: current.setEnabled(newValue);
592: }
593: }
594:
595: enabled = newValue;
596: }
597:
598: }
|