001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.visualweb.spi.designtime.idebridge.action;
043:
044: import com.sun.rave.designtime.DesignBean;
045: import java.awt.Component;
046: import java.awt.event.ActionEvent;
047: import java.beans.PropertyChangeListener;
048: import java.beans.PropertyChangeSupport;
049: import java.util.ArrayList;
050: import java.util.Collection;
051: import java.util.List;
052: import javax.swing.AbstractAction;
053: import javax.swing.Action;
054: import javax.swing.JMenuItem;
055: import org.openide.ErrorManager;
056: import org.openide.awt.Actions;
057: import org.openide.nodes.Node;
058: import org.openide.util.ContextAwareAction;
059: import org.openide.util.Lookup;
060: import org.openide.util.LookupEvent;
061: import org.openide.util.LookupListener;
062: import org.openide.util.WeakListeners;
063: import org.openide.util.actions.Presenter;
064:
065: /**
066: * An action which operates on <code>DesignBean</code> context. The subclasses
067: * need to implement the <code>isEnabled</code>, <code>perfomAction</code>
068: * and also <code>getDisplayName</code> and <code>getIconBase</code> methods
069: * taking the <code>DesignBean</code> array as an argument.
070: * If they wish to implement different than standard menu, toolbar or popup
071: * presenter, they can just override the corresponding method
072: * <code>getMenuPresenter</code>, <code>getPopupPresenter</code>
073: * or <code>getToolbarPresenter</code>.
074: *
075: * @author Peter Zavadsky
076: */
077: public abstract class AbstractDesignBeanAction extends AbstractAction
078: implements ContextAwareAction {
079:
080: /** Name of property designBeans. */
081: protected static final String PROP_DESIGN_BEANS = "designBeans"; // NOI18N
082:
083: /** Creates a new instance of AbstractDesignBeanAction */
084: public AbstractDesignBeanAction() {
085: // #6485313 To show the display name in the options dialog.
086: putValue(NAME, getDisplayName(new DesignBean[0]));
087: }
088:
089: /** This method is not used, only the context aware instance are in the game,
090: * this instance is only a placeholder in layer (or nodes). */
091: public final void actionPerformed(ActionEvent evt) {
092: ErrorManager
093: .getDefault()
094: .notify(
095: ErrorManager.INFORMATIONAL,
096: new IllegalStateException(
097: "This can't be called directly, it is just a placeholder," // NOI18N
098: + " the context aware instance has to be used.")); // NOI18N
099: }
100:
101: /** Creates the context aware instance working in the specific context. */
102: public final Action createContextAwareInstance(Lookup context) {
103: return new DelegateAction(this , context);
104: }
105:
106: /** Gets action display name based on provided beans. */
107: protected abstract String getDisplayName(DesignBean[] designBeans);
108:
109: /** Gets icon base based on provided beans, in the form "com/mycompany/myIcon.gif".
110: * @see org.openide.awt.Actions#connect(AbstractButton, Action) */
111: protected abstract String getIconBase(DesignBean[] designBeans);
112:
113: /** Implement in order to enable/disable the action based on provided beans. */
114: protected abstract boolean isEnabled(DesignBean[] designBeans);
115:
116: /** Implement to perform the action based on provided beans. */
117: protected abstract void performAction(DesignBean[] designBeans);
118:
119: // Presenters
120: /** Override if you wish to change the default presenter of the context aware action. */
121: protected JMenuItem getMenuPresenter(Action contextAwareAction,
122: Lookup.Result result) {
123: return new Actions.MenuItem(contextAwareAction, true);
124: }
125:
126: /** Override if you wish to change the default presenter of the context aware action. */
127: protected JMenuItem getPopupPresenter(Action contextAwareAction,
128: Lookup.Result result) {
129: return new Actions.MenuItem(contextAwareAction, false);
130: }
131:
132: /** Override if you wish to change the default presenter of the context aware action. */
133: protected Component getToolbarPresenter(Action contextAwareAction,
134: Lookup.Result result) {
135: return new Actions.ToolbarButton(contextAwareAction);
136: }
137:
138: protected static final DesignBean[] getDesignBeans(
139: Lookup.Result result) {
140: Node[] nodes = getNodes(result);
141: List designBeans = new ArrayList();
142:
143: for (int i = 0; i < nodes.length; i++) {
144: Node node = nodes[i];
145: DesignBean bean = (DesignBean) node.getLookup().lookup(
146: DesignBean.class);
147: if (bean != null && !designBeans.contains(bean)) {
148: designBeans.add(bean);
149: }
150: }
151: return (DesignBean[]) designBeans
152: .toArray(new DesignBean[designBeans.size()]);
153: }
154:
155: private static final Node[] getNodes(Lookup.Result result) {
156: Collection col = result.allInstances();
157: return (Node[]) col.toArray(new Node[col.size()]);
158: }
159:
160: /** Context aware implementation. */
161: private static class DelegateAction implements Action,
162: LookupListener, Presenter.Menu, Presenter.Popup,
163: Presenter.Toolbar {
164:
165: /** <code>AbstractDesignBeanAction</code> to delegate to. */
166: private final AbstractDesignBeanAction delegate;
167:
168: /** <code>Lookup.Result</code> we are associated with. */
169: private final Lookup.Result result;
170:
171: /** State of enabled. */
172: private boolean enabled = true;
173:
174: /** Support for listeners */
175: private final PropertyChangeSupport support = new PropertyChangeSupport(
176: this );
177:
178: public DelegateAction(AbstractDesignBeanAction delegate,
179: Lookup actionContext) {
180: this .delegate = delegate;
181:
182: this .result = actionContext.lookup(new Lookup.Template(
183: Node.class));
184: this .result
185: .addLookupListener((LookupListener) WeakListeners
186: .create(LookupListener.class, this ,
187: this .result));
188: resultChanged(null);
189: }
190:
191: /** Overrides superclass method, adds delegate description. */
192: public String toString() {
193: return super .toString() + "[delegate=" + delegate + "]"; // NOI18N
194: }
195:
196: /** Invoked when an action occurs. */
197: public void actionPerformed(ActionEvent evt) {
198: delegate.performAction(getDesignBeans(result));
199: }
200:
201: public void addPropertyChangeListener(
202: PropertyChangeListener listener) {
203: support.addPropertyChangeListener(listener);
204: }
205:
206: public void removePropertyChangeListener(
207: PropertyChangeListener listener) {
208: support.removePropertyChangeListener(listener);
209: }
210:
211: public void putValue(String key, Object object) {
212: delegate.putValue(key, object);
213: }
214:
215: public Object getValue(String key) {
216: // XXX Delegating display name and icon base to the
217: // context sensitive methods.
218: if (Action.NAME.equals(key)) {
219: return delegate.getDisplayName(getDesignBeans(result));
220: } else if ("iconBase".equals(key)) { // NOI18N
221: return delegate.getIconBase(getDesignBeans(result));
222: } else {
223: return delegate.getValue(key);
224: }
225: }
226:
227: public boolean isEnabled() {
228: return enabled;
229: }
230:
231: public void setEnabled(boolean enabled) {
232: if (this .enabled == enabled) {
233: return;
234: }
235:
236: this .enabled = enabled;
237: support.firePropertyChange("enabled", !enabled, enabled); // NOI18N
238: }
239:
240: public void resultChanged(LookupEvent evt) {
241: DesignBean[] designBeans = getDesignBeans(result);
242:
243: setEnabled(delegate.isEnabled(designBeans));
244:
245: support.firePropertyChange(PROP_DESIGN_BEANS, null,
246: designBeans);
247: }
248:
249: public JMenuItem getMenuPresenter() {
250: return delegate.getMenuPresenter(this , result);
251: }
252:
253: public JMenuItem getPopupPresenter() {
254: return delegate.getPopupPresenter(this , result);
255: }
256:
257: public Component getToolbarPresenter() {
258: return delegate.getToolbarPresenter(this , result);
259: }
260: } // End of DelegateAction.
261:
262: }
|