source: other-projects/FileTransfer-WebSocketPair/testGXTWithGreenstone/src/org/greenstone/gatherer/gui/MetadataValueTreePane.java@ 33053

Last change on this file since 33053 was 33053, checked in by ak19, 5 years ago

I still had some stuff of Nathan Kelly's (FileTransfer-WebSocketPair) sitting on my USB. Had already commited the Themes folder at the time, 2 years back. Not sure if he wanted this additional folder commited. But I didn't want to delete it and decided it will be better off on SVN. When we use his project, if we find we didn't need this test folder, we can remove it from svn then.

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