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

Last change on this file since 13531 was 12119, checked in by kjdon, 18 years ago

Changed text handling to use Dictionary.get rather than Dictionary.setText or Dictionary.registerBoth etc. also removed mnemonics cos they suck for other languages

  • Property svn:keywords set to Author Date Id Revision
File size: 13.7 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 "not only file only metadata selected" placeholder */
88 private String NOT_ONE_FILE_ONLY_METADATA_SELECTED_CARD = "Not one file only metadata selected";
89 /** The name of the panel containing the "no metadata element selected" placeholder */
90 private String NO_METADATA_ELEMENT_SELECTED_CARD = "No metadata element selected";
91
92 private JLabel metadata_value_tree_label = new JLabel();
93 private JTextArea extracted_metadata_element_selected_message;
94 private JTree metadata_value_tree;
95
96
97 public MetadataValueTreePane()
98 {
99 super();
100
101 // Card containing the metadata value tree
102 metadata_value_tree = new JTree();
103 metadata_value_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
104 metadata_value_tree.setModel(null);
105 metadata_value_tree.setRootVisible(false);
106 metadata_value_tree.putClientProperty("JTree.lineStyle", "Angled");
107
108 JPanel metadata_value_tree_pane = new JPanel();
109 metadata_value_tree_pane.setLayout(new BorderLayout());
110 metadata_value_tree_pane.add(metadata_value_tree_label, BorderLayout.NORTH);
111 metadata_value_tree_pane.add(new JScrollPane(metadata_value_tree), BorderLayout.CENTER);
112
113 // Card containing the "extracted metadata element selected" message
114 extracted_metadata_element_selected_message = new JTextArea("");
115 extracted_metadata_element_selected_message.setEditable(false);
116 extracted_metadata_element_selected_message.setLineWrap(true);
117 extracted_metadata_element_selected_message.setOpaque(false);
118 extracted_metadata_element_selected_message.setWrapStyleWord(true);
119
120 JPanel extracted_metadata_element_selected_pane = new JPanel();
121 extracted_metadata_element_selected_pane.setBorder(BorderFactory.createEmptyBorder(25,0,0,0));
122 extracted_metadata_element_selected_pane.setLayout(new BorderLayout());
123 extracted_metadata_element_selected_pane.add(extracted_metadata_element_selected_message, BorderLayout.CENTER);
124
125 // Card containing the "inherited metadata selected" message
126 JTextArea inherited_metadata_selected_message = new JTextArea(Dictionary.get("EnrichPane.InheritedMetadataSelected"));
127 inherited_metadata_selected_message.setEditable(false);
128 inherited_metadata_selected_message.setLineWrap(true);
129 inherited_metadata_selected_message.setOpaque(false);
130 inherited_metadata_selected_message.setWrapStyleWord(true);
131
132 JPanel inherited_metadata_selected_pane = new JPanel();
133 inherited_metadata_selected_pane.setBorder(BorderFactory.createEmptyBorder(25,0,0,0));
134 inherited_metadata_selected_pane.setLayout(new BorderLayout());
135 inherited_metadata_selected_pane.add(inherited_metadata_selected_message, BorderLayout.CENTER);
136
137 // Card containing the "not one file only metadata selected" message
138 JTextArea not_one_file_only_metadata_selected_message = new JTextArea(Dictionary.get("EnrichPane.NotOneFileOnlyMetadataSelected"));
139 not_one_file_only_metadata_selected_message.setEditable(false);
140 not_one_file_only_metadata_selected_message.setLineWrap(true);
141 not_one_file_only_metadata_selected_message.setOpaque(false);
142 not_one_file_only_metadata_selected_message.setWrapStyleWord(true);
143
144 JPanel not_one_file_only_metadata_selected_pane = new JPanel();
145 not_one_file_only_metadata_selected_pane.setBorder(BorderFactory.createEmptyBorder(25,0,0,0));
146 not_one_file_only_metadata_selected_pane.setLayout(new BorderLayout());
147 not_one_file_only_metadata_selected_pane.add(not_one_file_only_metadata_selected_message, BorderLayout.CENTER);
148
149 // Card containing the "no metadata element selected" message
150 JLabel no_metadata_element_selected_label = new JLabel(Dictionary.get("EnrichPane.No_Metadata_Element"));
151 no_metadata_element_selected_label.setHorizontalAlignment(JLabel.CENTER);
152 no_metadata_element_selected_label.setOpaque(false);
153 no_metadata_element_selected_label.setVerticalAlignment(JLabel.CENTER);
154
155 JPanel no_metadata_element_selected_pane = new JPanel();
156 no_metadata_element_selected_pane.setLayout(new BorderLayout());
157 no_metadata_element_selected_pane.add(no_metadata_element_selected_label, BorderLayout.CENTER);
158
159 card_layout = new CardLayout();
160
161 this.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
162 this.setFont(Configuration.getFont("general.font", false));
163 this.setLayout(card_layout);
164 this.add(no_metadata_element_selected_pane, NO_METADATA_ELEMENT_SELECTED_CARD);
165 this.add(extracted_metadata_element_selected_pane, EXTRACTED_METADATA_ELEMENT_SELECTED_CARD);
166 this.add(inherited_metadata_selected_pane, INHERITED_METADATA_SELECTED_CARD);
167 this.add(not_one_file_only_metadata_selected_pane, NOT_ONE_FILE_ONLY_METADATA_SELECTED_CARD);
168 this.add(metadata_value_tree_pane, METADATA_VALUE_TREE_CARD);
169 }
170
171
172 public void addMetadataValueTreeSelectionListener(TreeSelectionListener tree_selection_listener)
173 {
174 metadata_value_tree.addTreeSelectionListener(tree_selection_listener);
175 }
176
177
178 /** Returns a TreePath for the node most closely matching the metadata value. */
179 private TreePath getClosestPath(String metadata_value_string)
180 {
181 if (metadata_value_tree.getModel() == null) {
182 return null;
183 }
184
185 // Start at the root of the tree
186 MetadataValueTreeNode tree_node = (MetadataValueTreeNode) metadata_value_tree.getModel().getRoot();
187
188 // Separate hierarchical values
189 PatternTokenizer tokenizer = new PatternTokenizer(metadata_value_string, MetadataValueTreeNode.METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN);
190 while (tokenizer.hasMoreTokens()) {
191 String token = tokenizer.nextToken();
192
193 // All components except the last must match exactly
194 if (tokenizer.hasMoreTokens()) {
195 for (int i = 0; i < tree_node.getChildCount(); i++) {
196 MetadataValueTreeNode child_node = (MetadataValueTreeNode) tree_node.getChildAt(i);
197 if (child_node.getValue().equals(token)) {
198 // The matching node has been found, so move onto the next token
199 tree_node = child_node;
200 break;
201 }
202 }
203 }
204
205 // The last component may match partially
206 else {
207 for (int i = 0; i < tree_node.getChildCount(); i++) {
208 MetadataValueTreeNode child_node = (MetadataValueTreeNode) tree_node.getChildAt(i);
209 if (child_node.getFullValue().startsWith(metadata_value_string)) {
210 // The closest node has been found, so return its path
211 return new TreePath(child_node.getPath());
212 }
213 }
214
215 // Not even a partial match
216 return null;
217 }
218 }
219
220 // If nothing else, return the path of the root node
221 return new TreePath(tree_node.getPath());
222 }
223
224
225 public MetadataValueTreeNode getSelectedMetadataValueTreeNode()
226 {
227 if (metadata_value_tree.getSelectionCount() == 0 || ignore_tree_selection_event) {
228 return null;
229 }
230
231 return (MetadataValueTreeNode) metadata_value_tree.getSelectionPath().getLastPathComponent();
232 }
233
234
235 public void rebuild(MetadataValue new_metadata_value)
236 {
237 // If the metadata value hasn't changed there is nothing to do
238 if (new_metadata_value == metadata_value) {
239 return;
240 }
241
242 MetadataElement metadata_element = ((metadata_value != null) ? metadata_value.getMetadataElement() : null);
243 metadata_value = new_metadata_value;
244
245 // Selection cleared, so display "no metadata element selected" card and we're done
246 if (new_metadata_value == null) {
247 metadata_value_tree.setModel(null);
248 card_layout.show(this, NO_METADATA_ELEMENT_SELECTED_CARD);
249 return;
250 }
251
252 // If a piece of inherited metadata is selected, display "inherited metadata selected" card and we're done
253 if (new_metadata_value.isInheritedMetadata()) {
254 card_layout.show(this, INHERITED_METADATA_SELECTED_CARD);
255 return;
256 }
257
258 // If the metadata applies to multiple files, display "not one file only metadata selected" card and we're done
259 if (new_metadata_value.isOneFileOnlyMetadata() == false) {
260 card_layout.show(this, NOT_ONE_FILE_ONLY_METADATA_SELECTED_CARD);
261 return;
262 }
263
264 // If an extracted metadata element is selected, display "extracted metadata element selected" card
265 MetadataElement new_metadata_element = new_metadata_value.getMetadataElement();
266 if (new_metadata_element.isExtractedMetadataElement()) {
267 String[] args = new String[1];
268 args[0] = new_metadata_element.getDisplayName();
269 extracted_metadata_element_selected_message.setText(Dictionary.get("EnrichPane.AutoMessage", args));
270 card_layout.show(this, EXTRACTED_METADATA_ELEMENT_SELECTED_CARD);
271 return;
272 }
273
274 // Display the value tree for the selected metadata element
275 String[] args = new String[1];
276 args[0] = new_metadata_element.getDisplayName();
277 metadata_value_tree_label.setText(Dictionary.get("EnrichPane.ExistingValues", args));
278
279 metadata_value_tree.setModel(new_metadata_element.getMetadataValueTreeModel());
280 card_layout.show(this, METADATA_VALUE_TREE_CARD);
281 selectBestPathForMetadataValue(new_metadata_value.getFullValue());
282 }
283
284
285 public void selectBestPathForMetadataValue(String metadata_value_string)
286 {
287 TreePath best_path = getClosestPath(metadata_value_string);
288
289 // Select the new path in the tree
290 // The tree selection event this causes must be ignored, since it alters the metadata text field value
291 ignore_tree_selection_event = true;
292 metadata_value_tree.setSelectionPath(best_path);
293 ignore_tree_selection_event = false;
294
295 // If a folder has been specified, make sure it is expanded
296 if (metadata_value_string.endsWith(MetadataValueTreeNode.METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN) && !metadata_value_tree.isExpanded(best_path)) {
297 metadata_value_tree.expandPath(best_path);
298 }
299
300 // Make sure the tree path is expanded
301 metadata_value_tree.makeVisible(best_path);
302
303 // Make sure the tree path is visible on screen
304 final Rectangle bounds = metadata_value_tree.getPathBounds(best_path);
305 if (bounds != null) {
306 bounds.x = 0; // Want the tree to be always flushed left
307
308 // Scrolling the path to be visible must be done on the GUI thread
309 Runnable task = new Runnable() {
310 public void run() {
311 metadata_value_tree.scrollRectToVisible(bounds);
312 }
313 };
314 SwingUtilities.invokeLater(task);
315 }
316 }
317}
Note: See TracBrowser for help on using the repository browser.