/* * @(#)AbstractViewAction.java * * Copyright (c) 1996-2010 The authors and contributors of JHotDraw. * You may not use, copy or modify this file, except in compliance with the * accompanying license terms. */ package org.jhotdraw.app.action; import javax.annotation.Nullable; import java.beans.*; import javax.swing.*; import org.jhotdraw.app.Application; import org.jhotdraw.app.View; import org.jhotdraw.beans.WeakPropertyChangeListener; /** * This abstract class can be extended to implement an {@code Action} that acts * on behalf of a {@link View}. * <p> * If the current View object is disabled or is null, the * AbstractViewAction is disabled as well. * <p> * A property name can be specified. When the specified property * changes or when the current view changes, method updateView * is invoked. * * @author Werner Randelshofer * @version $Id$ */ public abstract class AbstractViewAction extends AbstractAction { private static final long serialVersionUID = 1L; private Application app; @Nullable private View view; private String propertyName; /** Set this to true if the action may create a new view if none exists.*/ private boolean mayCreateView; public static final String VIEW_PROPERTY = "view"; public static final String ENABLED_PROPERTY = "enabled"; /** Combined enabled value consisting of the enabled state of this action and * the enabled state of the view and the application. */ private boolean combinedEnabled = true; private PropertyChangeListener applicationListener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName() == Application.ACTIVE_VIEW_PROPERTY) { // Strings get interned updateView((View) evt.getOldValue(), (View) evt.getNewValue()); } } }; private PropertyChangeListener viewListener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { String name = evt.getPropertyName(); if ("enabled".equals(name)) { updateEnabled(); } else if (name == propertyName) { updateView(); } } }; /** Creates a new instance which acts on the specified view of the application. */ public AbstractViewAction(Application app, @Nullable View view) { this.app = app; this.view = view; this.enabled = true; app.addPropertyChangeListener(new WeakPropertyChangeListener(applicationListener)); if (view != null) { view.addPropertyChangeListener(viewListener); } } /** * Updates the listeners of this action depending on the current view * of the application. */ protected void updateView(@Nullable View oldValue, @Nullable View newValue) { // We only need to do this, if the view has not been explicitly set if (view == null) { if (oldValue != null) { uninstallViewListeners(oldValue); } if (newValue != null) { installViewListeners(newValue); } firePropertyChange(VIEW_PROPERTY, oldValue, newValue); updateEnabled(); updateView(); } } /** * Sets the property name. */ protected void setPropertyName(String name) { this.propertyName = name; if (name != null) { updateView(); } } /** * Gets the property name. */ protected String getPropertyName() { return propertyName; } /** * This method is invoked, when the property changed and when * the view changed. */ protected void updateView() { } /** * Installs listeners on the view object. */ protected void installViewListeners(View p) { p.addPropertyChangeListener(viewListener); } /** * Uninstalls listeners on the view object. */ protected void uninstallViewListeners(View p) { p.removePropertyChangeListener(viewListener); } /** * Updates the enabled state of this action depending on the new enabled * state of the view. */ protected void updateEnabled() { setEnabled(this.enabled); } public Application getApplication() { return app; } @Nullable public View getActiveView() { return (view == null) ? app.getActiveView() : view; } /** * Returns true if the action <i>and</i> the application and <i>the</i> view * is enabled. * * @return true if the action is enabled, false otherwise * @see Action#isEnabled */ @Override public boolean isEnabled() { return combinedEnabled; } /** * Enables or disables the action. The enabled state of the action * depends on the value that is set here and on the enabled state of * the application. * * @param newValue true to enable the action, false to * disable it * @see Action#setEnabled */ @Override public void setEnabled(boolean newValue) { boolean oldValue = combinedEnabled; this.enabled = newValue; combinedEnabled = getApplication().isEnabled() && (isMayCreateView() || getActiveView() != null && getActiveView().isEnabled()) && this.enabled; firePropertyChange(ENABLED_PROPERTY, oldValue, combinedEnabled); } /** Set this to true if the action may create a new view if none exists. * If this is false, the action will be disabled, if no view is available. */ protected void setMayCreateView(boolean b) { mayCreateView = b; } /** Returns to true if the action may create a new view if none exists.*/ protected boolean isMayCreateView() { return mayCreateView; } }