/*
* 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.
*/
/*
* ArgumentExplorer.java
* Creation date: May 26, 2004.
* By: Edward Lam
*/
package org.openquark.gems.client;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import org.openquark.gems.client.Gem.PartInput;
import org.openquark.gems.client.valueentry.ValueEditor;
/**
* This explorer presents a tree-based interface for viewing and manipulating the collector arguments.
* Note that this is primarily a UI class. The actual manipulation of the arguments is delegated to the ArgumentExplorerOwner.
* @author Edward Lam
*/
public class ArgumentExplorer extends JComponent {
private static final long serialVersionUID = -2718309462263262697L;
// Icons for the toolbar.
private static final ImageIcon showAllArgumentsIcon = new ImageIcon(ArgumentExplorer.class.getResource("/Resources/showAllArguments.gif"));
/** Constant to use when accessing/setting the selected state for an action. */
private static final String ACTION_SELECTED_KEY = "SelectedState";
/** The owner of the explorer, which completes most of the heavy duty work. */
private final ArgumentExplorerOwner argumentExplorerOwner;
/** The tree that is currently displayed. Note that this tree is reconstructed at each update. */
private final ArgumentTree argumentTree;
/** Wraps the explorer tree to ensure proper scrolling */
private final JScrollPane treeScrollPane;
/** The button panel with the buttons to modify the tree. */
private JPanel buttonPanel = null;
/** The button to toggle displaying unused arguments. */
private JToggleButton displayUnusedArgumentsButton = null;
/** The action for displaying unused arguments. */
private Action displayAllArgumentsAction = null;
//
// The following are also held by the argument tree model.
// They are different from the corresponding members in the model when the tree enters run mode.
//
/** The collector gem to display in the tree in edit mode. */
private CollectorGem collectorToDisplay;
/** Whether the tree should display all arguments when in edit mode. */
private boolean displayAllArguments = false;
/**
* Default constructor for the ArgumentExplorer.
* @param gemGraph the related GemGraph.
* @param owner the owner of this explorer
*/
public ArgumentExplorer(GemGraph gemGraph, ArgumentExplorerOwner owner) {
if (owner == null) {
throw new NullPointerException();
}
this.argumentExplorerOwner = owner;
// Create and set up the argument tree.
this.argumentTree = new ArgumentTree(gemGraph, owner);
argumentTree.setAutoscrolls(true);
// Create a scroll pane around the tree
treeScrollPane = new JScrollPane(argumentTree);
treeScrollPane.setPreferredSize(new Dimension(500,500));
// Add the scroll pane as the centre component for the explorer
this.setLayout(new BorderLayout());
this.add(treeScrollPane, BorderLayout.CENTER);
// Create a button panel and add it at the top.
JPanel buttonPanel = getArgumentTreeButtonPanel();
this.add(buttonPanel, BorderLayout.NORTH);
ArgumentTreeModel argumentTreeModel = argumentTree.getArgumentTreeModel();
this.collectorToDisplay = argumentTreeModel.getDisplayedCollector();
this.displayAllArguments = argumentTreeModel.getDisplayUnusedArguments();
}
/**
* @return Returns the argumentExplorerOwner.
*/
public ArgumentExplorerOwner getArgumentExplorerOwner() {
return argumentExplorerOwner;
}
/**
* Enables and disables the mouse events (such that the explorer can be used purely as a view).
* @param enabled whether to enable mouse events
*/
public void enableMouseInputs(boolean enabled) {
// enable mouse inputs on the argument tree.
argumentTree.enableMouseInputs(enabled);
}
/**
* Display the controls for argument entry.
* @param inputToEditorMap map from input to editor, for those inputs for which the currently
* running gem requires arguments. An iterator on this map should return the inputs in the correct order.
*/
public void showArgumentControls(Map<PartInput, ValueEditor> inputToEditorMap) {
argumentTree.showArgumentControls(inputToEditorMap);
// Temporarily change the tree display so that it focuses on the target collector.
ArgumentTreeModel treeModel = argumentTree.getArgumentTreeModel();
treeModel.setDisplayUnusedArguments(false);
treeModel.setCollectorToDisplay(treeModel.getGemGraph().getTargetCollector());
// Disable the button action.
displayAllArgumentsAction.setEnabled(false);
}
/**
* Hide the controls for argument entry.
*/
public void hideArgumentControls() {
argumentTree.hideArgumentControls();
// Restore the tree display.
ArgumentTreeModel treeModel = argumentTree.getArgumentTreeModel();
treeModel.setDisplayUnusedArguments(displayAllArguments);
treeModel.setCollectorToDisplay(collectorToDisplay);
// Enable the button action.
displayAllArgumentsAction.setEnabled(true);
}
/**
* Handle the case where the argument values have been cleared.
*/
public void resetArgumentValues() {
argumentTree.getArgumentTreeModel().targetArgumentNodesChanged();
}
/**
* @return the JPanel with the buttons to modify the argument tree.
*/
private JPanel getArgumentTreeButtonPanel() {
if (buttonPanel == null) {
buttonPanel = new JPanel();
buttonPanel.setLayout(new BorderLayout());
buttonPanel.setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 0));
// Create a toolbar.
JToolBar toolBar = new JToolBar();
toolBar.setFloatable(false);
toolBar.setRollover(true);
toolBar.setLayout(new BoxLayout(toolBar, BoxLayout.X_AXIS));
toolBar.setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 2));
// Add the buttons to the toolbar.
toolBar.addSeparator();
toolBar.add(getDisplayAllArgumentsButton());
// The toolbar appears on the right.
buttonPanel.add(toolBar, BorderLayout.EAST);
}
return buttonPanel;
}
/**
* Returns the toggle button for displaying all arguments in the explorer tree.
* @return JToggleButton
*/
private JToggleButton getDisplayAllArgumentsButton() {
if (displayUnusedArgumentsButton == null) {
displayUnusedArgumentsButton = makeNewButton(getDisplayAllArgumentsAction(), null);
displayUnusedArgumentsButton.setSelected(argumentTree.getArgumentTreeModel().getDisplayUnusedArguments());
// 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.
getDisplayAllArgumentsAction().addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
if (e.getPropertyName().equals(ACTION_SELECTED_KEY)) {
boolean displayingUnusedArguments = ((Boolean) e.getNewValue()).booleanValue();
String toolTipId = displayingUnusedArguments ? "AE_DisplayingAllArgumentsToolTip" : "AE_NotDisplayingAllArgumentsToolTip";
displayUnusedArgumentsButton.getModel().setSelected(displayingUnusedArguments);
displayUnusedArgumentsButton.setToolTipText(GemCutter.getResourceString(toolTipId));
}
}
});
}
return displayUnusedArgumentsButton;
}
/**
* Return a new action to toggle if all arguments should be show in the explorer tree..
* @return Action the new displayUnimportedGemsAction.
*/
private Action getDisplayAllArgumentsAction() {
if (displayAllArgumentsAction == null) {
String toolTipId = argumentTree.getArgumentTreeModel().getDisplayUnusedArguments() ?
"AE_DisplayingAllArgumentsToolTip" : "AE_NotDisplayingAllArgumentsToolTip";
displayAllArgumentsAction = new AbstractAction (GemCutter.getResourceString("AE_DisplayAllArguments"), showAllArgumentsIcon) {
private static final long serialVersionUID = -536379607757716250L;
public void actionPerformed(ActionEvent evt) {
ArgumentTreeModel treeModel = argumentTree.getArgumentTreeModel();
boolean wasDisplayingAllArguments = argumentTree.getArgumentTreeModel().getDisplayedCollector() == null;
displayAllArguments = !wasDisplayingAllArguments;
treeModel.setDisplayUnusedArguments(displayAllArguments);
// Set the collector to display in the tree model.
if (!wasDisplayingAllArguments) {
// Display all arguments.
collectorToDisplay = null;
} else {
// Display the target only.
collectorToDisplay = treeModel.getGemGraph().getTargetCollector();
}
treeModel.setCollectorToDisplay(collectorToDisplay);
// Update the action map.
putValue(ACTION_SELECTED_KEY, Boolean.valueOf(treeModel.getDisplayUnusedArguments()));
}
};
displayAllArgumentsAction.putValue(Action.SHORT_DESCRIPTION, GemCutter.getResourceString(toolTipId));
displayAllArgumentsAction.setEnabled(true);
}
return displayAllArgumentsAction;
}
/**
* Creates a new JButton and configures it for use in the button panel.
*
* TODOEL: This is copied from BrowserTreeActions.java.
*
* @param action the action used to configure the JButton
* @param buttonGroup the button group the button belongs in (can be null)
* @return JButton
*/
private static 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;
}
}