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.designer.jsf.action;
043:
044: import com.sun.rave.designtime.DesignBean;
045: import com.sun.rave.designtime.DesignContext;
046: import java.awt.Component;
047: import java.awt.event.ActionEvent;
048: import java.beans.PropertyChangeListener;
049: import java.beans.PropertyChangeSupport;
050: import java.util.ArrayList;
051: import java.util.Collection;
052: import java.util.List;
053: import javax.swing.AbstractAction;
054: import javax.swing.Action;
055: import javax.swing.JButton;
056: import javax.swing.JMenuItem;
057: import org.netbeans.modules.visualweb.designer.jsf.JsfForm;
058: import org.netbeans.modules.visualweb.designer.jsf.JsfSupportUtilities;
059: import org.openide.ErrorManager;
060: import org.openide.awt.Actions;
061: import org.openide.nodes.Node;
062: import org.openide.util.ContextAwareAction;
063: import org.openide.util.Lookup;
064: import org.openide.util.LookupEvent;
065: import org.openide.util.LookupListener;
066: import org.openide.util.WeakListeners;
067: import org.openide.util.actions.Presenter;
068: import org.w3c.dom.Element;
069:
070: /**
071: * An action which operates on component context represented by component root <code>Element</code>.
072: * The subclasses need to implement the <code>isEnabled</code>, <code>perfomAction</code>
073: * and also <code>getDisplayName</code> and <code>getIconBase</code> methods
074: * taking the <code>Element</code> array as an argument.
075: * If they wish to implement different than standard menu, toolbar or popup
076: * presenter, they can just override the corresponding method
077: * <code>getMenuPresenter</code>, <code>getPopupPresenter</code>
078: * or <code>getToolbarPresenter</code>.
079: *
080: * @author Peter Zavadsky
081: */
082: abstract class AbstractComponentAction extends AbstractAction implements
083: ContextAwareAction {
084:
085: /** Name of property elements. */
086: protected static final String PROP_ELEMENTS = "elements"; // NOI18N
087:
088: /** Creates a new instance of AbstractDesignBeanAction */
089: public AbstractComponentAction() {
090: // #6485313 To show the display name in the options dialog.
091: putValue(NAME, getDisplayName(null));
092: }
093:
094: /** This method is not used, only the context aware instance are in the game,
095: * this instance is only a placeholder in layer (or nodes). */
096: public final void actionPerformed(ActionEvent evt) {
097: ErrorManager
098: .getDefault()
099: .notify(
100: ErrorManager.INFORMATIONAL,
101: new IllegalStateException(
102: "This can't be called directly, it is just a placeholder," // NOI18N
103: + " the context aware instance has to be used.")); // NOI18N
104: }
105:
106: /** Creates the context aware instance working in the specific context. */
107: public final Action createContextAwareInstance(Lookup context) {
108: return new DelegateAction(this , context);
109: }
110:
111: /** Gets action display name based on provided beans. */
112: protected abstract String getDisplayName(
113: Element[] componentRootElements);
114:
115: /** Gets icon base based on provided beans, in the form "com/mycompany/myIcon.gif".
116: * @see org.openide.awt.Actions#connect(AbstractButton, Action) */
117: protected abstract String getIconBase(
118: Element[] componentRootElements);
119:
120: /** Implement in order to enable/disable the action based on provided beans. */
121: protected abstract boolean isEnabled(Element[] componentRootElements);
122:
123: /** Implement to perform the action based on provided beans. */
124: protected abstract void performAction(
125: Element[] componentRootElements);
126:
127: // Presenters
128: /** Override if you wish to change the default presenter of the context aware action. */
129: protected JMenuItem getMenuPresenter(Action contextAwareAction,
130: Lookup.Result<Node> result) {
131: return new Actions.MenuItem(contextAwareAction, true);
132: }
133:
134: /** Override if you wish to change the default presenter of the context aware action. */
135: protected JMenuItem getPopupPresenter(Action contextAwareAction,
136: Lookup.Result<Node> result) {
137: return new Actions.MenuItem(contextAwareAction, false);
138: }
139:
140: /** Override if you wish to change the default presenter of the context aware action. */
141: protected Component getToolbarPresenter(Action contextAwareAction,
142: Lookup.Result<Node> result) {
143: // return new Actions.ToolbarButton(contextAwareAction);
144: JButton toolbarButton = new JButton();
145: Actions.connect(toolbarButton, contextAwareAction);
146: return toolbarButton;
147: }
148:
149: private static final JsfForm getJsfForm(Lookup.Result<Node> result) {
150: Node[] nodes = getNodes(result);
151:
152: for (Node node : nodes) {
153: DesignBean designBean = node.getLookup().lookup(
154: DesignBean.class);
155: if (designBean == null) {
156: continue;
157: }
158: DesignContext designContext = designBean.getDesignContext();
159: if (designContext == null) {
160: continue;
161: }
162: JsfForm jsfForm = JsfForm.findJsfForm(designContext);
163: if (jsfForm != null) {
164: return jsfForm;
165: }
166: }
167: return null;
168: }
169:
170: protected static final Element[] getElements(
171: Lookup.Result<Node> result) {
172: Node[] nodes = getNodes(result);
173: List<Element> elements = new ArrayList<Element>();
174:
175: for (int i = 0; i < nodes.length; i++) {
176: Node node = nodes[i];
177: // Element componentRootElement = WebForm.getDomProviderService().getComponentRootElementFromNode(node);
178: Element componentRootElement = JsfSupportUtilities
179: .getComponentRootElementFromNode(node);
180: if (componentRootElement != null) {
181: elements.add(componentRootElement);
182: }
183: }
184: return elements.toArray(new Element[elements.size()]);
185: }
186:
187: private static final Node[] getNodes(Lookup.Result<Node> result) {
188: Collection<? extends Node> col = result.allInstances();
189: return col.toArray(new Node[col.size()]);
190: }
191:
192: /** Context aware implementation. */
193: private static class DelegateAction implements Action,
194: LookupListener, Presenter.Menu, Presenter.Popup,
195: Presenter.Toolbar {
196:
197: /** <code>AbstractDesignBeanAction</code> to delegate to. */
198: private final AbstractComponentAction delegate;
199:
200: /** <code>Lookup.Result</code> we are associated with. */
201: private final Lookup.Result<Node> result;
202:
203: /** State of enabled. */
204: private boolean enabled = true;
205:
206: /** Support for listeners */
207: private final PropertyChangeSupport support = new PropertyChangeSupport(
208: this );
209:
210: public DelegateAction(AbstractComponentAction delegate,
211: Lookup actionContext) {
212: this .delegate = delegate;
213:
214: this .result = actionContext
215: .lookup(new Lookup.Template<Node>(Node.class));
216: this .result.addLookupListener(WeakListeners.create(
217: LookupListener.class, this , this .result));
218: resultChanged(null);
219: }
220:
221: /** Overrides superclass method, adds delegate description. */
222: public String toString() {
223: return super .toString() + "[delegate=" + delegate + "]"; // NOI18N
224: }
225:
226: /** Invoked when an action occurs. */
227: public void actionPerformed(ActionEvent evt) {
228: delegate.performAction(getElements(result));
229: }
230:
231: public void addPropertyChangeListener(
232: PropertyChangeListener listener) {
233: support.addPropertyChangeListener(listener);
234: }
235:
236: public void removePropertyChangeListener(
237: PropertyChangeListener listener) {
238: support.removePropertyChangeListener(listener);
239: }
240:
241: public void putValue(String key, Object object) {
242: delegate.putValue(key, object);
243: }
244:
245: public Object getValue(String key) {
246: // XXX Delegating display name and icon base to the
247: // context sensitive methods.
248: if (Action.NAME.equals(key)) {
249: return delegate.getDisplayName(getElements(result));
250: } else if ("iconBase".equals(key)) { // NOI18N
251: return delegate.getIconBase(getElements(result));
252: } else {
253: return delegate.getValue(key);
254: }
255: }
256:
257: public boolean isEnabled() {
258: return enabled;
259: }
260:
261: public void setEnabled(boolean enabled) {
262: if (this .enabled == enabled) {
263: return;
264: }
265:
266: this .enabled = enabled;
267: support.firePropertyChange("enabled", !enabled, enabled); // NOI18N
268: }
269:
270: public void resultChanged(LookupEvent evt) {
271: Element[] elements = getElements(result);
272:
273: setEnabled(delegate.isEnabled(elements));
274:
275: support.firePropertyChange(PROP_ELEMENTS, null, elements);
276: }
277:
278: public JMenuItem getMenuPresenter() {
279: return delegate.getMenuPresenter(this , result);
280: }
281:
282: public JMenuItem getPopupPresenter() {
283: return delegate.getPopupPresenter(this , result);
284: }
285:
286: public Component getToolbarPresenter() {
287: return delegate.getToolbarPresenter(this , result);
288: }
289: } // End of DelegateAction.
290:
291: }
|