source: trunk/gli/src/org/greenstone/gatherer/valuetree/GValueTree.java@ 4354

Last change on this file since 4354 was 4354, checked in by jmt12, 21 years ago

Ensure replace is correctly enabled - John

  • Property svn:keywords set to Author Date Id Revision
File size: 31.7 KB
Line 
1package org.greenstone.gatherer.valuetree;
2/**
3 *#########################################################################
4 *
5 * A component of the Gatherer application, part of the Greenstone digital
6 * library suite from the New Zealand Digital Library Project at the
7 * University of Waikato, New Zealand.
8 *
9 * <BR><BR>
10 *
11 * Author: John Thompson, Greenstone Digital Library, University of Waikato
12 *
13 * <BR><BR>
14 *
15 * Copyright (C) 1999 New Zealand Digital Library Project
16 *
17 * <BR><BR>
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * <BR><BR>
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * <BR><BR>
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 *########################################################################
37 */
38import java.awt.*;
39import java.awt.event.*;
40import java.util.*;
41import javax.swing.*;
42import javax.swing.event.*;
43import javax.swing.text.*;
44import javax.swing.tree.*;
45import org.greenstone.gatherer.Gatherer;
46import org.greenstone.gatherer.gui.EditorDialog;
47import org.greenstone.gatherer.gui.MetaEditPane;
48import org.greenstone.gatherer.gui.SmarterTextArea;
49import org.greenstone.gatherer.gui.combobox.GComboBox;
50import org.greenstone.gatherer.gui.combobox.GComboBoxModel;
51import org.greenstone.gatherer.msm.ElementWrapper;
52import org.greenstone.gatherer.msm.Metadata;
53import org.greenstone.gatherer.msm.MetadataComboBoxModel;
54import org.greenstone.gatherer.msm.MSMAction;
55import org.greenstone.gatherer.msm.MSMEvent;
56import org.greenstone.gatherer.msm.MSMListener;
57import org.greenstone.gatherer.util.Utility;
58/**
59 * @author John Thompson, Greenstone Digital Library, University of Waikato
60 * @version 2.2
61 */
62public class GValueTree
63 extends JPanel
64 implements ActionListener, FocusListener, MSMListener, TreeSelectionListener {
65 /** Is the metadata currently shown in the edit controls common to all records selected. */
66 private boolean common = false;
67 /** Certain actions are disabled if the metadata selected isn't at file level. */
68 private boolean file_level = false;
69 private boolean ignore = false;
70 private boolean ignore_item_change = false;
71 private CardLayout card_layout;
72 private DefaultListModel list_model;
73 /** The metadata element that is currently selected. */
74 private ElementWrapper selected_metadata_element = null;
75 //private GComboBox elements;
76 private MetadataComboBoxModel em;
77 private GValueModel vm;
78 private Hashtable previous_values = new Hashtable();
79 private JButton add;
80 /** This button creates an editor dialog to allow for an expanded area to type in text. */
81 private JButton expand = null;
82 private JButton remove;
83 private JButton restore;
84 private JButton search;
85 private JButton update;
86 //private JLabel element_label;
87 private JLabel value_label;
88 private JList list;
89 private JPanel auto_pane;
90 private JPanel button_pane;
91 private JPanel center_pane;
92 //private JPanel list_pane;
93 private JPanel north_pane;
94 //private JPanel south_pane;
95 private JPanel tree_pane;
96 private JPanel value_pane;
97 private JTextArea auto_message;
98 private JTextField value;
99 private JTree tree;
100 private MetaEditPane metaedit;
101 private String args[] = new String[1];
102 private TreePath previous;
103 private ValueListener value_listener;
104 /** Stock standard size for labels. */
105 static final private Dimension LABEL_SIZE = new Dimension(132, 26);
106
107 //static final private String LIST = "List";
108 static final private String NONE = "None";
109 static final private String TREE = "Tree";
110
111
112 public GValueTree(MetaEditPane metaedit, int width, int height, JButton add, JButton update, JButton remove) {
113 this(metaedit, new Dimension(width, height), add, update, remove);
114 }
115
116 public GValueTree(MetaEditPane metaedit, Dimension size, JButton add, JButton update, JButton remove) {
117 super();
118
119 this.add = add;
120 this.metaedit = metaedit;
121 this.remove = remove;
122 this.update = update;
123
124 ///ystem.err.println("Created new ValueListener!");
125 value_listener = new ValueListener();
126
127 int height = size.height;
128 int width = size.width;
129
130 setFont(Gatherer.config.getFont("general.font", false));
131 //setSize(size);
132 setPreferredSize(size);
133
134 //north_pane = new JPanel();
135
136 //element_label = new JLabel(get("Element"));
137 //element_label.setPreferredSize(LABEL_SIZE);
138
139 //elements = new GComboBox();
140 //elements.addItemListener(this);
141 //elements.setEditable(false);
142 //elements.setMaximumRowCount(5);
143 //elements.setPreferredSize(new Dimension(413, 24));
144
145 center_pane = new JPanel();
146
147 card_layout = new CardLayout();
148
149 auto_pane = new JPanel();
150 args[0] = "Title";
151 auto_message = new SmarterTextArea(get("AutoMessage", args), false);
152 auto_message.setLineWrap(true);
153 auto_message.setOpaque(false);
154 auto_message.setWrapStyleWord(true);
155
156 tree_pane = new JPanel();
157
158 JLabel tree_label = new JLabel(get("Tree"));
159
160 tree = new JTree(new GValueModel());
161 tree.addTreeSelectionListener(this);
162 tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
163 tree.setRootVisible(true);
164 tree.putClientProperty("JTree.lineStyle", "Angled");
165 //setTreeEnabled(false);
166
167 //list_pane = new JPanel();
168 //JLabel list_label = new JLabel(get("List"));
169 //list_model = new DefaultListModel();
170 //list = new JList(list_model);
171 //list.addListSelectionListener(new ListSelectionListenerImpl());
172
173 JPanel controls_pane = new JPanel();
174
175 value_pane = new JPanel();
176 value_label = new JLabel(get("Value"));
177 value_label.setPreferredSize(LABEL_SIZE);
178 JPanel edit_pane = new JPanel();
179 expand = new JButton(get("General.Expand"));
180 expand.setMnemonic(KeyEvent.VK_E);
181 expand.setPreferredSize(MetaEditPane.BUTTON_SIZE);
182
183 value = new JTextField();
184 value.addActionListener(this);
185 value.setBackground(Gatherer.config.getColor("coloring.editable", false));
186 value.addFocusListener(this);
187 //value.addKeyListener(this);
188 value.setPreferredSize(new Dimension(413, 24));
189
190 button_pane = new JPanel();
191
192 JPanel inner_button_pane = new JPanel();
193
194 //restore = new JButton(get("Restore"));
195 //restore.setEnabled(false);
196 //restore.setMnemonic(KeyEvent.VK_T);
197
198 //search = new JButton(get("Search"));
199 //search.setMnemonic(KeyEvent.VK_S);
200
201 // Connection
202 expand.addActionListener(this);
203 //restore.addActionListener(this);
204 //search.addActionListener(this);
205 value.getDocument().addDocumentListener(new DocumentListenerImpl());
206
207 // Layout
208 //element_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
209 //north_pane.setLayout(new BorderLayout());
210 //north_pane.add(element_label, BorderLayout.CENTER);
211 //north_pane.add(elements, BorderLayout.EAST);
212
213 tree_pane.setLayout(new BorderLayout());
214 tree_pane.add(tree_label, BorderLayout.NORTH);
215 tree_pane.add(new JScrollPane(tree), BorderLayout.CENTER);
216
217 //list_pane.setLayout(new BorderLayout());
218 //list_pane.add(list_label, BorderLayout.NORTH);
219 //list_pane.add(new JScrollPane(list), BorderLayout.CENTER);
220
221 auto_pane.setBorder(BorderFactory.createEmptyBorder(25,10,25,10));
222 auto_pane.setLayout(new BorderLayout());
223 auto_pane.add(auto_message, BorderLayout.CENTER);
224
225 center_pane.setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
226 center_pane.setLayout(card_layout);
227 center_pane.add(tree_pane, TREE);
228 //center_pane.add(list_pane, LIST);
229 center_pane.add(auto_pane, NONE);
230
231 value_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
232
233 inner_button_pane.setLayout(new GridLayout(3,1,0,0));
234 inner_button_pane.add(add);
235 inner_button_pane.add(update);
236 inner_button_pane.add(remove);
237
238 edit_pane.setLayout(new BorderLayout());
239 edit_pane.add(expand, BorderLayout.NORTH);
240
241 button_pane.setLayout(new BorderLayout());
242 button_pane.add(inner_button_pane, BorderLayout.WEST);
243 button_pane.add(edit_pane, BorderLayout.EAST);
244
245 value_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
246 value_pane.setLayout(new BorderLayout());
247 value_pane.add(value_label, BorderLayout.CENTER);
248 value_pane.add(value, BorderLayout.EAST);
249 value_pane.add(button_pane, BorderLayout.SOUTH);
250
251 controls_pane.setLayout(new BorderLayout());
252 controls_pane.add(value_pane, BorderLayout.CENTER);
253 //controls_pane.add(button_pane, BorderLayout.SOUTH);
254
255 this.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
256 this.setLayout(new BorderLayout());
257 this.add(controls_pane, BorderLayout.NORTH);
258 this.add(center_pane, BorderLayout.CENTER);
259 //this.add(south_pane, BorderLayout.SOUTH);
260 }
261
262 public void actionPerformed(ActionEvent event) {
263 ignore = true;
264 if(event.getSource() == value) {
265 StringTokenizer tokenizer = new StringTokenizer(value.getText(), "\\");
266 TreePath closest = getClosestPath(tokenizer);
267 if(closest != null) {
268 TreePath path = tree.getSelectionPath();
269 GValueNode node = (GValueNode)path.getLastPathComponent();
270 ///ystem.err.println("1. Set value: " + node.toString());
271 value.setText(Utility.stripNL(node.toString()));//formatPath(path, false)));
272 value.setCaretPosition(0);
273 // Now systematically add to selected record.
274 add.doClick();
275 }
276 else {
277 int response = JOptionPane.showConfirmDialog(this, "Do you wish to create a new entry?", "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
278 if(response == JOptionPane.YES_OPTION) {
279 TreePath new_path = addNode(value.getText());
280 tree.setSelectionPath(new_path);
281 // tree.scrollPathToVisible(new_path);
282 scrollTreePathToVisible(new_path);
283 GValueNode node = (GValueNode)new_path.getLastPathComponent();
284 ///ystem.err.println("2. Set value: " + node.toString());
285 value.setText(Utility.stripNL(node.toString()));
286 value.setCaretPosition(0);
287 // Now systematically add to selected record.
288 add.doClick();
289 }
290 }
291 }
292 //else if(event.getSource() == search) {
293 // searchValues();
294 // restore.setEnabled(true);
295 // card_layout.show(center_pane, LIST);
296 //}
297 //else if(event.getSource() == restore) {
298 // restore.setEnabled(false);
299 // card_layout.show(center_pane, TREE);
300 //}
301 else if(event.getSource() == expand) {
302 EditorDialog ed = new EditorDialog();
303 String temp = ed.display(value.getText());
304 if(temp != null) {
305 ///ystem.err.println("3. Set value: " + temp);
306 value.setText(temp);
307 value.setCaretPosition(0);
308 }
309 //validateControls();
310 }
311 ignore = false;
312 }
313 /** Called whenever an element within the metadata set module changes in some way.
314 * @param event A <strong>MSMEvent</strong> which contains information about the change.
315 */
316 public void elementChanged(MSMEvent event) {
317 /* @TODO - Not sure. Figure out. */
318 }
319 public void focusGained(FocusEvent event) {
320
321 }
322
323 public void focusLost(FocusEvent event) {
324
325 }
326
327 public boolean getCommon() {
328 return common;
329 }
330
331 public ElementWrapper getSelectedMetadataElement() {
332 return selected_metadata_element;
333 }
334
335 public String getSelectedValue() {
336 String value_text = value.getText();
337 previous_values.put(selected_metadata_element, value_text);
338 return value_text;
339 }
340
341 public GValueModel getValueModel() {
342 return (GValueModel) tree.getModel();
343 }
344
345 /** This method is required for any ItemListener so that it can be informed when the state of an item set changes (such as when a new selection is made in a combobox). Note that this update is subtly different from the validateControls() method as it also gathers new models for each combobox as required. The reason this isn't done as part of validateControls() is that this would continously reset whatever the user is attempting to type (ie value would be found to be enabled and a new model would be loaded erasing whatever the user just typed in value to fire the validateControls() in the first place!)
346 * @param event An ItemEvent encapsulating all the information about this event.
347 */
348 /*
349 public void itemStateChanged(ItemEvent event) {
350 ///ystem.err.println("Item State Changed");
351 if(!ignore_item_change) {
352 ignore_item_change = true;
353 selected_metadata_element = (ElementWrapper)em.getSelectedItem();
354 if(selected_metadata_element != null) {
355 //elements.setToolTipText(selected_metadata_element.getToolTip());
356 vm = null;
357 vm = Gatherer.c_man.getCollection().msm.getValueTree(selected_metadata_element);
358 if(vm != null) {
359 ///ystem.err.println("Assigning value model.");
360 vm.addTreeModelListener(value_listener);
361 tree.addTreeSelectionListener(this);
362 setTreeEnabled(true);
363 }
364 else {
365 ///ystem.err.println("Creating new model.");
366 vm = new GValueModel(get("Not_Applicable"));
367 setTreeEnabled(false);
368 }
369 tree.setModel(vm);
370 }
371 else {
372 setTreeEnabled(false);
373 }
374 value.setText("");
375 metaedit.validateControls(false);
376 }
377 previous = null;
378 ignore_item_change = false;
379 validateControls();
380 }
381 */
382
383 /** Called whenever a metadata value is changed.
384 * @param event A <strong>MSMEvent</strong> which encapsulates relevant data about the change.
385 */
386 public void metadataChanged(MSMEvent event) {
387 // Don't care.
388 }
389
390 public void newMetadataSetManager() {
391 if(Gatherer.c_man != null && Gatherer.c_man.getCollection() != null && Gatherer.c_man.getCollection().msm != null) {
392 Gatherer.c_man.getCollection().msm.addMSMListener(this);
393 }
394 setChanged(null);
395 }
396
397 public void refreshValueTree() {
398 if(em != null && em.getSize() > 0) {
399 setSelectedMetadataElement((ElementWrapper)em.getSelectedItem());
400 }
401 }
402
403 public void registerModel(GValueModel model) {
404 vm = model;
405 vm.addTreeModelListener(value_listener);
406 tree.setModel(model);
407 tree.addTreeSelectionListener(this);
408 }
409 /** Called whenever a set within the metadata set module changes in some way.
410 * @param event A <strong>MSMEvent</strong> which contains information about the change.
411 */
412 public void setChanged(MSMEvent event) {
413 // Update the element model.
414 MetadataComboBoxModel model = Gatherer.c_man.getCollection().msm.getElementModel();
415 if(model.getSize() > 0) {
416 setElementModel(model);
417 model.setSelectedItem(model.getElementAt(0));
418 vm = Gatherer.c_man.getCollection().msm.getValueTree((ElementWrapper)model.getSelectedItem());
419 setTreeEnabled(true);
420 if(vm == null) {
421 vm = new GValueModel(get("Not_Applicable"));
422 setTreeEnabled(false);
423 }
424 }
425 else {
426 vm = new GValueModel();
427 setTreeEnabled(true);
428 }
429 vm.addTreeModelListener(value_listener);
430 tree.setModel(vm);
431 tree.addTreeSelectionListener(this);
432 }
433
434 public void setCommon(boolean common) {
435 this.common = common;
436 }
437
438 public void setElementModel(MetadataComboBoxModel model) {
439 ///ystem.err.println("Reset ElementModel.");
440 setTreeEnabled(true);
441 Gatherer.c_man.getCollection().msm.addMSMListener(this);
442 if(model == null) {
443 Gatherer.println("model = null");
444 System.exit(0);
445 }
446 ignore_item_change = true;
447 em = model;
448 //elements.setModel(em);
449 if(em.getSize() > 0) {
450 ///ystem.err.println("em.size() > 0");
451 //elements.setEnabled(true);
452 //elements.setSelectedIndex(0);
453 selected_metadata_element = (ElementWrapper)em.getSelectedItem();
454 //elements.setToolTipText(selected_metadata_element.getToolTip());
455 // First we create and install a blank model, or else no updates ever work.
456 vm = new GValueModel(get("Not_Applicable"));
457 tree.setModel(vm);
458 // Now we create a new model if applicable, disabling otherwise.
459 if(selected_metadata_element.getNamespace().length() > 0) {
460 vm = Gatherer.c_man.getCollection().msm.getValueTree(selected_metadata_element);
461 vm.addTreeModelListener(value_listener);
462 ///ystem.err.println("Found existing model containing " + vm.size() + " entries");
463 setTreeEnabled(true);
464 tree.setModel(vm); // This doesn't seem to work
465 }
466 else {
467 ///ystem.err.println("Creating new model.");
468 setTreeEnabled(false);
469 }
470 ///ystem.err.println("The value tree should have been updated by now.");
471 ///ystem.err.println("6. Set value: " + getLastValue());
472 value.setText(Utility.stripNL(getLastValue()));
473 value.setCaretPosition(0);
474 }
475 else {
476 ///ystem.err.println("No elements loaded.");
477 //elements.setEnabled(false);
478 //elements.setToolTipText(get("No_Description"));
479 //setTreeEnabled(false);
480 value.setText("");
481 }
482 previous = null;
483 ignore_item_change = false;
484 validateControls();
485 }
486
487 public void setFileLevel(boolean file_level) {
488 this.file_level = file_level;
489 }
490
491 public void setRootVisible(boolean val) {
492 tree.setRootVisible(val);
493 }
494
495 public void setSelectedMetadataElement(ElementWrapper element) {
496 if(!ignore_item_change) {
497 ignore_item_change = true;
498 if(element != null) {
499 selected_metadata_element = element;
500 //elements.setSelectedItem(element);
501 //elements.setToolTipText(element.getToolTip());
502 vm = Gatherer.c_man.getCollection().msm.getValueTree(element);
503 if(vm != null) {
504 vm.addTreeModelListener(value_listener);
505 setTreeEnabled(true);
506 }
507 else {
508 vm = new GValueModel(get("Not_Applicable"));
509 setTreeEnabled(false);
510 }
511 tree.setModel(vm);
512 ///ystem.err.println("7. Set value: " + getLastValue());
513 //value.setText(Utility.stripNL(getLastValue()));
514 //value.setCaretPosition(0);
515 }
516 else {
517 //elements.setToolTipText(get("No_Description"));
518 setTreeEnabled(false);
519 //value.setText("");
520 }
521 metaedit.validateControls(false);
522 }
523 previous = null;
524 ignore_item_change = false;
525 //validateControls();
526 }
527
528 public void setSelectedValue(String val) {
529 ignore = true;
530 value.setText(Utility.stripNL(val));
531 value.setCaretPosition(0);
532 StringTokenizer tokenizer = new StringTokenizer(val, "\\");
533 TreePath closest = getClosestPath(tokenizer);
534 if(previous != null) {
535 tree.collapsePath(getParent(previous));
536 previous = null;
537 }
538 if(closest != null) {
539 tree.setSelectionPath(closest);
540 // tree.scrollPathToVisible(closest);
541 scrollTreePathToVisible(closest);
542 }
543 ignore = false;
544 //validateControls();
545 }
546
547 /** This method enables or diables the various controls based upon the
548 * state of the system. This method should be called after every change
549 * which could affect the GUI. <br>
550 * Hack #1: For some reason this gets called 14 times for one selection. One day I'll figure out why, but for now I'll just ignore all but every fourteenth call.
551 */
552 public void validateControls() {
553 Metadata selected_metadata = metaedit.getSelectedMetadata();
554 if(metaedit.getSelectedNode() != null && selected_metadata != null) {
555 ElementWrapper element = selected_metadata.getElement();
556 if(element.getNamespace() != "") {
557 GValueNode value_node = selected_metadata.getValueNode();
558 ///ystem.err.println("Value node = " + value_node);
559 // We may be dealing with an element that has no current value
560 if(value_node == null) {
561 String new_value = value.getText();
562 if(new_value.length() > 0) {
563 add.setEnabled(true);
564 }
565 else {
566 add.setEnabled(false);
567 }
568 // Nothing to update
569 update.setEnabled(false);
570 // Nothing to remove
571 remove.setEnabled(false);
572 }
573 // Or else we have some current value that may or may not match the one in our value field.
574 else {
575 String current_value = selected_metadata.getValueNode().getFullPath();
576 String new_value = value.getText();
577 ///ystem.err.println("Current value: '" + current_value + "'");
578 ///ystem.err.println("New value: '" + new_value + "'");
579 if(new_value.length() > 0 && !current_value.equals(new_value)) {
580 add.setEnabled(true);
581 if(common) {
582 update.setEnabled(true);
583 }
584 else {
585 update.setEnabled(false);
586 }
587 }
588 else {
589 add.setEnabled(false);
590 update.setEnabled(false);
591 }
592 // If you have something selected, and we're at the file level, you can remove it.
593 if(file_level) {
594 remove.setEnabled(true);
595 }
596 else {
597 remove.setEnabled(false);
598 }
599 }
600 }
601 else {
602 add.setEnabled(false);
603 update.setEnabled(false);
604 remove.setEnabled(false);
605 }
606 }
607 else {
608 add.setEnabled(false);
609 update.setEnabled(false);
610 remove.setEnabled(false);
611 }
612 }
613
614 /** Called when the value tree of a certain element has changed significantly. If we are displaying the tree for the element noted in the event, then reload the value model.
615 * @param event A <strong>MSMEvent</strong> containing information about the event.
616 */
617 public void valueChanged(MSMEvent event) {
618 ElementWrapper element = event.getElement();
619 if(selected_metadata_element.equals(element)) {
620 GValueModel temp = Gatherer.c_man.getCollection().msm.getValueTree(element);
621 if(temp != null) {
622 vm = temp;
623 tree.setModel(vm);
624 vm.removeTreeModelListener(value_listener);
625 vm.addTreeModelListener(value_listener);
626 setTreeEnabled(true);
627 setSelectedValue(value.getText());
628 }
629 else {
630 vm = new GValueModel(get("Not_Applicable"));
631 tree.setModel(vm);
632 setTreeEnabled(false);
633 }
634 }
635 }
636
637 public void valueChanged(TreeSelectionEvent event) {
638 if(tree.getSelectionCount() != 0 && !ignore) {
639 TreePath path = tree.getSelectionPath();
640 GValueNode node = (GValueNode) path.getLastPathComponent();
641 value.setText(node.getFullPath());//formatPath(tree.getSelectionPath(), false)));
642 value.setCaretPosition(0);
643 validateControls();
644 }
645 }
646
647 private TreePath addNode(String reference) {
648 StringTokenizer tokenizer = new StringTokenizer(reference, "\\");
649 GValueModel model = (GValueModel)tree.getModel();
650 GValueNode current = (GValueNode)model.getRoot();
651 while(tokenizer.hasMoreElements()) {
652 String token = tokenizer.nextToken();
653 GValueNode node = (GValueNode)getClosestNode(token, current);
654 if(node == null) {
655 Gatherer.println("Before: '" + current.toString() + "'");
656 for(int i = 0; i < current.getChildCount(); i++) {
657 Gatherer.println(current.getChildAt(i).toString());
658 }
659 node = model.addValue(token, current, null);
660 Gatherer.println("After: '" + current.toString() + "'");
661 for(int i = 0; i < current.getChildCount(); i++) {
662 Gatherer.println(current.getChildAt(i).toString());
663 }
664 }
665 current = node;
666 }
667 tree.updateUI();
668 if(current != null) {
669 return new TreePath(current.getPath());
670 }
671 else {
672 return new TreePath(((GValueNode)model.getRoot()).getPath());
673 }
674 }
675 /** Returns the given tree path as path formatted string (ie subject\subject\subject).
676 * @param tree The <strong>JTree</strong> the TreePath came from. Used to determine if the root node should be encoded as well.
677 * @param path A <strong>TreePath</strong> that you wish to encode to String.
678 * @param full <i>true</i> if this is the full path (ie a leaf node), <i>false</i> otherwise.
679 * @return A <strong>String</strong> encoding the information from the TreePath.
680 * @see javax.swing.JTree
681 * @see javax.swing.tree.TreePath
682 */
683 static public String formatPath(JTree tree, TreePath path, boolean full) {
684 String text = "";
685 int i = 0;
686 if(tree == null || (!tree.isRootVisible() && !full)) {
687 i = 1;
688 }
689 for( ; i < path.getPathCount(); i++) {
690 GValueNode node = (GValueNode)path.getPathComponent(i);
691 text = text + node.toString();
692 if(node.getChildCount() > 0) {
693 text = text + "\\";
694 }
695 }
696 if(full && text.endsWith("\\")) {
697 return text.substring(0, text.length() - 1);
698 }
699 return text;
700 }
701
702 private String get(String key) {
703 return get(key, null);
704 }
705
706 private String get(String key, String args[]) {
707 if(key.indexOf('.') == -1) {
708 key = "MetaEdit." + key;
709 }
710 return Gatherer.dictionary.get(key,args);
711 }
712
713 private GValueNode getClosestNode(String target, GValueNode current) {
714 // We have struck it lucky.
715 if(startsWith(current.toString(), target)) {
716 return current;
717 }
718 GValueNode closest = null;
719 for(int i = 0; i < current.getChildCount() && closest == null; i++) {
720 closest = getClosestNode(target, (GValueNode)current.getChildAt(i));
721 }
722 return closest;
723 }
724
725 private TreePath getClosestPath(StringTokenizer tokenizer) {
726 if(tokenizer.countTokens() > 0) {
727 TreeNode tree_node = (TreeNode)tree.getModel().getRoot();
728 if(tree_node instanceof GValueNode) {
729 GValueNode current = (GValueNode)tree_node;
730 TreePath closest = null;
731 while(tokenizer.hasMoreElements() && current != null) {
732 current = getClosestNode(tokenizer.nextToken(), current);
733 }
734 if(current != null) {
735 return new TreePath(current.getPath());
736 }
737 return null;
738 }
739 }
740 return null;
741 }
742
743 private String getLastValue() {
744 if(previous_values.containsKey(selected_metadata_element)) {
745 return (String)previous_values.get(selected_metadata_element);
746 }
747 return "";
748 }
749
750 private TreePath getParent(TreePath path) {
751 if(path.getPathCount() > 1) {
752 TreeNode nodes[] = new TreeNode[path.getPathCount() - 1];
753 for(int i = 0; i < path.getPathCount() - 1; i++) {
754 nodes[i] = (TreeNode)path.getPathComponent(i);
755 }
756 return new TreePath(nodes);
757 }
758 return null;
759 }
760
761 private void searchValues() {
762 // Clear any old search results.
763 list_model.clear();
764 String target = value.getText();
765 GValueNode current = (GValueNode)tree.getModel().getRoot();
766 Vector search_space = new Vector();
767 search_space.add(current);
768 for(int i = 0; i < search_space.size(); i++) {
769 GValueNode node = (GValueNode)search_space.get(i);
770 // Add this nodes children.
771 for(int j = 0; j < node.getChildCount(); j++) {
772 search_space.add(node.getChildAt(j));
773 }
774 // And if this node matches add it to list, except for the very
775 // first node as that is AssignedValues the root node!
776 if(node.toString().indexOf(target) != -1 &&
777 node != current) {
778 list_model.add(list_model.size(), node);
779 }
780 }
781 }
782
783 private void setTreeEnabled(boolean value) {
784 tree.setRootVisible(!value);
785 tree.setEnabled(value);
786 if(value) {
787 card_layout.show(center_pane, TREE);
788 }
789 else {
790 Metadata selected_metadata = metaedit.getSelectedMetadata();
791 if(selected_metadata != null && selected_metadata.getElement() != null) {
792 args[0] = selected_metadata.getElement().toString();
793 }
794 else {
795 args[0] = "";
796 }
797 auto_message.setText(get("AutoMessage", args));
798 card_layout.show(center_pane, NONE);
799 }
800 }
801
802 private boolean startsWith(String longer, String shorter) {
803 if(longer.length() > shorter.length()) {
804 longer = longer.substring(0, shorter.length());
805 }
806 return longer.equalsIgnoreCase(shorter);
807 }
808
809 private void printTreePaths() {
810 ///ystem.out.println("Tree Paths according to getPath() method.");
811 Vector nodes = new Vector();
812 nodes.add(tree.getModel().getRoot());
813 while(nodes.size() > 0) {
814 GValueNode node = (GValueNode)nodes.get(0);
815 nodes.remove(node);
816 for(int i = 0; i < node.getChildCount(); i++) {
817 nodes.add(node.getChildAt(i));
818 }
819 ///ystem.out.println("TreePath = " + node.getPath());
820 }
821 }
822
823 /** This function is copied from JTree::setPathToVisible(), and modified so tree rows
824 are always shown flushed left. */
825 public void scrollTreePathToVisible(TreePath path) {
826 if (path != null) {
827 tree.makeVisible(path);
828
829 Rectangle bounds = tree.getPathBounds(path);
830
831 if (bounds != null) {
832 bounds.width += bounds.x;
833 bounds.x = 0;
834 tree.scrollRectToVisible(bounds);
835 // if (tree.getAccessibleContext() != null) {
836 // ((AccessibleJTree) tree.getAccessibleContext()).fireVisibleDataPropertyChange();
837 // }
838 }
839 }
840 }
841
842 private class DocumentListenerImpl
843 implements DocumentListener {
844 /** Gives notification that an attribute or set of attributes changed. */
845 public void changedUpdate(DocumentEvent e) {
846 validate();
847 }
848
849 /** Gives notification that there was an insert into the document. */
850 public void insertUpdate(DocumentEvent e) {
851 validate();
852 }
853
854 /** Gives notification that a portion of the document has been removed. */
855 public void removeUpdate(DocumentEvent e) {
856 validate();
857 }
858
859 public void validate() {
860 ignore = true;
861 ///ystem.err.println("Key released.");
862 StringTokenizer tokenizer = new StringTokenizer(value.getText(), "\\");
863 TreePath closest = getClosestPath(tokenizer);
864 if(closest == previous) {
865 validateControls();
866 ignore = false;
867 return;
868 }
869 else {
870 // Clear previous
871 if(previous != null) {
872 // We have a brand new match close up the old one.
873 if(closest != null) {
874 if(getParent(previous) != null &&
875 !getParent(previous).toString().equals("[AssignedValues]")) {
876 tree.collapsePath(getParent(previous));
877 }
878 previous = null;
879 }
880 // We haven't got a match, but we did have a matching path to
881 // this point. Move the selection to previous paths parent.
882 else {
883 tree.setSelectionPath(getParent(previous));
884 }
885 }
886
887 if(closest != null) {
888 tree.setSelectionPath(closest);
889 // tree.scrollPathToVisible(closest);
890 scrollTreePathToVisible(closest);
891 previous = closest;
892 }
893 }
894 ignore = false;
895 validateControls();
896 }
897 }
898
899 private class ListSelectionListenerImpl
900 implements ListSelectionListener {
901 public void valueChanged(ListSelectionEvent event) {
902 GValueNode node = (GValueNode)list.getSelectedValue();
903 value.setText(Utility.stripNL(node.toString()));//formatPath(node.getPath(), false)));
904 value.setCaretPosition(0);
905 }
906 }
907
908 private class ValueListener
909 implements TreeModelListener {
910 /* Called when nodes have been modified, but the model hasn't changed.
911 * @param event Everything you ever wanted to know about model changes
912 * in one tidy TreeModelEvent package.
913 */
914 public void treeNodesChanged(TreeModelEvent event) {
915 update();
916 }
917
918 /* Called when nodes have been added to the model.
919 * @param event Everything you ever wanted to know about model changes
920 * in one tidy TreeModelEvent package.
921 */
922 public void treeNodesInserted(TreeModelEvent event) {
923 update();
924 }
925
926 /* Called when nodes have been removed from the model.
927 * @param event Everything you ever wanted to know about model changes
928 * in one tidy TreeModelEvent package.
929 */
930 public void treeNodesRemoved(TreeModelEvent event) {
931 update();
932 }
933
934 /** Called when nodes have been rearranged within the model.
935 * @param event Everything you ever wanted to know about model changes
936 * in one tidy TreeModelEvent package.
937 */
938 public void treeStructureChanged(TreeModelEvent event) {
939 update();
940 }
941
942 private void update() {
943 // Don't bother updating if the metaedit tab isn't selected.
944 if(Gatherer.g_man.getSelectedView() == Gatherer.g_man.metaedit_pane) {
945 vm = null;
946 vm = Gatherer.c_man.getCollection().msm.getValueTree((ElementWrapper)em.getSelectedItem());
947 if(vm != null) {
948 vm.addTreeModelListener(value_listener);
949 }
950 else {
951 vm = new GValueModel(get("Not_Applicable"));
952 }
953 tree.setModel(vm);
954 tree.repaint();
955 }
956 }
957 }
958}
959
960
961
962
963
Note: See TracBrowser for help on using the repository browser.