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

Last change on this file since 23433 was 23433, checked in by ak19, 13 years ago

GLI now has a gs.FilenameEncoding metadata field which appears like all the others in GLI's EnrichPane, but is unique in that this metadata (once set, changed or removed) must be applied to the affected filenames in the Collection Tree. More importantly, the changes made for this are to allow GLI's java code to interact with the recent changes to Perl where strings were made unicode-aware (for proper regex matching) but which required other changes elsewhere. To still support filenames with different encodings Perl used URL encoded versions of filenames representing characters' code point values in URL encoding. This required that GLI write out URL encoded filenames to the metadata.xml files that are associated with each folder level of a collection, so that Perl can read them. In this way, they can both speak of the same filenames. Only works on unicode 16 (such as latin-1), non-UTF8 systems. The latter is a requirement since Java uses the filesystem encoding from startup. If it is UTF8, non-recognised characters are replaced by the invalid char for UTF8. This process being destructive, we can't get the original filenames' bytecodes back. The changes made to GLI will work on Windows which is UTF-16 (windows codepage 1252), presumably also Macs (some kind of UTF-16) and also works on Native Latin 1 Linux systems. UTF-8 Linux systems need to be reconfigured to Native Latin-1, or if not installed, an administrator can install it easily.

  • Property svn:keywords set to Author Date Id Revision
