/*******************************************************************************
* Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.tools.workbench.framework.action;
import java.awt.Cursor;
import java.awt.Dialog;
import java.awt.EventQueue;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.util.prefs.Preferences;
import javax.swing.AbstractAction;
import javax.swing.Icon;
import javax.swing.KeyStroke;
import org.eclipse.persistence.tools.workbench.framework.Application;
import org.eclipse.persistence.tools.workbench.framework.NodeManager;
import org.eclipse.persistence.tools.workbench.framework.app.ApplicationNode;
import org.eclipse.persistence.tools.workbench.framework.app.NavigatorSelectionModel;
import org.eclipse.persistence.tools.workbench.framework.context.ApplicationContext;
import org.eclipse.persistence.tools.workbench.framework.context.ShellWorkbenchContext;
import org.eclipse.persistence.tools.workbench.framework.context.WorkbenchContext;
import org.eclipse.persistence.tools.workbench.framework.help.HelpManager;
import org.eclipse.persistence.tools.workbench.framework.resources.ResourceRepository;
import org.eclipse.persistence.tools.workbench.uitools.swing.EmptyIcon;
/**
* This extension of AbstractAction ties an action to an application context.
* Subclasses have access to the selected nodes via the application context's
* node manager.
*
* Subclasses must override #initialize() and at least one of the
* following #execute() methods:
*
* #execute() Override this method if the action is not related to
* the tree selection or you would like to do something other
* than iterate through all the selected nodes.
*
* #execute(Node) Override this method if you would like to perform
* the same thing on each selected node. This method will be
* called for each of the selected nodes.
*
* This class also adds helper methods for setting the following properties:
* - text
* - mnemonic
* - accelerator
* - icon
* - tool-tip text
*/
public abstract class AbstractFrameworkAction extends AbstractAction implements FrameworkAction {
/** this is where we get the various properties from */
private WorkbenchContext workbenchContext;
protected static final Icon EMPTY_ICON = new EmptyIcon(16);
// ********** constructor/initialization **********
/**
* This constructor can be used by "typical" actions that are associated
* with a single workbench window (e.g. the drop-down menus, the tool
* bars, the navigator pop-up menus)
*/
protected AbstractFrameworkAction(WorkbenchContext workbenchContext) {
super();
this.workbenchContext = workbenchContext;
this.initialize();
}
/**
* This constructor can be used by actions that are associated with a
* properties page or panel that can be associated with multiple workbench
* windows (e.g. "add" buttons on nested panels); the action itself cannot
* use its *own* workbench context (since it will be a "shell" workbench
* context), but it can make calls to its panel, which *will* have the correct
* workbench context (since the panel is using a workbench context holder
* that is updated when the panel is installed on a different workbench
* window)
*/
protected AbstractFrameworkAction(ApplicationContext applicationContext) {
this(new ShellWorkbenchContext(applicationContext));
}
/**
* Initialize the action's text, mnemonic, accelerator,
* icon, tool-tip text, etc.
*/
protected void initialize() {
//call super.initialize() when overriding this method
}
protected void initializeText(String key) {
this.setText(this.resourceRepository().getString(key));
}
protected void initializeMnemonic(String key) {
this.setMnemonic(this.resourceRepository().getMnemonic(key));
}
/**
* most of the time the text and mnemonic share the same key
*/
protected void initializeTextAndMnemonic(String key) {
this.initializeText(key);
this.initializeMnemonic(key);
}
protected void initializeAccelerator(String key) {
this.setAccelerator(this.resourceRepository().getAccelerator(key));
}
protected void initializeIcon(String key) {
this.setIcon(this.resourceRepository().getIcon(key));
}
protected void initializeToolTipText(String key) {
this.setToolTipText(this.resourceRepository().getString(key));
}
public void setUp() {
// no listeners to add, see subclasses
}
public void tearDown() {
// no listeners to remove, see subclasses
}
// ********** ActionListener implementation **********
/**
* By default we invoke the #execute() method.
*/
public void actionPerformed(ActionEvent e) {
this.currentWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
this.execute();
this.currentWindow().setCursor(Cursor.getDefaultCursor());
}
/**
* This method is called by default from #actionPerformed(ActionEvent).
* Subclasses can override this method if the action is not related to
* the tree selection or the action performs something on all
* the nodes (not just the selected nodes).
*
* Loop through the selected nodes, calling #execute(ApplicationNode).
*/
protected void execute() {
ApplicationNode[] nodes = this.selectedNodes();
for (int i = nodes.length; i-- > 0; ) {
this.execute(nodes[i]);
}
}
/**
* This method is called once for each node selected in the tree.
* Unsupported - Subclasses must override either this method or #execute().
*/
protected void execute(ApplicationNode selectedNode) {
throw new UnsupportedOperationException();
}
// ********** FrameworkAction implementation **********
public String getText() {
return (String) this.getValue(NAME);
}
public int getMnemonic() {
Integer mnemonic = (Integer) this.getValue(MNEMONIC_KEY);
return (mnemonic == null) ? - 1 : mnemonic.intValue();
}
public KeyStroke getAccelerator() {
return (KeyStroke) this.getValue(ACCELERATOR_KEY);
}
public Icon getIcon() {
return (Icon) this.getValue(SMALL_ICON);
}
public String getToolTipText() {
return (String) this.getValue(SHORT_DESCRIPTION);
}
// ********** public setters **********
public void setIcon(Icon icon) {
this.putValue(SMALL_ICON, icon);
}
public void setText(String text) {
this.putValue(NAME, text);
}
public void setToolTipText(String toolTipText) {
this.putValue(SHORT_DESCRIPTION, toolTipText);
}
public void setAccelerator(KeyStroke accelerator) {
this.putValue(ACCELERATOR_KEY, accelerator);
}
public void setMnemonic(int mnemonic) {
this.putValue(MNEMONIC_KEY, new Integer(mnemonic));
}
// ********** convenience methods **********
public ApplicationContext getApplicationContext() {
return this.getWorkbenchContext().getApplicationContext();
}
public WorkbenchContext getWorkbenchContext() {
return this.workbenchContext;
}
public Application application() {
return this.getApplicationContext().getApplication();
}
public Preferences preferences() {
return this.getApplicationContext().getPreferences();
}
public ResourceRepository resourceRepository() {
return this.getApplicationContext().getResourceRepository();
}
public NodeManager nodeManager() {
return this.getApplicationContext().getNodeManager();
}
public HelpManager helpManager() {
return this.getApplicationContext().getHelpManager();
}
public Window currentWindow() {
return this.getWorkbenchContext().getCurrentWindow();
}
public NavigatorSelectionModel navigatorSelectionModel() {
return this.getWorkbenchContext().getNavigatorSelectionModel();
}
public ApplicationNode[] selectedNodes() {
return this.navigatorSelectionModel().getSelectedNodes();
}
public ApplicationNode[] selectedProjectNodes() {
return this.navigatorSelectionModel().getSelectedProjectNodes();
}
/**
* Default classification for a FrameworkAction is simply the
* class name.
*/
public String getClassification() {
return this.getClass().getName();
}
/**
* Build a launcher that can be dispatched via the AWT EventQueue.
*/
public static Runnable buildDialogLauncher(final Dialog d) {
return new Runnable() {
public void run() {
d.show();
}
};
}
/**
* Asynchronously launch the specified dialog via the AWT EventQueue.
* This is useful for opening a "wait" dialog while an action is executing.
*/
public static void launchLater(Dialog d) {
EventQueue.invokeLater(buildDialogLauncher(d));
}
/**
* Synchronously launch the specified dialog via the AWT EventQueue.
* This is useful for opening a dialog in another thread.
*/
public static void launchAndWait(Dialog d) {
try {
EventQueue.invokeAndWait(buildDialogLauncher(d));
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
}