1 | package 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 | */
|
---|
38 | import java.awt.*;
|
---|
39 | import java.awt.event.*;
|
---|
40 | import java.util.*;
|
---|
41 | import javax.swing.*;
|
---|
42 | import javax.swing.event.*;
|
---|
43 | import javax.swing.text.*;
|
---|
44 | import javax.swing.tree.*;
|
---|
45 | import org.greenstone.gatherer.Gatherer;
|
---|
46 | import org.greenstone.gatherer.gui.EditorDialog;
|
---|
47 | import org.greenstone.gatherer.gui.MetaEditPane;
|
---|
48 | import org.greenstone.gatherer.gui.SmarterTextArea;
|
---|
49 | import org.greenstone.gatherer.gui.combobox.GComboBox;
|
---|
50 | import org.greenstone.gatherer.gui.combobox.GComboBoxModel;
|
---|
51 | import org.greenstone.gatherer.msm.ElementWrapper;
|
---|
52 | import org.greenstone.gatherer.msm.Metadata;
|
---|
53 | import org.greenstone.gatherer.msm.MetadataComboBoxModel;
|
---|
54 | import org.greenstone.gatherer.msm.MSMAction;
|
---|
55 | import org.greenstone.gatherer.msm.MSMEvent;
|
---|
56 | import org.greenstone.gatherer.msm.MSMListener;
|
---|
57 | import org.greenstone.gatherer.util.Utility;
|
---|
58 | /**
|
---|
59 | * @author John Thompson, Greenstone Digital Library, University of Waikato
|
---|
60 | * @version 2.2
|
---|
61 | */
|
---|
62 | public 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 | }
|
---|