File size: 16.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.FilenameEncoding;
47import org.greenstone.gatherer.metadata.MetadataElement;
48import org.greenstone.gatherer.metadata.MetadataValue;
49import org.greenstone.gatherer.metadata.MetadataValueTableEntry;
50import org.greenstone.gatherer.metadata.MetadataValueTreeNode;
51import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
52
53
54/** Provides a view of controls for the editing of metadata.
55 */
56public class EnrichPane
57 extends JPanel
58 implements TreeSelectionListener
59{
60 static private Dimension MINIMUM_SIZE = new Dimension(100, 100);
61 static private Dimension COLLECTION_TREE_SIZE = new Dimension(250, 500);
62
63 private boolean has_focus = false;
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
83
84 public EnrichPane()
85 {
86 this.setComponentOrientation(Dictionary.getOrientation());
87 // Create the metadata value tree pane
88 metadata_value_tree_pane = new MetadataValueTreePane();
89 metadata_value_tree_pane.addMetadataValueTreeSelectionListener(new MetadataValueTreeSelectionListener());
90
91 // Create metadata value table pane
92 metadata_value_table_pane = new MetadataValueTablePane();
93 metadata_value_table_pane.addMetadataValueTableListSelectionListener(new MetadataValueTableListSelectionListener());
94 metadata_value_table_pane.addMetadataValueTableMouseListener(new MetadataValueTableMouseListener());
95 metadata_value_table_pane.addMetadataValueTextFieldDocumentListener(new MetadataValueTextFieldDocumentListener());
96 metadata_value_table_pane.addMetadataValueTextFieldKeyListener(new MetadataValueTextFieldKeyListener());
97 }
98
99
100 /** 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.
101 */
102 public void afterDisplay()
103 {
104 if (Dictionary.getOrientation().isLeftToRight()){
105 external_split.setDividerLocation(0.3);
106 }else{
107 external_split.setDividerLocation(0.7);
108 }
109 }
110
111
112 /** Used to create, connect and layout the components to be shown on this control panel.
113 * @see org.greenstone.gatherer.Gatherer
114 * @see org.greenstone.gatherer.file.FileOpenActionListener
115 * @see org.greenstone.gatherer.gui.Filter
116 */
117 public void display()
118 {
119 JPanel left_hand_pane = new JPanel(new BorderLayout());
120 left_hand_pane.setComponentOrientation(Dictionary.getOrientation());
121 GLIButton metadata_set_button = new GLIButton(Dictionary.get("EnrichPane.ManageMetadataSets"), Dictionary.get("EnrichPane.ManageMetadataSets_Tooltip"));
122 metadata_set_button.addActionListener(new ActionListener() {
123 public void actionPerformed(ActionEvent event) {
124 MetadataSetDialog msd = new MetadataSetDialog();
125 if (msd.setsChanged()) {
126 valueChanged(null);
127 }
128 }
129 });
130
131 // Collection Tree
132 collection_pane = new JPanel(new BorderLayout());
133 // collection_pane.setComponentOrientation(Dictionary.getOrientation());
134 collection_pane.setMinimumSize(MINIMUM_SIZE);
135 collection_pane.setPreferredSize(COLLECTION_TREE_SIZE);
136
137 collection_label = new JLabel(Dictionary.get("Collection.No_Collection"));
138 collection_label.setComponentOrientation(Dictionary.getOrientation());
139 collection_label.setOpaque(true);
140
141 collection_tree = Gatherer.c_man.getCollectionTree();
142 collection_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
143 collection_tree.addTreeSelectionListener(this);
144 collection_tree.setComponentOrientation(Dictionary.getOrientation());
145 collection_filter = collection_tree.getFilter();
146 external_split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
147 external_split.setComponentOrientation(Dictionary.getOrientation());
148 // Layout
149 collection_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(3,3,3,3), BorderFactory.createLoweredBevelBorder()));
150 collection_pane.setMinimumSize(MINIMUM_SIZE);
151 collection_pane.setPreferredSize(new Dimension(Gatherer.g_man.getSize().width / 3, Gatherer.g_man.getSize().height));
152 collection_pane.setComponentOrientation(Dictionary.getOrientation());
153 // Collection Pane
154 collection_pane.add(collection_label, BorderLayout.NORTH);
155
156 JSplitPane metadata_editing_pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
157 metadata_editing_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
158 metadata_editing_pane.setDividerSize(8);
159 metadata_editing_pane.setComponentOrientation(Dictionary.getOrientation());
160
161 metadata_editing_pane.add(metadata_value_table_pane, JSplitPane.TOP);
162 metadata_editing_pane.add(metadata_value_tree_pane, JSplitPane.BOTTOM);
163 metadata_editing_pane.setDividerLocation(250);
164
165 left_hand_pane.add(collection_pane, BorderLayout.CENTER);
166 left_hand_pane.add(metadata_set_button, BorderLayout.SOUTH);
167 if (Dictionary.getOrientation().isLeftToRight()){
168 external_split.add(left_hand_pane, JSplitPane.LEFT);
169 external_split.add(metadata_editing_pane, JSplitPane.RIGHT);
170 }else{
171 external_split.add(left_hand_pane, JSplitPane.RIGHT);
172 external_split.add(metadata_editing_pane, JSplitPane.LEFT);
173 }
174
175
176
177 this.setLayout(new BorderLayout());
178 this.add(external_split, BorderLayout.CENTER);
179 }
180
181
182 /** Called to inform this pane that it has just gained focus as an effect of the user clicking on its tab
183 */
184 public void gainFocus()
185 {
186 // Remember that we currently have focus
187 has_focus = true;
188
189 // Add the collection tree and filter back into this pane
190 collection_scroll = new JScrollPane(collection_tree);
191 collection_pane.add(collection_scroll, BorderLayout.CENTER);
192 collection_pane.add(collection_filter, BorderLayout.SOUTH);
193
194 // Select the first node in the tree if nothing is already selected
195 if (collection_tree.getSelectionPaths() == null && collection_tree.getRowCount() > 0) {
196 collection_tree.setImmediate(true);
197 collection_tree.setSelectionRow(0);
198 collection_tree.setImmediate(false);
199 return;
200 }
201
202 // Force all of the controls to be updated
203 valueChanged(null);
204 }
205
206
207 /** Called to inform this pane that it has just lost focus as an effect of the user clicking on another tab
208 */
209 public void loseFocus()
210 {
211 // Very important: make sure metadata value is saved before leaving the pane
212 metadata_value_table_pane.stopEditingAndRebuild(file_nodes);
213
214 // Make sure all the metadata has been saved to file
215 MetadataXMLFileManager.saveMetadataXMLFiles();
216
217 // Remove the collection tree and filter from this pane so it can be added to the Gather pane
218 collection_pane.remove(collection_scroll);
219 collection_pane.remove(collection_filter);
220
221 // Remember that we no longer have focus
222 has_focus = false;
223 }
224
225
226 /** 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)
227 * @param mode the mode level as an int
228 */
229 public void modeChanged(int mode)
230 {
231 collection_filter.setEditable(mode >= Configuration.LIBRARIAN_MODE);
232 }
233
234
235 /** Refresh this pane, depending on what has just happened (refresh_reason). */
236 public void refresh(int refresh_reason, boolean collection_loaded)
237 {
238 if (collection_loaded) {
239 // Update collection label
240 collection_label.setText(Dictionary.get("Collection.Collection"));
241 collection_label.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
242 collection_label.setForeground(Configuration.getColor("coloring.collection_heading_foreground", false));
243
244 // Update collection tree
245 if (refresh_reason == Gatherer.COLLECTION_OPENED) {
246 collection_tree.setModel(Gatherer.c_man.getCollectionTreeModel());
247 }
248
249 // Update collection filter
250 collection_filter.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
251 }
252 else {
253 // Update collection label
254 collection_label.setText(Dictionary.get("Collection.No_Collection"));
255 collection_label.setBackground(Color.lightGray);
256 collection_label.setForeground(Color.black);
257
258 // Update collection tree
259 collection_tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode("Error")));
260
261 // Update collection filter
262 collection_filter.setBackground(Color.lightGray);
263 }
264
265 // Enable or disable the controls
266 collection_tree.setEnabled(collection_loaded);
267 collection_filter.setEnabled(collection_loaded);
268
269 // Force the metadata table to be rebuilt (for switching extracted metadata on or off)
270 if (refresh_reason == Gatherer.PREFERENCES_CHANGED) {
271 metadata_value_table_pane.stopEditingAndRebuild(file_nodes);
272 }
273 }
274
275
276 /** Allows other classes to request the enrich pane to prepare for metadata
277 * saving.
278 * @author John Thompson, DL Consulting Ltd
279 */
280 public void stopEditingAndRebuild()
281 {
282 // Update the metadata value table (and consequently, the metadata value tree)
283 metadata_value_table_pane.stopEditingAndRebuild(file_nodes);
284 }
285 /** stopEditingAndRebuild() **/
286
287 /** Called whenever the collection tree selection changes. This causes the metadata value table to be rebuilt. */
288 public void valueChanged(TreeSelectionEvent event)
289 {
290 if(FilenameEncoding.isRefreshRequired()) {
291 // The CollectionTree is in the process of being re-built to deal with filename-encodings,
292 // so don't mess up the table during that time.
293 // (CollectionTreeNode.refreshDescendantEncodings() doesn't cope well if this method
294 // responds on Tree selection changes while the tree is updating its encodings, resulting in lost
295 // and misplaced metadata values in the table and thereby in the metadata.xml files themselves).
296 return;
297 }
298
299
300 // If we haven't got focus then it must have been a selection in the Gather pane, so don't bother rebuilding
301 if (has_focus == false) {
302 return;
303 }
304
305 // Nothing selected in the collection tree
306 if (collection_tree.getSelectionCount() == 0) {
307 file_nodes = null;
308 }
309
310 // Some files selected in the collection tree
311 else {
312 TreePath paths[] = collection_tree.getSelectionPaths();
313 file_nodes = new CollectionTreeNode[paths.length];
314 for (int i = 0; i < paths.length; i++) {
315 file_nodes[i] = (CollectionTreeNode) paths[i].getLastPathComponent();
316 }
317 }
318
319 // Update the metadata value table (and consequently, the metadata value tree)
320 metadata_value_table_pane.stopEditingAndRebuild(file_nodes);
321 }
322
323
324 private class MetadataValueTableListSelectionListener
325 implements ListSelectionListener
326 {
327 public void valueChanged(ListSelectionEvent list_selection_event)
328 {
329 // We only want to handle one event per selection, so wait for the value to stabilise
330 if (list_selection_event.getValueIsAdjusting()) {
331 return;
332 }
333
334 // Update the metadata value tree for the current table selection
335 metadata_value_tree_pane.rebuild(metadata_value_table_pane.getSelectedMetadataValueTableEntry());
336 }
337 }
338
339
340 private class MetadataValueTableMouseListener
341 extends MouseAdapter
342 {
343 public void mouseClicked(MouseEvent mouse_event)
344 {
345 // We're only interested in clicks on the inherited column
346 if (metadata_value_table_pane.isMouseEventForInheritedMetadataValueTableColumn(mouse_event) == false) {
347 return;
348 }
349
350 // If the selected metadata is inherited, switch to the folder it came from
351 MetadataValueTableEntry selected_metadata_value_table_entry = metadata_value_table_pane.getSelectedMetadataValueTableEntry();
352 if (selected_metadata_value_table_entry.isInheritedMetadata()) {
353 collection_tree.setSelection(selected_metadata_value_table_entry.getFolderMetadataInheritedFrom());
354 }
355 }
356 }
357
358
359 private class MetadataValueTextFieldDocumentListener
360 implements DocumentListener
361 {
362 /** Gives notification that an attribute or set of attributes changed */
363 public void changedUpdate(DocumentEvent document_event) {
364 validate(document_event);
365 }
366
367 /** Gives notification that there was an insert into the document */
368 public void insertUpdate(DocumentEvent document_event) {
369 validate(document_event);
370 }
371
372 /** Gives notification that a portion of the document has been removed */
373 public void removeUpdate(DocumentEvent document_event) {
374 validate(document_event);
375 }
376
377
378 /** Ensures that the value tree is updated in response to changes in the value text field */
379 private void validate(DocumentEvent document_event)
380 {
381 try {
382 Document document = document_event.getDocument();
383 String metadata_value_string = document.getText(0, document.getLength());
384 metadata_value_tree_pane.selectBestPathForMetadataValue(metadata_value_string);
385 }
386 catch (Exception exception) {
387 DebugStream.printStackTrace(exception);
388 }
389 }
390 }
391
392
393 private class MetadataValueTextFieldKeyListener
394 extends KeyAdapter
395 {
396 /** Gives notification of key events on the text field */
397 public void keyPressed(KeyEvent key_event)
398 {
399 // Tab: Auto-complete what is selected in the metadata value tree
400 if (key_event.getKeyCode() == KeyEvent.VK_TAB) {
401 MetadataValueTreeNode selected_metadata_value_tree_node = metadata_value_tree_pane.getSelectedMetadataValueTreeNode();
402 if (selected_metadata_value_tree_node != null) {
403 metadata_value_table_pane.setMetadataValueTextFieldValue(selected_metadata_value_tree_node.getFullValue());
404 }
405
406 // We do not want this event to be processed by the table also
407 key_event.consume();
408 }
409
410 // Enter: save the current value then add a blank row for the selected metadata element
411 if (key_event.getKeyCode() == KeyEvent.VK_ENTER) {
412 metadata_value_table_pane.stopEditingAndAddBlankRowForSelectedMetadataElement();
413 }
414 }
415 }
416
417
418 private class MetadataValueTreeSelectionListener
419 implements TreeSelectionListener
420 {
421 public void valueChanged(TreeSelectionEvent tree_selection_event)
422 {
423 // When a node is selected in the tree, fill the metadata value text field with the selected node's value
424 MetadataValueTreeNode selected_metadata_value_tree_node = metadata_value_tree_pane.getSelectedMetadataValueTreeNode();
425 if (selected_metadata_value_tree_node != null) {
426 metadata_value_table_pane.setMetadataValueTextFieldValue(selected_metadata_value_tree_node.getFullValue());
427 }
428 }
429 }
430}
Note: See TracBrowser for help on using the repository browser.