Changeset 9856
- Timestamp:
- 2005-05-12T12:24:38+12:00 (19 years ago)
- Location:
- trunk/gli/src/org/greenstone/gatherer
- Files:
-
- 3 added
- 1 deleted
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/gli/src/org/greenstone/gatherer/collection/CollectionManager.java
r9828 r9856 59 59 import org.greenstone.gatherer.gui.WarningDialog; 60 60 import org.greenstone.gatherer.metadata.DocXMLFileManager; 61 import org.greenstone.gatherer.metadata.MetadataChangedListener; 61 62 import org.greenstone.gatherer.metadata.MetadataSet; 62 63 import org.greenstone.gatherer.metadata.MetadataSetManager; … … 78 79 */ 79 80 public class CollectionManager 80 implements GShellListener {81 81 implements GShellListener, MetadataChangedListener 82 { 82 83 /** Are we currently in the process of building? */ 83 84 private boolean building = false; … … 111 112 this.importing = false; 112 113 this.collection = null; 114 115 MetadataXMLFileManager.addMetadataChangedListener(this); 113 116 } 114 117 … … 947 950 public synchronized void message(GShellEvent event) { 948 951 } 952 953 954 public void metadataChanged(CollectionTreeNode[] file_nodes) 955 { 956 if (collection != null) { 957 collection.setMetadataChanged(true); 958 } 959 } 960 949 961 950 962 /** This call is fired whenever a process within a GShell created by this class begins. -
trunk/gli/src/org/greenstone/gatherer/gui/EditorDialog.java
r8994 r9856 62 62 private String result = null; 63 63 /** The size of the edit pop-up. */ 64 final static private Dimension SIZE = new Dimension(400, 425);64 final static private Dimension SIZE = new Dimension(400, 300); 65 65 66 66 /** Constructor */ -
trunk/gli/src/org/greenstone/gatherer/gui/EnrichPane.java
r9350 r9856 1 1 /** 2 *######################################################################### 3 * 4 * A component of the Gatherer application, part of the Greenstone digital 5 * library suite from the New Zealand Digital Library Project at the 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 6 5 * University of Waikato, New Zealand. 7 6 * 8 * <BR><BR> 7 * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ 8 * Based on code by John Thompson 9 9 * 10 * Author: John Thompson, Greenstone Digital Library, University of Waikato 11 * 12 * <BR><BR> 13 * 14 * Copyright (C) 1999 New Zealand Digital Library Project 15 * 16 * <BR><BR> 10 * Copyright (C) 2005 New Zealand Digital Library Project 17 11 * 18 12 * This program is free software; you can redistribute it and/or modify … … 21 15 * (at your option) any later version. 22 16 * 23 * <BR><BR>24 *25 17 * This program is distributed in the hope that it will be useful, 26 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of … … 28 20 * GNU General Public License for more details. 29 21 * 30 * <BR><BR>31 *32 22 * You should have received a copy of the GNU General Public License 33 23 * along with this program; if not, write to the Free Software 34 24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 35 *######################################################################## 25 *############################################################################ 36 26 */ 27 37 28 package org.greenstone.gatherer.gui; 38 29 … … 44 35 import javax.swing.*; 45 36 import javax.swing.event.*; 46 import javax.swing.t able.*;37 import javax.swing.text.*; 47 38 import javax.swing.tree.*; 48 39 import org.greenstone.gatherer.Configuration; … … 56 47 import org.greenstone.gatherer.metadata.MetadataValue; 57 48 import org.greenstone.gatherer.metadata.MetadataValueTableEntry; 58 import org.greenstone.gatherer.metadata.MetadataValueTableModel;59 import org.greenstone.gatherer.metadata.MetadataValueTreeModel;60 49 import org.greenstone.gatherer.metadata.MetadataValueTreeNode; 61 import org.greenstone.gatherer.metadata.MetadataXMLFileManager;62 50 import org.greenstone.gatherer.util.DragGroup; 63 import org.greenstone.gatherer.util.PatternTokenizer;64 51 import org.greenstone.gatherer.util.TreeSynchronizer; 65 import org.greenstone.gatherer.util.Utility;66 import org.greenstone.gatherer.util.XMLTools;67 52 68 53 … … 71 56 public class EnrichPane 72 57 extends JPanel 73 implements ActionListener,TreeSelectionListener58 implements TreeSelectionListener 74 59 { 75 static private Dimension CONTROL_SIZE = new Dimension(560, 240);76 60 static private Dimension MINIMUM_SIZE = new Dimension(100, 100); 77 static private Dimension TABLE_SIZE = new Dimension(560, 25); 78 static private Dimension TREE_SIZE = new Dimension(250, 500); 79 static private int MINIMUM_TABLE_HEADER_SIZE = 15; 80 81 private MetadataValueTable metadata_value_table = null; 82 /** The layout manager used to display either the MetadataValueTable (when files are selected) or a placeholder panel */ 83 private CardLayout metadata_value_table_card_layout = null; 84 /** The name of the panel containing the metadata table */ 85 static final private String TABLE_CARD = ""; 86 /** The name of the panel containing the "no files selected" placeholder for the metadata table */ 87 static final private String TABLE_CARD_NO_FILES_SELECTED = "No files selected"; 88 /** The name of the panel containing the "no metadata available" placeholder for the metadata table */ 89 static final private String TABLE_CARD_NO_METADATA_AVAILABLE = "No metadata available"; 90 91 private JTextField metadata_value_text_field = null; 92 /** The MetadataValueTree graphically shows the available metadata that has been previously assigned, and provides controls for adding, updating and removing metadata, depending on the user's selections in the other important components. */ 93 private MetadataValueTree metadata_value_tree = null; 94 /** The layout manager used to display either the MetadataValueTree (when metadata is selected) or a placeholder panel */ 95 private CardLayout metadata_value_tree_card_layout = null; 96 /** The name of the panel containing the metadata value tree */ 97 static final private String TREE_CARD = ""; 98 /** The name of the panel containing the "no metadata element selected" placeholder for the metadata table */ 99 static final private String TREE_CARD_NO_METADATA_ELEMENT_SELECTED = "No metadata element selected"; 100 101 /** Used to dynamically filter the collection tree at user request. Note that this is synchronized with the collection tree filter in the Gather view. */ 102 private Filter collection_filter = null; 61 static private Dimension COLLECTION_TREE_SIZE = new Dimension(250, 500); 62 63 /** The collection tree. */ 64 private CollectionTree collection_tree = null; 103 65 /** The currently reported selection. */ 104 66 private CollectionTreeNode[] file_nodes = null; 105 /** The button, which when clicked, adds metadata to the selected records. */ 106 private JButton add; 107 /** The button, which when clicked, removes the selected metadata from the selected records. */ 108 private JButton remove; 109 /** The button, which when clicked, updates the selected metadata from the selected records. */ 110 private JButton replace; 111 /** This button creates an editor dialog to allow for an expanded area to type in text. */ 112 private JButton expand; 113 private JButton expand_for_extracted; 67 /** Used to dynamically filter the collection tree. Synchronized with the same filter in the Gather view. */ 68 private Filter collection_filter = null; 114 69 /** The label at the top of the collection tree, which shows the collection name. */ 115 70 private JLabel collection_label; 116 /** The panel in which the metadata value card layout resides. */ 117 private JPanel control_pane; 118 /** The panel in which the metadata table card layout resides. */ 119 private JPanel table_card_pane; 120 /** The splitpane dividing the collection tree and the metadata based controls. */ 71 /** The splitpane dividing the collection tree and the metadata editing controls. */ 121 72 private JSplitPane external_split; 122 /** The label shown at the top of the metadata table detailing the current selection statistics. */123 private JTextField table_label;124 /** A reference to the collection tree. */125 private CollectionTree collection_tree;73 /** The metadata value table shows the metadata values that are currently assigned to a file. */ 74 private MetadataValueTablePane metadata_value_table_pane = null; 75 /** The metadata value tree shows the metadata values that are currently assigned to a metadata element. */ 76 private MetadataValueTreePane metadata_value_tree_pane = null; 126 77 /** Provide synchronization between the collection trees in this view and the collection pane view. */ 127 78 private TreeSynchronizer collection_tree_sync = null; 128 private boolean metadata_edit_event = false;129 79 130 80 … … 136 86 this.collection_tree_sync = collection_tree_sync; 137 87 138 add = new GLIButton(); 139 add.addActionListener(this); 140 add.setEnabled(false); 141 add.setMnemonic(KeyEvent.VK_A); 142 add.setPreferredSize(Utility.MINIMUM_BUTTON_SIZE); 143 Dictionary.registerBoth(add, "EnrichPane.Accumulate", "EnrichPane.Accumulate_Tooltip"); 144 145 replace = new GLIButton(); 146 replace.addActionListener(this); 147 replace.setEnabled(false); 148 replace.setMnemonic(KeyEvent.VK_P); 149 replace.setPreferredSize(Utility.MINIMUM_BUTTON_SIZE); 150 Dictionary.registerBoth(replace, "EnrichPane.Overwrite", "EnrichPane.Overwrite_Tooltip"); 151 152 remove = new GLIButton(); 153 remove.addActionListener(this); 154 remove.setEnabled(false); 155 remove.setMnemonic(KeyEvent.VK_R); 156 remove.setPreferredSize(Utility.MINIMUM_BUTTON_SIZE); 157 Dictionary.registerBoth(remove, "EnrichPane.Remove", "EnrichPane.Remove_Tooltip"); 158 159 expand = new GLIButton(); 160 expand.addActionListener(this); 161 expand.setEnabled(true); 162 expand.setMnemonic(KeyEvent.VK_E); 163 expand.setPreferredSize(new Dimension(25, 25)); 164 Dictionary.registerBoth(expand, "EnrichPane.Expand", "EnrichPane.Expand_Tooltip"); 165 166 expand_for_extracted = new GLIButton(); 167 expand_for_extracted.addActionListener(this); 168 expand_for_extracted.setEnabled(true); 169 expand_for_extracted.setMnemonic(KeyEvent.VK_E); 170 expand_for_extracted.setPreferredSize(new Dimension(25, 25)); 171 Dictionary.registerBoth(expand_for_extracted, "EnrichPane.Expand", "EnrichPane.Expand_Tooltip"); 172 173 metadata_value_text_field = new JTextField(); 174 metadata_value_table = new MetadataValueTable(); 175 metadata_value_tree = new MetadataValueTree(CONTROL_SIZE.width, CONTROL_SIZE.height); 176 } 177 178 179 /** Called whenever an action occurs on one of our registered buttons. 180 * @param event An <strong>ActionEvent</strong> containing information about the event. 181 */ 182 public void actionPerformed(ActionEvent event) 183 { 184 Object esrc = event.getSource(); 185 186 // One of the metadata editing buttons was pressed 187 if (esrc == add || esrc == replace || esrc == remove) { 188 // Double-check that some files and a metadata element have been selected 189 MetadataValueTableEntry selected_metadata_value_table_entry = metadata_value_table.getSelectedMetadataValueTableEntry(); 190 if (file_nodes == null || selected_metadata_value_table_entry == null) { 191 return; 192 } 193 194 // If we're adding metadata to folders display the warning 195 if (esrc == add && !file_nodes[0].isLeaf()) { 196 WarningDialog dialog = new WarningDialog("warning.DirectoryLevelMetadata", "DirectoryLevelMetadata.Title", "DirectoryLevelMetadata.Message", null, true); 197 int dialog_result = dialog.display(); 198 dialog.dispose(); 199 200 if (dialog_result != JOptionPane.OK_OPTION) { 201 return; 202 } 203 } 204 205 // Lock the interface so nothing can be changed while the metadata edit is being processed 206 Gatherer.g_man.wait(true); 207 208 // Add button pressed 209 if (esrc == add) { 210 MetadataElement metadata_element = metadata_value_table.getSelectedMetadataElement(); 211 MetadataValueTreeNode metadata_value_tree_node = metadata_element.addMetadataValue(metadata_value_tree.getSelectedValue()); 212 MetadataValue metadata_value = new MetadataValue(metadata_element, metadata_value_tree_node); 213 metadata_value.setIsAccumulatingMetadata(true); 214 (new AppendMetadataTask(metadata_value)).run(); 215 } 216 217 // Replace button pressed 218 else if (esrc == replace) { 219 MetadataElement metadata_element = metadata_value_table.getSelectedMetadataElement(); 220 MetadataValueTreeNode metadata_value_tree_node = metadata_element.addMetadataValue(metadata_value_tree.getSelectedValue()); 221 MetadataValue metadata_value = new MetadataValue(metadata_element, metadata_value_tree_node); 222 metadata_value.setIsAccumulatingMetadata(!metadata_value_table.getSelectedMetadataValueTableEntry().isInheritedMetadata()); 223 (new ReplaceMetadataTask(metadata_value, selected_metadata_value_table_entry)).run(); 224 } 225 226 // Remove button pressed 227 else if (esrc == remove) { 228 (new RemoveMetadataTask(selected_metadata_value_table_entry)).run(); 229 } 230 231 // Note that the collection's metadata has been changed 232 Gatherer.c_man.getCollection().setMetadataChanged(true); 233 } 234 235 // Expand button pressed 236 else if (esrc == expand) { 237 EditorDialog ed = new EditorDialog(); 238 String new_metadata_value = ed.display(metadata_value_tree.getSelectedValue()); 239 if (new_metadata_value != null) { 240 metadata_value_tree.setSelectedValue(new_metadata_value); 241 } 242 } 243 244 // Expand button for extracted metadata pressed 245 else if (esrc == expand_for_extracted) { 246 EditorDialog ed = new EditorDialog(); 247 ed.setEditable(false); 248 ed.display(metadata_value_table.getSelectedMetadataValueTableEntry().getFullValue()); 249 } 88 // Create the metadata value tree pane 89 metadata_value_tree_pane = new MetadataValueTreePane(); 90 metadata_value_tree_pane.addMetadataValueTreeSelectionListener(new MetadataValueTreeSelectionListener()); 91 92 // Create metadata value table pane 93 metadata_value_table_pane = new MetadataValueTablePane(); 94 metadata_value_table_pane.addMetadataValueTableListSelectionListener(new MetadataValueTableListSelectionListener()); 95 metadata_value_table_pane.addMetadataValueTableMouseListener(new MetadataValueTableMouseListener()); 96 metadata_value_table_pane.addMetadataValueTextFieldDocumentListener(new MetadataValueTextFieldDocumentListener()); 97 metadata_value_table_pane.addMetadataValueTextFieldKeyListener(new MetadataValueTextFieldKeyListener()); 250 98 } 251 99 … … 269 117 JPanel collection_pane = new JPanel(new BorderLayout()); 270 118 collection_pane.setMinimumSize(MINIMUM_SIZE); 271 collection_pane.setPreferredSize( TREE_SIZE);119 collection_pane.setPreferredSize(COLLECTION_TREE_SIZE); 272 120 273 121 external_split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); … … 311 159 collection_pane.add(collection_filter, BorderLayout.SOUTH); 312 160 313 JSplitPane main_split_pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 314 main_split_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 315 main_split_pane.setDividerSize(8); 316 317 // Metadata Table. In order to achieve what Ian envisions I'm going 318 // to have to do a tricky. The table itself will sit in a stacked 319 // CardLayout. Card zero will be a see-through JPanel with a message 320 // smack bang in the center, something like "No Metadata". If any 321 // page of the table would appear to have no metadata this card will 322 // be swapped to the front. 323 324 JPanel table_pane = new JPanel(); 325 table_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0)); 326 327 JPanel table_title_pane = new JPanel(); 328 329 table_label = new JTextField(); 330 table_label.setBackground(Configuration.getColor("coloring.collection_tree_background", false)); 331 table_label.setEditable(false); 332 Dictionary.registerText(table_label, "EnrichPane.No_File"); 333 334 table_card_pane = new JPanel(); 335 336 JPanel table_pane_zero = new JPanel(); 337 table_pane_zero.setOpaque(false); 338 339 JPanel table_pane_two = new JPanel(); 340 table_pane_two.setOpaque(false); 341 342 JLabel no_file_message = new JLabel(); 343 no_file_message.setHorizontalAlignment(JLabel.CENTER); 344 no_file_message.setOpaque(false); 345 no_file_message.setVerticalAlignment(JLabel.CENTER); 346 Dictionary.registerText(no_file_message, "EnrichPane.No_File"); 347 348 JLabel no_metadata_message = new JLabel(); 349 no_metadata_message.setHorizontalAlignment(JLabel.CENTER); 350 no_metadata_message.setOpaque(false); 351 no_metadata_message.setVerticalAlignment(JLabel.CENTER); 352 Dictionary.registerText(no_metadata_message, "EnrichPane.No_Metadata"); 353 354 JPanel table_pane_one = new JPanel(); 355 356 JScrollPane table_scroll = new JScrollPane(metadata_value_table); 357 table_scroll.getViewport().setBackground(Configuration.getColor("coloring.collection_tree_background", false)); 358 table_scroll.setOpaque(true); 359 360 // Create the cards for the metadata value table 361 metadata_value_table_card_layout = new CardLayout(); 362 363 table_pane_zero.setLayout(new BorderLayout()); 364 table_pane_zero.add(no_file_message, BorderLayout.CENTER); 365 366 table_pane_one.setLayout(new BorderLayout()); 367 table_pane_one.add(table_scroll, BorderLayout.CENTER); 368 369 table_pane_two.setLayout(new BorderLayout()); 370 table_pane_two.add(no_metadata_message, BorderLayout.CENTER); 371 372 table_card_pane.setLayout(metadata_value_table_card_layout); 373 table_card_pane.add(table_pane_zero, TABLE_CARD_NO_FILES_SELECTED); 374 table_card_pane.add(table_pane_one, TABLE_CARD); 375 table_card_pane.add(table_pane_two, TABLE_CARD_NO_METADATA_AVAILABLE); 376 377 // Create the cards for the metadata value tree 378 metadata_value_tree_card_layout = new CardLayout(); 379 380 // Control pane 381 control_pane = new JPanel(); 382 control_pane.setBorder(BorderFactory.createLoweredBevelBorder()); 383 control_pane.setMinimumSize(MINIMUM_SIZE); 384 control_pane.setSize(CONTROL_SIZE); 385 control_pane.setPreferredSize(CONTROL_SIZE); 386 387 JPanel tools_off_pane = new JPanel(); 388 389 JLabel tools_off_label = new JLabel(); 390 tools_off_label.setHorizontalAlignment(JLabel.CENTER); 391 tools_off_label.setOpaque(false); 392 tools_off_label.setVerticalAlignment(JLabel.CENTER); 393 Dictionary.registerText(tools_off_label, "EnrichPane.No_Metadata_Element"); 394 395 JPanel tools_on_pane = new JPanel(); 396 tools_on_pane.setMinimumSize(MINIMUM_SIZE); 397 tools_on_pane.setSize(TABLE_SIZE); 398 tools_on_pane.setPreferredSize(TABLE_SIZE); 399 400 // Layout. 401 402 // Metaedit controls 403 tools_off_pane.setLayout(new BorderLayout()); 404 tools_off_pane.add(tools_off_label, BorderLayout.CENTER); 405 406 tools_on_pane.setLayout(new BorderLayout()); 407 tools_on_pane.add(metadata_value_tree, BorderLayout.CENTER); 408 409 control_pane.setLayout(metadata_value_tree_card_layout); 410 control_pane.add(tools_off_pane, TREE_CARD_NO_METADATA_ELEMENT_SELECTED); 411 control_pane.add(tools_on_pane, TREE_CARD); 412 413 // Table components 414 table_title_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0)); 415 table_title_pane.setLayout(new BorderLayout()); 416 table_title_pane.add(table_label, BorderLayout.CENTER); 417 418 table_pane.setLayout(new BorderLayout()); 419 table_pane.add(table_title_pane, BorderLayout.NORTH); 420 table_pane.add(table_card_pane, BorderLayout.CENTER); 421 422 main_split_pane.add(table_pane, JSplitPane.TOP); 423 main_split_pane.add(control_pane, JSplitPane.BOTTOM); 424 main_split_pane.setDividerLocation(250); 161 JSplitPane metadata_editing_pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 162 metadata_editing_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5)); 163 metadata_editing_pane.setDividerSize(8); 164 165 metadata_editing_pane.add(metadata_value_table_pane, JSplitPane.TOP); 166 metadata_editing_pane.add(metadata_value_tree_pane, JSplitPane.BOTTOM); 167 metadata_editing_pane.setDividerLocation(250); 425 168 426 169 external_split.add(collection_pane, JSplitPane.LEFT); 427 external_split.add(m ain_split_pane, JSplitPane.RIGHT);170 external_split.add(metadata_editing_pane, JSplitPane.RIGHT); 428 171 429 172 this.setLayout(new BorderLayout()); … … 432 175 433 176 434 /** Called to inform this control panel that it has just gained focus as an effect of the user clicking on its tab.177 /** Called to inform this pane that it has just gained focus as an effect of the user clicking on its tab 435 178 */ 436 179 public void gainFocus() … … 450 193 451 194 // Force all of the controls to be updated 452 valueChanged(n ew TreeSelectionEvent(this, null, false, null, null));195 valueChanged(null); 453 196 } 454 197 … … 502 245 // Force the metadata table to be rebuilt (for switching extracted metadata on or off) 503 246 if (refresh_reason == Gatherer.PREFERENCES_CHANGED) { 504 valueChanged(null); 505 } 506 } 507 508 509 /** This method is called whenever the selection within the collection 510 * tree changes. This causes the table to be rebuilt with a new model. 511 */ 247 metadata_value_table_pane.stopEditingAndRebuild(file_nodes); 248 } 249 } 250 251 252 /** Called whenever the collection tree selection changes. This causes the metadata value table to be rebuilt. */ 512 253 public void valueChanged(TreeSelectionEvent event) 513 254 { … … 515 256 if (collection_tree.getSelectionCount() == 0) { 516 257 file_nodes = null; 517 518 // Update the label to show nothing is selected in the collection tree519 Dictionary.registerText(table_label, "EnrichPane.No_File");520 521 // Display the "no file selected" card522 metadata_value_table_card_layout.show(table_card_pane, TABLE_CARD_NO_FILES_SELECTED);523 258 } 524 259 … … 530 265 file_nodes[i] = (CollectionTreeNode) paths[i].getLastPathComponent(); 531 266 } 532 533 // Update the label to show what is selected in the collection tree534 table_label.setText(collection_tree.getSelectionDetails());535 267 } 536 268 537 269 // Update the metadata value table (and consequently, the metadata value tree) 538 MetadataValue previously_selected_metadata_value = metadata_value_table.getSelectedMetadataValueTableEntry(); 539 metadata_value_table.rebuildAndSelectRowWithValueClosestTo(previously_selected_metadata_value); 540 } 541 542 543 private class AppendMetadataTask 544 extends Thread 545 { 546 private MetadataValue metadata_value = null; 547 548 private AppendMetadataTask(MetadataValue metadata_value) 549 { 550 this.metadata_value = metadata_value; 551 } 552 553 public void run() 270 metadata_value_table_pane.stopEditingAndRebuild(file_nodes); 271 } 272 273 274 private class MetadataValueTableListSelectionListener 275 implements ListSelectionListener 276 { 277 public void valueChanged(ListSelectionEvent list_selection_event) 278 { 279 // We only want to handle one event per selection, so wait for the value to stabilise 280 if (list_selection_event.getValueIsAdjusting()) { 281 return; 282 } 283 284 // Update the metadata value tree for the current table selection 285 metadata_value_tree_pane.rebuild(metadata_value_table_pane.getSelectedMetadataValueTableEntry()); 286 } 287 } 288 289 290 private class MetadataValueTableMouseListener 291 extends MouseAdapter 292 { 293 public void mouseClicked(MouseEvent mouse_event) 294 { 295 // We're only interested in clicks on the inherited column 296 if (metadata_value_table_pane.isMouseEventForInheritedMetadataValueTableColumn(mouse_event) == false) { 297 return; 298 } 299 300 // If the selected metadata is inherited, switch to the folder it came from 301 MetadataValueTableEntry selected_metadata_value_table_entry = metadata_value_table_pane.getSelectedMetadataValueTableEntry(); 302 if (selected_metadata_value_table_entry.isInheritedMetadata()) { 303 collection_tree.setSelection(selected_metadata_value_table_entry.getFolderMetadataInheritedFrom()); 304 } 305 } 306 } 307 308 309 private class MetadataValueTextFieldDocumentListener 310 implements DocumentListener 311 { 312 /** Gives notification that an attribute or set of attributes changed */ 313 public void changedUpdate(DocumentEvent document_event) { 314 validate(document_event); 315 } 316 317 /** Gives notification that there was an insert into the document */ 318 public void insertUpdate(DocumentEvent document_event) { 319 validate(document_event); 320 } 321 322 /** Gives notification that a portion of the document has been removed */ 323 public void removeUpdate(DocumentEvent document_event) { 324 validate(document_event); 325 } 326 327 328 /** Ensures that the value tree is updated in response to changes in the value text field */ 329 private void validate(DocumentEvent document_event) 554 330 { 555 331 try { 556 // Edit metadata.xml files to add the metadata 557 MetadataXMLFileManager.addMetadata(file_nodes, metadata_value); 558 559 // Update the metadata value table and tree 560 metadata_edit_event = true; 561 metadata_value_table.rebuildAndSelectRowWithValueClosestTo(metadata_value); 562 metadata_edit_event = false; 332 Document document = document_event.getDocument(); 333 String metadata_value_string = document.getText(0, document.getLength()); 334 metadata_value_tree_pane.selectBestPathForMetadataValue(metadata_value_string); 563 335 } 564 336 catch (Exception exception) { 565 // We need to catch any exceptions here so the interface is unlocked below566 337 DebugStream.printStackTrace(exception); 567 338 } 568 569 // Operation finished, so turn busy cursor off and unlock interface 570 Gatherer.g_man.wait(false); 571 } 572 } 573 574 575 private class ReplaceMetadataTask 576 extends Thread 577 { 578 private MetadataValue metadata_value = null; 579 private MetadataValueTableEntry selected_metadata_value_table_entry = null; 580 581 private ReplaceMetadataTask(MetadataValue metadata_value, MetadataValueTableEntry selected_metadata_value_table_entry) 582 { 583 this.metadata_value = metadata_value; 584 this.selected_metadata_value_table_entry = selected_metadata_value_table_entry; 585 } 586 587 public void run() 588 { 589 try { 590 // Edit metadata.xml files to replace the metadata 591 MetadataXMLFileManager.removeMetadata(file_nodes, selected_metadata_value_table_entry); 592 MetadataXMLFileManager.addMetadata(file_nodes, metadata_value); 593 594 // Update the metadata value table and tree 595 metadata_edit_event = true; 596 metadata_value_table.rebuildAndSelectRowWithValueClosestTo(metadata_value); 597 metadata_edit_event = false; 598 } 599 catch (Exception exception) { 600 // We need to catch any exceptions here so the interface is unlocked below 601 DebugStream.printStackTrace(exception); 602 } 603 604 // Operation finished, so turn busy cursor off and unlock interface 605 Gatherer.g_man.wait(false); 606 } 607 } 608 609 610 private class RemoveMetadataTask 611 extends Thread 612 { 613 private MetadataValueTableEntry selected_metadata_value_table_entry = null; 614 615 private RemoveMetadataTask(MetadataValueTableEntry selected_metadata_value_table_entry) 616 { 617 this.selected_metadata_value_table_entry = selected_metadata_value_table_entry; 618 } 619 620 public void run() 621 { 622 try { 623 // Edit metadata.xml files to remove the metadata 624 MetadataXMLFileManager.removeMetadata(file_nodes, selected_metadata_value_table_entry); 625 626 // Update the metadata value table and tree 627 metadata_edit_event = true; 628 metadata_value_table.rebuildAndSelectRowWithValueClosestTo(selected_metadata_value_table_entry); 629 metadata_edit_event = false; 630 } 631 catch (Exception exception) { 632 // We need to catch any exceptions here so the interface is unlocked below 633 DebugStream.printStackTrace(exception); 634 } 635 636 // Operation finished, so turn busy cursor off and unlock interface 637 Gatherer.g_man.wait(false); 638 } 639 } 640 641 642 private class MetadataValueTable 643 extends JTable 644 { 645 private MetadataValueTableModel metadata_value_table_model = null; 646 /** The currently selected metadata value table entry */ 647 private MetadataValueTableEntry selected_metadata_value_table_entry = null; 648 649 650 public MetadataValueTable() 651 { 652 metadata_value_table_model = new MetadataValueTableModel(); 653 setModel(metadata_value_table_model); 654 655 // We allow only one row to be selected at a time 656 setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 657 getSelectionModel().addListSelectionListener(new MetadataValueTableListSelectionListener()); 658 659 // The default JTable doesn't quite have the desired properties - when a 660 // table cell is clicked on, the table is scrolled so the cell is as 661 // visible as possible. This means that the left-most cells can become 662 // hidden. To fix this, the MouseInputHandler in BasicTableUI is removed 663 // as a MouseListener on the table, and a very slightly altered copy is 664 // added in its place (TableMouseInputHandler). 665 MouseListener[] mls = getMouseListeners(); 666 for (int i = 0; i < mls.length; i++) { 667 // Remove the instances of MouseInputHandler 668 if (mls[i].toString().startsWith("javax.swing.plaf.basic.BasicTableUI$MouseInputHandler@")) { 669 removeMouseListener(mls[i]); 339 } 340 } 341 342 343 private class MetadataValueTextFieldKeyListener 344 extends KeyAdapter 345 { 346 /** Gives notification of key events on the text field */ 347 public void keyPressed(KeyEvent key_event) 348 { 349 // Tab: Auto-complete what is selected in the metadata value tree 350 if (key_event.getKeyCode() == KeyEvent.VK_TAB) { 351 MetadataValueTreeNode selected_metadata_value_tree_node = metadata_value_tree_pane.getSelectedMetadataValueTreeNode(); 352 if (selected_metadata_value_tree_node != null) { 353 metadata_value_table_pane.setMetadataValueTextFieldValue(selected_metadata_value_tree_node.getFullValue()); 670 354 } 671 } 672 // Add the slightly-altered mouse listener 673 addMouseListener(new TableMouseInputHandler()); 674 675 // We also have to ensure that the table column header hasn't gone on a severe Jenny Craig binge and has somehow lost 7/8th of its component size 676 JTableHeader table_header = getTableHeader(); 677 Dimension table_header_preferred_size = table_header.getPreferredSize(); 678 if (table_header_preferred_size.height < MINIMUM_TABLE_HEADER_SIZE) { 679 table_header_preferred_size.setSize(table_header_preferred_size.width, MINIMUM_TABLE_HEADER_SIZE); 680 table_header.setPreferredSize(table_header_preferred_size); 681 } 682 683 // Set the table columns as we want them 684 setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 685 Dimension table_size = getPreferredSize(); 686 TableColumnModel column_model = getColumnModel(); 687 688 TableColumn inherited_column = column_model.getColumn(0); 689 inherited_column.setPreferredWidth(20); 690 inherited_column.setCellRenderer(new MetadataValueTableCellRenderer(metadata_value_table_model)); 691 692 TableColumn element_column = column_model.getColumn(1); 693 element_column.setPreferredWidth((TABLE_SIZE.width / 4) - 15); 694 element_column.setCellRenderer(new MetadataValueTableCellRenderer(metadata_value_table_model)); 695 696 TableColumn value_column = column_model.getColumn(2); 697 value_column.setPreferredWidth(((3 * TABLE_SIZE.width) / 4) - 30); 698 value_column.setCellRenderer(new MetadataValueTableCellRenderer(metadata_value_table_model)); 699 } 700 701 702 public MetadataElement getSelectedMetadataElement() 703 { 704 return selected_metadata_value_table_entry.getMetadataElement(); 705 } 706 707 708 public MetadataValueTableEntry getSelectedMetadataValueTableEntry() 709 { 710 return selected_metadata_value_table_entry; 711 } 712 713 714 public boolean isSelectedMetadataValueTableEntryCommon() 715 { 716 return metadata_value_table_model.isCommon(selected_metadata_value_table_entry); 717 } 718 719 720 public void moveSelectionDown() 721 { 722 int new_row_to_select = getSelectedRow() + 1; 723 if (new_row_to_select < metadata_value_table_model.getRowCount()) { 724 changeSelection(new_row_to_select, 1, false, false); 725 } 726 } 727 728 729 public void moveSelectionUp() 730 { 731 int new_row_to_select = getSelectedRow() - 1; 732 if (new_row_to_select >= 0) { 733 changeSelection(new_row_to_select, 1, false, false); 734 } 735 } 736 737 738 public void rebuildAndSelectRowWithValueClosestTo(MetadataValue optimal_metadata_value_to_select_when_building_complete) 739 { 740 // We don't want a lot of ListSelectionEvents while the table is rebuilding 741 clearSelection(); 742 743 // Rebuild the metadata value table model 744 metadata_value_table_model.rebuild(file_nodes); 745 746 // If the metadata value table is empty there isn't much to do 747 if (metadata_value_table_model.getRowCount() == 0) { 748 // ...except display the "no metadata available" card, unless no files are selected 749 if (file_nodes != null) { 750 metadata_value_table_card_layout.show(table_card_pane, TABLE_CARD_NO_METADATA_AVAILABLE); 751 } 752 return; 753 } 754 755 // Display the card with the metadata value table 756 metadata_value_table_card_layout.show(table_card_pane, TABLE_CARD); 757 758 // If we don't need to select a row in the table after rebuilding, we're done 759 if (optimal_metadata_value_to_select_when_building_complete == null) { 760 return; 761 } 762 763 MetadataElement optimal_metadata_element = optimal_metadata_value_to_select_when_building_complete.getMetadataElement(); 764 765 // Find the row containing the closest value to the optimal value 766 int optimal_row_to_select = 0; 767 for (int i = 0; i < metadata_value_table_model.getRowCount(); i++) { 768 MetadataValueTableEntry metadata_value_table_entry = metadata_value_table_model.getMetadataValueTableEntry(i); 769 MetadataElement metadata_element = metadata_value_table_entry.getMetadataElement(); 770 if (metadata_element.equals(optimal_metadata_element)) { 771 // This row will be the optimal row, unless the next row matches better 772 optimal_row_to_select = i; 773 } 774 775 int c = metadata_value_table_entry.compareTo(optimal_metadata_value_to_select_when_building_complete); 776 if (c >= 0) { 777 // We've either found an exact match, or there is no exact match, so stop here 778 break; 779 } 780 } 781 782 changeSelection(optimal_row_to_select, 1, false, false); 783 metadata_value_text_field.requestFocus(); 784 } 785 786 787 private class MetadataValueTableListSelectionListener 788 implements ListSelectionListener 789 { 790 public void valueChanged(ListSelectionEvent event) 791 { 792 // We only want to handle one event per selection, so wait for the value to stabilise 793 if (getSelectionModel().getValueIsAdjusting() == true) { 794 return; 795 } 796 797 selected_metadata_value_table_entry = null; 798 MetadataElement selected_metadata_element = null; 799 String selected_metadata_value = ""; 800 801 // We have a SINGLE_SELECTION model set so there is at most one selection 802 int selected_row = getSelectedRow(); 803 if (selected_row >= 0) { 804 selected_metadata_value_table_entry = metadata_value_table_model.getMetadataValueTableEntry(selected_row); 805 selected_metadata_element = selected_metadata_value_table_entry.getMetadataElement(); 806 MetadataValueTreeNode metadata_value_tree_node = selected_metadata_value_table_entry.getMetadataValueTreeNode(); 807 if (metadata_value_tree_node != null) { 808 selected_metadata_value = metadata_value_tree_node.getFullValue(); 809 } 810 } 811 812 // Update the metadata value tree 813 metadata_value_tree.rebuild(selected_metadata_element, selected_metadata_value); 814 } 815 } 816 817 818 /** A direct copy of javax.swing.plaf.basic.BasicTableUI$MouseInputHandler, except for one change in adjustFocusAndSelection(). The purpose of this change is to always keep the left-most cells of the table row selected visible. */ 819 private class TableMouseInputHandler implements MouseInputListener 820 { 821 // Component receiving mouse events during editing. 822 // May not be editorComponent. 823 private Component dispatchComponent; 824 private boolean selectedOnPress; 825 826 // The Table's mouse listener methods. 827 828 public void mouseClicked(MouseEvent e) {} 829 830 private void setDispatchComponent(MouseEvent e) { 831 Component editorComponent = getEditorComponent(); 832 Point p = e.getPoint(); 833 Point p2 = SwingUtilities.convertPoint(metadata_value_table, p, editorComponent); 834 dispatchComponent = SwingUtilities.getDeepestComponentAt(editorComponent, 835 p2.x, p2.y); 836 } 837 838 private boolean repostEvent(MouseEvent e) { 839 // Check for isEditing() in case another event has 840 // caused the editor to be removed. See bug #4306499. 841 if (dispatchComponent == null || !isEditing()) { 842 return false; 843 } 844 MouseEvent e2 = SwingUtilities.convertMouseEvent(metadata_value_table, e, dispatchComponent); 845 dispatchComponent.dispatchEvent(e2); 846 return true; 847 } 848 849 private void setValueIsAdjusting(boolean flag) { 850 getSelectionModel().setValueIsAdjusting(flag); 851 getColumnModel().getSelectionModel().setValueIsAdjusting(flag); 852 } 853 854 private boolean shouldIgnore(MouseEvent e) { 855 return e.isConsumed() || (!(SwingUtilities.isLeftMouseButton(e) && isEnabled())); 856 } 857 858 public void mousePressed(MouseEvent e) { 859 if (e.isConsumed()) { 860 selectedOnPress = false; 861 return; 862 } 863 selectedOnPress = true; 864 adjustFocusAndSelection(e); 865 } 866 867 void adjustFocusAndSelection(MouseEvent e) { 868 if (shouldIgnore(e)) { 869 return; 870 } 871 872 Point p = e.getPoint(); 873 int row = rowAtPoint(p); 874 int column = columnAtPoint(p); 875 // The autoscroller can generate drag events outside the Table's range. 876 if ((column == -1) || (row == -1)) { 877 return; 878 } 879 880 if (editCellAt(row, column, e)) { 881 setDispatchComponent(e); 882 repostEvent(e); 883 } 884 // Commented this out and added the line below it to keep the value text field in focus 885 // else if (isRequestFocusEnabled()) { 886 // requestFocus(); 887 // } 888 metadata_value_text_field.requestFocus(); 889 890 CellEditor editor = getCellEditor(); 891 if (editor == null || editor.shouldSelectCell(e)) { 892 boolean adjusting = (e.getID() == MouseEvent.MOUSE_PRESSED) ? true : false; 893 setValueIsAdjusting(adjusting); 894 895 // Special code for clicking the first column (folder-level metadata) 896 if (column == 0) { 897 selected_metadata_value_table_entry = metadata_value_table_model.getMetadataValueTableEntry(row); 898 899 // If this metadata is inherited, switch to the folder it came from 900 if (selected_metadata_value_table_entry.isInheritedMetadata()) { 901 File folder_metadata_inherited_from = selected_metadata_value_table_entry.getFolderMetadataInheritedFrom(); 902 if (folder_metadata_inherited_from != null) { 903 collection_tree.setSelection(folder_metadata_inherited_from); 904 } 905 } 906 907 changeSelection(row, 0, e.isControlDown(), e.isShiftDown()); 908 } 909 else { 910 changeSelection(row, 1, e.isControlDown(), e.isShiftDown()); 911 } 912 } 913 } 914 915 public void mouseReleased(MouseEvent e) { 916 if (selectedOnPress) { 917 if (shouldIgnore(e)) { 918 return; 919 } 920 921 repostEvent(e); 922 dispatchComponent = null; 923 setValueIsAdjusting(false); 924 } else { 925 adjustFocusAndSelection(e); 926 } 927 } 928 929 930 public void mouseEntered(MouseEvent e) {} 931 932 public void mouseExited(MouseEvent e) {} 933 934 // The Table's mouse motion listener methods. 935 936 public void mouseMoved(MouseEvent e) {} 937 938 public void mouseDragged(MouseEvent e) { 939 if (shouldIgnore(e)) { 940 return; 941 } 942 943 repostEvent(e); 944 945 CellEditor editor = getCellEditor(); 946 if (editor == null || editor.shouldSelectCell(e)) { 947 Point p = e.getPoint(); 948 int row = rowAtPoint(p); 949 int column = columnAtPoint(p); 950 // The autoscroller can generate drag events outside the Table's range. 951 if ((column == -1) || (row == -1)) { 952 return; 953 } 954 changeSelection(row, column, false, true); 955 } 956 } 957 } 958 } 959 960 961 /** 962 * This class is a little bit complex, a little bit subtle, and a little bit odd. 963 * The strange interaction model is due to the fact that it is very tightly 964 * coupled to the EnrichPane. 965 * 966 * The interaction is complex because there are three separate controls that the 967 * user may interact with, each of which can affect the other two. The three 968 * controls are: 969 * - The "assigned metadata" table, at the top right of the meta edit pane. 970 * - The "metadata value" text field, where users can type in new values. 971 * - The "metadata value tree", which shows other values that have been 972 * assigned to the selected metadata element. 973 * 974 * The interactions are: 975 * - The "assigned metadata" table 976 * Users may select one (and only one) row in this table. Selecting a row 977 * chooses one metadata element. The text field will be set to the current 978 * value of the metadata element. This value will also be selected in the 979 * metadata value tree. 980 * 981 * - The "metadata value" text field 982 * If the value the user has typed in this is a prefix of an entry in the 983 * value tree, this value will be selected in the value tree. In this case, 984 * pressing "Tab" will complete the value (ie. make the value in the text 985 * field the same as the value in the tree). This is to allow users to 986 * quickly and easily assign existing metadata values to new documents. 987 * 988 * - The "metadata value tree" 989 * Selecting a value in the tree will set the text field to this value. 990 */ 991 private class MetadataValueTree 992 extends JPanel 993 { 994 private boolean ignore_tree_selection_event = false; 995 private boolean manual_text_edit_event = false; 996 private CardLayout card_layout; 997 private String card_showing = null; 998 /** The metadata element that is currently selected. */ 999 private MetadataElement selected_metadata_element = null; 1000 private JTextArea extracted_message; 1001 private JTree tree; 1002 1003 static final private String NONE = "None"; 1004 static final private String TREE = "Tree"; 1005 1006 1007 public MetadataValueTree(int width, int height) 1008 { 1009 super(); 1010 1011 setFont(Configuration.getFont("general.font", false)); 1012 setPreferredSize(new Dimension(width, height)); 1013 1014 JPanel metadata_pane = new JPanel(); 1015 1016 JPanel value_pane = new JPanel(); 1017 JLabel value_label = new JLabel(); 1018 Dictionary.registerText(value_label, "EnrichPane.Value"); 1019 1020 JPanel value_field_pane = new JPanel(); 1021 metadata_value_text_field.setBackground(Configuration.getColor("coloring.editable_background", false)); 1022 metadata_value_text_field.setForeground(Configuration.getColor("coloring.editable_foreground", false)); 1023 metadata_value_text_field.setPreferredSize(new Dimension(413, 24)); 1024 metadata_value_text_field.getDocument().addDocumentListener(new DocumentListenerImpl()); 1025 metadata_value_text_field.addKeyListener(new MetadataValueTextFieldKeyListener()); 1026 metadata_value_text_field.setFocusTraversalKeysEnabled(false); 1027 Dictionary.setTooltip(metadata_value_text_field, "EnrichPane.Value_Field_Tooltip"); 1028 1029 JPanel button_pane = new JPanel(); 1030 1031 JPanel tree_pane = new JPanel(); 1032 JLabel tree_label = new JLabel(); 1033 Dictionary.registerText(tree_label, "EnrichPane.Tree"); 1034 1035 tree = new JTree(); 1036 tree.addMouseListener(new MetadataValueTreeMouseListener()); 1037 tree.addTreeSelectionListener(new MetadataValueTreeSelectionListener()); 1038 tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); 1039 tree.setRootVisible(false); 1040 tree.putClientProperty("JTree.lineStyle", "Angled"); 1041 1042 JPanel extracted_pane = new JPanel(); 1043 JPanel extracted_header_pane = new JPanel(); 1044 extracted_message = new JTextArea(""); 1045 extracted_message.setEditable(false); 1046 extracted_message.setLineWrap(true); 1047 extracted_message.setOpaque(false); 1048 extracted_message.setWrapStyleWord(true); 1049 1050 card_layout = new CardLayout(); 1051 1052 // Layout 1053 value_field_pane.setBorder(BorderFactory.createEmptyBorder(0,5,0,5)); 1054 value_field_pane.setLayout(new BorderLayout(0, 0)); 1055 value_field_pane.add(metadata_value_text_field, BorderLayout.CENTER); 1056 1057 button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0)); 1058 button_pane.setLayout(new GridLayout()); 1059 button_pane.add(add); 1060 button_pane.add(replace); 1061 button_pane.add(remove); 1062 1063 value_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0)); 1064 value_pane.setLayout(new BorderLayout()); 1065 value_pane.add(value_label, BorderLayout.WEST); 1066 value_pane.add(value_field_pane, BorderLayout.CENTER); 1067 value_pane.add(expand, BorderLayout.EAST); 1068 value_pane.add(button_pane, BorderLayout.SOUTH); 1069 1070 tree_pane.setLayout(new BorderLayout()); 1071 tree_pane.add(tree_label, BorderLayout.NORTH); 1072 tree_pane.add(new JScrollPane(tree), BorderLayout.CENTER); 1073 1074 metadata_pane.setLayout(new BorderLayout()); 1075 metadata_pane.add(value_pane, BorderLayout.NORTH); 1076 metadata_pane.add(tree_pane, BorderLayout.CENTER); 1077 1078 extracted_header_pane.setLayout(new BorderLayout()); 1079 extracted_header_pane.add(expand_for_extracted, BorderLayout.EAST); 1080 1081 extracted_pane.setBorder(BorderFactory.createEmptyBorder(0,10,25,0)); 1082 extracted_pane.setLayout(new BorderLayout()); 1083 extracted_pane.add(extracted_header_pane, BorderLayout.NORTH); 1084 extracted_pane.add(extracted_message, BorderLayout.CENTER); 1085 1086 this.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 1087 this.setLayout(card_layout); 1088 this.add(metadata_pane, TREE); 1089 this.add(extracted_pane, NONE); 1090 card_showing = TREE; 1091 } 1092 1093 1094 /** Returns a TreePath for the node most closely matching the metadata value. */ 1095 private TreePath getClosestPath(String val) 1096 { 1097 // Start at the root of the tree 1098 MetadataValueTreeNode tree_node = (MetadataValueTreeNode) tree.getModel().getRoot(); 1099 1100 // Separate hierarchical values 1101 PatternTokenizer tokenizer = new PatternTokenizer(val, MetadataValueTreeNode.METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN); 1102 while (tokenizer.hasMoreTokens()) { 1103 String token = tokenizer.nextToken(); 1104 1105 // All components except the last must match exactly 1106 if (tokenizer.hasMoreTokens()) { 1107 for (int i = 0; i < tree_node.getChildCount(); i++) { 1108 MetadataValueTreeNode child_node = (MetadataValueTreeNode) tree_node.getChildAt(i); 1109 if (child_node.getValue().equals(token)) { 1110 // The matching node has been found, so move onto the next token 1111 tree_node = child_node; 1112 break; 1113 } 1114 } 1115 } 1116 1117 // The last component may match partially 1118 else { 1119 for (int i = 0; i < tree_node.getChildCount(); i++) { 1120 MetadataValueTreeNode child_node = (MetadataValueTreeNode) tree_node.getChildAt(i); 1121 if (child_node.getFullValue().startsWith(val)) { 1122 // The closest node has been found, so return its path 1123 return new TreePath(child_node.getPath()); 1124 } 1125 } 1126 1127 // Not even a partial match 1128 return null; 1129 } 1130 } 1131 1132 // If nothing else, return the path of the root node 1133 return new TreePath(tree_node.getPath()); 1134 } 1135 1136 1137 public String getSelectedValue() 1138 { 1139 String metadata_value_raw = metadata_value_text_field.getText(); 1140 String metadata_value = XMLTools.removeInvalidCharacters(metadata_value_raw); 1141 return metadata_value.replaceAll("\\\\", MetadataValueTreeNode.METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN); 1142 } 1143 1144 1145 public void rebuild(MetadataElement metadata_element, String metadata_value) 1146 { 1147 // System.err.println("In MetadataValueTree.rebuild()..."); 1148 1149 // Clear selection 1150 if (metadata_element == null) { 1151 if (metadata_edit_event == false) { 1152 // System.err.println("Clearing selection..."); 1153 selected_metadata_element = null; 1154 validateDisplay(); 1155 } 1156 return; 1157 } 1158 1159 // Reload the value tree model if the selected metadata element has changed 1160 if (selected_metadata_element != metadata_element) { 1161 selected_metadata_element = metadata_element; 1162 tree.setModel(selected_metadata_element.getMetadataValueTreeModel()); 1163 } 1164 1165 validateDisplay(); 1166 1167 setSelectedValue(metadata_value); 1168 } 1169 1170 1171 /** This function is copied from JTree::setPathToVisible(), and modified so tree rows 1172 are always shown flushed left. Note: doesn't do accessibleContext stuff. */ 1173 private void scrollTreePathToVisible(TreePath path) 1174 { 1175 if (path != null) { 1176 tree.makeVisible(path); 1177 1178 Rectangle bounds = tree.getPathBounds(path); 1179 if (bounds != null) { 1180 bounds.width += bounds.x; 1181 bounds.x = 0; 1182 tree.scrollRectToVisible(bounds); 1183 } 1184 } 1185 } 1186 1187 1188 /** Sets the value in the text field. */ 1189 private void setSelectedValue(String metadata_value) 1190 { 1191 // Setting the text of the field causes the DocumentListener to be notified, and 1192 // updating the tree is handled there (DocumentListenerImpl::validate()) 1193 if (!card_showing.equals(NONE)) { 1194 manual_text_edit_event = metadata_value.equals(""); // Set to false unless val == "" 1195 metadata_value_text_field.setText(metadata_value); 1196 manual_text_edit_event = true; 1197 } 1198 } 1199 1200 1201 private void validateDisplay() 1202 { 1203 // If no metadata is selected in the metadata value table, display "no metadata element selected" card 1204 if (file_nodes == null || selected_metadata_element == null) { 1205 metadata_value_tree_card_layout.show(control_pane, TREE_CARD_NO_METADATA_ELEMENT_SELECTED); 1206 } 1207 1208 // Otherwise, display the card with the metadata value tree 1209 else { 1210 metadata_value_tree_card_layout.show(control_pane, TREE_CARD); 1211 1212 // Special case the extracted metadata set 1213 if (selected_metadata_element.getNamespace().equals(Utility.EXTRACTED_METADATA_NAMESPACE)) { 1214 // Display the panel showing the "you cannot edit this metadata" message 1215 String[] args = new String[1]; 1216 args[0] = selected_metadata_element.getFullName(); 1217 Dictionary.registerText(extracted_message, "EnrichPane.AutoMessage", args); 1218 card_layout.show(this, NONE); 1219 card_showing = NONE; 1220 } 1221 else { 1222 // Display the panel for viewing and assigning metadata 1223 card_layout.show(this, TREE); 1224 card_showing = TREE; 1225 } 1226 1227 // Validate the buttons above the value tree 1228 MetadataValueTableEntry metadata_value_table_entry = metadata_value_table.getSelectedMetadataValueTableEntry(); 1229 if (metadata_value_table_entry.getValue().equals("")) { 1230 // Can only append if something has been entered 1231 add.setEnabled((getSelectedValue().length() > 0)); 1232 1233 // Nothing to replace or remove 1234 replace.setEnabled(false); 1235 remove.setEnabled(false); 1236 return; 1237 } 1238 1239 // Check if the text in the value field is the same as the metadata value 1240 if (getSelectedValue().equals(metadata_value_table_entry.getFullValue())) { 1241 // Can't replace 1242 replace.setEnabled(false); 1243 1244 // Adding, however, is dependant on whether the selected metadata is common or uncommon. If the later then you can append so as to make it common. 1245 add.setEnabled(!metadata_value_table.isSelectedMetadataValueTableEntryCommon()); 1246 } 1247 else { 1248 // Can append or replace, if something has been entered 1249 add.setEnabled((getSelectedValue().length() > 0)); 1250 replace.setEnabled((getSelectedValue().length() > 0)); 1251 } 1252 1253 // Can only remove if the metadata is file level 1254 if (metadata_value_table_entry != null) { // Shouldn't be necessary, but is 1255 remove.setEnabled((metadata_value_table_entry.isInheritedMetadata() == false)); 1256 } 1257 } 1258 } 1259 1260 1261 private class MetadataValueTextFieldKeyListener 1262 extends KeyAdapter 1263 { 1264 /** Gives notification of key events on the text field */ 1265 public void keyPressed(KeyEvent e) 1266 { 1267 // Tab: Auto-complete 1268 if (e.getKeyCode() == KeyEvent.VK_TAB) { 1269 if (tree.getSelectionCount() != 0 && !getSelectedValue().equals("")) { 1270 TreePath path = tree.getSelectionPath(); 1271 MetadataValueTreeNode node = (MetadataValueTreeNode) path.getLastPathComponent(); 1272 setSelectedValue(node.getFullValue()); 1273 } 1274 } 1275 1276 // Enter: Append the metadata value, if we're allowed to 1277 if (e.getKeyCode() == KeyEvent.VK_ENTER) { 1278 if (add.isEnabled()) { 1279 add.doClick(); 1280 } 1281 } 1282 1283 // Down: Change the metadata value table selection 1284 if (e.getKeyCode() == KeyEvent.VK_DOWN) { 1285 metadata_value_table.moveSelectionDown(); 1286 } 1287 1288 // Up: Change the metadata value table selection 1289 if (e.getKeyCode() == KeyEvent.VK_UP) { 1290 metadata_value_table.moveSelectionUp(); 1291 } 1292 } 1293 } 1294 1295 1296 private class MetadataValueTreeMouseListener 1297 extends MouseAdapter 1298 { 1299 public void mouseClicked(MouseEvent e) 1300 { 1301 // Double click: assign the selected value tree node immediately (if possible) 1302 if (e.getClickCount() == 2 && tree.getSelectionCount() != 0) { 1303 TreePath path = tree.getSelectionPath(); 1304 MetadataValueTreeNode node = (MetadataValueTreeNode) path.getLastPathComponent(); 1305 1306 // Leaf nodes only (folder nodes will expand/contract) 1307 if (node.getChildCount() == 0 && add.isEnabled()) { 1308 add.doClick(); 1309 } 1310 } 1311 } 1312 } 1313 1314 1315 private class MetadataValueTreeSelectionListener 1316 implements TreeSelectionListener 1317 { 1318 public void valueChanged(TreeSelectionEvent event) 1319 { 1320 // Select a node in the tree: fill the metadata value text field with the selected node's value 1321 if (tree.getSelectionCount() != 0 && !ignore_tree_selection_event) { 1322 TreePath path = tree.getSelectionPath(); 1323 MetadataValueTreeNode node = (MetadataValueTreeNode) path.getLastPathComponent(); 1324 setSelectedValue(node.getFullValue()); 1325 } 1326 } 1327 } 1328 1329 1330 private class DocumentListenerImpl 1331 implements DocumentListener 1332 { 1333 /** Gives notification that an attribute or set of attributes changed */ 1334 public void changedUpdate(DocumentEvent e) { 1335 validate(); 1336 } 1337 1338 /** Gives notification that there was an insert into the document */ 1339 public void insertUpdate(DocumentEvent e) { 1340 validate(); 1341 } 1342 1343 /** Gives notification that a portion of the document has been removed */ 1344 public void removeUpdate(DocumentEvent e) { 1345 validate(); 1346 } 1347 1348 1349 /** Ensures that the value text field and value tree are synchronized */ 1350 private void validate() 1351 { 1352 String value_text = getSelectedValue(); 1353 1354 // Ignore the validate() with empty text that occurs when value.setText() is used 1355 if (!value_text.equals("") || manual_text_edit_event == true) { 1356 TreePath closest_path = getClosestPath(value_text); 1357 1358 // Select the new path in the tree 1359 // The tree selection event this causes must be ignored, since it alters value 1360 ignore_tree_selection_event = true; 1361 tree.setSelectionPath(closest_path); 1362 ignore_tree_selection_event = false; 1363 1364 // If a folder has been specified, make sure it is expanded 1365 if (value_text.endsWith(MetadataValueTreeNode.METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN) && !tree.isExpanded(closest_path)) { 1366 tree.expandPath(closest_path); 1367 } 1368 1369 // Make sure the path is visible on the screen 1370 scrollTreePathToVisible(closest_path); 1371 // One call should be enough, but it isn't in some cases (for some reason) 1372 scrollTreePathToVisible(closest_path); 1373 1374 // Update the status of the buttons 1375 validateDisplay(); 1376 } 355 356 // We do not want this event to be processed by the table also 357 key_event.consume(); 358 } 359 360 // Enter: save the current value then add a blank row for the selected metadata element 361 if (key_event.getKeyCode() == KeyEvent.VK_ENTER) { 362 metadata_value_table_pane.stopEditingAndAddBlankRowForSelectedMetadataElement(); 363 } 364 } 365 } 366 367 368 private class MetadataValueTreeSelectionListener 369 implements TreeSelectionListener 370 { 371 public void valueChanged(TreeSelectionEvent tree_selection_event) 372 { 373 // When a node is selected in the tree, fill the metadata value text field with the selected node's value 374 MetadataValueTreeNode selected_metadata_value_tree_node = metadata_value_tree_pane.getSelectedMetadataValueTreeNode(); 375 if (selected_metadata_value_tree_node != null) { 376 metadata_value_table_pane.setMetadataValueTextFieldValue(selected_metadata_value_tree_node.getFullValue()); 1377 377 } 1378 378 } … … 1538 538 } 1539 539 } 1540 // finally we have the correct selection paths! !540 // finally we have the correct selection paths! 1541 541 1542 542 // Create an appropriate context menu, based on what is selected -
trunk/gli/src/org/greenstone/gatherer/metadata/MetadataTools.java
r8996 r9856 119 119 return ""; 120 120 } 121 122 123 static public String getRegularExpressionThatMatchesFilePath(String file_path) 124 { 125 // Convert the file path into a regular expression that will match it 126 String file_path_regexp = file_path; 127 file_path_regexp = file_path_regexp.replaceAll("\\.", "\\\\."); 128 file_path_regexp = file_path_regexp.replaceAll("\\(", "\\\\("); 129 file_path_regexp = file_path_regexp.replaceAll("\\)", "\\\\)"); 130 file_path_regexp = file_path_regexp.replaceAll("\\[", "\\\\["); 131 file_path_regexp = file_path_regexp.replaceAll("\\]", "\\\\]"); 132 file_path_regexp = file_path_regexp.replaceAll("\\{", "\\\\{"); 133 file_path_regexp = file_path_regexp.replaceAll("\\}", "\\\\}"); 134 file_path_regexp = file_path_regexp.replaceAll("\\+", "\\\\+"); 135 return file_path_regexp; 136 } 121 137 } -
trunk/gli/src/org/greenstone/gatherer/metadata/MetadataValueTableEntry.java
r9846 r9856 28 28 29 29 30 /** This class represents one metadata (element, value) pair*/30 /** This class represents one entry in the metadata value table. */ 31 31 public class MetadataValueTableEntry 32 32 extends MetadataValue -
trunk/gli/src/org/greenstone/gatherer/metadata/MetadataValueTableModel.java
r9350 r9856 34 34 import javax.swing.table.*; 35 35 import org.greenstone.gatherer.Configuration; 36 import org.greenstone.gatherer.DebugStream; 36 37 import org.greenstone.gatherer.Dictionary; 37 38 import org.greenstone.gatherer.Gatherer; … … 51 52 52 53 54 public int addBlankRowForMetadataElement(MetadataElement metadata_element) 55 { 56 MetadataValueTableModelBuilder metadata_value_table_model_builder = new MetadataValueTableModelBuilder(); 57 MetadataValue blank_metadata_value = new MetadataValue(metadata_element, new MetadataValueTreeNode("")); 58 return metadata_value_table_model_builder.insertMetadataValue(blank_metadata_value); 59 } 60 61 62 public int findMetadataValueTableEntryToSelect(MetadataValueTableEntry metadata_value_table_entry) 63 { 64 MetadataElement metadata_element = metadata_value_table_entry.getMetadataElement(); 65 66 // Find the correct entry to select 67 for (int i = 0; i < metadata_value_table_entries.size(); i++) { 68 MetadataValueTableEntry current_metadata_value_table_entry = (MetadataValueTableEntry) metadata_value_table_entries.get(i); 69 int element_comparison = MetadataSetManager.compareMetadataElements(current_metadata_value_table_entry.getMetadataElement(), metadata_element); 70 71 // We've found the right element, so check if the value already exists 72 if (element_comparison == 0) { 73 int value_comparison = current_metadata_value_table_entry.compareTo(metadata_value_table_entry); 74 if (value_comparison == 0) { 75 // Entry found! 76 return i; 77 } 78 } 79 80 // We've just gone past the correct entry to select 81 if (element_comparison > 0) { 82 return i - 1; 83 } 84 } 85 86 // Have to select the last entry 87 return metadata_value_table_entries.size() - 1; 88 } 89 90 91 public Class getColumnClass(int col) 92 { 93 return getValueAt(0, col).getClass(); 94 } 95 96 53 97 /** Returns the number of columns in this table. */ 54 98 public int getColumnCount() … … 108 152 109 153 110 /** Determine if the given metadata is common to all selected file nodes given the context of the current view. */ 154 public boolean isCellEditable(int row, int col) 155 { 156 // The inherited and element columns are never editable 157 if (col < 2) { 158 return false; 159 } 160 161 // Extracted and inherited metadata is not editable 162 MetadataValueTableEntry metadata_value_table_entry = (MetadataValueTableEntry) metadata_value_table_entries.get(row); 163 if (metadata_value_table_entry.getMetadataElement().isExtractedMetadataElement() || metadata_value_table_entry.isInheritedMetadata()) { 164 return false; 165 } 166 167 return true; 168 } 169 170 171 /** Determine if the given metadata is common to all selected file nodes. */ 111 172 public boolean isCommon(MetadataValueTableEntry metadata_value_table_entry) 112 173 { … … 115 176 116 177 117 /** Determine if the given metadata is common to all selected file nodes given the context of the current view. */178 /** Determine if the given metadata is common to all selected file nodes. */ 118 179 public boolean isCommon(int row) 119 180 { … … 146 207 147 208 209 public void setValueAt(Object new_metadata_value, int row, int col) 210 { 211 MetadataValueTableEntry metadata_value_table_entry = getMetadataValueTableEntry(row); 212 213 // If nothing has changed no action is necessary 214 String old_metadata_value = metadata_value_table_entry.getFullValue(); 215 if (new_metadata_value.equals(old_metadata_value)) { 216 return; 217 } 218 219 // Lock the interface so nothing can be changed while the metadata edit is being processed 220 Gatherer.g_man.wait(true); 221 222 // Metadata value added 223 if (old_metadata_value.equals("") && !new_metadata_value.equals("")) { 224 // If we're adding metadata to folders display the warning 225 if (!file_nodes[0].isLeaf()) { 226 WarningDialog dialog = new WarningDialog("warning.DirectoryLevelMetadata", "DirectoryLevelMetadata.Title", "DirectoryLevelMetadata.Message", null, true); 227 int dialog_result = dialog.display(); 228 dialog.dispose(); 229 if (dialog_result != JOptionPane.OK_OPTION) { 230 return; 231 } 232 } 233 234 MetadataElement metadata_element = metadata_value_table_entry.getMetadataElement(); 235 MetadataValueTreeNode metadata_value_tree_node = metadata_element.addMetadataValue((String) new_metadata_value); 236 MetadataValue metadata_value = new MetadataValue(metadata_element, metadata_value_tree_node); 237 metadata_value.setIsAccumulatingMetadata(true); 238 (new AppendMetadataTask(metadata_value)).run(); 239 } 240 241 // Metadata value removed 242 else if (!old_metadata_value.equals("") && new_metadata_value.equals("")) { 243 (new RemoveMetadataTask(metadata_value_table_entry)).run(); 244 } 245 246 // Metadata value replaced 247 else { 248 MetadataElement metadata_element = metadata_value_table_entry.getMetadataElement(); 249 MetadataValueTreeNode metadata_value_tree_node = metadata_element.addMetadataValue((String) new_metadata_value); 250 MetadataValue metadata_value = new MetadataValue(metadata_element, metadata_value_tree_node); 251 metadata_value.setIsAccumulatingMetadata(!metadata_value_table_entry.isInheritedMetadata()); 252 (new ReplaceMetadataTask(metadata_value_table_entry, metadata_value)).run(); 253 } 254 } 255 256 257 private class AppendMetadataTask 258 // extends Thread 259 { 260 private MetadataValue metadata_value = null; 261 262 private AppendMetadataTask(MetadataValue metadata_value) 263 { 264 this.metadata_value = metadata_value; 265 } 266 267 public void run() 268 { 269 try { 270 // Edit metadata.xml files to add the metadata 271 MetadataXMLFileManager.addMetadata(file_nodes, metadata_value); 272 } 273 catch (Exception exception) { 274 // We need to catch any exceptions here so the interface is unlocked below 275 DebugStream.printStackTrace(exception); 276 } 277 278 // Operation finished, so turn busy cursor off and unlock interface 279 Gatherer.g_man.wait(false); 280 } 281 } 282 283 284 private class ReplaceMetadataTask 285 // extends Thread 286 { 287 private MetadataValueTableEntry selected_metadata_value_table_entry = null; 288 private MetadataValue metadata_value = null; 289 290 private ReplaceMetadataTask(MetadataValueTableEntry selected_metadata_value_table_entry, MetadataValue metadata_value) 291 { 292 this.selected_metadata_value_table_entry = selected_metadata_value_table_entry; 293 this.metadata_value = metadata_value; 294 } 295 296 public void run() 297 { 298 try { 299 // Edit metadata.xml files to replace the metadata 300 MetadataXMLFileManager.replaceMetadata(file_nodes, selected_metadata_value_table_entry, metadata_value); 301 } 302 catch (Exception exception) { 303 // We need to catch any exceptions here so the interface is unlocked below 304 DebugStream.printStackTrace(exception); 305 } 306 307 // Operation finished, so turn busy cursor off and unlock interface 308 Gatherer.g_man.wait(false); 309 } 310 } 311 312 313 private class RemoveMetadataTask 314 // extends Thread 315 { 316 private MetadataValueTableEntry selected_metadata_value_table_entry = null; 317 318 private RemoveMetadataTask(MetadataValueTableEntry selected_metadata_value_table_entry) 319 { 320 this.selected_metadata_value_table_entry = selected_metadata_value_table_entry; 321 } 322 323 public void run() 324 { 325 try { 326 // Edit metadata.xml files to remove the metadata 327 MetadataXMLFileManager.removeMetadata(file_nodes, selected_metadata_value_table_entry); 328 } 329 catch (Exception exception) { 330 // We need to catch any exceptions here so the interface is unlocked below 331 DebugStream.printStackTrace(exception); 332 } 333 334 // Operation finished, so turn busy cursor off and unlock interface 335 Gatherer.g_man.wait(false); 336 } 337 } 338 339 148 340 private class MetadataValueTableModelBuilder 149 341 { 150 342 public void run() 151 343 { 344 // System.err.println("Building MetadataValueTableModel..."); 345 152 346 // Build a list of MetadataValueTableEntries that represent the metadata asssigned to the selected files 153 347 boolean hid_extracted_metadata = false; 154 boolean has_inherited_metadata = false;155 348 ArrayList metadata_elements_seen = new ArrayList(); 156 349 … … 165 358 MetadataElement metadata_element = metadata_value.getMetadataElement(); 166 359 167 // Note if there is inherited (folder-level) metadata in the table168 has_inherited_metadata = has_inherited_metadata || metadata_value.isInheritedMetadata();169 170 360 // Insert this metadata value into the table, unless it already exists (in which case increment its count) 171 insertMetadataValue IntoTable(metadata_value);361 insertMetadataValue(metadata_value); 172 362 173 363 // Remember we have seen this metadata element … … 184 374 185 375 // Insert this metadata value into the table, unless it already exists (in which case increment its count) 186 insertMetadataValue IntoTable(metadata_value);376 insertMetadataValue(metadata_value); 187 377 } 188 378 } … … 202 392 203 393 // Add it to the table 204 insertMetadataValue IntoTable(metadata_value_table_entry);394 insertMetadataValueTableEntry(metadata_value_table_entry); 205 395 } 206 396 } … … 210 400 showExtractedMetadataWarning(); 211 401 } 212 213 // If there is inherited metadata, display the warning 214 if (has_inherited_metadata) { 215 showInheritedMetadataWarning(); 216 } 217 } 218 219 220 /** Alphabetically inserts the new metadata value into the table */ 221 private void insertMetadataValueIntoTable(MetadataValue metadata_value) 222 { 223 insertMetadataValueIntoTable(new MetadataValueTableEntry(metadata_value)); 224 } 225 226 227 /** Alphabetically inserts the new metadata value into the table */ 228 private void insertMetadataValueIntoTable(MetadataValueTableEntry metadata_value_table_entry) 229 { 402 } 403 404 405 /** Inserts the new metadata value into the table */ 406 private int insertMetadataValue(MetadataValue metadata_value) 407 { 408 return insertMetadataValueTableEntry(new MetadataValueTableEntry(metadata_value)); 409 } 410 411 412 /** Inserts the new metadata value table entry into the table */ 413 private int insertMetadataValueTableEntry(MetadataValueTableEntry metadata_value_table_entry) 414 { 415 MetadataElement metadata_element = metadata_value_table_entry.getMetadataElement(); 416 417 // Find the correct place to insert the table entry 230 418 for (int i = 0; i < metadata_value_table_entries.size(); i++) { 231 419 MetadataValueTableEntry current_metadata_value_table_entry = (MetadataValueTableEntry) metadata_value_table_entries.get(i); 232 int c = current_metadata_value_table_entry.compareTo(metadata_value_table_entry); 233 234 // Insert value before existing entry 235 if (c > 0) { 420 int element_comparison = MetadataSetManager.compareMetadataElements(current_metadata_value_table_entry.getMetadataElement(), metadata_element); 421 422 // We've found the right element, so check if the value already exists 423 if (element_comparison == 0) { 424 int value_comparison = current_metadata_value_table_entry.compareTo(metadata_value_table_entry); 425 if (value_comparison == 0) { 426 // Entry already exists, so increment count (except for blank entries) 427 if (!metadata_value_table_entry.getFullValue().equals("")) { 428 current_metadata_value_table_entry.anotherOccurrence(); 429 } 430 return i; 431 } 432 } 433 434 // Found insertion point 435 if (element_comparison > 0) { 236 436 metadata_value_table_entries.add(i, metadata_value_table_entry); 237 437 fireTableRowsInserted(i, i); 238 return; 239 } 240 241 // Entry already exists (increment existing count) 242 if (c == 0) { 243 current_metadata_value_table_entry.anotherOccurrence(); 244 return; 438 return i; 245 439 } 246 440 } … … 249 443 metadata_value_table_entries.add(metadata_value_table_entry); 250 444 fireTableRowsInserted(metadata_value_table_entries.size() - 1, metadata_value_table_entries.size() - 1); 445 return metadata_value_table_entries.size() - 1; 251 446 } 252 447 … … 264 459 SwingUtilities.invokeLater(task); 265 460 } 266 267 268 private void showInheritedMetadataWarning()269 {270 Runnable task = new Runnable() {271 public void run() {272 WarningDialog dialog = new WarningDialog("warning.InheritedMetadata", "InheritedMetadata.Title", "InheritedMetadata.Message", null, false);273 dialog.display();274 dialog.dispose();275 dialog = null;276 }277 };278 SwingUtilities.invokeLater(task);279 }280 461 } 281 462 } -
trunk/gli/src/org/greenstone/gatherer/metadata/MetadataXMLFile.java
r9525 r9856 69 69 70 70 // Form a regular expression that specifies the scope of the metadata 71 String file_path_regexp = file_relative_path; 72 if (file_path_regexp.equals("")) { 71 String file_path_regexp; 72 if (file_relative_path.equals("")) { 73 // Special case for matching all files in the directory 73 74 file_path_regexp = DIRECTORY_FILENAME; 74 75 } 75 76 else { 76 77 // Convert the file path into a regular expression that will match it 77 file_path_regexp = file_path_regexp.replaceAll("\\.", "\\\\."); 78 file_path_regexp = file_path_regexp.replaceAll("\\(", "\\\\("); 79 file_path_regexp = file_path_regexp.replaceAll("\\)", "\\\\)"); 80 file_path_regexp = file_path_regexp.replaceAll("\\[", "\\\\["); 81 file_path_regexp = file_path_regexp.replaceAll("\\]", "\\\\]"); 82 file_path_regexp = file_path_regexp.replaceAll("\\{", "\\\\{"); 83 file_path_regexp = file_path_regexp.replaceAll("\\}", "\\\\}"); 84 file_path_regexp = file_path_regexp.replaceAll("\\+", "\\\\+"); 85 } 78 file_path_regexp = MetadataTools.getRegularExpressionThatMatchesFilePath(file_relative_path); 79 } 80 81 // Remove any characters that are invalid in XML 82 String metadata_value_string = XMLTools.removeInvalidCharacters(metadata_value.getFullValue()); 86 83 87 84 // Square brackets need to be escaped because they are a special character in Greenstone 88 String metadata_value_string = metadata_value.getFullValue();89 85 metadata_value_string = metadata_value_string.replaceAll("\\[", "["); 90 86 metadata_value_string = metadata_value_string.replaceAll("\\]", "]"); … … 313 309 314 310 // Form a regular expression that specifies the scope of the metadata 315 String file_path_regexp = file_relative_path; 316 if (file_path_regexp.equals("")) { 311 String file_path_regexp; 312 if (file_relative_path.equals("")) { 313 // Special case for matching all files in the directory 317 314 file_path_regexp = DIRECTORY_FILENAME; 318 315 } 319 316 else { 320 317 // Convert the file path into a regular expression that will match it 321 file_path_regexp = file_path_regexp.replaceAll("\\.", "\\\\."); 322 file_path_regexp = file_path_regexp.replaceAll("\\(", "\\\\("); 323 file_path_regexp = file_path_regexp.replaceAll("\\)", "\\\\)"); 324 file_path_regexp = file_path_regexp.replaceAll("\\[", "\\\\["); 325 file_path_regexp = file_path_regexp.replaceAll("\\]", "\\\\]"); 326 file_path_regexp = file_path_regexp.replaceAll("\\{", "\\\\{"); 327 file_path_regexp = file_path_regexp.replaceAll("\\}", "\\\\}"); 328 file_path_regexp = file_path_regexp.replaceAll("\\+", "\\\\+"); 329 } 318 file_path_regexp = MetadataTools.getRegularExpressionThatMatchesFilePath(file_relative_path); 319 } 320 321 // Remove any characters that are invalid in XML 322 String metadata_value_string = XMLTools.removeInvalidCharacters(metadata_value.getFullValue()); 330 323 331 324 // Square brackets need to be escaped because they are a special character in Greenstone 332 String metadata_value_string = metadata_value.getFullValue();333 325 metadata_value_string = metadata_value_string.replaceAll("\\[", "["); 334 326 metadata_value_string = metadata_value_string.replaceAll("\\]", "]"); 335 327 336 328 // Read all the FileSet elements in the file 337 329 NodeList fileset_elements_nodelist = document.getElementsByTagName(FILESET_ELEMENT); … … 378 370 // Remove this Metadata element 379 371 current_metadata_element.getParentNode().removeChild(current_metadata_element); 372 } 373 } 374 375 // Rewrite the metadata.xml file 376 XMLTools.writeXMLFile(this, document); 377 } 378 379 380 public void replaceMetadata(File file, MetadataValue old_metadata_value, MetadataValue new_metadata_value) 381 { 382 // Parse the metadata.xml file 383 Document document = XMLTools.parseXMLFile(this); 384 if (document == null) { 385 System.err.println("Error: Could not parse metadata.xml file " + getAbsolutePath()); 386 return; 387 } 388 389 // Determine the file's path relative to the location of the metadata.xml file 390 File metadata_xml_file_directory = getParentFile(); 391 String file_relative_path = file.getAbsolutePath().substring(metadata_xml_file_directory.getAbsolutePath().length()); 392 if (file_relative_path.startsWith(File.separator)) { 393 file_relative_path = file_relative_path.substring(File.separator.length()); 394 } 395 396 // Form a regular expression that specifies the scope of the metadata 397 String file_path_regexp; 398 if (file_relative_path.equals("")) { 399 // Special case for matching all files in the directory 400 file_path_regexp = DIRECTORY_FILENAME; 401 } 402 else { 403 // Convert the file path into a regular expression that will match it 404 file_path_regexp = MetadataTools.getRegularExpressionThatMatchesFilePath(file_relative_path); 405 } 406 407 // Remove any characters that are invalid in XML 408 String old_metadata_value_string = XMLTools.removeInvalidCharacters(old_metadata_value.getFullValue()); 409 String new_metadata_value_string = XMLTools.removeInvalidCharacters(new_metadata_value.getFullValue()); 410 411 // Square brackets need to be escaped because they are a special character in Greenstone 412 old_metadata_value_string = old_metadata_value_string.replaceAll("\\[", "["); 413 old_metadata_value_string = old_metadata_value_string.replaceAll("\\]", "]"); 414 new_metadata_value_string = new_metadata_value_string.replaceAll("\\[", "["); 415 new_metadata_value_string = new_metadata_value_string.replaceAll("\\]", "]"); 416 417 // Read all the FileSet elements in the file 418 NodeList fileset_elements_nodelist = document.getElementsByTagName(FILESET_ELEMENT); 419 for (int i = 0; i < fileset_elements_nodelist.getLength(); i++) { 420 Element current_fileset_element = (Element) fileset_elements_nodelist.item(i); 421 boolean current_fileset_matches = false; 422 423 // Check the FileName elements of the FileSet to see if we have a match 424 NodeList filename_elements_nodelist = current_fileset_element.getElementsByTagName(FILENAME_ELEMENT); 425 for (int j = 0; j < filename_elements_nodelist.getLength(); j++) { 426 Element current_filename_element = (Element) filename_elements_nodelist.item(j); 427 String current_filename_element_value = XMLTools.getElementTextValue(current_filename_element); 428 429 // Only exact matches can be edited 430 if (current_filename_element_value.equals(file_path_regexp)) { 431 current_fileset_matches = true; 432 break; 433 } 434 } 435 436 // The FileSet doesn't apply, so move onto the next one 437 if (current_fileset_matches == false) { 438 continue; 439 } 440 441 // Each metadata value is only allowed to be assigned once 442 boolean new_metadata_value_already_exists = false; 443 Element metadata_element_to_edit = null; 444 445 // Find the Metadata element to replace in the fileset 446 String metadata_element_name_full = old_metadata_value.getMetadataElement().getFullName(); 447 NodeList metadata_elements_nodelist = current_fileset_element.getElementsByTagName(METADATA_ELEMENT); 448 for (int k = 0; k < metadata_elements_nodelist.getLength(); k++) { 449 Element current_metadata_element = (Element) metadata_elements_nodelist.item(k); 450 451 // Check the metadata element name matches 452 String current_metadata_element_name_full = current_metadata_element.getAttribute("name"); 453 if (!current_metadata_element_name_full.equals(metadata_element_name_full)) { 454 continue; 455 } 456 457 // Check the new metadata value doesn't already exist 458 String current_metadata_value_string = XMLTools.getElementTextValue(current_metadata_element); 459 if (current_metadata_value_string.equals(new_metadata_value_string)) { 460 new_metadata_value_already_exists = true; 461 } 462 463 // Check the metadata element value matches 464 if (current_metadata_value_string.equals(old_metadata_value_string)) { 465 metadata_element_to_edit = current_metadata_element; 466 } 467 } 468 469 // If the new metadata value already existed, remove the original value 470 if (new_metadata_value_already_exists) { 471 metadata_element_to_edit.getParentNode().removeChild(metadata_element_to_edit); 472 } 473 // Otherwise replace the old value with the new value 474 else { 475 XMLTools.setElementTextValue(metadata_element_to_edit, new_metadata_value_string); 380 476 } 381 477 } -
trunk/gli/src/org/greenstone/gatherer/metadata/MetadataXMLFileManager.java
r8783 r9856 7 7 * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ 8 8 * 9 * Copyright (C) 200 4New Zealand Digital Library Project9 * Copyright (C) 2005 New Zealand Digital Library Project 10 10 * 11 11 * This program is free software; you can redistribute it and/or modify … … 40 40 { 41 41 static private ArrayList metadata_xml_files = new ArrayList(); 42 /** The objects listening for MetadataChanged events. */ 43 static private ArrayList metadata_changed_listeners = new ArrayList(); 42 44 43 45 … … 83 85 } 84 86 } 87 88 // Let any listeners know that the metadata has changed 89 fireMetadataChangedEvent(file_nodes); 90 } 91 92 93 static public void addMetadataChangedListener(MetadataChangedListener metadata_changed_listener) 94 { 95 metadata_changed_listeners.add(metadata_changed_listener); 85 96 } 86 97 … … 89 100 { 90 101 metadata_xml_files.clear(); 102 } 103 104 105 static private void fireMetadataChangedEvent(CollectionTreeNode[] file_nodes) 106 { 107 // Send the event off to all the MetadataChangedListeners 108 for (int i = 0; i < metadata_changed_listeners.size(); i++) { 109 ((MetadataChangedListener) metadata_changed_listeners.get(i)).metadataChanged(file_nodes); 110 } 91 111 } 92 112 … … 254 274 } 255 275 } 276 277 // Let any listeners know that the metadata has changed 278 fireMetadataChangedEvent(file_nodes); 279 } 280 281 282 static public void removeMetadataChangedListener(MetadataChangedListener metadata_changed_listener) 283 { 284 metadata_changed_listeners.remove(metadata_changed_listener); 285 } 286 287 288 static public void replaceMetadata(CollectionTreeNode[] file_nodes, MetadataValue old_metadata_value, MetadataValue new_metadata_value) 289 { 290 // Replace the metadata in each file node in turn 291 for (int i = 0; i < file_nodes.length; i++) { 292 File current_file = file_nodes[i].getFile(); 293 DebugStream.println("Replacing metadata in " + current_file.getAbsolutePath()); 294 295 // Find which metadata.xml file needs editing 296 File current_file_directory = (current_file.isDirectory() ? current_file : current_file.getParentFile()); 297 for (int j = 0; j < metadata_xml_files.size(); j++) { 298 MetadataXMLFile metadata_xml_file = (MetadataXMLFile) metadata_xml_files.get(j); 299 300 // This metadata.xml file is only applicable if it is at the same level as the file 301 if (current_file_directory.getAbsolutePath().equals(metadata_xml_file.getParentFile().getAbsolutePath())) { 302 metadata_xml_file.replaceMetadata(current_file, old_metadata_value, new_metadata_value); 303 } 304 } 305 } 306 307 // Let any listeners know that the metadata has changed 308 fireMetadataChangedEvent(file_nodes); 256 309 } 257 310 -
trunk/gli/src/org/greenstone/gatherer/util/XMLTools.java
r9160 r9856 178 178 179 179 return new String(safe_characters, 0, j); 180 } 181 182 183 static public void setElementTextValue(Element element, String text) 184 { 185 // Remove all text node children 186 NodeList children_nodelist = element.getChildNodes(); 187 for (int i = children_nodelist.getLength() - 1; i >= 0; i--) { 188 Node child_node = children_nodelist.item(i); 189 if (child_node.getNodeType() == Node.TEXT_NODE) { 190 element.removeChild(child_node); 191 } 192 } 193 194 // Add a new text node 195 if (text != null) { 196 element.appendChild(element.getOwnerDocument().createTextNode(text)); 197 } 180 198 } 181 199
Note:
See TracChangeset
for help on using the changeset viewer.