source: trunk/gli/src/org/greenstone/gatherer/gui/MetadataValueTreePane.java@ 10556

Last change on this file since 10556 was 9871, checked in by mdewsnip, 19 years ago

Fixed a small bug where switching from an inherited piece of metadata to a non-inherited piece of metadata (for the same metadata element) would not cause the metadata value tree to be displayed.

  • Property svn:keywords set to Author Date Id Revision
File size: 12.5 KB
Line 
1/**
2 *############################################################################
3 * A component of the Greenstone Librarian Interface, part of the Greenstone
4 * digital library suite from the New Zealand Digital Library Project at the
5 * University of Waikato, New Zealand.
6 *
7 * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
8 *
9 * Copyright (C) 2005 New Zealand Digital Library Project
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *############################################################################
25 */
26
27package org.greenstone.gatherer.gui;
28
29
30import java.awt.*;
31import javax.swing.*;
32import javax.swing.event.*;
33import javax.swing.tree.*;
34import org.greenstone.gatherer.Configuration;
35import org.greenstone.gatherer.Dictionary;
36import org.greenstone.gatherer.metadata.MetadataElement;
37import org.greenstone.gatherer.metadata.MetadataValue;
38import org.greenstone.gatherer.metadata.MetadataValueTreeNode;
39import org.greenstone.gatherer.util.PatternTokenizer;
40
41
42/**
43 * This class is a little bit complex, a little bit subtle, and a little bit odd.
44 * The strange interaction model is due to the fact that it is very tightly
45 * coupled to the EnrichPane.
46 *
47 * The interaction is complex because there are three separate controls that the
48 * user may interact with, each of which can affect the other two. The three
49 * controls are:
50 * - The "assigned metadata" table, at the top right of the meta edit pane.
51 * - The "metadata value" text field, where users can type in new values.
52 * - The "metadata value tree", which shows other values that have been
53 * assigned to the selected metadata element.
54 *
55 * The interactions are:
56 * - The "assigned metadata" table
57 * Users may select one (and only one) row in this table. Selecting a row
58 * chooses one metadata element. The text field will be set to the current
59 * value of the metadata element. This value will also be selected in the
60 * metadata value tree.
61 *
62 * - The "metadata value" text field
63 * If the value the user has typed in this is a prefix of an entry in the
64 * value tree, this value will be selected in the value tree. In this case,
65 * pressing "Tab" will complete the value (ie. make the value in the text
66 * field the same as the value in the tree). This is to allow users to
67 * quickly and easily assign existing metadata values to new documents.
68 *
69 * - The "metadata value tree"
70 * Selecting a value in the tree will set the text field to this value.
71 */
72public class MetadataValueTreePane
73 extends JPanel
74{
75 private boolean ignore_tree_selection_event = false;
76 /** The metadata value that the tree pane is built on */
77 private MetadataValue metadata_value = null;
78
79 /** Used to display either the MetadataValueTree (when metadata is selected) or a placeholder panel */
80 private CardLayout card_layout = null;
81 /** The name of the panel containing the metadata value tree */
82 private String METADATA_VALUE_TREE_CARD = "";
83 /** The name of the panel containing the "extracted metadata element selected" placeholder */
84 private String EXTRACTED_METADATA_ELEMENT_SELECTED_CARD = "Extracted metadata element selected";
85 /** The name of the panel containing the "inherited metadata selected" placeholder */
86 private String INHERITED_METADATA_SELECTED_CARD = "Inherited metadata selected";
87 /** The name of the panel containing the "no metadata element selected" placeholder */
88 private String NO_METADATA_ELEMENT_SELECTED_CARD = "No metadata element selected";
89
90 private JLabel metadata_value_tree_label = new JLabel();
91 private JTextArea extracted_metadata_element_selected_message;
92 private JTree metadata_value_tree;
93
94
95 public MetadataValueTreePane()
96 {
97 super();
98
99 // Card containing the metadata value tree
100 metadata_value_tree = new JTree();
101 metadata_value_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
102 metadata_value_tree.setModel(null);
103 metadata_value_tree.setRootVisible(false);
104 metadata_value_tree.putClientProperty("JTree.lineStyle", "Angled");
105
106 JPanel metadata_value_tree_pane = new JPanel();
107 metadata_value_tree_pane.setLayout(new BorderLayout());
108 metadata_value_tree_pane.add(metadata_value_tree_label, BorderLayout.NORTH);
109 metadata_value_tree_pane.add(new JScrollPane(metadata_value_tree), BorderLayout.CENTER);
110
111 // Card containing the "extracted metadata element selected" message
112 extracted_metadata_element_selected_message = new JTextArea("");
113 extracted_metadata_element_selected_message.setEditable(false);
114 extracted_metadata_element_selected_message.setLineWrap(true);
115 extracted_metadata_element_selected_message.setOpaque(false);
116 extracted_metadata_element_selected_message.setWrapStyleWord(true);
117
118 JPanel extracted_metadata_element_selected_pane = new JPanel();
119 extracted_metadata_element_selected_pane.setBorder(BorderFactory.createEmptyBorder(25,0,0,0));
120 extracted_metadata_element_selected_pane.setLayout(new BorderLayout());
121 extracted_metadata_element_selected_pane.add(extracted_metadata_element_selected_message, BorderLayout.CENTER);
122
123 // Card containing the "inherited metadata selected" message
124 JTextArea inherited_metadata_selected_message = new JTextArea("");
125 inherited_metadata_selected_message.setEditable(false);
126 inherited_metadata_selected_message.setLineWrap(true);
127 inherited_metadata_selected_message.setOpaque(false);
128 inherited_metadata_selected_message.setWrapStyleWord(true);
129 Dictionary.registerText(inherited_metadata_selected_message, "EnrichPane.InheritedMetadataSelected");
130
131 JPanel inherited_metadata_selected_pane = new JPanel();
132 inherited_metadata_selected_pane.setBorder(BorderFactory.createEmptyBorder(25,0,0,0));
133 inherited_metadata_selected_pane.setLayout(new BorderLayout());
134 inherited_metadata_selected_pane.add(inherited_metadata_selected_message, BorderLayout.CENTER);
135
136 // Card containing the "no metadata element selected" message
137 JLabel no_metadata_element_selected_label = new JLabel();
138 no_metadata_element_selected_label.setHorizontalAlignment(JLabel.CENTER);
139 no_metadata_element_selected_label.setOpaque(false);
140 no_metadata_element_selected_label.setVerticalAlignment(JLabel.CENTER);
141 Dictionary.registerText(no_metadata_element_selected_label, "EnrichPane.No_Metadata_Element");
142
143 JPanel no_metadata_element_selected_pane = new JPanel();
144 no_metadata_element_selected_pane.setLayout(new BorderLayout());
145 no_metadata_element_selected_pane.add(no_metadata_element_selected_label, BorderLayout.CENTER);
146
147 card_layout = new CardLayout();
148
149 this.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
150 this.setFont(Configuration.getFont("general.font", false));
151 this.setLayout(card_layout);
152 this.add(no_metadata_element_selected_pane, NO_METADATA_ELEMENT_SELECTED_CARD);
153 this.add(extracted_metadata_element_selected_pane, EXTRACTED_METADATA_ELEMENT_SELECTED_CARD);
154 this.add(inherited_metadata_selected_pane, INHERITED_METADATA_SELECTED_CARD);
155 this.add(metadata_value_tree_pane, METADATA_VALUE_TREE_CARD);
156 }
157
158
159 public void addMetadataValueTreeSelectionListener(TreeSelectionListener tree_selection_listener)
160 {
161 metadata_value_tree.addTreeSelectionListener(tree_selection_listener);
162 }
163
164
165 /** Returns a TreePath for the node most closely matching the metadata value. */
166 private TreePath getClosestPath(String metadata_value_string)
167 {
168 if (metadata_value_tree.getModel() == null) {
169 return null;
170 }
171
172 // Start at the root of the tree
173 MetadataValueTreeNode tree_node = (MetadataValueTreeNode) metadata_value_tree.getModel().getRoot();
174
175 // Separate hierarchical values
176 PatternTokenizer tokenizer = new PatternTokenizer(metadata_value_string, MetadataValueTreeNode.METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN);
177 while (tokenizer.hasMoreTokens()) {
178 String token = tokenizer.nextToken();
179
180 // All components except the last must match exactly
181 if (tokenizer.hasMoreTokens()) {
182 for (int i = 0; i < tree_node.getChildCount(); i++) {
183 MetadataValueTreeNode child_node = (MetadataValueTreeNode) tree_node.getChildAt(i);
184 if (child_node.getValue().equals(token)) {
185 // The matching node has been found, so move onto the next token
186 tree_node = child_node;
187 break;
188 }
189 }
190 }
191
192 // The last component may match partially
193 else {
194 for (int i = 0; i < tree_node.getChildCount(); i++) {
195 MetadataValueTreeNode child_node = (MetadataValueTreeNode) tree_node.getChildAt(i);
196 if (child_node.getFullValue().startsWith(metadata_value_string)) {
197 // The closest node has been found, so return its path
198 return new TreePath(child_node.getPath());
199 }
200 }
201
202 // Not even a partial match
203 return null;
204 }
205 }
206
207 // If nothing else, return the path of the root node
208 return new TreePath(tree_node.getPath());
209 }
210
211
212 public MetadataValueTreeNode getSelectedMetadataValueTreeNode()
213 {
214 if (metadata_value_tree.getSelectionCount() == 0 || ignore_tree_selection_event) {
215 return null;
216 }
217
218 return (MetadataValueTreeNode) metadata_value_tree.getSelectionPath().getLastPathComponent();
219 }
220
221
222 public void rebuild(MetadataValue new_metadata_value)
223 {
224 // If the metadata value hasn't changed there is nothing to do
225 if (new_metadata_value == metadata_value) {
226 return;
227 }
228
229 MetadataElement metadata_element = ((metadata_value != null) ? metadata_value.getMetadataElement() : null);
230 metadata_value = new_metadata_value;
231
232 // Selection cleared, so display "no metadata element selected" card and we're done
233 if (new_metadata_value == null) {
234 metadata_value_tree.setModel(null);
235 card_layout.show(this, NO_METADATA_ELEMENT_SELECTED_CARD);
236 return;
237 }
238
239 // If a piece of inherited metadata is selected, display "inherited metadata selected" card and we're done
240 if (new_metadata_value.isInheritedMetadata()) {
241 card_layout.show(this, INHERITED_METADATA_SELECTED_CARD);
242 return;
243 }
244
245 // If an extracted metadata element is selected, display "extracted metadata element selected" card
246 MetadataElement new_metadata_element = new_metadata_value.getMetadataElement();
247 if (new_metadata_element.isExtractedMetadataElement()) {
248 String[] args = new String[1];
249 args[0] = new_metadata_element.getDisplayName();
250 Dictionary.registerText(extracted_metadata_element_selected_message, "EnrichPane.AutoMessage", args);
251 card_layout.show(this, EXTRACTED_METADATA_ELEMENT_SELECTED_CARD);
252 return;
253 }
254
255 // Display the value tree for the selected metadata element
256 String[] args = new String[1];
257 args[0] = new_metadata_element.getDisplayName();
258 Dictionary.registerText(metadata_value_tree_label, "EnrichPane.ExistingValues", args);
259
260 metadata_value_tree.setModel(new_metadata_element.getMetadataValueTreeModel());
261 card_layout.show(this, METADATA_VALUE_TREE_CARD);
262 selectBestPathForMetadataValue(new_metadata_value.getFullValue());
263 }
264
265
266 public void selectBestPathForMetadataValue(String metadata_value_string)
267 {
268 TreePath best_path = getClosestPath(metadata_value_string);
269
270 // Select the new path in the tree
271 // The tree selection event this causes must be ignored, since it alters the metadata text field value
272 ignore_tree_selection_event = true;
273 metadata_value_tree.setSelectionPath(best_path);
274 ignore_tree_selection_event = false;
275
276 // If a folder has been specified, make sure it is expanded
277 if (metadata_value_string.endsWith(MetadataValueTreeNode.METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN) && !metadata_value_tree.isExpanded(best_path)) {
278 metadata_value_tree.expandPath(best_path);
279 }
280
281 // Make sure the tree path is expanded
282 metadata_value_tree.makeVisible(best_path);
283
284 // Make sure the tree path is visible on screen
285 final Rectangle bounds = metadata_value_tree.getPathBounds(best_path);
286 if (bounds != null) {
287 bounds.x = 0; // Want the tree to be always flushed left
288
289 // Scrolling the path to be visible must be done on the GUI thread
290 Runnable task = new Runnable() {
291 public void run() {
292 metadata_value_tree.scrollRectToVisible(bounds);
293 }
294 };
295 SwingUtilities.invokeLater(task);
296 }
297 }
298}
Note: See TracBrowser for help on using the repository browser.