source: trunk/gli/src/org/greenstone/gatherer/gui/CollectionPane.java@ 5327

Last change on this file since 5327 was 5327, checked in by mdewsnip, 21 years ago

Moved "stop action" button into the progress bar panel, and changed it to a simple text button.

  • Property svn:keywords set to Author Date Id Revision
File size: 35.1 KB
Line 
1package org.greenstone.gatherer.gui;
2/**
3 *#########################################################################
4 *
5 * A component of the Gatherer application, part of the Greenstone digital
6 * library suite from the New Zealand Digital Library Project at the
7 * University of Waikato, New Zealand.
8 *
9 * <BR><BR>
10 *
11 * Author: John Thompson, Greenstone Digital Library, University of Waikato
12 *
13 * <BR><BR>
14 *
15 * Copyright (C) 1999 New Zealand Digital Library Project
16 *
17 * <BR><BR>
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * <BR><BR>
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * <BR><BR>
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 *########################################################################
37 */
38import java.awt.*;
39import java.awt.event.*;
40import java.io.*;
41import java.util.*;
42import javax.swing.*;
43import javax.swing.event.*;
44import javax.swing.tree.*;
45import org.greenstone.gatherer.Gatherer;
46import org.greenstone.gatherer.file.FileNode;
47import org.greenstone.gatherer.file.FileOpenActionListener;
48import org.greenstone.gatherer.file.FileQueue;
49import org.greenstone.gatherer.file.FileSystemModel;
50import org.greenstone.gatherer.gui.Filter;
51import org.greenstone.gatherer.gui.GComboBox;
52import org.greenstone.gatherer.gui.tree.DragTree;
53import org.greenstone.gatherer.undo.UndoManager;
54import org.greenstone.gatherer.util.DragComponent;
55import org.greenstone.gatherer.util.DragGroup;
56import org.greenstone.gatherer.util.TreeSynchronizer;
57import org.greenstone.gatherer.util.Utility;
58import org.greenstone.gatherer.util.WinRegistry;
59/** The collection pane is analogous with a file manager. It is there that the user chooses which files to include in their collection and what structure the file hierarchy should take. The later aspect is not important for the Greenstone Suite, but is usefull for grouping files for ease of metadata markup. The view essentially consists of two file trees, one denoting the entire source workspace and the other the files within your collection. The trees themselves have a title bar at the top, a filter control at the bottom, and are coloured to indicate activity (grey for disabled). The remainder of the screen is taken by a status area, to indicate current file job progress during copying etc, and three buttons for controlling features of the view.
60 * @author John Thompson, Greenstone Digital Library, University of Waikato
61 * @version 2.3
62 */
63public class CollectionPane
64 extends JPanel
65 implements ActionListener, FocusListener {
66 /** The group encompassing all of the components available as drop targets for drag and drop actions. Required so that only one component renders the ghost and higlights itself as a target, which the other members are restored to their original, pristine, condition. */
67 private DragGroup group = null;
68 /** The tree showing the files within the collection. */
69 private DragTree collection_tree = null;
70 /** The tree showing the available source workspace. */
71 private DragTree workspace_tree = null;
72 /** The threaded queue that handles the actually movement of files, so that the gui remains responsive. */
73 private FileQueue file_queue = null;
74 /** The filter currently applied to the collection tree. */
75 private Filter collection_filter = null;
76 /** The filter currently applied to the workspace tree. */
77 private Filter workspace_filter = null;
78 /** The collection model which is used to build, and hold the data of, the collection tree. */
79 private TreeModel collection = null;
80 /** The GTree model used as the data source for the workspace tree. */
81 private TreeModel workspace = null;
82 /** The button used to cancel all pending file queue jobs. */
83 private JButton stop_action = null;
84 /** The button used to create a new folder in the collection tree. */
85 private JButton new_folder = null;
86 /** The label shown at the top of the collection tree. */
87 private JLabel collection_label = null;
88 /** The label shown in the status area explaining the file apon which action is taking place. */
89 private JLabel filename_label = null;
90 /** The label shown explaining the current state of the file queue thread. */
91 private JLabel status_label = null;
92 /** The label at the top of the workspace tree. */
93 private JLabel workspace_label = null;
94 /** The panel that contains the collection tree. */
95 private JPanel collection_pane = null;
96 /** The panel that contains the various controls including the status area. */
97 private JPanel control_pane = null;
98 /** The panel that contains the workspace tree. */
99 private JPanel workspace_pane = null;
100 /** The scrollable area into which the collection tree is placed. */
101 private JScrollPane collection_scroll = null;
102 /** The scrollable area into which the workspace tree is placed. */
103 private JScrollPane workspace_scroll = null;
104 /** A split pane seperating the two trees, allowing for the screen real-estate for each to be changed. */
105 private JSplitPane tree_pane = null;
106 /** Text fragment arguments used to fill in phrases returned from the dictionary. */
107 private String args[] = null;
108 /** Ensures that expansion and selection events between collection trees based on the same model are synchronized. */
109 private TreeSynchronizer collection_tree_sync = null;
110 /** Ensures that expansion and selection events between workspace trees based on the same model are synchronized. */
111 private TreeSynchronizer workspace_tree_sync = null;
112 /** The button used to delete files, which also doubles as a drop target for files from the Trees. */
113 private UndoManager bin_button = null;
114 /** The default size of a label in the interface. */
115 static final private Dimension LABEL_SIZE = new Dimension(100,30);
116 /** The default size of a special mapping dialog. */
117 static final Dimension DIALOG_SIZE = new Dimension(400, 120);
118 /** The minimum size a gui component can become. */
119 static private Dimension MIN_SIZE = new Dimension( 90, 90);
120 /** The default size of the status area. */
121 static private Dimension STATUS_SIZE = new Dimension(450, 120);
122 /** The initial size of the trees. */
123 static private Dimension TREE_SIZE = new Dimension(400, 430);
124 /* Constructor.
125 * @param tree_sync Ensures that expansion events between like trees are synchronized.
126 * @see org.greenstone.gatherer.file.FileManager
127 * @see org.greenstone.gatherer.file.FileQueue
128 */
129 public CollectionPane(TreeSynchronizer workspace_tree_sync, TreeSynchronizer collection_tree_sync) {
130 this.group = new DragGroup();
131 this.file_queue = Gatherer.f_man.getQueue();
132 this.collection_tree_sync = collection_tree_sync;
133 this.workspace_tree_sync = workspace_tree_sync;
134
135 // Create components.
136 stop_action = new JButton(get("Browser.Stop"));
137 stop_action.addActionListener(this);
138 stop_action.setEnabled(false);
139
140 new_folder = new JButton(Utility.getImage("folder.gif"));
141 new_folder.addActionListener(this);
142 new_folder.setEnabled(false);
143 new_folder.setMinimumSize(MIN_SIZE);
144 new_folder.setPreferredSize(MIN_SIZE);
145 }
146 /** Any implementation of ActionListener requires this method so that when an action is performed the appropriate effect can occur. In this case there are three valid possibilities. If the action occured on the recycle bin, then delete the current selection from the collection tree. If the action instead occured on the new folder button, then create a new folder under the current (single) selection in the collection tree. And finally if the cancel button was pressed, cancel the current, and remaining, jobs on the file queue. */
147 public void actionPerformed(ActionEvent event) {
148 // If a user has clicked on the bin button directly remove whatever
149 // files are selected in the active tree.
150 if(event.getSource() == bin_button) {
151 if(!bin_button.ignore()) {
152 // Find the active tree (you've made selections in).
153 DragTree tree = (DragTree) group.getActive();
154 // Fudge things a bit
155 group.setSource(tree);
156 // Determine the selection.
157 TreePath paths[] = tree.getSelectionPaths();
158 if(paths != null) {
159 FileNode[] source_nodes = new FileNode[paths.length];
160 for(int i = 0; i < paths.length; i++) {
161 source_nodes[i] = (FileNode)(paths[i].getLastPathComponent());
162 }
163 Gatherer.f_man.action(tree, source_nodes, bin_button, null);
164 }
165 }
166 }
167 // If a user has clicked on new_folder create a new folder under
168 // whatever node is selected.
169 else if(event.getSource() == new_folder && collection_tree != null) {
170 int count = collection_tree.getSelectionCount();
171 boolean error = false;
172 if(count == 1) {
173 TreePath path = collection_tree.getSelectionPath();
174 FileNode node = (FileNode) path.getLastPathComponent();
175 if(node.getAllowsChildren()) {
176 Gatherer.f_man.newFolder(collection_tree, node);
177 }
178 else {
179 // try the parent
180 FileNode parent = (FileNode)node.getParent();
181 if (parent!=null && parent.getAllowsChildren()) {
182 Gatherer.f_man.newFolder(collection_tree, parent);
183 } else {
184 error = true;
185 }
186 }
187 }
188 else {
189 error = true;
190 }
191 if(error) {
192 // instead of an error, we now create a new folder at the root
193 FileNode node = (FileNode) collection_tree.getModel().getRoot();
194 Gatherer.f_man.newFolder(collection_tree, node);
195 //JOptionPane.showMessageDialog(Gatherer.g_man, Gatherer.dictionary.get("FileActions.No_Parent_For_New_Folder"), Gatherer.dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
196 }
197 }
198 else if(event.getSource() == stop_action) {
199 file_queue.cancelAction();
200 }
201 }
202 /** Called whenever a significant change occurs in the current collections state, such as a new collection being loaded or the current one being closed. Several actions must occur in the GUI to indicate this change to the user, such as en/disabling the collection tree.
203 * @param ready <i>true</i> if a collection is loaded and ready to be modified, <i>false</i> otherwise.
204 * @see org.greenstone.gatherer.Configuration
205 * @see org.greenstone.gatherer.Gatherer
206 * @see org.greenstone.gatherer.collection.CollectionManager
207 * @see org.greenstone.gatherer.gui.Coloring
208 * @see org.greenstone.gatherer.gui.Filter
209 * @see org.greenstone.gatherer.util.TreeSynchronizer
210 */
211 public void collectionChanged(boolean ready) {
212 // Try to retrieve the collections record set.
213 collection = Gatherer.c_man.getRecordSet();
214 if(collection != null) {
215 args = new String[1];
216 args[0] = Gatherer.c_man.getCollection().getName();
217 collection_label.setText(get("Collection", args));
218 collection_tree.setModel(collection);
219 collection_tree.repaint();
220 collection_filter.setBackground(Gatherer.config.getColor("coloring.collection_heading_background", false));
221 }
222 else {
223 String args[] = new String[1];
224 args[0] = get("Collection.No_Collection");
225 collection_label.setText(get("Collection", args));
226 args = null;
227 collection_tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode("Error")));
228 collection_filter.setBackground(Color.lightGray);
229 }
230 collection_tree.setEnabled(ready);
231 collection_filter.setEnabled(ready);
232
233 // Change the label at the top of collection tree.
234 setEnabled(collection_label, ready, Gatherer.config.getColor("coloring.collection_heading_foreground", false), Gatherer.config.getColor("coloring.collection_heading_background", false));
235 // Ensure that this tree view of the collection record set is synchronized with any others.
236 collection_tree_sync.add(collection_tree);
237
238 refreshWorkspace();
239
240 // Enable or disable the control buttons
241 bin_button.setEnabled(ready);
242 stop_action.setEnabled(ready);
243 new_folder.setEnabled(ready);
244 }
245 /** Generates the pane on controls used to 'collect' files into the collection. Resposible for creating, connecting and laying out these controls. */
246 public void display() {
247 // Create Components.
248 KeyListenerImpl key_listener = new KeyListenerImpl();
249 MouseListenerImpl mouse_listener = new MouseListenerImpl();
250 this.addKeyListener(key_listener);
251
252 // Workspace Tree
253 workspace_pane = new JPanel();
254 workspace_pane.setMinimumSize(MIN_SIZE);
255 workspace_pane.setPreferredSize(TREE_SIZE);
256 workspace_pane.setSize(TREE_SIZE);
257
258 workspace_label = new JLabel(get("Workspace"));
259 workspace_label.setOpaque(true);
260 workspace_label.setBackground(Gatherer.config.getColor("coloring.workspace_heading_background", false));
261 workspace_label.setForeground(Gatherer.config.getColor("coloring.workspace_heading_foreground", false));
262
263 workspace = Gatherer.c_man.getWorkspace();
264 workspace_tree = new DragTree(Utility.WORKSPACE_TREE, workspace, null, true);
265 group.add(workspace_tree);
266 workspace_tree.addFocusListener(this);
267 workspace_tree.addKeyListener(key_listener);
268 workspace_tree.addMouseListener(mouse_listener);
269 workspace_tree.addMouseListener(Gatherer.g_man.foa_listener);
270 workspace_tree.addTreeExpansionListener(Gatherer.g_man.foa_listener);
271 workspace_tree.addTreeSelectionListener(file_queue);
272 workspace_tree.putClientProperty("JTree.lineStyle", "Angled");
273 workspace_tree.setBackgroundNonSelectionColor(Gatherer.config.getColor("coloring.workspace_tree_background", false));
274 workspace_tree.setTextNonSelectionColor(Gatherer.config.getColor("coloring.workspace_tree_foreground", false));
275 workspace_tree.setBackgroundSelectionColor(Gatherer.config.getColor("coloring.workspace_selection_background", false));
276 workspace_tree.setTextSelectionColor(Gatherer.config.getColor("coloring.workspace_selection_foreground", false));
277 workspace_tree.setRootVisible(false);
278
279 workspace_scroll = new JScrollPane(workspace_tree);
280
281 workspace_filter = Gatherer.g_man.getFilter(workspace_tree);
282 workspace_filter.setBackground(Gatherer.config.getColor("coloring.workspace_heading_background", false));
283 // Change the default colours of this filters combobox.
284 GComboBox fcb = workspace_filter.getComboBox();
285 fcb.setBackgroundNonSelectionColor(Gatherer.config.getColor("coloring.editable_background", false));
286 fcb.setTextNonSelectionColor(Gatherer.config.getColor("coloring.workspace_tree_foreground", false));
287 fcb.setBackgroundSelectionColor(Gatherer.config.getColor("coloring.collection_selection_background", false));
288 fcb.setTextSelectionColor(Gatherer.config.getColor("coloring.collection_selection_foreground", false));
289 fcb = null;
290
291 // Collection Tree
292 collection_pane = new JPanel();
293 collection_pane.setMinimumSize(MIN_SIZE);
294 collection_pane.setPreferredSize(TREE_SIZE);
295 collection_pane.setSize(TREE_SIZE);
296
297 args = new String[1];
298 args[0] = get("Collection.No_Collection");
299 collection_label = new JLabel(get("Collection", args));
300 collection_label.setOpaque(true);
301
302 collection = Gatherer.c_man.getRecordSet();
303 if(collection != null) {
304 collection_tree = new DragTree(Utility.COLLECTION_TREE, collection, null, true);
305 collection_tree.setEnabled(true);
306 }
307 else {
308 collection_tree = new DragTree(Utility.COLLECTION_TREE, null, true);
309 collection_tree.setEnabled(false);
310 }
311 group.add(collection_tree);
312 collection_tree.addFocusListener(this);
313 collection_tree.addKeyListener(key_listener);
314 collection_tree.addMouseListener(mouse_listener);
315 collection_tree.addMouseListener(Gatherer.g_man.foa_listener);
316 collection_tree.addTreeSelectionListener(file_queue);
317 collection_tree.addTreeExpansionListener(Gatherer.g_man.foa_listener);
318 collection_tree.putClientProperty("JTree.lineStyle", "Angled");
319 collection_tree.setBackgroundNonSelectionColor(Gatherer.config.getColor("coloring.collection_tree_background", false));
320 collection_tree.setTextNonSelectionColor(Gatherer.config.getColor("coloring.collection_tree_foreground", false));
321 collection_tree.setBackgroundSelectionColor(Gatherer.config.getColor("coloring.collection_selection_background", false));
322 collection_tree.setTextSelectionColor(Gatherer.config.getColor("coloring.collection_selection_foreground", false));
323 collection_tree.setRootVisible(false);
324 //collection_tree.setRootVisible(true);
325
326 collection_scroll = new JScrollPane(collection_tree);
327
328 collection_filter = Gatherer.g_man.getFilter(collection_tree);
329 if(collection != null) {
330 collection_filter.setBackground(Gatherer.config.getColor("coloring.collection_heading_background", false));
331 }
332 else {
333 collection_filter.setBackground(Color.lightGray);
334 }
335 // Change the default colours of this filters combobox.
336 fcb = collection_filter.getComboBox();
337 fcb.setBackgroundNonSelectionColor(Gatherer.config.getColor("coloring.editable_background", false));
338 fcb.setTextNonSelectionColor(Gatherer.config.getColor("coloring.collection_tree_foreground", false));
339 fcb.setBackgroundSelectionColor(Gatherer.config.getColor("coloring.collection_selection_background", false));
340 fcb.setTextSelectionColor(Gatherer.config.getColor("coloring.collection_selection_foreground", false));
341 fcb = null;
342
343 tree_pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
344
345 // Status pane
346 control_pane = new JPanel();
347
348 JPanel inner_pane = new JPanel();
349 inner_pane.setSize(STATUS_SIZE);
350
351 JPanel file_pane = new JPanel();
352 //file_pane.setBackground(Color.white);
353 //JPanel job_pane = new JPanel();
354 //job_pane.setBackground(Color.white);
355 JPanel progress_pane = new JPanel();
356 //progress_pane.setBackground(Color.white);
357 JLabel file_status = file_queue.getFileStatus();
358 //JLabel job_status = job_queue.getJobStatus();
359
360 JProgressBar progress = file_queue.getProgress();
361
362 JPanel button_pane = new JPanel();
363
364 bin_button = Gatherer.c_man.undo;
365 bin_button.addActionListener(this);
366 bin_button.setEnabled(false);
367 bin_button.setMinimumSize(MIN_SIZE);
368 bin_button.setPreferredSize(MIN_SIZE);
369 group.add(bin_button);
370
371 // Layout Components.
372 workspace_pane.setLayout(new BorderLayout());
373 workspace_pane.add(workspace_label, BorderLayout.NORTH);
374 workspace_pane.add(workspace_scroll, BorderLayout.CENTER);
375 workspace_pane.add(workspace_filter, BorderLayout.SOUTH);
376
377 collection_pane.setLayout(new BorderLayout());
378 collection_pane.add(collection_label, BorderLayout.NORTH);
379 collection_pane.add(collection_scroll, BorderLayout.CENTER);
380 collection_pane.add(collection_filter, BorderLayout.SOUTH);
381
382 tree_pane.add(workspace_pane, JSplitPane.LEFT);
383 tree_pane.add(collection_pane, JSplitPane.RIGHT);
384 tree_pane.setDividerLocation(TREE_SIZE.width - 10);
385
386 //job_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
387 //job_pane.setLayout(new BorderLayout());
388 //job_pane.add(job_status, BorderLayout.CENTER);
389
390 file_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
391 file_pane.setLayout(new BorderLayout());
392 file_pane.add(file_status, BorderLayout.CENTER);
393 file_pane.add(stop_action, BorderLayout.EAST);
394
395 progress_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
396 progress_pane.setLayout(new BorderLayout());
397 progress_pane.add(progress, BorderLayout.CENTER);
398
399 inner_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(10,10,10,10), BorderFactory.createLoweredBevelBorder()));
400 inner_pane.setLayout(new GridLayout(2,1));
401 //inner_pane.add(job_pane);
402 inner_pane.add(file_pane);
403 inner_pane.add(progress_pane);
404
405 button_pane.add(new_folder);
406 button_pane.add(bin_button);
407
408 control_pane.setLayout(new BorderLayout());
409 //control_pane.add(new_folder, BorderLayout.WEST);
410 control_pane.add(inner_pane, BorderLayout.CENTER);
411 control_pane.add(button_pane, BorderLayout.EAST);
412
413 this.setLayout(new BorderLayout());
414 this.add(tree_pane, BorderLayout.CENTER);
415 this.add(control_pane, BorderLayout.SOUTH);
416 }
417 /** This method ensures that a certain tree path is visible and selected within the collection tree, expanding nodes if necessary. If the method is successful the bounds of the new selection are returned. */
418 public Rectangle expandPath(TreePath path) {
419 collection_tree.setImmediate(true);
420 collection_tree.scrollPathToVisible(path);
421 collection_tree.setSelectionPath(path);
422 collection_tree.setImmediate(false);
423 return collection_tree.getRowBounds(collection_tree.getRowForPath(path));
424 }
425 /** Called whenever this pane gains focus, this method ensures that the various tree renderers are correctly colouring the tree (as these settings sometimes get lost).
426 * @param event A <strong>FocusEvent</strong> containing details about the focus action performed.
427 */
428 public void focusGained(FocusEvent event) {
429 DefaultTreeCellRenderer def = new DefaultTreeCellRenderer();
430 DefaultTreeCellRenderer w = (DefaultTreeCellRenderer)workspace_tree.getCellRenderer();
431 DefaultTreeCellRenderer c = (DefaultTreeCellRenderer)collection_tree.getCellRenderer();
432 if(event.getSource() == workspace_tree) {
433 w.setBackgroundSelectionColor(def.getBackgroundSelectionColor());
434 c.setBackgroundSelectionColor(Color.lightGray);
435 }
436 else if(event.getSource() == collection_tree) {
437 c.setBackgroundSelectionColor(def.getBackgroundSelectionColor());
438 w.setBackgroundSelectionColor(Color.lightGray);
439 }
440 repaint();
441 }
442 /** Implementation side-effect, not used in any way.
443 * @param event A <strong>FocusEvent</strong> containing details about the focus action performed.
444 */
445 public void focusLost(FocusEvent event) {
446 }
447
448 /** Called to inform this control panel that it has just gained focus as an effect of the user clicking on its tab.
449 * @see org.greenstone.gatherer.tree.GTree
450 */
451 public void gainFocus() {
452 // Update the menubar's idea of whats been selected
453 if (collection_tree != null) {
454 if (collection_tree.isSelectionEmpty()) {
455 Gatherer.g_man.menu_bar.setMetaAuditSuffix(null);
456 }
457 else {
458 Gatherer.g_man.menu_bar.setMetaAuditSuffix(collection_tree.getSelectionDetails());
459 }
460 }
461 // Update the meta-audit view to show the current selection, if any.
462 Gatherer.g_man.meta_audit.setRecords(getSelected());
463 }
464
465 /** Retrieve a list of the currently selected file records in the active tree. */
466 public FileNode[] getSelected() {
467 TreePath paths[] = collection_tree.getSelectionPaths();
468 FileNode records[] = null;
469 if(paths != null) {
470 records = new FileNode[paths.length];
471 for(int i = 0; i < records.length; i++) {
472 records[i] = (FileNode) paths[i].getLastPathComponent();
473 }
474 }
475 return records;
476 }
477
478 public String getSelectionDetails() {
479 return collection_tree.getSelectionDetails();
480 }
481
482 public DragTree getWorkspaceTree() {
483 return workspace_tree;
484 }
485
486 public void refreshTrees() {
487 collection_tree.refresh(null);
488 workspace_tree.refresh(null);
489 }
490
491 public void refreshWorkspace() {
492 workspace = Gatherer.c_man.getWorkspace();
493 workspace_tree.setModel(workspace);
494 workspace_tree_sync.add(workspace_tree);
495 }
496
497 /** Retrieve a phrase from the dictionary based on the key.
498 * @param key A <strong>String</strong> used to uniquely identify the phrase to be retrieved.
499 */
500 private String get(String key) {
501 return get(key, null);
502 }
503 /** Retrieve a phrase from the dictionary based on the key, and filled in using text fragments from an arguments array.
504 * @param key A <strong>String</strong> used to uniquely identify the phrase to be retrieved.
505 * @param args A <strong>String[]</strong> used as parameters to be inserted in the phrase retrieved.
506 * @see org.greenstone.gatherer.Dictionary
507 * @see org.greenstone.gatherer.Gatherer
508 */
509 private String get(String key, String args[]) {
510 if(key.indexOf('.') == -1) {
511 key = "Collection." + key;
512 }
513 return Gatherer.dictionary.get(key, args);
514 }
515 /** Used to set the enabled state, and hence the colouring, of the two tree labels.
516 * @param label The <strong>JLabel</strong> to be affected.
517 * @param state <i>true</i> for enabled, i.e. when a collection is ready, <i>false</i> otherwise.
518 * @param foreground The <strong>Color</strong> to make the foreground text of the label when enabled.
519 * @param background The <strong>Color</strong> to make the background of the label when enabled.
520 */
521 private void setEnabled(JLabel label, boolean state, Color foreground, Color background) {
522 ///ystem.err.println("Setting the label color to state " + state);
523 if(state) {
524 label.setBackground(background);
525 label.setForeground(foreground);
526 }
527 else {
528 label.setBackground(Color.lightGray);
529 label.setForeground(Color.black);
530 }
531 label.repaint();
532 ///ystem.err.println("Color is now " + label.getBackground());
533 }
534 /** When a user right-clicks within the trees on the collection pane view they are presented with a small popup menu of context based options. This class provides such functionality.
535 */
536 private class GPopupMenu
537 extends JPopupMenu
538 implements ActionListener {
539 /** The tree over which the right click action occured. */
540 private DragTree tree = null;
541 /** The file record over which the right click action occured, if any. */
542 private FileNode node = null;
543 /** A menu item enabled if a delete action is appropriate in the menus current context. */
544 private JMenuItem delete = null;
545 /** A menu item enabled if a special directory mapping is appropriate in the menus current context. */
546 private JMenuItem map = null;
547 /** A menu item enabled if a new folder action is appropriate in the menus current context. */
548 private JMenuItem new_folder = null;
549 /** A menu item enabled if a show meta-audit dialog action is appropriate in the menus current context. */
550 private JMenuItem show_metaaudit = null;
551 /** A menu item allowing a user to unmap a special directory, if and only if a special directory is selected. */
552 private JMenuItem unmap = null;
553 /** Constructor. */
554 public GPopupMenu(DragTree tree, MouseEvent event) {
555 super();
556 this.tree = tree;
557 TreePath path = tree.getClosestPathForLocation(event.getX(), event.getY());
558 if(path != null) {
559 node = (FileNode)path.getLastPathComponent();
560 // Set Options based on selection and tree
561 if(tree.getSelectionCount() != 0 && tree == collection_tree) {
562 show_metaaudit = new JMenuItem(get("Menu.Metadata_View") + " " + collection_tree.getSelectionDetails(), KeyEvent.VK_V);
563 show_metaaudit.addActionListener(this);
564 add(show_metaaudit);
565 }
566 if(tree == collection_tree && node != null && node.getFile() != null && node.getFile().isDirectory() && !node.isReadOnly()) {
567 new_folder = new JMenuItem(get("New_Folder"), KeyEvent.VK_N);
568 new_folder.addActionListener(this);
569 add(new_folder);
570 add(new JSeparator());
571 }
572 if(node == null || (node != null && !node.isReadOnly())) {
573 delete = new JMenuItem(get("Delete"), KeyEvent.VK_D);
574 delete.addActionListener(this);
575 add(delete);
576 }
577 if(tree == workspace_tree && node != null && !node.isLeaf()) {
578 String node_name = node.toString();
579 FileNode root = (FileNode) tree.getModel().getRoot();
580 if(!node_name.equals(get("Tree.World")) && !node_name.equals(get("Tree.Root")) && !node_name.equals(get("Tree.Public")) && !node_name.equals(get("Tree.Private"))) {
581 // You can unmap 1st level nodes.
582 if(root.getIndex(node) != -1) {
583 unmap = new JMenuItem(get("MappingPrompt.Unmap"), KeyEvent.VK_U);
584 unmap.addActionListener(this);
585 add(unmap);
586 }
587 // Or map any other level directories.
588 else {
589 map = new JMenuItem(get("MappingPrompt.Map"), KeyEvent.VK_M);
590 map.addActionListener(this);
591 add(map);
592 }
593 }
594 }
595 show(tree, event.getX(), event.getY());
596 }
597 }
598 /** Called whenever one of the menu items is actioned apon, this method then causes the appropriate effect. */
599 public void actionPerformed(ActionEvent event) {
600 if(event.getSource() == delete) {
601 // Retrieve the selection. Of course this gets a bit tricky as the user may have right clicked over a node not in the current selection, in which case we remove only that node.
602 TreePath[] selection_paths = tree.getSelectionPaths();
603 if(selection_paths != null) {
604 FileNode[] source_nodes = new FileNode[selection_paths.length];
605 boolean found = false;
606 for(int i = 0; i < selection_paths.length; i++) {
607 source_nodes[i] = (FileNode) selection_paths[i].getLastPathComponent();
608 if(node != null) {
609 found = found || source_nodes[i].equals(node);
610 }
611 }
612 if(node != null && !found) {
613 source_nodes = null;
614 source_nodes = new FileNode[1];
615 source_nodes[0] = node;
616 }
617 // Fire a delete action
618 Gatherer.f_man.action(tree, source_nodes, bin_button, null);
619 source_nodes = null;
620 }
621 selection_paths = null;
622 }
623 else if(event.getSource() == map && node != null) {
624 MappingPrompt mp = new MappingPrompt(node.getFile());
625 mp.destroy();
626 mp = null;
627 }
628 else if(event.getSource() == new_folder && node != null) {
629 Gatherer.f_man.newFolder(tree, node);
630 }
631 else if(event.getSource() == show_metaaudit) {
632 Gatherer.g_man.showMetaAuditBox();
633 }
634 else if(event.getSource() == unmap && node != null) {
635 Gatherer.c_man.removeDirectoryMapping(node);
636 }
637 }
638 /** Retrieve a phrase from the dictionary based on the key.
639 * @param key A <strong>String</strong> used to uniquely identify the phrase to be retrieved.
640 */
641 private String get(String key) {
642 return get(key, null);
643 }
644 /** Retrieve a phrase from the dictionary based on the key, and filled in using text fragments from an arguments array.
645 * @param key A <strong>String</strong> used to uniquely identify the phrase to be retrieved.
646 * @param args A <strong>String[]</strong> used as parameters to be inserted in the phrase retrieved.
647 * @see org.greenstone.gatherer.Dictionary
648 * @see org.greenstone.gatherer.Gatherer
649 */
650 private String get(String key, String args[]) {
651 if(key.indexOf('.') == -1) {
652 key = "CollectionPopupMenu." + key;
653 }
654 return Gatherer.dictionary.get(key, args);
655 }
656 }
657 /** This class listens for certain key presses, such as [Enter] or [Delete], and responds appropriately. */
658 private class KeyListenerImpl
659 extends KeyAdapter {
660 /** 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). */
661 public void keyReleased(KeyEvent event) {
662 ///ystem.err.println("Key Release detected. " + event.getKeyCode());
663 if(event.getKeyCode() == KeyEvent.VK_DELETE) {
664 // Get the selected files from the tree and removal them using the default dnd removal method.
665 // Find the active tree (you've made selections in).
666 DragTree tree = (DragTree) group.getActive();
667 // Fudge things a bit
668 group.setSource(tree);
669 // Determine the selection.
670 TreePath paths[] = tree.getSelectionPaths();
671 if(paths != null) {
672 FileNode[] source_nodes = new FileNode[paths.length];
673 for(int i = 0; i < source_nodes.length; i++) {
674 source_nodes[i] = (FileNode) paths[i].getLastPathComponent();
675 }
676 Gatherer.f_man.action(tree, source_nodes, bin_button, null);
677 source_nodes = null;
678 }
679 }
680 else if(event.getKeyCode() == KeyEvent.VK_ENTER) {
681 // Get the first selected file.
682 DragTree tree = (DragTree)event.getSource();
683 TreePath path = tree.getSelectionPath();
684 if(path != null) {
685 File file = ((FileNode)path.getLastPathComponent()).getFile();
686 if(file != null && file.isFile()) {
687 Gatherer.self.spawnApplication(file);
688 }
689 else {
690 if(!tree.isExpanded(path)) {
691 tree.expandPath(path);
692 }
693 else {
694 tree.collapsePath(path);
695 }
696 }
697 }
698 }
699 }
700 }
701
702 /** This provides a small prompt for gathering addition details about a special directory mapping such as its symbolic name. */
703 private class MappingPrompt
704 extends JDialog
705 implements ActionListener, KeyListener {
706 private boolean cancelled = false;
707 private JButton cancel_button = null;
708 private JButton ok_button = null;
709 private JTextField name_field = null;
710 public MappingPrompt(File file) {
711 super(Gatherer.g_man);
712 setModal(true);
713 setSize(DIALOG_SIZE);
714 setTitle(get("MappingPrompt.Title"));
715 // Creation
716 JPanel content_pane = (JPanel) getContentPane();
717 JPanel center_pane = new JPanel();
718 JPanel file_pane = new JPanel();
719 JLabel file_label = new JLabel(get("MappingPrompt.File"));
720 file_label.setPreferredSize(LABEL_SIZE);
721 JLabel file_field = new JLabel(file.getAbsolutePath());
722 JPanel name_pane = new JPanel();
723 JLabel name_label = new JLabel(get("MappingPrompt.Name"));
724 name_label.setPreferredSize(LABEL_SIZE);
725 name_field = new JTextField(file.getName());
726 JPanel button_pane = new JPanel();
727 ok_button = new JButton(get("General.OK"));
728 ok_button.setEnabled(name_field.getText().length() > 0);
729 cancel_button = new JButton(get("General.Cancel"));
730 // Connection
731 cancel_button.addActionListener(this);
732 ok_button.addActionListener(this);
733 name_field.addKeyListener(this);
734 // Layout
735 file_pane.setLayout(new BorderLayout());
736 file_pane.add(file_label, BorderLayout.WEST);
737 file_pane.add(file_field, BorderLayout.CENTER);
738
739 name_pane.setLayout(new BorderLayout());
740 name_pane.add(name_label, BorderLayout.WEST);
741 name_pane.add(name_field, BorderLayout.CENTER);
742
743 center_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
744 center_pane.setLayout(new GridLayout(2,1,5,5));
745 center_pane.add(file_pane);
746 center_pane.add(name_pane);
747
748 button_pane.setLayout(new GridLayout(1,2,5,5));
749 button_pane.add(ok_button);
750 button_pane.add(cancel_button);
751
752 content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
753 content_pane.setLayout(new BorderLayout());
754 content_pane.add(center_pane, BorderLayout.CENTER);
755 content_pane.add(button_pane, BorderLayout.SOUTH);
756 // Display
757 Dimension screen_size = Gatherer.config.screen_size;
758 setLocation((screen_size.width - DIALOG_SIZE.width) / 2, (screen_size.height - DIALOG_SIZE.height) / 2);
759 show();
760 // If not cancelled create mapping.
761 if(!cancelled) {
762 Gatherer.c_man.addDirectoryMapping(name_field.getText(), file);
763 }
764 }
765 public void actionPerformed(ActionEvent event) {
766 if(event.getSource() == cancel_button) {
767 cancelled = true;
768 }
769 dispose();
770 }
771 public void destroy() {
772 cancel_button = null;
773 ok_button = null;
774 name_field = null;
775 }
776 public void keyPressed(KeyEvent event) {
777 }
778 public void keyReleased(KeyEvent event) {
779 ok_button.setEnabled(name_field.getText().length() > 0);
780
781 }
782 public void keyTyped(KeyEvent event) {
783 }
784 }
785 /** This class listens for mouse clicks and responds right mouse button clicks (popup menu). */
786 private class MouseListenerImpl
787 extends MouseAdapter {
788 /** Any subclass of MouseAdapter can override this method to respond to mouse click events. In this case we want to open a pop-up menu if we detect a right mouse click over one of our registered components, and start an external application if someone double clicks on a certain file record. */
789 public void mouseClicked(MouseEvent event) {
790 if(SwingUtilities.isRightMouseButton(event)) {
791 new GPopupMenu((DragTree)event.getSource(), event);
792 }
793 }
794 }
795}
Note: See TracBrowser for help on using the repository browser.