source: trunk/gli/src/org/greenstone/gatherer/gui/EnrichPane.java@ 11627

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

The collection tree object is now created and owned by CollectionManager.

  • Property svn:keywords set to Author Date Id Revision
File size: 14.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 * Based on code by John Thompson
9 *
10 * Copyright (C) 2005 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *############################################################################
26 */
27
28package org.greenstone.gatherer.gui;
29
30
31import java.awt.*;
32import java.awt.event.*;
33import java.io.*;
34import java.util.*;
35import javax.swing.*;
36import javax.swing.event.*;
37import javax.swing.text.*;
38import javax.swing.tree.*;
39import org.greenstone.gatherer.Configuration;
40import org.greenstone.gatherer.DebugStream;
41import org.greenstone.gatherer.Dictionary;
42import org.greenstone.gatherer.Gatherer;
43import org.greenstone.gatherer.collection.CollectionTree;
44import org.greenstone.gatherer.collection.CollectionTreeNode;
45import org.greenstone.gatherer.gui.tree.DragTree;
46import org.greenstone.gatherer.metadata.MetadataElement;
47import org.greenstone.gatherer.metadata.MetadataValue;
48import org.greenstone.gatherer.metadata.MetadataValueTableEntry;
49import org.greenstone.gatherer.metadata.MetadataValueTreeNode;
50import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
51import org.greenstone.gatherer.util.DragGroup;
52import org.greenstone.gatherer.util.TreeSynchronizer;
53
54
55/** Provides a view of controls for the editing of metadata.
56 */
57public class EnrichPane
58 extends JPanel
59 implements TreeSelectionListener
60{
61 static private Dimension MINIMUM_SIZE = new Dimension(100, 100);
62 static private Dimension COLLECTION_TREE_SIZE = new Dimension(250, 500);
63
64 /** The collection tree. */
65 private CollectionTree collection_tree = null;
66 /** The currently reported selection. */
67 private CollectionTreeNode[] file_nodes = null;
68 /** Used to dynamically filter the collection tree. */
69 private Filter collection_filter = null;
70 /** The label at the top of the collection tree, which shows the collection name. */
71 private JLabel collection_label;
72 /** The panel that contains the collection tree. */
73 private JPanel collection_pane = null;
74 /** The scrollable area into which the collection tree is placed. */
75 private JScrollPane collection_scroll = null;
76 /** The splitpane dividing the collection tree and the metadata editing controls. */
77 private JSplitPane external_split;
78 /** The metadata value table shows the metadata values that are currently assigned to a file. */
79 private MetadataValueTablePane metadata_value_table_pane = null;
80 /** The metadata value tree shows the metadata values that are currently assigned to a metadata element. */
81 private MetadataValueTreePane metadata_value_tree_pane = null;
82 /** Provide synchronization between the collection trees in this view and the collection pane view. */
83 private TreeSynchronizer collection_tree_sync = null;
84
85
86 /** Constructor.
87 * @param tree_sync The <strong>TreeSynchronizer</strong> to be used on the collection tree
88 */
89 public EnrichPane(TreeSynchronizer collection_tree_sync)
90 {
91 this.collection_tree_sync = collection_tree_sync;
92
93 // Create the metadata value tree pane
94 metadata_value_tree_pane = new MetadataValueTreePane();
95 metadata_value_tree_pane.addMetadataValueTreeSelectionListener(new MetadataValueTreeSelectionListener());
96
97 // Create metadata value table pane
98 metadata_value_table_pane = new MetadataValueTablePane();
99 metadata_value_table_pane.addMetadataValueTableListSelectionListener(new MetadataValueTableListSelectionListener());
100 metadata_value_table_pane.addMetadataValueTableMouseListener(new MetadataValueTableMouseListener());
101 metadata_value_table_pane.addMetadataValueTextFieldDocumentListener(new MetadataValueTextFieldDocumentListener());
102 metadata_value_table_pane.addMetadataValueTextFieldKeyListener(new MetadataValueTextFieldKeyListener());
103 }
104
105
106 /** Some actions can only occur after this panel has been displayed on-screen, so this method is provided to do exactly that. Such actions include the proportioning of the split panes and the setting of table column widths.
107 */
108 public void afterDisplay()
109 {
110 external_split.setDividerLocation(0.3);
111 }
112
113
114 /** Used to create, connect and layout the components to be shown on this control panel.
115 * @see org.greenstone.gatherer.Gatherer
116 * @see org.greenstone.gatherer.file.FileOpenActionListener
117 * @see org.greenstone.gatherer.gui.Filter
118 */
119 public void display()
120 {
121 // Creation
122 collection_pane = new JPanel(new BorderLayout());
123 collection_pane.setMinimumSize(MINIMUM_SIZE);
124 collection_pane.setPreferredSize(COLLECTION_TREE_SIZE);
125
126 external_split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
127
128 collection_label = new JLabel();
129 Dictionary.registerText(collection_label, "Collection.No_Collection");
130 collection_label.setOpaque(true);
131
132 DragGroup group = new DragGroup();
133 collection_tree = Gatherer.c_man.getCollectionTree();
134 group.add(collection_tree);
135 collection_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
136 collection_tree.addTreeSelectionListener(this);
137 collection_filter = collection_tree.getFilter();
138
139 // Layout
140 collection_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(3,3,3,3), BorderFactory.createLoweredBevelBorder()));
141 collection_pane.setMinimumSize(MINIMUM_SIZE);
142 collection_pane.setPreferredSize(new Dimension(Gatherer.g_man.getSize().width / 3, Gatherer.g_man.getSize().height));
143
144 // Collection Pane
145 collection_pane.add(collection_label, BorderLayout.NORTH);
146
147 JSplitPane metadata_editing_pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
148 metadata_editing_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
149 metadata_editing_pane.setDividerSize(8);
150
151 metadata_editing_pane.add(metadata_value_table_pane, JSplitPane.TOP);
152 metadata_editing_pane.add(metadata_value_tree_pane, JSplitPane.BOTTOM);
153 metadata_editing_pane.setDividerLocation(250);
154
155 external_split.add(collection_pane, JSplitPane.LEFT);
156 external_split.add(metadata_editing_pane, JSplitPane.RIGHT);
157
158 this.setLayout(new BorderLayout());
159 this.add(external_split, BorderLayout.CENTER);
160 }
161
162
163 /** Called to inform this pane that it has just gained focus as an effect of the user clicking on its tab
164 */
165 public void gainFocus()
166 {
167 // If there is nothing in the collection tree there is nothing to do
168 if (collection_tree == null || collection_tree.getRowCount() == 0) {
169 return;
170 }
171
172 // Add the collection tree and filter back into this pane
173 collection_scroll = new JScrollPane(collection_tree);
174 collection_pane.add(collection_scroll, BorderLayout.CENTER);
175 collection_pane.add(collection_filter, BorderLayout.SOUTH);
176
177 // Select the first node in the tree if nothing is already selected
178 if (collection_tree.getSelectionPaths() == null) {
179 collection_tree.setImmediate(true);
180 collection_tree.setSelectionRow(0);
181 collection_tree.setImmediate(false);
182 return;
183 }
184
185 // Force all of the controls to be updated
186 valueChanged(null);
187 }
188
189
190 /** Called to inform this pane that it has just lost focus as an effect of the user clicking on another tab
191 */
192 public void loseFocus()
193 {
194 // Very important: make sure metadata value is saved before leaving the pane
195 metadata_value_table_pane.stopEditingAndRebuild(file_nodes);
196
197 // Upload the modified metadata.xml files to the server now, if we're using one
198 MetadataXMLFileManager.uploadModifiedMetadataXMLFiles();
199
200 // Remove the collection tree and filter from this pane so it can be added to the Gather pane
201 collection_pane.remove(collection_scroll);
202 collection_pane.remove(collection_filter);
203 }
204
205
206 /** Called whenever the detail mode changes to ensure the filters are at an appropriate level (ie only editable by those that understand regular expression matching)
207 * @param mode the mode level as an int
208 */
209 public void modeChanged(int mode)
210 {
211 collection_filter.setEditable(mode > Configuration.LIBRARIAN_MODE);
212 }
213
214
215 /** Refresh this pane, depending on what has just happened (refresh_reason). */
216 public void refresh(int refresh_reason, boolean collection_loaded)
217 {
218 if (collection_loaded) {
219 // Update collection label
220 Dictionary.registerText(collection_label, "Collection.Collection");
221 collection_label.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
222 collection_label.setForeground(Configuration.getColor("coloring.collection_heading_foreground", false));
223
224 // Update collection tree
225 if (refresh_reason == Gatherer.COLLECTION_OPENED) {
226 collection_tree.setModel(Gatherer.c_man.getCollectionTreeModel());
227 }
228
229 // Update collection filter
230 collection_filter.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
231 }
232 else {
233 // Update collection label
234 Dictionary.registerText(collection_label, "Collection.No_Collection");
235 collection_label.setBackground(Color.lightGray);
236 collection_label.setForeground(Color.black);
237
238 // Update collection tree
239 collection_tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode("Error")));
240
241 // Update collection filter
242 collection_filter.setBackground(Color.lightGray);
243 }
244
245 // Enable or disable the controls
246 collection_tree.setEnabled(collection_loaded);
247 collection_filter.setEnabled(collection_loaded);
248
249 // Ensure that this collection tree view is synchronized with all others
250 collection_tree_sync.add(collection_tree);
251
252 // Force the metadata table to be rebuilt (for switching extracted metadata on or off)
253 if (refresh_reason == Gatherer.PREFERENCES_CHANGED) {
254 metadata_value_table_pane.stopEditingAndRebuild(file_nodes);
255 }
256 }
257
258
259 /** Called whenever the collection tree selection changes. This causes the metadata value table to be rebuilt. */
260 public void valueChanged(TreeSelectionEvent event)
261 {
262 // Nothing selected in the collection tree
263 if (collection_tree.getSelectionCount() == 0) {
264 file_nodes = null;
265 }
266
267 // Some files selected in the collection tree
268 else {
269 TreePath paths[] = collection_tree.getSelectionPaths();
270 file_nodes = new CollectionTreeNode[paths.length];
271 for (int i = 0; i < paths.length; i++) {
272 file_nodes[i] = (CollectionTreeNode) paths[i].getLastPathComponent();
273 }
274 }
275
276 // Update the metadata value table (and consequently, the metadata value tree)
277 metadata_value_table_pane.stopEditingAndRebuild(file_nodes);
278 }
279
280
281 private class MetadataValueTableListSelectionListener
282 implements ListSelectionListener
283 {
284 public void valueChanged(ListSelectionEvent list_selection_event)
285 {
286 // We only want to handle one event per selection, so wait for the value to stabilise
287 if (list_selection_event.getValueIsAdjusting()) {
288 return;
289 }
290
291 // Update the metadata value tree for the current table selection
292 metadata_value_tree_pane.rebuild(metadata_value_table_pane.getSelectedMetadataValueTableEntry());
293 }
294 }
295
296
297 private class MetadataValueTableMouseListener
298 extends MouseAdapter
299 {
300 public void mouseClicked(MouseEvent mouse_event)
301 {
302 // We're only interested in clicks on the inherited column
303 if (metadata_value_table_pane.isMouseEventForInheritedMetadataValueTableColumn(mouse_event) == false) {
304 return;
305 }
306
307 // If the selected metadata is inherited, switch to the folder it came from
308 MetadataValueTableEntry selected_metadata_value_table_entry = metadata_value_table_pane.getSelectedMetadataValueTableEntry();
309 if (selected_metadata_value_table_entry.isInheritedMetadata()) {
310 collection_tree.setSelection(selected_metadata_value_table_entry.getFolderMetadataInheritedFrom());
311 }
312 }
313 }
314
315
316 private class MetadataValueTextFieldDocumentListener
317 implements DocumentListener
318 {
319 /** Gives notification that an attribute or set of attributes changed */
320 public void changedUpdate(DocumentEvent document_event) {
321 validate(document_event);
322 }
323
324 /** Gives notification that there was an insert into the document */
325 public void insertUpdate(DocumentEvent document_event) {
326 validate(document_event);
327 }
328
329 /** Gives notification that a portion of the document has been removed */
330 public void removeUpdate(DocumentEvent document_event) {
331 validate(document_event);
332 }
333
334
335 /** Ensures that the value tree is updated in response to changes in the value text field */
336 private void validate(DocumentEvent document_event)
337 {
338 try {
339 Document document = document_event.getDocument();
340 String metadata_value_string = document.getText(0, document.getLength());
341 metadata_value_tree_pane.selectBestPathForMetadataValue(metadata_value_string);
342 }
343 catch (Exception exception) {
344 DebugStream.printStackTrace(exception);
345 }
346 }
347 }
348
349
350 private class MetadataValueTextFieldKeyListener
351 extends KeyAdapter
352 {
353 /** Gives notification of key events on the text field */
354 public void keyPressed(KeyEvent key_event)
355 {
356 // Tab: Auto-complete what is selected in the metadata value tree
357 if (key_event.getKeyCode() == KeyEvent.VK_TAB) {
358 MetadataValueTreeNode selected_metadata_value_tree_node = metadata_value_tree_pane.getSelectedMetadataValueTreeNode();
359 if (selected_metadata_value_tree_node != null) {
360 metadata_value_table_pane.setMetadataValueTextFieldValue(selected_metadata_value_tree_node.getFullValue());
361 }
362
363 // We do not want this event to be processed by the table also
364 key_event.consume();
365 }
366
367 // Enter: save the current value then add a blank row for the selected metadata element
368 if (key_event.getKeyCode() == KeyEvent.VK_ENTER) {
369 metadata_value_table_pane.stopEditingAndAddBlankRowForSelectedMetadataElement();
370 }
371 }
372 }
373
374
375 private class MetadataValueTreeSelectionListener
376 implements TreeSelectionListener
377 {
378 public void valueChanged(TreeSelectionEvent tree_selection_event)
379 {
380 // When a node is selected in the tree, fill the metadata value text field with the selected node's value
381 MetadataValueTreeNode selected_metadata_value_tree_node = metadata_value_tree_pane.getSelectedMetadataValueTreeNode();
382 if (selected_metadata_value_tree_node != null) {
383 metadata_value_table_pane.setMetadataValueTextFieldValue(selected_metadata_value_tree_node.getFullValue());
384 }
385 }
386 }
387}
Note: See TracBrowser for help on using the repository browser.