/**
* Copyright (C) 2015 Valkyrie RCP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.valkyriercp.command.support;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.binding.collection.AbstractCachingMapDecorator;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.valkyriercp.command.CommandServices;
import org.valkyriercp.command.SecuredActionCommandExecutor;
import org.valkyriercp.command.config.*;
import org.valkyriercp.core.support.AbstractPropertyChangePublisher;
import org.valkyriercp.factory.ButtonFactory;
import org.valkyriercp.factory.ComponentFactory;
import org.valkyriercp.factory.MenuFactory;
import org.valkyriercp.util.ValkyrieRepository;
import javax.swing.*;
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* <p>
* Base class for commands. Extend this class by implementing the
* {@link #execute()} method.
* </p>
*
* <p>
* Most (if not all) commands result in a UI component. Several methods are
* provided here to deliver abstractButtons or menuItems. Configuring this
* visual aspect of the command is done by a number of
* {@link CommandFaceDescriptor}s. One of these will be registered as the
* default while others can be used to create a different look by providing a
* faceDescriptorId.
* </p>
*
* @see CommandFaceDescriptor
*
* @author Keith Donald
* @author Jan Hoskens
*
*/
public abstract class AbstractCommand extends AbstractPropertyChangePublisher implements
BeanNameAware, SecuredActionCommandExecutor {
/** Property used to notify changes in the <em>enabled</em> state. */
public static final String ENABLED_PROPERTY_NAME = "enabled";
/** Property used to notify changes in the <em>visible</em> state. */
public static final String VISIBLE_PROPERTY_NAME = "visible";
private static final String DEFAULT_FACE_DESCRIPTOR_ID = "default";
private String id;
private String defaultFaceDescriptorId = DEFAULT_FACE_DESCRIPTOR_ID;
private boolean enabled = true;
private boolean visible = true;
private boolean authorized = true;
private String securityControllerId = null;
private String[] authorities;
private Map faceButtonManagers;
private CommandServices commandServices;
private CommandFaceDescriptorRegistry faceDescriptorRegistry;
private Boolean oldEnabledState;
private Boolean oldVisibleState;
/**
* Default constructor. Id can be set by context.
*
* @see BeanNameAware
*/
protected AbstractCommand() {
this(null);
}
/**
* Constructor providing an id for configuration.
*
* @param id
*/
protected AbstractCommand(String id) {
super();
setId(id);
// keep track of enable state for buttons
addEnabledListener(new ButtonEnablingListener());
// keep track of visible state for buttons
addPropertyChangeListener(VISIBLE_PROPERTY_NAME, new ButtonVisibleListener());
afterPropertiesSet();
}
/**
* Constructor providing id and encodedLabel. A default FaceDescriptor will
* be created by passing the encodedLabel.
*
* @param id
* @param encodedLabel label to use when creating the default
* {@link CommandFaceDescriptor}.
*/
protected AbstractCommand(String id, String encodedLabel) {
this(id, new CommandFaceDescriptor(encodedLabel));
}
/**
* Constructor providing id and a number of parameters to create a default
* {@link CommandFaceDescriptor}.
*
* @param id
* @param encodedLabel label for the default {@link CommandFaceDescriptor}.
* @param icon icon for the default {@link CommandFaceDescriptor}.
* @param caption caption for the default {@link CommandFaceDescriptor}.
*/
protected AbstractCommand(String id, String encodedLabel, Icon icon, String caption) {
this(id, new CommandFaceDescriptor(encodedLabel, icon, caption));
}
/**
* Constructor providing an id and the default FaceDescriptor.
*
* @param id
* @param faceDescriptor the default FaceDescriptor to use.
*/
protected AbstractCommand(String id, CommandFaceDescriptor faceDescriptor) {
this(id);
if (faceDescriptor != null) {
setFaceDescriptor(faceDescriptor);
}
afterPropertiesSet();
}
/**
* Constructor providing an id and a number of FaceDescriptors. No default
* faceDescriptor is set.
*
* @param id
* @param faceDescriptors a map which contains <faceDescriptorId,
* faceDescriptor> pairs.
*/
protected AbstractCommand(String id, Map faceDescriptors) {
this(id);
setFaceDescriptors(faceDescriptors);
afterPropertiesSet();
}
/**
* @return id of this Command.
*/
public String getId() {
return this.id;
}
/**
* Set the id. In most cases, this is provided by the constructor or through
* the beanId provided in the applicationContext.
*
* @param id
*/
protected void setId(String id) {
if (!StringUtils.hasText(id)) {
id = null;
}
this.id = id;
}
/**
* {@inheritDoc}
*/
public void setBeanName(String name) {
if (getId() == null) {
setId(name);
}
}
/**
* Set the default faceDescriptor to use for this command.
*
* @param faceDescriptor the {@link CommandFaceDescriptor} to use as
* default.
*/
public void setFaceDescriptor(CommandFaceDescriptor faceDescriptor) {
setFaceDescriptor(getDefaultFaceDescriptorId(), faceDescriptor);
}
/**
* Add an additional {@link CommandFaceDescriptor}.
*
* @param faceDescriptorId key to identify and use this faceDescriptor.
* @param faceDescriptor additional {@link CommandFaceDescriptor}.
*/
public void setFaceDescriptor(String faceDescriptorId, CommandFaceDescriptor faceDescriptor) {
getButtonManager(faceDescriptorId).setFaceDescriptor(faceDescriptor);
}
/**
* Add a number of {@link CommandFaceDescriptor}s to this Command.
*
* @param faceDescriptors a {@link Map} which contains <faceDescriptorId,
* CommandFaceDescriptor> pairs.
*/
public void setFaceDescriptors(Map faceDescriptors) {
Assert.notNull(faceDescriptors);
Iterator it = faceDescriptors.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String faceDescriptorId = (String) entry.getKey();
CommandFaceDescriptor faceDescriptor = (CommandFaceDescriptor) entry.getValue();
setFaceDescriptor(faceDescriptorId, faceDescriptor);
}
}
/**
* Change the default FaceDescriptor.
*
* @param defaultFaceDescriptorId the id of the faceDescriptor to be used as
* default.
*/
public void setDefaultFaceDescriptorId(String defaultFaceDescriptorId) {
this.defaultFaceDescriptorId = defaultFaceDescriptorId;
}
/**
* Set the {@link CommandFaceDescriptorRegistry} to use when
* registering/looking up {@link CommandFaceDescriptor}s.
*
* @param faceDescriptorRegistry registry to use for the
* {@link CommandFaceDescriptor}s.
*/
public void setFaceDescriptorRegistry(CommandFaceDescriptorRegistry faceDescriptorRegistry) {
this.faceDescriptorRegistry = faceDescriptorRegistry;
}
/**
* Set the {@link CommandServices}.
*/
public void setCommandServices(CommandServices services) {
this.commandServices = services;
}
/**
* Set the provided label on the default {@link CommandFaceDescriptor}.
*
* @see CommandFaceDescriptor#setButtonLabelInfo(String)
*/
public void setLabel(String encodedLabel) {
getOrCreateFaceDescriptor().setButtonLabelInfo(encodedLabel);
}
/**
* Set the provided label on the default {@link CommandFaceDescriptor}.
*
* @see CommandFaceDescriptor#setLabelInfo(CommandButtonLabelInfo)
*/
public void setLabel(CommandButtonLabelInfo label) {
getOrCreateFaceDescriptor().setLabelInfo(label);
}
/**
* Set the provided description on the default {@link CommandFaceDescriptor}.
*
* @see CommandFaceDescriptor#setCaption(String)
*/
public void setCaption(String shortDescription) {
getOrCreateFaceDescriptor().setCaption(shortDescription);
}
/**
* Set the provided icon on the default {@link CommandFaceDescriptor}.
*
* @see CommandFaceDescriptor#setIcon(Icon)
*/
public void setIcon(Icon icon) {
getOrCreateFaceDescriptor().setIcon(icon);
}
/**
* Set the provided iconInfo on the default {@link CommandFaceDescriptor}.
*
* @see CommandFaceDescriptor#setIconInfo(CommandButtonIconInfo)
*/
public void setIconInfo(CommandButtonIconInfo iconInfo) {
getOrCreateFaceDescriptor().setIconInfo(iconInfo);
}
/**
* Set the provided foreground colour on the default {@link CommandFaceDescriptor}.
*
* @see CommandFaceDescriptor#setForeground(java.awt.Color)
*/
public void setForeground(Color foreground) {
getOrCreateFaceDescriptor().setForeground(foreground);
}
/**
* Set the provided background colour on the default {@link CommandFaceDescriptor}.
*
* @see CommandFaceDescriptor#setBackground(Color)
*/
public void setBackground(Color background) {
getOrCreateFaceDescriptor().setBackground(background);
}
/**
* Performs initialisation and validation of this instance after its
* dependencies have been set. If subclasses override this method, they
* should begin by calling {@code super.afterPropertiesSet()}.
*/
public void afterPropertiesSet() {
if (getId() == null) {
logger.info("Command " + this + " has no set id; note: anonymous commands cannot be used in registries.");
}
if (this instanceof ActionCommand && !isFaceConfigured()) {
logger.info("The face descriptor property is not yet set for action command '" + getId()
+ "'; configuring");
}
}
/**
* Returns the defaultFaceDescriptor. Creates one if needed.
*/
private CommandFaceDescriptor getOrCreateFaceDescriptor() {
if (!isFaceConfigured()) {
if (logger.isInfoEnabled()) {
logger.info("Lazily instantiating default face descriptor on behalf of caller to prevent npe; "
+ "command is being configured manually, right?");
}
if(ValkyrieRepository.isCurrentlyRunningInContext()) {
ValkyrieRepository.getInstance().getApplicationConfig().commandConfigurer().configure(this);
} else {
setFaceDescriptor(new CommandFaceDescriptor());
}
}
return getFaceDescriptor();
}
/**
* Returns the default faceDescriptorId.
*/
public String getDefaultFaceDescriptorId() {
if (!StringUtils.hasText(defaultFaceDescriptorId)) {
return DEFAULT_FACE_DESCRIPTOR_ID;
}
return defaultFaceDescriptorId;
}
/**
* Returns the default faceDescriptor.
*/
protected CommandFaceDescriptor getFaceDescriptor() {
return getDefaultButtonManager().getFaceDescriptor();
}
/**
* Returns <code>true</code> if this command has a default faceDescriptor.
*/
public boolean isFaceConfigured() {
return getDefaultButtonManager().isFaceConfigured();
}
/**
* Returns the icon from the default faceDescriptor or <code>null</code>
* if no faceDescriptor is available.
*/
public Icon getIcon() {
if (isFaceConfigured()) {
return getFaceDescriptor().getIcon();
}
return null;
}
/**
* Returns the text from the default faceDescriptor or the default text of
* the {@link CommandButtonLabelInfo#BLANK_BUTTON_LABEL#getText()}.
*/
public String getText() {
if (isFaceConfigured()) {
return getFaceDescriptor().getText();
}
return CommandButtonLabelInfo.BLANK_BUTTON_LABEL.getText();
}
/**
* Returns the mnemonic from the default faceDescriptor or the default
* mnemonic of the
* {@link CommandButtonLabelInfo#BLANK_BUTTON_LABEL#getMnemonic()}.
*/
public int getMnemonic() {
if (isFaceConfigured()) {
return getFaceDescriptor().getMnemonic();
}
return CommandButtonLabelInfo.BLANK_BUTTON_LABEL.getMnemonic();
}
/**
* Returns the mnemonicIndex from the default faceDescriptor or the default
* mnemonicIndex of the
* {@link CommandButtonLabelInfo#BLANK_BUTTON_LABEL#getMnemonicIndex()}.
*/
public int getMnemonicIndex() {
if (isFaceConfigured()) {
return getFaceDescriptor().getMnemonicIndex();
}
return CommandButtonLabelInfo.BLANK_BUTTON_LABEL.getMnemonicIndex();
}
/**
* Returns the accelerator from the default faceDescriptor or the default
* accelerator of the
* {@link CommandButtonLabelInfo#BLANK_BUTTON_LABEL#getAccelerator()}.
*/
public KeyStroke getAccelerator() {
if (isFaceConfigured()) {
return getFaceDescriptor().getAccelerator();
}
return CommandButtonLabelInfo.BLANK_BUTTON_LABEL.getAccelerator();
}
/**
* Returns the {@link CommandFaceDescriptorRegistry} of this
* {@link AbstractCommand} which holds all face descriptors.
*/
public CommandFaceDescriptorRegistry getFaceDescriptorRegistry() {
return faceDescriptorRegistry;
}
/**
* Returns the {@link CommandServices} for this {@link AbstractCommand}.
*/
protected CommandServices getCommandServices() {
if (commandServices == null) {
commandServices = ValkyrieRepository.getInstance().getApplicationConfig().commandServices();
}
return this.commandServices;
}
/**
* Set the Id of the security controller that should manage this object.
* @param controllerId Id (bean name) of the security controller
*/
public void setSecurityControllerId(String controllerId) {
this.securityControllerId = controllerId;
}
/**
* Get the id (bean name) of the security controller that should manage this
* object.
* @return controller id
*/
public String getSecurityControllerId() {
return securityControllerId;
}
/**
* Set the authorized state. Setting authorized to false will override any
* call to {@link #setEnabled(boolean)}. As long as this object is
* unauthorized, it can not be enabled.
* @param authorized Pass <code>true</code> if the object is to be
* authorized
*/
public void setAuthorized(boolean authorized) {
boolean wasAuthorized = isAuthorized();
if (hasChanged(wasAuthorized, authorized)) {
this.authorized = authorized;
firePropertyChange(AUTHORIZED_PROPERTY, wasAuthorized, authorized);
updatedEnabledState();
}
}
/**
* Returns <code>true</code> if the command is authorized.
*/
public boolean isAuthorized() {
return authorized;
}
/**
* Returns <code>true</code> if the command is enabled and
* {@link #isAuthorized()}.
*
* @see #isAuthorized()
*/
public boolean isEnabled() {
return enabled && isAuthorized();
}
/**
* This method is called when any predicate for enabled state has changed.
* This implementation fires the enabled changed event if the return value
* of {@link #isEnabled()} has changed.
* <p>
* Subclasses which have an additional predicate to enabled state must call
* this method if the state of the predicate changes.
*/
protected void updatedEnabledState() {
boolean isEnabled = isEnabled();
if (oldEnabledState == null || hasChanged(oldEnabledState.booleanValue(), isEnabled)) {
firePropertyChange(ENABLED_PROPERTY_NAME, oldEnabledState == null ? !isEnabled : oldEnabledState
.booleanValue(), isEnabled);
}
oldEnabledState = Boolean.valueOf(isEnabled);
}
/**
* Set the enabled state of this command. Note that if we are currently not
* authorized, then the new value will just be recorded and no change in the
* current enabled state will be made.
* @param enabled state
*/
public void setEnabled(boolean enabled) {
if (hasChanged(this.enabled, enabled)) {
this.enabled = enabled;
updatedEnabledState();
}
}
/**
* Listener to keep track of enabled state. When enable on command changes,
* each button has to be checked and set.
*/
private class ButtonEnablingListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
// We need to keep the buttons in sync with the command, so go
// through the buttons and set Enabled state.
// alternative is to add a listener to the enabled value and change
// buttons in that listener
// NOT redundant
boolean enabled = evt.getNewValue() == Boolean.TRUE;
Iterator it = buttonIterator();
while (it.hasNext()) {
AbstractButton button = (AbstractButton) it.next();
button.setEnabled(enabled);
}
}
}
/**
* Listener to keep track of visible state. When visible on command changes,
* each button has to be checked and set.
*/
private class ButtonVisibleListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
// We need to keep the buttons in sync with the command, so go
// through the buttons and set visible state.
// alternative is to add a listener to the visible value and change
// buttons in that listener
// NOT redundant
boolean enabled = evt.getNewValue() == Boolean.TRUE;
Iterator it = buttonIterator();
while (it.hasNext()) {
AbstractButton button = (AbstractButton) it.next();
button.setVisible(enabled);
}
}
}
/**
* {@inheritDoc}
*/
public void addEnabledListener(PropertyChangeListener listener) {
addPropertyChangeListener(ENABLED_PROPERTY_NAME, listener);
}
/**
* {@inheritDoc}
*/
public void removeEnabledListener(PropertyChangeListener listener) {
removePropertyChangeListener(ENABLED_PROPERTY_NAME, listener);
}
/**
* <p>
* Returns an iterator over all buttons in the default
* {@link CommandFaceButtonManager}.
* </p>
* <p>
* To traverse all buttons of all {@link CommandFaceButtonManager}s see
* {@link #buttonIterator()}.
* </p>
*/
protected final Iterator defaultButtonIterator() {
return getDefaultButtonManager().iterator();
}
/**
* Returns an iterator over <em>all</em> buttons by traversing
* <em>each</em> {@link CommandFaceButtonManager}.
*/
protected final Iterator buttonIterator() {
if (this.faceButtonManagers == null)
return Collections.EMPTY_SET.iterator();
return new NestedButtonIterator(this.faceButtonManagers.values().iterator());
}
/**
* Iterator to traverse all buttons in every
* {@link CommandFaceButtonManager} of this {@link AbstractCommand}.
*/
private static final class NestedButtonIterator implements Iterator {
private final Iterator managerIterator;
private Iterator currentButtonIterator;
private AbstractButton nextButton;
NestedButtonIterator(Iterator it) {
this.managerIterator = it;
preFetchNextButton();
}
public boolean hasNext() {
return nextButton != null;
}
public Object next() {
if (nextButton == null) {
throw new NoSuchElementException();
}
AbstractButton lastButton = nextButton;
preFetchNextButton();
return lastButton;
}
public void remove() {
throw new UnsupportedOperationException("Can't use a button-iterator on AbstractCommand to remove buttons.");
}
private void preFetchNextButton() {
while (this.currentButtonIterator == null || !this.currentButtonIterator.hasNext()) {
if (this.managerIterator.hasNext()) {
CommandFaceButtonManager cfbm = (CommandFaceButtonManager) this.managerIterator.next();
this.currentButtonIterator = cfbm.iterator();
}
else {
this.currentButtonIterator = null;
this.nextButton = null;
return;
}
}
if (this.currentButtonIterator.hasNext())
nextButton = (AbstractButton) this.currentButtonIterator.next();
else
nextButton = null;
}
}
/**
* Returns <code>true</code> if this command doesn't have an Id.
*/
public boolean isAnonymous() {
return id == null;
}
/**
* Returns <code>true</code> if the command is visible.
*/
public boolean isVisible() {
return this.visible;
}
/**
* Set this command visible and update all associated buttons.
*/
public void setVisible(boolean value) {
if (visible != value) {
this.visible = value;
updatedVisibleState();
}
}
/**
* <p>
* This method is called when any predicate for visible state has changed.
* This implementation fires the visible changed event if the return value
* of {@link #isVisible()} has changed.
* </p>
* <p>
* Subclasses which have an additional predicate to visible state must call
* this method if the state of the predicate changes.
* </p>
*/
protected void updatedVisibleState() {
boolean isVisible = isVisible();
if (oldVisibleState == null || hasChanged(oldVisibleState.booleanValue(), isVisible)) {
firePropertyChange(VISIBLE_PROPERTY_NAME, oldVisibleState == null ? !isVisible : oldVisibleState
.booleanValue(), isVisible);
}
oldVisibleState = Boolean.valueOf(isVisible);
}
/**
* Create a button using the defaults for faceDescriptorId, buttonFactory
* and buttonConfigurer.
*
* @see #createButton(String, ButtonFactory, CommandButtonConfigurer)
*/
public final AbstractButton createButton() {
return createButton(getDefaultFaceDescriptorId(), getButtonFactory(), getDefaultButtonConfigurer());
}
/**
* Create a button using the defaults for buttonFactory and
* buttonConfigurer.
*
* @see #createButton(String, ButtonFactory, CommandButtonConfigurer)
*/
public final AbstractButton createButton(String faceDescriptorId) {
return createButton(faceDescriptorId, getButtonFactory(), getDefaultButtonConfigurer());
}
/**
* Create a button using the defaults for faceDescriptorId and
* buttonConfigurer.
*
* @see #createButton(String, ButtonFactory, CommandButtonConfigurer)
*/
public final AbstractButton createButton(ButtonFactory buttonFactory) {
return createButton(getDefaultFaceDescriptorId(), buttonFactory, getDefaultButtonConfigurer());
}
/**
* Create a button using the default buttonConfigurer.
*
* @see #createButton(String, ButtonFactory, CommandButtonConfigurer)
*/
public final AbstractButton createButton(String faceDescriptorId, ButtonFactory buttonFactory) {
return createButton(faceDescriptorId, buttonFactory, getDefaultButtonConfigurer());
}
/**
* Create a button using the default buttonFactory.
*
* @see #createButton(String, ButtonFactory, CommandButtonConfigurer)
*/
public final AbstractButton createButton(ButtonFactory buttonFactory, CommandButtonConfigurer buttonConfigurer) {
return createButton(getDefaultFaceDescriptorId(), buttonFactory, buttonConfigurer);
}
/**
* Creates a button using the provided id, factory and configurer.
*
* @param faceDescriptorId id of the faceDescriptor used to configure the
* button.
* @param buttonFactory factory that delivers the button.
* @param buttonConfigurer configurer mapping the faceDescriptor on the
* button.
* @return a button attached to this command.
*/
public AbstractButton createButton(String faceDescriptorId, ButtonFactory buttonFactory,
CommandButtonConfigurer buttonConfigurer) {
AbstractButton button = buttonFactory.createButton();
attach(button, faceDescriptorId, buttonConfigurer);
return button;
}
/**
* Create a menuItem using the defaults for faceDescriptorId, menuFactory
* and menuItemButtonConfigurer.
*
* @see #createMenuItem(String, MenuFactory, CommandButtonConfigurer)
*/
public final JMenuItem createMenuItem() {
return createMenuItem(getDefaultFaceDescriptorId(), getMenuFactory(), getMenuItemButtonConfigurer());
}
/**
* Create a menuItem using the defaults for menuFactory and
* menuItemButtonConfigurer.
*
* @see #createMenuItem(String, MenuFactory, CommandButtonConfigurer)
*/
public final JMenuItem createMenuItem(String faceDescriptorId) {
return createMenuItem(faceDescriptorId, getMenuFactory(), getMenuItemButtonConfigurer());
}
/**
* Create a menuItem using the defaults for faceDescriptorId and
* menuItemButtonConfigurer.
*
* @see #createMenuItem(String, MenuFactory, CommandButtonConfigurer)
*/
public final JMenuItem createMenuItem(MenuFactory menuFactory) {
return createMenuItem(getDefaultFaceDescriptorId(), menuFactory, getMenuItemButtonConfigurer());
}
/**
* Create a menuItem using the default and menuItemButtonConfigurer.
*
* @see #createMenuItem(String, MenuFactory, CommandButtonConfigurer)
*/
public final JMenuItem createMenuItem(String faceDescriptorId, MenuFactory menuFactory) {
return createMenuItem(faceDescriptorId, menuFactory, getMenuItemButtonConfigurer());
}
/**
* Create a menuItem using the default faceDescriptorId.
*
* @see #createMenuItem(String, MenuFactory, CommandButtonConfigurer)
*/
public final JMenuItem createMenuItem(MenuFactory menuFactory, CommandButtonConfigurer buttonConfigurer) {
return createMenuItem(getDefaultFaceDescriptorId(), menuFactory, buttonConfigurer);
}
/**
* Create a menuItem using the provided id, factory and configurer.
*
* @param faceDescriptorId id of the faceDescriptor used to configure the
* button.
* @param menuFactory factory that delivers the menuItem.
* @param buttonConfigurer configurer mapping the faceDescriptor on the
* button.
* @return a menuItem attached to this command.
*/
public JMenuItem createMenuItem(String faceDescriptorId, MenuFactory menuFactory,
CommandButtonConfigurer buttonConfigurer) {
JMenuItem menuItem = menuFactory.createMenuItem();
attach(menuItem, faceDescriptorId, buttonConfigurer);
return menuItem;
}
/**
* Attach and configure the button to the default faceDescriptor using the
* default configurer.
*
* @see #attach(AbstractButton, String, CommandButtonConfigurer)
*/
public void attach(AbstractButton button) {
attach(button, getDefaultFaceDescriptorId(), getCommandServices().getDefaultButtonConfigurer());
}
/**
* Attach and configure the button to the default faceDescriptor using the
* given configurer.
*
* @see #attach(AbstractButton, String, CommandButtonConfigurer)
*/
public void attach(AbstractButton button, CommandButtonConfigurer configurer) {
attach(button, getDefaultFaceDescriptorId(), configurer);
}
/**
* Attach and configure the button to the faceDescriptorId using the configurer.
*
* @param button the button to attach and configure.
* @param faceDescriptorId the id of the faceDescriptor.
* @param configurer that maps the faceDescriptor on the button.
*/
public void attach(AbstractButton button, String faceDescriptorId, CommandButtonConfigurer configurer) {
getButtonManager(faceDescriptorId).attachAndConfigure(button, configurer);
onButtonAttached(button);
}
/**
* Additional code to execute when attaching a button.
*
* @param button the button that has been attached.
*/
protected void onButtonAttached(AbstractButton button) {
if (logger.isDebugEnabled()) {
logger.debug("Configuring newly attached button for command '" + getId() + "' enabled=" + isEnabled()
+ ", visible=" + isVisible());
}
button.setEnabled(isEnabled());
button.setVisible(isVisible());
}
/**
* Detach the button from the {@link CommandFaceButtonManager}.
*
* @param button the button to detach.
*/
public void detach(AbstractButton button) {
if (getDefaultButtonManager().isAttachedTo(button)) {
getDefaultButtonManager().detach(button);
onButtonDetached();
}
}
/**
* Returns <code>true</code> if the provided button is attached to the
* default {@link CommandFaceButtonManager}.
*
* @param b the button to check.
* @return <code>true</code> if b is attached to the default
* {@link CommandFaceButtonManager}.
*/
public boolean isAttached(AbstractButton b) {
return getDefaultButtonManager().isAttachedTo(b);
}
/**
* Implement this to add custom code executed when detaching a button.
*/
protected void onButtonDetached() {
// default no implementation, subclasses may override
}
/**
* Returns the {@link CommandFaceButtonManager} for the default
* {@link CommandFaceDescriptor}.
*/
private CommandFaceButtonManager getDefaultButtonManager() {
return getButtonManager(getDefaultFaceDescriptorId());
}
/**
* Returns the {@link CommandFaceButtonManager} for the given
* faceDescriptorId.
*
* @param faceDescriptorId id of the {@link CommandFaceDescriptor}.
* @return the {@link CommandFaceButtonManager} managing buttons configured
* with the {@link CommandFaceDescriptor}.
*/
private CommandFaceButtonManager getButtonManager(String faceDescriptorId) {
if (this.faceButtonManagers == null) {
this.faceButtonManagers = new AbstractCachingMapDecorator() {
protected Object create(Object key) {
return new CommandFaceButtonManager(AbstractCommand.this, (String) key);
}
};
}
CommandFaceButtonManager m = (CommandFaceButtonManager) this.faceButtonManagers.get(faceDescriptorId);
return m;
}
/**
* @see CommandServices#getDefaultButtonConfigurer()
*/
protected CommandButtonConfigurer getDefaultButtonConfigurer() {
return getCommandServices().getDefaultButtonConfigurer();
}
/**
* @see CommandServices#getToolBarButtonConfigurer()
*/
protected CommandButtonConfigurer getToolBarButtonConfigurer() {
return getCommandServices().getToolBarButtonConfigurer();
}
/**
* @see CommandServices#getToolBarButtonFactory()
*/
protected ButtonFactory getToolBarButtonFactory() {
return getCommandServices().getToolBarButtonFactory();
}
/**
* @see CommandServices#getMenuItemButtonConfigurer()
*/
protected CommandButtonConfigurer getMenuItemButtonConfigurer() {
return getCommandServices().getMenuItemButtonConfigurer();
}
/**
* @see CommandServices#getComponentFactory()
*/
protected ComponentFactory getComponentFactory() {
return getCommandServices().getComponentFactory();
}
/**
* @see CommandServices#getButtonFactory()
*/
protected ButtonFactory getButtonFactory() {
return getCommandServices().getButtonFactory();
}
/**
* @see CommandServices#getMenuFactory()
*/
protected MenuFactory getMenuFactory() {
return getCommandServices().getMenuFactory();
}
/**
* Search for a button representing this command in the provided container
* and let it request the focus.
*
* @param container the container which holds the command button.
* @return <code>true</code> if the focus request is likely to succeed.
*
* @see #getButtonIn(Container)
* @see JComponent#requestFocusInWindow()
*/
public boolean requestFocusIn(Container container) {
AbstractButton button = getButtonIn(container);
if (button != null) {
return button.requestFocusInWindow();
}
return false;
}
/**
* Search for the first button of this command that is a child component of
* the given container.
*
* @param container the container to be searched.
* @return the {@link AbstractButton} representing this command that is
* embedded in the container or <code>null</code> if none was found.
*/
public AbstractButton getButtonIn(Container container) {
Iterator it = buttonIterator();
while (it.hasNext()) {
AbstractButton button = (AbstractButton) it.next();
if (SwingUtilities.isDescendingFrom(button, container)) {
return button;
}
}
return null;
}
public String[] getAuthorities() {
return authorities;
}
public void setAuthorities(String... authorities) {
this.authorities = authorities;
}
/**
* {@inheritDoc}
*/
public String toString() {
return new ToStringCreator(this).append("id", getId()).append("enabled", enabled).append("visible", visible)
.append("defaultFaceDescriptorId", defaultFaceDescriptorId).toString();
}
}