source: main/trunk/gli/src/org/greenstone/gatherer/collection/CollectionTree.java@ 37191

Last change on this file since 37191 was 37191, checked in by kjdon, 15 months ago

added 'new file' into the right click menu in the collection tree. Its handled using replacefile task, but instead of replacing the current file, its using the specified node as the parent, and adding the new file into that folder

  • Property svn:keywords set to Author Date Id Revision
File size: 16.0 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 *
9 * Copyright (C) 2006 New Zealand Digital Library Project
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *############################################################################
25 */
26
27package org.greenstone.gatherer.collection;
28
29import java.awt.*;
30import java.awt.dnd.DropTargetDropEvent;
31import java.awt.event.*;
32import javax.swing.*;
33import javax.swing.tree.*;
34import org.greenstone.gatherer.Configuration;
35import org.greenstone.gatherer.Dictionary;
36import org.greenstone.gatherer.Gatherer;
37import org.greenstone.gatherer.gui.tree.DragTree;
38import org.greenstone.gatherer.gui.tree.DragTreeCellRenderer;
39
40
41public class CollectionTree
42 extends DragTree
43 implements MouseListener
44{
45 public CollectionTree(CollectionTreeModel collection_tree_model, boolean mixed_selection)
46 {
47 super(collection_tree_model, mixed_selection);
48 addMouseListener(this);
49
50 setCellRenderer(new CollectionTreeCellRenderer());
51 setBackgroundNonSelectionColor(Configuration.getColor("coloring.collection_tree_background", false));
52 setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
53 setTextNonSelectionColor(Configuration.getColor("coloring.collection_tree_foreground", false));
54 setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
55
56 filter.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
57 filter.setEditable(Configuration.getMode() >= Configuration.LIBRARIAN_MODE);
58 }
59
60
61 public boolean isDraggable()
62 {
63 return true;
64 }
65
66
67 public boolean isDroppable()
68 {
69 return true;
70 }
71
72 // Overridden here: when a successful drag and drop takes place
73 // make sure nothing is selected in the tree, so that no valueChanged()
74 // event gets fired anymore by items getting reselected in the tree
75 // (this used to result in the metadata table in EnrichPane being updated
76 // upon its valueChanged() getting called and funny things happened to
77 // the metadata due to state inconsistencies).
78 public void drop(DropTargetDropEvent event) {
79 if (!isDroppable()) {
80 return;
81 }
82
83 setImmediate(true);
84 clearSelection();
85 setImmediate(false);
86
87 // let the superclass' drop() process the rest of the drag event
88 super.drop(event);
89
90 }
91
92 public void mouseClicked(MouseEvent event)
93 {
94 if (SwingUtilities.isRightMouseButton(event)) {
95 new CollectionTreeRightClickMenu(this, event);
96 }
97 }
98
99 public void mouseEntered(MouseEvent event) { }
100
101 public void mouseExited(MouseEvent event) { }
102
103 public void mousePressed(MouseEvent event) { }
104
105 public void mouseReleased(MouseEvent event) { }
106
107
108 public String toString()
109 {
110 return "Collection";
111 }
112
113
114 private class CollectionTreeCellRenderer
115 extends DragTreeCellRenderer
116 {
117 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus)
118 {
119 JLabel tree_cell = (JLabel) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
120
121 // Mark explodable files and SrcReplaceable files with a different icon (Green file icon)
122 if(value instanceof CollectionTreeNode) {
123 if(((CollectionTreeNode) value).isExplodable() || ((CollectionTreeNode) value).isSrcReplaceable()) {
124 tree_cell.setIcon(CollectionTreeNode.GREEN_FILE_ICON);
125 }
126 }
127
128 return tree_cell;
129 }
130 }
131
132
133 /** When a user right-clicks within the workspace and collection trees they are presented with a small popup menu of context based options. This class provides such functionality.
134 */
135 private class CollectionTreeRightClickMenu
136 extends JPopupMenu
137 implements ActionListener
138 {
139 /** The tree over which the right click action occurred. */
140 private CollectionTree collection_tree = null;
141 /** The tree nodes selected when the right click action occurred. */
142 private TreePath[] selection_paths = null;
143 /** The file record over which the right click action occurred. */
144 private CollectionTreeNode node = null;
145
146 private JMenuItem collapse_folder = null;
147 private JMenuItem expand_folder = null;
148 private JMenuItem explode_metadata_database = null;
149 private JMenuItem replace_srcdoc_with_html = null;
150 private JMenuItem delete = null;
151 private JMenuItem metaaudit = null;
152 private JMenuItem new_folder = null;
153 private JMenuItem new_file = null;
154 private JMenuItem new_dummy_doc = null;
155 private JMenuItem refresh = null; // for refreshing folder view
156 private JMenuItem open_externally = null;
157 private JMenuItem rename = null;
158 private JMenuItem replace = null;
159
160
161 private CollectionTreeRightClickMenu(CollectionTree collection_tree, MouseEvent event)
162 {
163 super();
164 this.collection_tree = collection_tree;
165
166 // Note we have to use setImmediate() with the set selction paths
167 // otherwise the selection doesn't get updated until after the
168 // popup comes up.
169
170 // the right click position
171 TreePath right_click_path = collection_tree.getPathForLocation(event.getX(), event.getY());
172 if (right_click_path == null) {
173 // user has clicked outside of the tree, clear the selection
174 selection_paths = null;
175 collection_tree.setImmediate(true);
176 collection_tree.clearSelection();
177 collection_tree.setImmediate(false);
178 }
179 else {
180 // Get the paths currently selected in the tree
181 selection_paths = collection_tree.getSelectionPaths();
182 if (selection_paths == null) {
183 // nothing currently selected - we shift the selection to
184 // the node that was right clicked on
185 selection_paths = new TreePath[1];
186 selection_paths[0] = right_click_path;
187 collection_tree.setImmediate(true);
188 collection_tree.setSelectionPath(right_click_path);
189 collection_tree.setImmediate(false);
190 }
191 else if (selection_paths.length == 1 && ! selection_paths[0].equals( right_click_path)) {
192 collection_tree.setImmediate(true);
193 collection_tree.clearSelection();
194 collection_tree.setSelectionPath(right_click_path);
195 collection_tree.setImmediate(false);
196 selection_paths[0] = right_click_path;
197 }
198 else {
199 // we had multiply selected paths in the tree.
200 // if we clicked on one of those paths, then use all the
201 // current selection, otherwise clear the selection and
202 // select the one we right clicked on
203 boolean clicked_in_selection = false;
204 for (int i = 0; i < selection_paths.length; i++) {
205 if (selection_paths[i].equals(right_click_path)) {
206 clicked_in_selection = true;
207 break;
208 }
209 }
210 if (!clicked_in_selection) {
211 // want the tree to update right away
212 collection_tree.setImmediate(true);
213 collection_tree.clearSelection();
214 collection_tree.setSelectionPath(right_click_path);
215 collection_tree.setImmediate(false);
216 selection_paths = new TreePath[1];
217 selection_paths[0] = right_click_path;
218 }
219 }
220 }
221
222 // Create an appropriate context menu, based on what is selected
223 buildContextMenu(selection_paths);
224
225 // Show the popup menu on screen
226 show(collection_tree, event.getX(), event.getY());
227 }
228
229 /** Checks whether the files selected are of the same filetype (have the same extension).
230 * @param selectedFilePaths - the full file paths to the treenodes selected in the
231 * collection fileview.
232 * @return true if the file extensions of all the selected files are the same. False is
233 * returned if the file extension of any selected file is different (this means that if
234 * a folder was selected, false would be returned). False is also returned if nothing was
235 * selected.
236 * For use with replace_srcdoc_with_html.pl
237 */
238 private boolean selectedFilesOfSameType(TreePath[] selectedFilePaths) {
239 if(selectedFilePaths == null || selectedFilePaths.length <= 0)
240 return false;
241
242 boolean sameExtension = true;
243
244 // get just the filename from the path and extract its extension
245 String firstFile = selectedFilePaths[0].getLastPathComponent().toString();
246 int period = firstFile.lastIndexOf('.');
247 if(period == -1) { // someone could have selected a folder
248 return false;
249 }
250 String extension = firstFile.substring(period); // includes period
251
252 // compare with the other selected files' extensions:
253 for(int i = 1; i < selectedFilePaths.length && sameExtension; i++) {
254 String otherFile = selectedFilePaths[i].getLastPathComponent().toString();
255 String otherFileExt = otherFile.substring(otherFile.lastIndexOf('.'));
256 if(!extension.equals(otherFileExt))
257 sameExtension = false;
258 }
259 return sameExtension;
260 }
261
262 private void buildContextMenu(TreePath[] selection_paths)
263 {
264 // If nothing is selected, only the new folder/dummy doc options are available...
265 if (selection_paths == null) {
266 new_folder = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Folder"), KeyEvent.VK_N);
267 new_folder.addActionListener(this);
268 add(new_folder);
269
270 new_file = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_File"));
271 new_file.addActionListener(this);
272 add(new_file);
273
274 new_dummy_doc = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Dummy_Doc"));
275 new_dummy_doc.addActionListener(this);
276 add(new_dummy_doc);
277
278 refresh = new JMenuItem(Dictionary.get("CollectionPopupMenu.Refresh"));
279 if(Gatherer.isGsdlRemote) {
280 refresh.setEnabled(false);
281 }
282 refresh.addActionListener(this);
283 add(refresh);
284
285 node = (CollectionTreeNode) collection_tree.getModel().getRoot();
286 return;
287 }
288
289 // Meta-audit and delete options
290 metaaudit = new JMenuItem(Dictionary.get("Menu.Metadata_View", collection_tree.getSelectionDetails()), KeyEvent.VK_A);
291 metaaudit.addActionListener(this);
292 add(metaaudit);
293
294 delete = new JMenuItem(Dictionary.get("CollectionPopupMenu.Delete"), KeyEvent.VK_D);
295 delete.addActionListener(this);
296 add(delete);
297
298 // The src doc replaceable (with html file) option is only available when all files selected are of the
299 // same type (same extension). For srcreplaceable files only. Works with replace_srcdoc_with_html.pl
300 CollectionTreeNode firstSelectedNode = (CollectionTreeNode)selection_paths[0].getLastPathComponent();
301 if(firstSelectedNode.isSrcReplaceable()) { // test the first selected node
302 replace_srcdoc_with_html = new JMenuItem(Dictionary.get("Menu.Replace_SrcDoc_With_HTML"), KeyEvent.VK_H);
303 replace_srcdoc_with_html.addActionListener(this);
304 add(replace_srcdoc_with_html);
305
306 // Now the menu is there, grey it out if not all the files are of the same type
307 if(!selectedFilesOfSameType(selection_paths)) {
308 replace_srcdoc_with_html.setEnabled(false);
309 }
310 }
311
312 // Only meta-audit and delete (and possibly replace_srcdoc) are available if multiple items are selected...
313 if (selection_paths.length > 1) {
314 return;
315 }
316
317 // Rename option
318 rename = new JMenuItem(Dictionary.get("CollectionPopupMenu.Rename"), KeyEvent.VK_R);
319 rename.addActionListener(this);
320 add(rename);
321
322 TreePath path = selection_paths[0];
323 node = (CollectionTreeNode) path.getLastPathComponent();
324
325 // ---- Options for file nodes ----
326 if (node.isLeaf()) {
327 // Explode metadata databases, for explodable files only
328 if (node.isExplodable()) {
329 explode_metadata_database = new JMenuItem(Dictionary.get("Menu.Explode_Metadata_Database"), KeyEvent.VK_E);
330 explode_metadata_database.addActionListener(this);
331 add(explode_metadata_database);
332 }
333
334 // Replace file
335 replace = new JMenuItem(Dictionary.get("CollectionPopupMenu.Replace"), KeyEvent.VK_P);
336 replace.addActionListener(this);
337 add(replace);
338 // Open the file in an external program
339 open_externally = new JMenuItem(Dictionary.get("Menu.Open_Externally"), KeyEvent.VK_O);
340 open_externally.addActionListener(this);
341 add(open_externally);
342
343 return;
344 }
345
346 // ---- Options for folder nodes ----
347 // Collapse or expand, depending on current status
348 if (collection_tree.isExpanded(path)) {
349 collapse_folder = new JMenuItem(Dictionary.get("Menu.Collapse"), KeyEvent.VK_C);
350 collapse_folder.addActionListener(this);
351 add(collapse_folder);
352 }
353 else {
354 expand_folder = new JMenuItem(Dictionary.get("Menu.Expand"), KeyEvent.VK_O);
355 expand_folder.addActionListener(this);
356 add(expand_folder);
357 }
358
359 // New folder/dummy doc options
360 if (!node.isReadOnly()) {
361 new_folder = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Folder"), KeyEvent.VK_N);
362 new_folder.addActionListener(this);
363 add(new_folder);
364
365
366 new_file = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_File"));
367 new_file.addActionListener(this);
368 add(new_file);
369
370 new_dummy_doc = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Dummy_Doc"));
371 new_dummy_doc.addActionListener(this);
372 add(new_dummy_doc);
373 }
374 }
375
376
377 /** Called whenever one of the menu items is clicked, this method then causes the appropriate effect. */
378 public void actionPerformed(ActionEvent event)
379 {
380 Object source = event.getSource();
381
382 // Collapse folder
383 if (source == collapse_folder) {
384 collection_tree.collapsePath(selection_paths[0]);
385 }
386
387 // Expand folder
388 else if (source == expand_folder) {
389 collection_tree.expandPath(selection_paths[0]);
390 }
391
392 // Explode metadata database
393 else if (source == explode_metadata_database) {
394 Gatherer.f_man.explodeMetadataDatabase(node.getFile());
395 }
396
397 // Replace source document with generated html (works with replace_srcdoc_with_html.pl)
398 else if (source == replace_srcdoc_with_html) {
399 java.io.File[] source_files = new java.io.File[selection_paths.length];
400 for (int i = 0; i < selection_paths.length; i++) {
401 CollectionTreeNode node = (CollectionTreeNode) selection_paths[i].getLastPathComponent();
402 source_files[i] = node.getFile();
403 }
404 Gatherer.f_man.replaceSrcDocWithHtml(source_files); // passing the selected files
405 }
406
407 // Delete
408 else if (source == delete) {
409 CollectionTreeNode[] source_nodes = new CollectionTreeNode[selection_paths.length];
410 for (int i = 0; i < selection_paths.length; i++) {
411 source_nodes[i] = (CollectionTreeNode) selection_paths[i].getLastPathComponent();
412 }
413
414 // Fire a delete action
415 Gatherer.f_man.action(collection_tree, source_nodes, Gatherer.recycle_bin, null);
416 }
417
418 // Meta-audit
419 else if (source == metaaudit) {
420 Gatherer.g_man.showMetaAuditBox();
421 }
422
423 // New folder
424 else if (source == new_folder) {
425 Gatherer.f_man.newFolder(collection_tree, node);
426 }
427 else if (source == new_file) {
428 Gatherer.f_man.newCollectionFile(collection_tree, node);
429 }
430 // New dummy doc
431 else if (source == new_dummy_doc) {
432 Gatherer.f_man.newDummyDoc(collection_tree, node);
433 }
434
435 // Refresh action to reload folder view
436 else if (source == refresh) { // Refresh collection tree
437 Gatherer.g_man.refreshCollectionTree(DragTree.COLLECTION_CONTENTS_CHANGED);
438 }
439
440 // Open in external program
441 else if (source == open_externally) {
442 Gatherer.f_man.openFileInExternalApplication(node.getFile());
443 }
444
445 // Rename
446 else if (source == rename) {
447 Gatherer.f_man.renameCollectionFile(collection_tree, node);
448 }
449
450 // Replace
451 else if (source == replace) {
452 Gatherer.f_man.replaceCollectionFile(collection_tree, node);
453 }
454 }
455 }
456}
Note: See TracBrowser for help on using the repository browser.