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

Last change on this file since 11662 was 11301, checked in by mdewsnip, 18 years ago

Now detects and prevents you from editing metadata in metadata.xml files that applies to multiple files (ie. the FileSet element includes wildcards).

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