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

Last change on this file since 9888 was 9856, checked in by mdewsnip, 19 years ago

Major changes to the metadata value table and tree in the Enrich pane. The metadata value table now allows direct editing in the table -- hopefully much more obvious to the user. Classes involved have been untangled and are much more re-usable. Special code for replacing metadata has been added, which uses a more direct and efficient method rather than removing then adding metadata as before. And many many minor tidy-ups.

  • Property svn:keywords set to Author Date Id Revision
File size: 23.5 KB
Line 
1/**
2 *############################################################################
3 * A component of the Greenstone Librarian Interface, part of the Greenstone
4 * digital library suite from the New Zealand Digital Library Project at the
5 * University of Waikato, New Zealand.
6 *
7 * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
8 * Based on code by John Thompson
9 *
10 * Copyright (C) 2005 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *############################################################################
26 */
27
28package org.greenstone.gatherer.gui;
29
30
31import java.awt.*;
32import java.awt.event.*;
33import java.io.*;
34import java.util.*;
35import javax.swing.*;
36import javax.swing.event.*;
37import javax.swing.text.*;
38import javax.swing.tree.*;
39import org.greenstone.gatherer.Configuration;
40import org.greenstone.gatherer.DebugStream;
41import org.greenstone.gatherer.Dictionary;
42import org.greenstone.gatherer.Gatherer;
43import org.greenstone.gatherer.collection.CollectionTree;
44import org.greenstone.gatherer.collection.CollectionTreeNode;
45import org.greenstone.gatherer.gui.tree.DragTree;
46import org.greenstone.gatherer.metadata.MetadataElement;
47import org.greenstone.gatherer.metadata.MetadataValue;
48import org.greenstone.gatherer.metadata.MetadataValueTableEntry;
49import org.greenstone.gatherer.metadata.MetadataValueTreeNode;
50import org.greenstone.gatherer.util.DragGroup;
51import org.greenstone.gatherer.util.TreeSynchronizer;
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 /** The collection tree. */
64 private CollectionTree collection_tree = null;
65 /** The currently reported selection. */
66 private CollectionTreeNode[] file_nodes = null;
67 /** Used to dynamically filter the collection tree. Synchronized with the same filter in the Gather view. */
68 private Filter collection_filter = null;
69 /** The label at the top of the collection tree, which shows the collection name. */
70 private JLabel collection_label;
71 /** The splitpane dividing the collection tree and the metadata editing controls. */
72 private JSplitPane external_split;
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;
77 /** Provide synchronization between the collection trees in this view and the collection pane view. */
78 private TreeSynchronizer collection_tree_sync = null;
79
80
81 /** Constructor.
82 * @param tree_sync The <strong>TreeSynchronizer</strong> to be used on the collection tree
83 */
84 public EnrichPane(TreeSynchronizer collection_tree_sync)
85 {
86 this.collection_tree_sync = collection_tree_sync;
87
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());
98 }
99
100
101 /** 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.
102 */
103 public void afterDisplay()
104 {
105 external_split.setDividerLocation(0.3);
106 }
107
108
109 /** Used to create, connect and layout the components to be shown on this control panel.
110 * @see org.greenstone.gatherer.Gatherer
111 * @see org.greenstone.gatherer.file.FileOpenActionListener
112 * @see org.greenstone.gatherer.gui.Filter
113 */
114 public void display()
115 {
116 // Creation
117 JPanel collection_pane = new JPanel(new BorderLayout());
118 collection_pane.setMinimumSize(MINIMUM_SIZE);
119 collection_pane.setPreferredSize(COLLECTION_TREE_SIZE);
120
121 external_split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
122
123 collection_label = new JLabel();
124 Dictionary.registerText(collection_label, "Collection.No_Collection");
125 collection_label.setOpaque(true);
126
127 DragGroup group = new DragGroup();
128 collection_tree = new CollectionTree("Enrich", Gatherer.c_man.getCollectionTreeModel(), false);
129 group.add(collection_tree);
130 collection_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
131 collection_tree.putClientProperty("JTree.lineStyle", "Angled");
132 collection_tree.addMouseListener(Gatherer.g_man.foa_listener);
133 collection_tree.addMouseListener(new RightButtonListener());
134 collection_tree.addTreeSelectionListener(this);
135 collection_tree.addTreeExpansionListener(Gatherer.g_man.foa_listener);
136 collection_tree.setBackgroundNonSelectionColor(Configuration.getColor("coloring.collection_tree_background", false));
137 collection_tree.setTextNonSelectionColor(Configuration.getColor("coloring.collection_tree_foreground", false));
138 collection_tree.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
139 collection_tree.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
140 collection_tree.setRootVisible(false);
141
142 KeyListenerImpl key_listener = new KeyListenerImpl();
143 collection_tree.addKeyListener(key_listener);
144 JScrollPane collection_scroll = new JScrollPane(collection_tree);
145
146 collection_filter = Gatherer.g_man.getFilter(collection_tree);
147 collection_filter.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
148 collection_filter.setEditable(Configuration.getMode() > Configuration.LIBRARIAN_MODE);
149 Dictionary.registerTooltip(collection_filter.getComboBox(), "Collection.Filter_Tooltip");
150
151 // Layout
152 collection_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(3,3,3,3), BorderFactory.createLoweredBevelBorder()));
153 collection_pane.setMinimumSize(MINIMUM_SIZE);
154 collection_pane.setPreferredSize(new Dimension(Gatherer.g_man.getSize().width / 3, Gatherer.g_man.getSize().height));
155
156 // Collection Pane
157 collection_pane.add(collection_label, BorderLayout.NORTH);
158 collection_pane.add(collection_scroll, BorderLayout.CENTER);
159 collection_pane.add(collection_filter, BorderLayout.SOUTH);
160
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);
168
169 external_split.add(collection_pane, JSplitPane.LEFT);
170 external_split.add(metadata_editing_pane, JSplitPane.RIGHT);
171
172 this.setLayout(new BorderLayout());
173 this.add(external_split, BorderLayout.CENTER);
174 }
175
176
177 /** Called to inform this pane that it has just gained focus as an effect of the user clicking on its tab
178 */
179 public void gainFocus()
180 {
181 // If there is nothing in the collection tree there is nothing to do
182 if (collection_tree == null || collection_tree.getRowCount() == 0) {
183 return;
184 }
185
186 // Select the first node in the tree if nothing is already selected
187 if (collection_tree.getSelectionPaths() == null) {
188 collection_tree.setImmediate(true);
189 collection_tree.setSelectionRow(0);
190 collection_tree.setImmediate(false);
191 return;
192 }
193
194 // Force all of the controls to be updated
195 valueChanged(null);
196 }
197
198
199 /** 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)
200 * @param mode the mode level as an int
201 */
202 public void modeChanged(int mode)
203 {
204 collection_filter.setEditable(mode > Configuration.LIBRARIAN_MODE);
205 }
206
207
208 /** Refresh this pane, depending on what has just happened (refresh_reason). */
209 public void refresh(int refresh_reason, boolean collection_loaded)
210 {
211 if (collection_loaded) {
212 // Update collection label
213 Dictionary.registerText(collection_label, "Collection.Collection");
214 collection_label.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
215 collection_label.setForeground(Configuration.getColor("coloring.collection_heading_foreground", false));
216
217 // Update collection tree
218 if (refresh_reason == Gatherer.COLLECTION_OPENED) {
219 collection_tree.setModel(Gatherer.c_man.getCollectionTreeModel());
220 }
221
222 // Update collection filter
223 collection_filter.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
224 }
225 else {
226 // Update collection label
227 Dictionary.registerText(collection_label, "Collection.No_Collection");
228 collection_label.setBackground(Color.lightGray);
229 collection_label.setForeground(Color.black);
230
231 // Update collection tree
232 collection_tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode("Error")));
233
234 // Update collection filter
235 collection_filter.setBackground(Color.lightGray);
236 }
237
238 // Enable or disable the controls
239 collection_tree.setEnabled(collection_loaded);
240 collection_filter.setEnabled(collection_loaded);
241
242 // Ensure that this collection tree view is synchronized with all others
243 collection_tree_sync.add(collection_tree);
244
245 // Force the metadata table to be rebuilt (for switching extracted metadata on or off)
246 if (refresh_reason == Gatherer.PREFERENCES_CHANGED) {
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. */
253 public void valueChanged(TreeSelectionEvent event)
254 {
255 // Nothing selected in the collection tree
256 if (collection_tree.getSelectionCount() == 0) {
257 file_nodes = null;
258 }
259
260 // Some files selected in the collection tree
261 else {
262 TreePath paths[] = collection_tree.getSelectionPaths();
263 file_nodes = new CollectionTreeNode[paths.length];
264 for (int i = 0; i < paths.length; i++) {
265 file_nodes[i] = (CollectionTreeNode) paths[i].getLastPathComponent();
266 }
267 }
268
269 // Update the metadata value table (and consequently, the metadata value tree)
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)
330 {
331 try {
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);
335 }
336 catch (Exception exception) {
337 DebugStream.printStackTrace(exception);
338 }
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());
354 }
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());
377 }
378 }
379 }
380
381
382 /** This class listens for certain key presses, such as [Up] or [Down], -copied from Gather Pane */
383 private class KeyListenerImpl
384 extends KeyAdapter {
385 private boolean vk_left_pressed = false;
386 /** Called whenever a key that was pressed is released, it is this action that will cause the desired effects (this allows for the key event itself to be processed prior to this listener dealing with it). */
387 public void keyReleased(KeyEvent event) {
388 ///ystem.err.println("Key Release detected. " + event.getKeyCode());
389 if (event.getKeyCode() == KeyEvent.VK_UP || event.getKeyCode() == KeyEvent.VK_DOWN) {
390 DragTree tree = (DragTree)event.getSource();
391 // we need to manually do the up and down selections
392 boolean up = (event.getKeyCode() == KeyEvent.VK_UP);
393 int current_row = tree.getLeadSelectionRow();
394 tree.setImmediate(true);
395 if (up) {
396 if (current_row > 0) {
397 tree.clearSelection();
398 tree.setSelectionRow(current_row-1);
399 }
400 } else {
401 if (current_row < tree.getRowCount()-1){
402 tree.clearSelection();
403 tree.setSelectionRow(current_row+1);
404 }
405 }
406 tree.setImmediate(false);
407 }
408 else if (event.getKeyCode() == KeyEvent.VK_LEFT) {
409 // left key on a file shifts the selection to the parent folder
410 DragTree tree = (DragTree)event.getSource();
411 TreePath path = tree.getLeadSelectionPath();
412 if(path != null) {
413 File file = ((CollectionTreeNode) path.getLastPathComponent()).getFile();
414 if(file != null) {
415 if (file.isFile() || vk_left_pressed) {
416 vk_left_pressed = false;
417 TreePath parent_path = path.getParentPath();
418 if (parent_path != null && parent_path.getParentPath() != null) {
419 // if this file is in the top level folder, don't move the focus
420 tree.setImmediate(true);
421 tree.clearSelection();
422 tree.setSelectionPath(parent_path);
423 tree.setImmediate(false);
424 }
425 }
426 }
427 }
428 }
429 }
430
431 // we need to watch for left clicks on an unopened folder - should shift the focus to teh parent folder. But because there is some other mysterious key listener that does opening and closing folders on right and left clicks, we must detect the situation before the other handler has done its job, and process it after.
432 public void keyPressed(KeyEvent event) {
433 if (event.getKeyCode() == KeyEvent.VK_LEFT) {
434 // left key on closed directory shifts the selection to the parent folder
435 DragTree tree = (DragTree)event.getSource();
436 TreePath path = tree.getLeadSelectionPath();
437 if(path == null) return;
438 File file = ((CollectionTreeNode) path.getLastPathComponent()).getFile();
439 if(file == null) return;
440
441 if (file.isDirectory() && tree.isCollapsed(path)) {
442 vk_left_pressed = true;
443 }
444 }
445 }
446 }
447
448
449 /** A listener for right mouse button clicks over the collection tree. */
450 private class RightButtonListener
451 extends MouseAdapter {
452 /** Called whenever a mouse click occurs (right or left) over a target component.
453 * @param event A <strong>MouseEvent</strong> containing further information about the mouse click action.
454 * @see org.greenstone.gatherer.gui.EnrichPane.RightButtonMenu
455 */
456 public void mouseClicked(MouseEvent event) {
457 if (SwingUtilities.isRightMouseButton(event)) {
458 new RightButtonMenu(event);
459 }
460 }
461 }
462
463
464 /** When a user right-clicks within the collection tree they are presented with a small popup menu of context based options. This class provides such functionality.
465 */
466 private class RightButtonMenu
467 extends JPopupMenu
468 implements ActionListener {
469
470 /** The tree over which the right click action occurred. */
471 private DragTree tree = null;
472 /** The tree nodes selected when the right click action occurred. */
473 private TreePath[] selection_paths = null;
474 /** The file record over which the right click action occurred. */
475 private CollectionTreeNode node = null;
476
477 private JMenuItem collapse_folder = null;
478 private JMenuItem expand_folder = null;
479 private JMenuItem metaaudit = null;
480 private JMenuItem open_externally = null;
481
482
483 private RightButtonMenu(MouseEvent event)
484 {
485 super();
486 this.tree = collection_tree;
487
488 // Note we have to use setImmediate() with the set selction paths
489 // otherwise the selection doesn't get updated until after the
490 // popup comes up.
491
492 // the right click position
493 TreePath right_click_path = tree.getPathForLocation(event.getX(), event.getY());
494 if (right_click_path == null) {
495 // user has clicked outside of the tree, clear the selection
496 selection_paths = null;
497 tree.setImmediate(true);
498 tree.clearSelection();
499 tree.setImmediate(false);
500 } else {
501 // Get the paths currently selected in the tree
502 selection_paths = tree.getSelectionPaths();
503 if (selection_paths == null) {
504 // nothing currently selected - we shift the selection to
505 // the node that was right clicked on
506 selection_paths = new TreePath[1];
507 selection_paths[0] = right_click_path;
508 tree.setImmediate(true);
509 tree.setSelectionPath(right_click_path);
510 tree.setImmediate(false);
511 } else if (selection_paths.length == 1 && ! selection_paths[0].equals( right_click_path)) {
512 tree.setImmediate(true);
513 tree.clearSelection();
514 tree.setSelectionPath(right_click_path);
515 tree.setImmediate(false);
516 selection_paths[0] = right_click_path;
517 } else {
518 // we had multiply selected paths in the tree.
519 // if we clicked on one of those paths, then use all the
520 // current selection, otherwise clear the selection and
521 // select the one we right clicked on
522 boolean clicked_in_selection = false;
523 for (int i=0; i<selection_paths.length; i++) {
524 if (selection_paths[i].equals(right_click_path)) {
525 clicked_in_selection = true;
526 break;
527 }
528 }
529 if (!clicked_in_selection) {
530 // want the tree to update right away
531 tree.setImmediate(true);
532 tree.clearSelection();
533 tree.setSelectionPath(right_click_path);
534 tree.setImmediate(false);
535 selection_paths = new TreePath[1];
536 selection_paths[0] = right_click_path;
537 }
538 }
539 }
540 // finally we have the correct selection paths!
541
542 // Create an appropriate context menu, based on what is selected
543 buildContextMenu(selection_paths);
544
545 // Show the popup menu on screen
546 show(tree, event.getX(), event.getY());
547 }
548
549
550 private void buildContextMenu(TreePath[] selection_paths)
551 {
552 // If nothing is selected, no options are available
553 if (selection_paths == null) {
554 return;
555 }
556
557 DebugStream.println("Number of files/folders selected: " + selection_paths.length);
558
559 // Always have meta-audit option
560 metaaudit = new JMenuItem(Dictionary.get("Menu.Metadata_View", collection_tree.getSelectionDetails()), KeyEvent.VK_A);
561 metaaudit.addActionListener(this);
562 add(metaaudit);
563
564 // Only meta-audit is available if multiple items are selected...
565 if (selection_paths.length > 1) {
566 return;
567 }
568
569 TreePath path = selection_paths[0];
570 node = (CollectionTreeNode) path.getLastPathComponent();
571
572 // ---- Options for file nodes ----
573 if (node.isLeaf()) {
574 // Open the file in an external program
575 open_externally = new JMenuItem(Dictionary.get("Menu.Open_Externally"), KeyEvent.VK_O);
576 open_externally.addActionListener(this);
577 add(open_externally);
578 return;
579 }
580
581 // ---- Options for folder nodes ----
582 // Collapse or expand, depending on current status
583 if (tree.isExpanded(path)) {
584 collapse_folder = new JMenuItem(Dictionary.get("Menu.Collapse"), KeyEvent.VK_C);
585 collapse_folder.addActionListener(this);
586 add(collapse_folder);
587 }
588 else {
589 expand_folder = new JMenuItem(Dictionary.get("Menu.Expand"), KeyEvent.VK_O);
590 expand_folder.addActionListener(this);
591 add(expand_folder);
592 }
593 }
594
595
596 /** Called whenever one of the menu items is clicked, this method then causes the appropriate effect. */
597 public void actionPerformed(ActionEvent event)
598 {
599 Object source = event.getSource();
600
601 // Collapse folder
602 if (source == collapse_folder) {
603 tree.collapsePath(selection_paths[0]);
604 }
605
606 // Expand folder
607 else if (source == expand_folder) {
608 tree.expandPath(selection_paths[0]);
609 }
610
611 // Meta-audit
612 else if (source == metaaudit) {
613 Gatherer.g_man.showMetaAuditBox();
614 }
615
616 // Open in external program
617 else if (source == open_externally) {
618 Gatherer.self.spawnApplication(node.getFile());
619 }
620 }
621 }
622}
Note: See TracBrowser for help on using the repository browser.