/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * BrowserTreeActions.java * Creation date: Apr 14, 2003. * By: Edward Lam */ package org.openquark.gems.client.browser; import java.awt.Color; import java.awt.Container; import java.awt.Cursor; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.ImageIcon; import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JToggleButton; import javax.swing.JToolBar; import javax.swing.tree.TreePath; import org.openquark.cal.compiler.ModuleName; import org.openquark.cal.services.GemEntity; import org.openquark.cal.services.MetaModule; import org.openquark.gems.client.GemCutter; import org.openquark.gems.client.ModuleNameDisplayUtilities.TreeViewDisplayMode; import org.openquark.gems.client.navigator.NavAddress; import org.openquark.util.ui.UIUtilities; /** * A helper class to provide some default actions for a browser tree. * @author Edward Lam */ public class BrowserTreeActions { /** The browser tree with which this popup menu is associated. */ private final BrowserTree browserTree; /** * The action for displaying unimported gems. This action is only * created once since it is used to synchronized state between * the menu item and corresponding toggle button. */ private Action displayUnimportedGemsAction = null; /** * The action for displaying type expressions in the browser. * Only created once since it is shared between the menu item * and corresponding toggle button. */ private Action displayTypeExprAction = null; /** * The action for displaying only public gems in the browser. * Only created once since it is shared between the menu item and * corresponding toggle button. * */ private Action displayPublicGemsOnlyAction = null; /** The button to sort the root node alphabetically. */ private JToggleButton sortAZButton = null; /** The button to sort the root node by gem type. */ private JToggleButton sortGemTypeButton = null; /** The button to categorize the root node by module (flat abbreviated view). */ private JToggleButton catByModuleFlatAbbreviatedButton = null; /** The button to categorize the root node by module (flat fully qualified view). */ private JToggleButton catByModuleFlatFullyQualifiedButton = null; /** The button to categorize the root node by module (hierarchical view). */ private JToggleButton catByModuleHierarchicalButton = null; /** The button to categorize the root node by arity. */ private JToggleButton catByArityButton = null; /** The button to categorize the root node by gem type. */ private JToggleButton catByGemTypeButton = null; /** The button to categorize the root node by input type. */ private JToggleButton catByInputTypeButton = null; /** The button to categorize the root node by output type. */ private JToggleButton catByOutputTypeButton = null; /** The button for displaying unimported gems. */ private JToggleButton displayUnimportedGemsButton = null; /** The button for displaying type expr. */ private JToggleButton displayTypeExprButton = null; /** The button for displaying public gems only */ private JToggleButton displayPublicGemsButton = null; /** The button group for the mutually exclusive sort/categorization toggle buttons. */ private final ButtonGroup buttonGroup = new ButtonGroup(); /** The button panel with the buttons to modify the browser tree. */ private JPanel buttonPanel = null; private static final ImageIcon sortAZIcon; private static final ImageIcon sortConstructorsFunctionsIcon; private static final ImageIcon catByModuleFlatAbbrevIcon; private static final ImageIcon catByModuleFlatIcon; private static final ImageIcon catByModuleHierarchicalIcon; private static final ImageIcon catByArityIcon; private static final ImageIcon catByGemTypeIcon; private static final ImageIcon catByInputTypeIcon; private static final ImageIcon catByOutputTypeIcon; private static final ImageIcon showUnimportedGemsIcon; private static final ImageIcon showTypeExprIcon; private static final ImageIcon showPublicGemsIcon; static { sortAZIcon = new ImageIcon(BrowserTreeActions.class.getResource("/Resources/sortAZ.gif")); sortConstructorsFunctionsIcon = new ImageIcon(BrowserTreeActions.class.getResource("/Resources/sortConstructorsFunctions.gif")); catByModuleFlatAbbrevIcon = new ImageIcon(BrowserTreeActions.class.getResource("/Resources/nav_flatAbbrev.gif")); catByModuleFlatIcon = new ImageIcon(BrowserTreeActions.class.getResource("/Resources/nav_flat.gif")); catByModuleHierarchicalIcon = new ImageIcon(BrowserTreeActions.class.getResource("/Resources/nav_hierarchical.gif")); catByArityIcon = new ImageIcon(BrowserTreeActions.class.getResource("/Resources/catByArity.gif")); catByGemTypeIcon = new ImageIcon(BrowserTreeActions.class.getResource("/Resources/catByGemType.gif")); catByInputTypeIcon = new ImageIcon(BrowserTreeActions.class.getResource("/Resources/catByInputType.gif")); catByOutputTypeIcon = new ImageIcon(BrowserTreeActions.class.getResource("/Resources/catByOutputType.gif")); showUnimportedGemsIcon = new ImageIcon(GemBrowser.class.getResource("/Resources/showUnimportedGems.gif")); showTypeExprIcon = new ImageIcon(GemBrowser.class.getResource("/Resources/showTypeExpressions.gif")); showPublicGemsIcon = new ImageIcon(GemBrowser.class.getResource("/Resources/showPublicGemsOnly.gif")); } /** * A simple class that enables a single method to be invoked on the browser tree. * @author Edward Lam */ private static abstract class ActionHolder { /** * Perform the action */ abstract void doAction(); } /** * Constructor for a BrowserTreeActions object */ BrowserTreeActions(BrowserTree browserTree) { this.browserTree = browserTree; } /** * @return the JPanel with the buttons to modify the browser tree. */ public JPanel getBrowserTreeButtonPanel() { if (buttonPanel == null) { buttonPanel = new JPanel(); buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); JToolBar toolBar = new JToolBar(); toolBar.setFloatable(false); toolBar.setRollover(true); buttonPanel.add(Box.createHorizontalGlue()); buttonPanel.add(toolBar); buttonPanel.add(Box.createHorizontalGlue()); toolBar.add(getSortAlphabeticallyButton()); toolBar.add(getSortByFormButton()); toolBar.add(getCategorizeByModuleFlatAbbreviatedButton()); toolBar.add(getCategorizeByModuleFlatFullyQualifiedButton()); toolBar.add(getCategorizeByModuleHierarchicalButton()); toolBar.add(getCategorizeByArityButton()); toolBar.add(getCategorizeByGemTypeButton()); toolBar.add(getCategorizeByInputTypeButton()); toolBar.add(getCategorizeByOutputTypeButton()); toolBar.addSeparator(); toolBar.add(getDisplayTypeExprButton()); toolBar.add(getDisplayUnimportedGemsButton()); toolBar.add(getDisplayPublicGemsButton()); } return buttonPanel; } /** * Return a new default popup for the browser tree * The popup will contain applicable actions in this object, appropriately activated. * @param selectionPath the selection path on which the popup was invoked. * @return JPopupMenu the default popup menu for the browser tree. */ public JPopupMenu getDefaultBrowserTreePopup(TreePath selectionPath) { JPopupMenu popupMenu = new JPopupMenu(); BrowserTreeNode selectedNode = (selectionPath == null) ? null : (BrowserTreeNode)selectionPath.getLastPathComponent(); addDefaultMenuItems(popupMenu, selectedNode); return popupMenu; } /** * Add supported built-in popup menu items for actions in this object. * Menu items with icons will have their icons left-justified to the menu border. * @param targetMenu the popup menu to which to add the items. * @param selectedNode the node for which the items should be added (if any) */ public void addDefaultMenuItems(JPopupMenu targetMenu, BrowserTreeNode selectedNode) { // We should not be showing menu items for namespace nodes, // which do not really correspond to actual modes final boolean shouldAddItems; if (selectedNode instanceof GemDrawer) { shouldAddItems = !((GemDrawer)selectedNode).isNamespaceNode(); } else { shouldAddItems = true; } if (shouldAddItems) { addSortCategorizeMenuItems(targetMenu, selectedNode); targetMenu.addSeparator(); addDisplayMenuItems(targetMenu); // Can only view/edit metadata if a navigator owner is setup. if (browserTree.getNavigatorOwner() != null) { targetMenu.addSeparator(); addMetadataEditMenuItems(targetMenu, selectedNode); } } } /** * Add the built-in popup menu items for changing the gem browser display settings. * @param targetMenu the popup menu to which to add the items. */ public void addDisplayMenuItems(JPopupMenu targetMenu) { // Add menu item for displaying unimported gems JCheckBoxMenuItem displayGems = new JCheckBoxMenuItem(); displayGems.setAction(getDisplayUnimportedGemsAction()); displayGems.setToolTipText(null); displayGems.setIcon(null); displayGems.setSelected(((BrowserTreeModel) browserTree.getModel()).getShowAllModules()); targetMenu.add(displayGems); // Add a menu item for displaying type expressions JCheckBoxMenuItem displayTypeExpr = new JCheckBoxMenuItem(); displayTypeExpr.setAction(getDisplayTypeExprAction()); displayTypeExpr.setToolTipText(null); displayTypeExpr.setIcon(null); displayTypeExpr.setSelected(browserTree.getDisplayTypeExpr()); targetMenu.add(displayTypeExpr); // Add a menu item for displaying public gems only JCheckBoxMenuItem publicGemsOnly = new JCheckBoxMenuItem(); publicGemsOnly.setAction(getDisplayPublicGemsAction()); publicGemsOnly.setToolTipText(null); publicGemsOnly.setIcon(null); publicGemsOnly.setSelected(((BrowserTreeModel) browserTree.getModel()).getShowPublicGemsOnly()); targetMenu.add(publicGemsOnly); } /** * Add the built-in popup menu items for sorting and categorization. * @param targetMenu the popup menu to which to add the items. * @param selectedNode the node for which the items should be added (if any) */ public void addSortCategorizeMenuItems(JPopupMenu targetMenu, BrowserTreeNode selectedNode) { targetMenu.add(UIUtilities.makeNewMenuItem(getSortAlphabeticallyAction(selectedNode))); targetMenu.add(UIUtilities.makeNewMenuItem(getSortByFormAction(selectedNode))); targetMenu.addSeparator(); targetMenu.add(UIUtilities.makeNewMenuItem(getCategorizeByModuleFlatAbbreviatedAction(selectedNode))); targetMenu.add(UIUtilities.makeNewMenuItem(getCategorizeByModuleFlatFullyQualifiedAction(selectedNode))); targetMenu.add(UIUtilities.makeNewMenuItem(getCategorizeByModuleHierarchicalAction(selectedNode))); targetMenu.add(UIUtilities.makeNewMenuItem(getCategorizeByArityAction(selectedNode))); targetMenu.add(UIUtilities.makeNewMenuItem(getCategorizeByGemTypeAction(selectedNode))); targetMenu.add(UIUtilities.makeNewMenuItem(getCategorizeByInputTypeAction(selectedNode))); targetMenu.add(UIUtilities.makeNewMenuItem(getCategorizeByOutputTypeAction(selectedNode))); } /** * Add menu items for metadata viewing and editing. * @param targetMenu the popup menu to which to add the items. * @param selectedNode the node for which the items should be added (if any) */ public void addMetadataEditMenuItems(JPopupMenu targetMenu, BrowserTreeNode selectedNode) { targetMenu.add(UIUtilities.makeNewMenuItem(getEditMetadataAction(selectedNode))); targetMenu.add(UIUtilities.makeNewMenuItem(getViewMetadataAction(selectedNode))); } /** * @return the button to sort the root node alphabetically */ JToggleButton getSortAlphabeticallyButton() { if (sortAZButton == null) { BrowserTreeNode rootNode = ((BrowserTreeModel) browserTree.getModel()).getWorkspaceNode(); sortAZButton = makeNewButton(getSortAlphabeticallyAction(rootNode), buttonGroup); } return sortAZButton; } /** * @return the button to sort the root node by gem type */ JToggleButton getSortByFormButton() { if (sortGemTypeButton == null) { BrowserTreeNode rootNode = ((BrowserTreeModel) browserTree.getModel()).getWorkspaceNode(); sortGemTypeButton = makeNewButton(getSortByFormAction(rootNode), buttonGroup); } return sortGemTypeButton; } /** * @return the button to categorize the root node by module (flat abbreviated view) */ JToggleButton getCategorizeByModuleFlatAbbreviatedButton() { if (catByModuleFlatAbbreviatedButton == null) { BrowserTreeNode rootNode = ((BrowserTreeModel) browserTree.getModel()).getWorkspaceNode(); catByModuleFlatAbbreviatedButton = makeNewButton(getCategorizeByModuleFlatAbbreviatedAction(rootNode), buttonGroup); } return catByModuleFlatAbbreviatedButton; } /** * @return the button to categorize the root node by module (flat fully qualified view) */ JToggleButton getCategorizeByModuleFlatFullyQualifiedButton() { if (catByModuleFlatFullyQualifiedButton == null) { BrowserTreeNode rootNode = ((BrowserTreeModel) browserTree.getModel()).getWorkspaceNode(); catByModuleFlatFullyQualifiedButton = makeNewButton(getCategorizeByModuleFlatFullyQualifiedAction(rootNode), buttonGroup); } return catByModuleFlatFullyQualifiedButton; } /** * @return the button to categorize the root node by module (flat hierarchical view) */ JToggleButton getCategorizeByModuleHierarchicalButton() { if (catByModuleHierarchicalButton == null) { BrowserTreeNode rootNode = ((BrowserTreeModel) browserTree.getModel()).getWorkspaceNode(); catByModuleHierarchicalButton = makeNewButton(getCategorizeByModuleHierarchicalAction(rootNode), buttonGroup); } return catByModuleHierarchicalButton; } /** * @return the button to categorize the root node by arity */ JToggleButton getCategorizeByArityButton() { if (catByArityButton == null) { BrowserTreeNode rootNode = ((BrowserTreeModel) browserTree.getModel()).getWorkspaceNode(); catByArityButton = makeNewButton(getCategorizeByArityAction(rootNode), buttonGroup); } return catByArityButton; } /** * @return the button to categorize the root node by gem type */ JToggleButton getCategorizeByGemTypeButton() { if (catByGemTypeButton == null) { BrowserTreeNode rootNode = ((BrowserTreeModel) browserTree.getModel()).getWorkspaceNode(); catByGemTypeButton = makeNewButton(getCategorizeByGemTypeAction(rootNode), buttonGroup); } return catByGemTypeButton; } /** * @return the button to categorize the root node by input type */ JToggleButton getCategorizeByInputTypeButton() { if (catByInputTypeButton == null) { BrowserTreeNode rootNode = ((BrowserTreeModel) browserTree.getModel()).getWorkspaceNode(); catByInputTypeButton = makeNewButton(getCategorizeByInputTypeAction(rootNode), buttonGroup); } return catByInputTypeButton; } /** * @return the button to categorize the root node by output type */ JToggleButton getCategorizeByOutputTypeButton() { if (catByOutputTypeButton == null) { BrowserTreeNode rootNode = ((BrowserTreeModel) browserTree.getModel()).getWorkspaceNode(); catByOutputTypeButton = makeNewButton(getCategorizeByOutputTypeAction(rootNode), buttonGroup); } return catByOutputTypeButton; } /** * Returns the toggle button for displaying unimported gems in the gem browser. * @return JToggleButton */ JToggleButton getDisplayUnimportedGemsButton () { if (displayUnimportedGemsButton == null) { displayUnimportedGemsButton = makeNewButton(getDisplayUnimportedGemsAction(), null); // Add a property change listener to this action so we can change the state of // the button if the corresponding menu item invokes this action. getDisplayUnimportedGemsAction().addPropertyChangeListener(new PropertyChangeListener () { public void propertyChange(PropertyChangeEvent e) { if (e.getPropertyName().equals(GemBrowserActionKeys.ACTION_SELECTED_KEY)) { boolean showingGems = ((Boolean) e.getNewValue()).booleanValue(); String toolTipId = showingGems ? "GB_DisplayingUnimportedGemsToolTip" : "GB_HidingUnimportedGemsToolTip"; displayUnimportedGemsButton.getModel().setSelected(showingGems); displayUnimportedGemsButton.setToolTipText(BrowserMessages.getString(toolTipId)); } } }); } return displayUnimportedGemsButton; } /** * Returns the toggle button for displaying unimported gems in the gem browser. * @return JToggleButton */ JToggleButton getDisplayTypeExprButton () { if (displayTypeExprButton == null) { displayTypeExprButton = makeNewButton(getDisplayTypeExprAction(), null); // Add a property change listener to this action so we can change the state of // the button if the corresponding menu item invokes this action. getDisplayTypeExprAction().addPropertyChangeListener(new PropertyChangeListener () { public void propertyChange(PropertyChangeEvent e) { if (e.getPropertyName().equals(GemBrowserActionKeys.ACTION_SELECTED_KEY)) { boolean showingTypeExpr = ((Boolean) e.getNewValue()).booleanValue(); String toolTipId = showingTypeExpr ? "GB_DisplayingTypeExprToolTip" : "GB_HidingTypeExprToolTip"; displayTypeExprButton.getModel().setSelected(showingTypeExpr); displayTypeExprButton.setToolTipText(BrowserMessages.getString(toolTipId)); } } }); } return displayTypeExprButton; } /** * Returns the toggle button for displaying only the public gems in the gem browser. * @return JToggleButton */ JToggleButton getDisplayPublicGemsButton() { if (displayPublicGemsButton == null){ displayPublicGemsButton = makeNewButton(getDisplayPublicGemsAction(),null); //Add a property change listener getDisplayPublicGemsAction().addPropertyChangeListener ( new PropertyChangeListener () { public void propertyChange(PropertyChangeEvent e) { if (e.getPropertyName().equals(GemBrowserActionKeys.ACTION_SELECTED_KEY)) { boolean showingPublicGems = ((Boolean) e.getNewValue()).booleanValue(); String toolTipId = showingPublicGems ? "GB_DisplayingPublicGemsOnlyToolTip" : "GB_DisplayingAllGemsToolTip"; displayPublicGemsButton.getModel().setSelected(showingPublicGems); displayPublicGemsButton.setToolTipText(BrowserMessages.getString(toolTipId)); } } }); } return displayPublicGemsButton; } /** * Return a new action that handles sorting alphabetically * @param selectedNode the node on which to invoke the action. * @return Action */ Action getSortAlphabeticallyAction(final BrowserTreeNode selectedNode) { Action sortAlphabeticallyAction = new AbstractAction (BrowserMessages.getString("GB_SortAlpha"), sortAZIcon) { private static final long serialVersionUID = -4510477496332052077L; public void actionPerformed(ActionEvent evt) { doBrowserAction(new ActionHolder() { @Override void doAction(){ BrowserTreeModel browserTreeModel = (BrowserTreeModel)browserTree.getModel(); browserTreeModel.sortByUnqualifiedName(selectedNode); if (selectedNode == browserTreeModel.getWorkspaceNode()) { updateButtonGroup(sortAZButton); } } }, evt.getSource()); } }; sortAlphabeticallyAction.putValue(Action.MNEMONIC_KEY, Integer.valueOf(GemBrowserActionKeys.MNEMONIC_SORT_ALPHABETICALLY)); sortAlphabeticallyAction.putValue(Action.SHORT_DESCRIPTION, BrowserMessages.getString("GB_SortAlphaToolTip")); enableSortCategorizeAction(selectedNode, sortAlphabeticallyAction); return sortAlphabeticallyAction; } /** * Return a new action that handles sorting by form (gem "type"..). * What is meant by 'Sort by Gem Type' is that the Gems will be sorted * into two sets, the Data Constructor set, and the Supercombinator set. * @param selectedNode the node on which to invoke the action. * @return Action */ Action getSortByFormAction(final BrowserTreeNode selectedNode) { Action sortByFormAction = new AbstractAction (BrowserMessages.getString("GB_SortConstructorsThenFunctions"), sortConstructorsFunctionsIcon) { private static final long serialVersionUID = 7730729244475313080L; public void actionPerformed(ActionEvent evt) { doBrowserAction(new ActionHolder() { @Override void doAction() { BrowserTreeModel browserModel = (BrowserTreeModel)browserTree.getModel(); browserModel.sortByForm(selectedNode); if (selectedNode == browserModel.getWorkspaceNode()) { updateButtonGroup(sortGemTypeButton); } } }, evt.getSource()); } }; sortByFormAction.putValue(Action.MNEMONIC_KEY, Integer.valueOf(GemBrowserActionKeys.MNEMONIC_SORT_BY_FORM)); sortByFormAction.putValue(Action.SHORT_DESCRIPTION, BrowserMessages.getString("GB_SortConstructorsThenFunctionsToolTip")); enableSortCategorizeAction(selectedNode, sortByFormAction); return sortByFormAction; } /** * Return a new action that handles categorization by modules (flat abbreviated view). * @param selectedNode the node on which to invoke the action. * @return Action */ Action getCategorizeByModuleFlatAbbreviatedAction(final BrowserTreeNode selectedNode) { Action categorizeByModuleAction = new AbstractAction (BrowserMessages.getString("GB_CatByModuleFlatAbbrev"), catByModuleFlatAbbrevIcon) { private static final long serialVersionUID = -4160939901530872712L; public void actionPerformed(ActionEvent evt) { doBrowserAction(new ActionHolder() { @Override void doAction() { BrowserTreeModel browserTreeModel = (BrowserTreeModel)browserTree.getModel(); browserTreeModel.categorizeByModule(selectedNode, TreeViewDisplayMode.FLAT_ABBREVIATED); if (selectedNode == browserTreeModel.getWorkspaceNode()) { updateButtonGroup(catByModuleFlatAbbreviatedButton); GemBrowser.setPreferredModuleTreeDisplayMode(TreeViewDisplayMode.FLAT_ABBREVIATED); } } }, evt.getSource()); } }; categorizeByModuleAction.putValue(Action.MNEMONIC_KEY, Integer.valueOf(GemBrowserActionKeys.MNEMONIC_CATEGORIZE_BY_MODULE_FLAT_ABBREV)); categorizeByModuleAction.putValue(Action.SHORT_DESCRIPTION, BrowserMessages.getString("GB_CatByModuleFlatAbbrevToolTip")); enableSortCategorizeAction(selectedNode, categorizeByModuleAction); return categorizeByModuleAction; } /** * Return a new action that handles categorization by modules (flat fully qualified view). * @param selectedNode the node on which to invoke the action. * @return Action */ Action getCategorizeByModuleFlatFullyQualifiedAction(final BrowserTreeNode selectedNode) { Action categorizeByModuleAction = new AbstractAction (BrowserMessages.getString("GB_CatByModuleFlat"), catByModuleFlatIcon) { private static final long serialVersionUID = 2855158975387678224L; public void actionPerformed(ActionEvent evt) { doBrowserAction(new ActionHolder() { @Override void doAction() { BrowserTreeModel browserTreeModel = (BrowserTreeModel)browserTree.getModel(); browserTreeModel.categorizeByModule(selectedNode, TreeViewDisplayMode.FLAT_FULLY_QUALIFIED); if (selectedNode == browserTreeModel.getWorkspaceNode()) { updateButtonGroup(catByModuleFlatFullyQualifiedButton); GemBrowser.setPreferredModuleTreeDisplayMode(TreeViewDisplayMode.FLAT_FULLY_QUALIFIED); } } }, evt.getSource()); } }; categorizeByModuleAction.putValue(Action.MNEMONIC_KEY, Integer.valueOf(GemBrowserActionKeys.MNEMONIC_CATEGORIZE_BY_MODULE_FLAT)); categorizeByModuleAction.putValue(Action.SHORT_DESCRIPTION, BrowserMessages.getString("GB_CatByModuleFlatToolTip")); enableSortCategorizeAction(selectedNode, categorizeByModuleAction); return categorizeByModuleAction; } /** * Return a new action that handles categorization by modules (hierarchical view). * @param selectedNode the node on which to invoke the action. * @return Action */ Action getCategorizeByModuleHierarchicalAction(final BrowserTreeNode selectedNode) { Action categorizeByModuleAction = new AbstractAction (BrowserMessages.getString("GB_CatByModuleHierarchical"), catByModuleHierarchicalIcon) { private static final long serialVersionUID = 3999294713899147893L; public void actionPerformed(ActionEvent evt) { doBrowserAction(new ActionHolder() { @Override void doAction() { BrowserTreeModel browserTreeModel = (BrowserTreeModel)browserTree.getModel(); browserTreeModel.categorizeByModule(selectedNode, TreeViewDisplayMode.HIERARCHICAL); if (selectedNode == browserTreeModel.getWorkspaceNode()) { updateButtonGroup(catByModuleHierarchicalButton); GemBrowser.setPreferredModuleTreeDisplayMode(TreeViewDisplayMode.HIERARCHICAL); } } }, evt.getSource()); } }; categorizeByModuleAction.putValue(Action.MNEMONIC_KEY, Integer.valueOf(GemBrowserActionKeys.MNEMONIC_CATEGORIZE_BY_MODULE_HIERARCHCICAL)); categorizeByModuleAction.putValue(Action.SHORT_DESCRIPTION, BrowserMessages.getString("GB_CatByModuleHierarchicalToolTip")); enableSortCategorizeAction(selectedNode, categorizeByModuleAction); return categorizeByModuleAction; } /** * Return a new action that handles categorizing by gem type. * @param selectedNode the node on which to invoke the action. * @return Action */ Action getCategorizeByGemTypeAction(final BrowserTreeNode selectedNode) { Action categorizeByTypeAction = new AbstractAction (BrowserMessages.getString("GB_CatByGemType"), catByGemTypeIcon) { private static final long serialVersionUID = 4989845787502335699L; public void actionPerformed(ActionEvent evt) { doBrowserAction(new ActionHolder() { @Override void doAction() { BrowserTreeModel browserTreeModel = (BrowserTreeModel)browserTree.getModel(); browserTreeModel.categorizeByGemType(selectedNode); if (selectedNode == browserTreeModel.getWorkspaceNode()) { updateButtonGroup(catByGemTypeButton); } } }, evt.getSource()); } }; categorizeByTypeAction.putValue(Action.MNEMONIC_KEY, Integer.valueOf(GemBrowserActionKeys.MNEMONIC_CATEGORIZE_BY_TYPE)); categorizeByTypeAction.putValue(Action.SHORT_DESCRIPTION, BrowserMessages.getString("GB_CatByGemTypeToolTip")); enableSortCategorizeAction(selectedNode, categorizeByTypeAction); return categorizeByTypeAction; } /** * Return a new action that handles categorizing by arity * @param selectedNode the node on which to invoke the action. * @return Action */ Action getCategorizeByArityAction(final BrowserTreeNode selectedNode) { Action categorizeByArityAction = new AbstractAction (BrowserMessages.getString("GB_CatByArity"), catByArityIcon) { private static final long serialVersionUID = 933194855360216607L; public void actionPerformed(ActionEvent evt) { doBrowserAction(new ActionHolder() { @Override void doAction() { BrowserTreeModel browserTreeModel = (BrowserTreeModel)browserTree.getModel(); browserTreeModel.categorizeByArity(selectedNode); if (selectedNode == browserTreeModel.getWorkspaceNode()) { updateButtonGroup(catByArityButton); } } }, evt.getSource()); } }; categorizeByArityAction.putValue(Action.MNEMONIC_KEY, Integer.valueOf(GemBrowserActionKeys.MNEMONIC_CATEGORIZE_BY_ARITY)); categorizeByArityAction.putValue(Action.SHORT_DESCRIPTION, BrowserMessages.getString("GB_CatByArityToolTip")); enableSortCategorizeAction(selectedNode, categorizeByArityAction); return categorizeByArityAction; } /** * Return a new action that handles categorizing by output type * @param selectedNode the node on which to invoke the action. * @return Action */ Action getCategorizeByOutputTypeAction(final BrowserTreeNode selectedNode) { Action categorizeByOutputAction = new AbstractAction (BrowserMessages.getString("GB_CatByOutputType"), catByOutputTypeIcon) { private static final long serialVersionUID = 148408557706639845L; public void actionPerformed(ActionEvent evt) { doBrowserAction(new ActionHolder() { @Override void doAction() { BrowserTreeModel browserTreeModel = (BrowserTreeModel)browserTree.getModel(); browserTreeModel.categorizeByOutput(selectedNode); if (selectedNode == browserTreeModel.getWorkspaceNode()) { updateButtonGroup(catByOutputTypeButton); } } }, evt.getSource()); } }; categorizeByOutputAction.putValue(Action.MNEMONIC_KEY, Integer.valueOf(GemBrowserActionKeys.MNEMONIC_CATEGORIZE_BY_OUTPUT)); categorizeByOutputAction.putValue(Action.SHORT_DESCRIPTION, BrowserMessages.getString("GB_CatByOutputTypeToolTip")); enableSortCategorizeAction(selectedNode, categorizeByOutputAction); return categorizeByOutputAction; } /** * Return a new action that handles categorizing by output type * @param selectedNode the node on which to invoke the action. * @return Action */ Action getCategorizeByInputTypeAction(final BrowserTreeNode selectedNode) { Action categorizeByInputAction = new AbstractAction (BrowserMessages.getString("GB_CatByInputType"), catByInputTypeIcon) { private static final long serialVersionUID = 6989782310657432696L; public void actionPerformed(ActionEvent evt) { doBrowserAction(new ActionHolder() { @Override void doAction() { BrowserTreeModel browserTreeModel = (BrowserTreeModel)browserTree.getModel(); browserTreeModel.categorizeByInput(selectedNode); if (selectedNode == browserTreeModel.getWorkspaceNode()) { updateButtonGroup(catByInputTypeButton); } } }, evt.getSource()); } }; categorizeByInputAction.putValue(Action.MNEMONIC_KEY, Integer.valueOf(GemBrowserActionKeys.MNEMONIC_CATEGORIZE_BY_INPUT)); categorizeByInputAction.putValue(Action.SHORT_DESCRIPTION, BrowserMessages.getString("GB_CatByInputTypeToolTip")); enableSortCategorizeAction(selectedNode, categorizeByInputAction); return categorizeByInputAction; } /** * Return a new action that handles editing metadata for a gem * @param selectedNode the node on which to invoke the action. * @return Action */ Action getEditMetadataAction(final BrowserTreeNode selectedNode) { Action editMetadataAction = new AbstractAction (BrowserMessages.getString("GB_EditGemProperties"), new ImageIcon(GemCutter.class.getResource("/Resources/nav_edit.gif"))) { private static final long serialVersionUID = -7408780266351267761L; public void actionPerformed(ActionEvent evt) { doBrowserAction(new ActionHolder() { @Override void doAction() { final NavAddress address; if (selectedNode instanceof GemTreeNode) { GemEntity gemEntity = (GemEntity) selectedNode.getUserObject(); address = NavAddress.getAddress(gemEntity); browserTree.getNavigatorOwner().editMetadata(address); } else if (selectedNode instanceof GemDrawer) { final GemDrawer gemDrawer = (GemDrawer) selectedNode; final ModuleName moduleName = gemDrawer.getModuleName(); if (gemDrawer.isNamespaceNode()) { address = NavAddress.getModuleNamespaceAddress(moduleName); } else { MetaModule metaModule = browserTree.getNavigatorOwner().getPerspective().getMetaModule(moduleName); address = NavAddress.getAddress(metaModule); } browserTree.getNavigatorOwner().editMetadata(address); } } }, evt.getSource()); } }; editMetadataAction.putValue(Action.MNEMONIC_KEY, Integer.valueOf(GemBrowserActionKeys.MNEMONIC_EDIT_METADATA)); editMetadataAction.putValue(Action.SHORT_DESCRIPTION, BrowserMessages.getString("GB_EditGemPropertiesToolTip")); enableMetadataAction(selectedNode, editMetadataAction); return editMetadataAction; } /** * Return a new action that handles viewing metadata for a gem * @param selectedNode the node on which to invoke the action. * @return Action */ Action getViewMetadataAction(final BrowserTreeNode selectedNode) { Action viewMetadataAction = new AbstractAction (BrowserMessages.getString("GB_ViewGemProperties")) { private static final long serialVersionUID = 3203818148537546800L; public void actionPerformed(ActionEvent evt) { doBrowserAction(new ActionHolder() { @Override void doAction() { final NavAddress address; if (selectedNode instanceof GemTreeNode) { GemEntity gemEntity = (GemEntity) selectedNode.getUserObject(); address = NavAddress.getAddress(gemEntity); browserTree.getNavigatorOwner().displayMetadata(address, true); } else if (selectedNode instanceof GemDrawer) { final GemDrawer gemDrawer = (GemDrawer) selectedNode; final ModuleName moduleName = gemDrawer.getModuleName(); if (gemDrawer.isNamespaceNode()) { address = NavAddress.getModuleNamespaceAddress(moduleName); } else { MetaModule metaModule = browserTree.getNavigatorOwner().getPerspective().getMetaModule(moduleName); address = NavAddress.getAddress(metaModule); } browserTree.getNavigatorOwner().displayMetadata(address, true); } } }, evt.getSource()); } }; viewMetadataAction.putValue(Action.MNEMONIC_KEY, Integer.valueOf(GemBrowserActionKeys.MNEMONIC_VIEW_METADATA)); viewMetadataAction.putValue(Action.SHORT_DESCRIPTION, BrowserMessages.getString("GB_ViewGemPropertiesToolTip")); enableMetadataAction(selectedNode, viewMetadataAction); return viewMetadataAction; } /** * Return a new action to toggle if hidden modules should be shown in the gem browser. * * @return Action the new displayUnimportedGemsAction. */ Action getDisplayUnimportedGemsAction() { if (displayUnimportedGemsAction == null) { final BrowserTreeModel browserTreeModel = (BrowserTreeModel) browserTree.getModel(); boolean showingGems = ((BrowserTreeModel) browserTree.getModel()).getShowAllModules(); String toolTipId = showingGems ? "GB_DisplayingUnimportedGemsToolTip" : "GB_HidingUnimportedGemsToolTip"; displayUnimportedGemsAction = new AbstractAction (BrowserMessages.getString("GB_DisplayUnimportedGems"), showUnimportedGemsIcon) { private static final long serialVersionUID = 3138132771127291139L; public void actionPerformed(ActionEvent evt) { BrowserTreeModel.invokeOnEventDispatchThread(new Runnable (){ public void run(){ boolean hiddenModulesAreShowing = browserTreeModel.getShowAllModules(); browserTree.saveState(); browserTreeModel.setShowAllModules(!hiddenModulesAreShowing); browserTreeModel.reload(); browserTree.restoreSavedState(); putValue(GemBrowserActionKeys.ACTION_SELECTED_KEY, Boolean.valueOf(!hiddenModulesAreShowing)); } }); } }; displayUnimportedGemsAction.putValue(Action.SHORT_DESCRIPTION, BrowserMessages.getString(toolTipId)); displayUnimportedGemsAction.setEnabled(true); } return displayUnimportedGemsAction; } /** * Returns a new action to toggle if type expressions are shown in the gem browser. * * @return Action the new displayTypeExprAction */ Action getDisplayTypeExprAction() { if (displayTypeExprAction == null) { boolean showingTypeExpr = browserTree.getDisplayTypeExpr(); String toolTipId = showingTypeExpr ? "GB_DisplayingTypeExprToolTip" : "GB_HidingTypeExprToolTip"; displayTypeExprAction = new AbstractAction (BrowserMessages.getString("GB_DisplayTypeExpr"), showTypeExprIcon) { private static final long serialVersionUID = 806950495350707496L; public void actionPerformed(ActionEvent evt) { browserTree.setDisplayTypeExpr(!browserTree.getDisplayTypeExpr()); putValue(GemBrowserActionKeys.ACTION_SELECTED_KEY, Boolean.valueOf(browserTree.getDisplayTypeExpr())); } }; displayTypeExprAction.putValue(Action.SHORT_DESCRIPTION, BrowserMessages.getString(toolTipId)); displayTypeExprAction.setEnabled(true); } return displayTypeExprAction; } /** * Return a new action to toggle if only public gems should be shown in the gem browser * * @return Action the new displayPublicGemsAction. */ Action getDisplayPublicGemsAction(){ if (displayPublicGemsOnlyAction ==null) { final BrowserTreeModel browserTreeModel = (BrowserTreeModel) browserTree.getModel(); boolean showingPublicGems = browserTreeModel.getShowPublicGemsOnly(); String toolTipId = showingPublicGems ? "GB_DisplayingPublicGemsOnlyToolTip" : "GB_DisplayingAllGemsToolTip"; displayPublicGemsOnlyAction = new AbstractAction (BrowserMessages.getString("GB_DisplayPublicGemsOnly"), showPublicGemsIcon) { private static final long serialVersionUID = 8426923208607274866L; public void actionPerformed(ActionEvent evt) { BrowserTreeModel.invokeOnEventDispatchThread(new Runnable (){ public void run(){ boolean onlyPublicGemsAreShowing = browserTreeModel.getShowPublicGemsOnly(); browserTree.saveState(); browserTreeModel.setShowPublicGemsOnly(!onlyPublicGemsAreShowing); browserTreeModel.reload(); browserTree.restoreSavedState(); putValue(GemBrowserActionKeys.ACTION_SELECTED_KEY, Boolean.valueOf(browserTreeModel.getShowPublicGemsOnly())); } }); } }; displayPublicGemsOnlyAction.putValue(Action.SHORT_DESCRIPTION, BrowserMessages.getString(toolTipId)); displayPublicGemsOnlyAction.setEnabled(true); } return displayPublicGemsOnlyAction; } /** * Perform an action invoked from the popup menu. * This method exists to factor out some code used by all the actions. * @param browserActionHolder * @param source the object that originated the event. */ private void doBrowserAction(ActionHolder browserActionHolder, Object source) { // The re-organizing may take awhile, so change cursor to wait. Container parentContainer = browserTree.getTopLevelAncestor(); parentContainer.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); try { browserActionHolder.doAction(); // Determine whether the action was activated by a popup on the browser tree. boolean invokedFromBrowserTreePopup = (source instanceof JMenuItem) && (((JMenuItem)source).getParent() instanceof JPopupMenu) && (((JPopupMenu)((JMenuItem)source).getParent()).getInvoker() == browserTree); BrowserTreeNode selectedNode; if (!invokedFromBrowserTreePopup) { // If the action was not activated from the popup then scroll the workspace node into view. selectedNode = ((BrowserTreeModel) browserTree.getModel()).getWorkspaceNode(); browserTree.scrollPathToTop(new TreePath(selectedNode.getPath())); } else { selectedNode = (BrowserTreeNode) browserTree.getSelectionPath().getLastPathComponent(); } // Expand the node the action was performed on. browserTree.expandPath(new TreePath(selectedNode.getPath())); } finally { // Re-organization done, set cursor back to norm. parentContainer.setCursor(null); } } /** * Creates a new JButton and configures it for use in the button panel. * @param action the action used to configure the JButton * @param buttonGroup the button group the button belongs in (can be null) * @return JButton */ private JToggleButton makeNewButton(Action action, ButtonGroup buttonGroup) { JToggleButton newButton = new JToggleButton(); // Specify some of the customized characteristics here. newButton.setAction(action); newButton.setText(null); newButton.setMargin(new Insets(0, 0, 0, 0)); // Clear the mnemonic so that the buttons are not activated by them. newButton.setMnemonic(KeyEvent.KEY_LOCATION_UNKNOWN); newButton.setBackground(new Color(0,0,0,0)); newButton.setOpaque(false); // Add it to the button group if (buttonGroup != null) { buttonGroup.add(newButton); } return newButton; } /** * Enable or disable a sort/categorize action according to whether it applies to a given node. * @param selectedNode the selected node. * @param targetAction the action to enable / disable. */ private void enableSortCategorizeAction(BrowserTreeNode selectedNode, Action targetAction) { // Enable on category folders. // Assumption is that it will be a category folder if it's a node which isn't a GemTreeNode. boolean enableSortCategorizeAction = (selectedNode != null && !(selectedNode instanceof GemTreeNode)); targetAction.setEnabled(enableSortCategorizeAction); } /** * Enable or disable a metadata action according to whether it applies to a given node. * @param selectedNode the selected node. * @param targetAction the action to enable / disable. */ private void enableMetadataAction(BrowserTreeNode selectedNode, Action targetAction) { // Enable on modules and gems. boolean enableMetadataAction = selectedNode instanceof GemTreeNode || selectedNode instanceof GemDrawer; targetAction.setEnabled(enableMetadataAction); } /** * Updates the browser tree button group to select the given button. * @param selectedButton the button to select */ private void updateButtonGroup(JToggleButton selectedButton) { buttonGroup.setSelected(selectedButton.getModel(), true); } }