/** *############################################################################ * A component of the Greenstone Librarian Interface, part of the Greenstone * digital library suite from the New Zealand Digital Library Project at the * University of Waikato, New Zealand. * * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ * * Copyright (C) 2006 New Zealand Digital Library Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *############################################################################ */ package org.greenstone.gatherer.collection; import java.awt.*; import java.awt.dnd.DropTargetDropEvent; import java.awt.event.*; import javax.swing.*; import javax.swing.tree.*; import org.greenstone.gatherer.Configuration; import org.greenstone.gatherer.Dictionary; import org.greenstone.gatherer.Gatherer; import org.greenstone.gatherer.gui.tree.DragTree; import org.greenstone.gatherer.gui.tree.DragTreeCellRenderer; public class CollectionTree extends DragTree implements MouseListener { public CollectionTree(CollectionTreeModel collection_tree_model, boolean mixed_selection) { super(collection_tree_model, mixed_selection); addMouseListener(this); setCellRenderer(new CollectionTreeCellRenderer()); setBackgroundNonSelectionColor(Configuration.getColor("coloring.collection_tree_background", false)); setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false)); setTextNonSelectionColor(Configuration.getColor("coloring.collection_tree_foreground", false)); setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false)); filter.setBackground(Configuration.getColor("coloring.collection_heading_background", false)); filter.setEditable(Configuration.getMode() >= Configuration.LIBRARIAN_MODE); } public boolean isDraggable() { return true; } public boolean isDroppable() { return true; } // Overridden here: when a successful drag and drop takes place // make sure nothing is selected in the tree, so that no valueChanged() // event gets fired anymore by items getting reselected in the tree // (this used to result in the metadata table in EnrichPane being updated // upon its valueChanged() getting called and funny things happened to // the metadata due to state inconsistencies). public void drop(DropTargetDropEvent event) { if (!isDroppable()) { return; } setImmediate(true); clearSelection(); setImmediate(false); // let the superclass' drop() process the rest of the drag event super.drop(event); } public void mouseClicked(MouseEvent event) { if (SwingUtilities.isRightMouseButton(event)) { new CollectionTreeRightClickMenu(this, event); } } public void mouseEntered(MouseEvent event) { } public void mouseExited(MouseEvent event) { } public void mousePressed(MouseEvent event) { } public void mouseReleased(MouseEvent event) { } public String toString() { return "Collection"; } private class CollectionTreeCellRenderer extends DragTreeCellRenderer { public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { JLabel tree_cell = (JLabel) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); // Mark explodable files and SrcReplaceable files with a different icon (Green file icon) if(value instanceof CollectionTreeNode) { if(((CollectionTreeNode) value).isExplodable() || ((CollectionTreeNode) value).isSrcReplaceable()) { tree_cell.setIcon(CollectionTreeNode.GREEN_FILE_ICON); } } return tree_cell; } } /** 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. */ private class CollectionTreeRightClickMenu extends JPopupMenu implements ActionListener { /** The tree over which the right click action occurred. */ private CollectionTree collection_tree = null; /** The tree nodes selected when the right click action occurred. */ private TreePath[] selection_paths = null; /** The file record over which the right click action occurred. */ private CollectionTreeNode node = null; private JMenuItem collapse_folder = null; private JMenuItem expand_folder = null; private JMenuItem explode_metadata_database = null; private JMenuItem replace_srcdoc_with_html = null; private JMenuItem delete = null; private JMenuItem metaaudit = null; private JMenuItem new_folder = null; private JMenuItem new_dummy_doc = null; private JMenuItem refresh = null; // for refreshing folder view private JMenuItem open_externally = null; private JMenuItem rename = null; private JMenuItem replace = null; private CollectionTreeRightClickMenu(CollectionTree collection_tree, MouseEvent event) { super(); this.collection_tree = collection_tree; // Note we have to use setImmediate() with the set selction paths // otherwise the selection doesn't get updated until after the // popup comes up. // the right click position TreePath right_click_path = collection_tree.getPathForLocation(event.getX(), event.getY()); if (right_click_path == null) { // user has clicked outside of the tree, clear the selection selection_paths = null; collection_tree.setImmediate(true); collection_tree.clearSelection(); collection_tree.setImmediate(false); } else { // Get the paths currently selected in the tree selection_paths = collection_tree.getSelectionPaths(); if (selection_paths == null) { // nothing currently selected - we shift the selection to // the node that was right clicked on selection_paths = new TreePath[1]; selection_paths[0] = right_click_path; collection_tree.setImmediate(true); collection_tree.setSelectionPath(right_click_path); collection_tree.setImmediate(false); } else if (selection_paths.length == 1 && ! selection_paths[0].equals( right_click_path)) { collection_tree.setImmediate(true); collection_tree.clearSelection(); collection_tree.setSelectionPath(right_click_path); collection_tree.setImmediate(false); selection_paths[0] = right_click_path; } else { // we had multiply selected paths in the tree. // if we clicked on one of those paths, then use all the // current selection, otherwise clear the selection and // select the one we right clicked on boolean clicked_in_selection = false; for (int i = 0; i < selection_paths.length; i++) { if (selection_paths[i].equals(right_click_path)) { clicked_in_selection = true; break; } } if (!clicked_in_selection) { // want the tree to update right away collection_tree.setImmediate(true); collection_tree.clearSelection(); collection_tree.setSelectionPath(right_click_path); collection_tree.setImmediate(false); selection_paths = new TreePath[1]; selection_paths[0] = right_click_path; } } } // Create an appropriate context menu, based on what is selected buildContextMenu(selection_paths); // Show the popup menu on screen show(collection_tree, event.getX(), event.getY()); } /** Checks whether the files selected are of the same filetype (have the same extension). * @param selectedFilePaths - the full file paths to the treenodes selected in the * collection fileview. * @return true if the file extensions of all the selected files are the same. False is * returned if the file extension of any selected file is different (this means that if * a folder was selected, false would be returned). False is also returned if nothing was * selected. * For use with replace_srcdoc_with_html.pl */ private boolean selectedFilesOfSameType(TreePath[] selectedFilePaths) { if(selectedFilePaths == null || selectedFilePaths.length <= 0) return false; boolean sameExtension = true; // get just the filename from the path and extract its extension String firstFile = selectedFilePaths[0].getLastPathComponent().toString(); int period = firstFile.lastIndexOf('.'); if(period == -1) { // someone could have selected a folder return false; } String extension = firstFile.substring(period); // includes period // compare with the other selected files' extensions: for(int i = 1; i < selectedFilePaths.length && sameExtension; i++) { String otherFile = selectedFilePaths[i].getLastPathComponent().toString(); String otherFileExt = otherFile.substring(otherFile.lastIndexOf('.')); if(!extension.equals(otherFileExt)) sameExtension = false; } return sameExtension; } private void buildContextMenu(TreePath[] selection_paths) { // If nothing is selected, only the new folder/dummy doc options are available... if (selection_paths == null) { new_folder = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Folder"), KeyEvent.VK_N); new_folder.addActionListener(this); add(new_folder); new_dummy_doc = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Dummy_Doc")); new_dummy_doc.addActionListener(this); add(new_dummy_doc); refresh = new JMenuItem(Dictionary.get("CollectionPopupMenu.Refresh")); if(Gatherer.isGsdlRemote) { refresh.setEnabled(false); } refresh.addActionListener(this); add(refresh); node = (CollectionTreeNode) collection_tree.getModel().getRoot(); return; } // Meta-audit and delete options metaaudit = new JMenuItem(Dictionary.get("Menu.Metadata_View", collection_tree.getSelectionDetails()), KeyEvent.VK_A); metaaudit.addActionListener(this); add(metaaudit); delete = new JMenuItem(Dictionary.get("CollectionPopupMenu.Delete"), KeyEvent.VK_D); delete.addActionListener(this); add(delete); // The src doc replaceable (with html file) option is only available when all files selected are of the // same type (same extension). For srcreplaceable files only. Works with replace_srcdoc_with_html.pl CollectionTreeNode firstSelectedNode = (CollectionTreeNode)selection_paths[0].getLastPathComponent(); if(firstSelectedNode.isSrcReplaceable()) { // test the first selected node replace_srcdoc_with_html = new JMenuItem(Dictionary.get("Menu.Replace_SrcDoc_With_HTML"), KeyEvent.VK_H); replace_srcdoc_with_html.addActionListener(this); add(replace_srcdoc_with_html); // Now the menu is there, grey it out if not all the files are of the same type if(!selectedFilesOfSameType(selection_paths)) { replace_srcdoc_with_html.setEnabled(false); } } // Only meta-audit and delete (and possibly replace_srcdoc) are available if multiple items are selected... if (selection_paths.length > 1) { return; } // Rename option rename = new JMenuItem(Dictionary.get("CollectionPopupMenu.Rename"), KeyEvent.VK_R); rename.addActionListener(this); add(rename); TreePath path = selection_paths[0]; node = (CollectionTreeNode) path.getLastPathComponent(); // ---- Options for file nodes ---- if (node.isLeaf()) { // Explode metadata databases, for explodable files only if (node.isExplodable()) { explode_metadata_database = new JMenuItem(Dictionary.get("Menu.Explode_Metadata_Database"), KeyEvent.VK_E); explode_metadata_database.addActionListener(this); add(explode_metadata_database); } // Replace file replace = new JMenuItem(Dictionary.get("CollectionPopupMenu.Replace"), KeyEvent.VK_P); replace.addActionListener(this); add(replace); // Open the file in an external program open_externally = new JMenuItem(Dictionary.get("Menu.Open_Externally"), KeyEvent.VK_O); open_externally.addActionListener(this); add(open_externally); return; } // ---- Options for folder nodes ---- // Collapse or expand, depending on current status if (collection_tree.isExpanded(path)) { collapse_folder = new JMenuItem(Dictionary.get("Menu.Collapse"), KeyEvent.VK_C); collapse_folder.addActionListener(this); add(collapse_folder); } else { expand_folder = new JMenuItem(Dictionary.get("Menu.Expand"), KeyEvent.VK_O); expand_folder.addActionListener(this); add(expand_folder); } // New folder/dummy doc options if (!node.isReadOnly()) { new_folder = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Folder"), KeyEvent.VK_N); new_folder.addActionListener(this); add(new_folder); new_dummy_doc = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Dummy_Doc")); new_dummy_doc.addActionListener(this); add(new_dummy_doc); } } /** Called whenever one of the menu items is clicked, this method then causes the appropriate effect. */ public void actionPerformed(ActionEvent event) { Object source = event.getSource(); // Collapse folder if (source == collapse_folder) { collection_tree.collapsePath(selection_paths[0]); } // Expand folder else if (source == expand_folder) { collection_tree.expandPath(selection_paths[0]); } // Explode metadata database else if (source == explode_metadata_database) { Gatherer.f_man.explodeMetadataDatabase(node.getFile()); } // Replace source document with generated html (works with replace_srcdoc_with_html.pl) else if (source == replace_srcdoc_with_html) { java.io.File[] source_files = new java.io.File[selection_paths.length]; for (int i = 0; i < selection_paths.length; i++) { CollectionTreeNode node = (CollectionTreeNode) selection_paths[i].getLastPathComponent(); source_files[i] = node.getFile(); } Gatherer.f_man.replaceSrcDocWithHtml(source_files); // passing the selected files } // Delete else if (source == delete) { CollectionTreeNode[] source_nodes = new CollectionTreeNode[selection_paths.length]; for (int i = 0; i < selection_paths.length; i++) { source_nodes[i] = (CollectionTreeNode) selection_paths[i].getLastPathComponent(); } // Fire a delete action Gatherer.f_man.action(collection_tree, source_nodes, Gatherer.recycle_bin, null); } // Meta-audit else if (source == metaaudit) { Gatherer.g_man.showMetaAuditBox(); } // New folder else if (source == new_folder) { Gatherer.f_man.newFolder(collection_tree, node); } // New dummy doc else if (source == new_dummy_doc) { Gatherer.f_man.newDummyDoc(collection_tree, node); } // Refresh action to reload folder view else if (source == refresh) { // Refresh collection tree Gatherer.g_man.refreshCollectionTree(DragTree.COLLECTION_CONTENTS_CHANGED); } // Open in external program else if (source == open_externally) { Gatherer.f_man.openFileInExternalApplication(node.getFile()); } // Rename else if (source == rename) { Gatherer.f_man.renameCollectionFile(collection_tree, node); } // Replace else if (source == replace) { Gatherer.f_man.replaceCollectionFile(collection_tree, node); } } } }