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.insync.action;
043:
044: import com.sun.rave.designtime.CheckedDisplayAction;
045: import com.sun.rave.designtime.DesignBean;
046: import com.sun.rave.designtime.DesignContext;
047: import com.sun.rave.designtime.DisplayAction;
048: import com.sun.rave.designtime.DisplayActionSet;
049: import com.sun.rave.designtime.Result; // XXX FIXME this shouldn't depend on insync.
050: import org.netbeans.modules.visualweb.insync.ResultHandler;
051: import org.netbeans.modules.visualweb.insync.UndoEvent;
052: import org.netbeans.modules.visualweb.insync.live.LiveUnit;
053: import org.netbeans.modules.visualweb.insync.models.FacesModel;
054: import org.netbeans.modules.visualweb.spi.designtime.idebridge.action.AbstractDesignBeanAction;
055: import java.awt.Component;
056: import java.awt.event.ActionEvent;
057: import java.util.ArrayList;
058: import java.util.Arrays;
059: import java.util.List;
060: import javax.swing.AbstractAction;
061: import javax.swing.Action;
062: import javax.swing.JCheckBoxMenuItem;
063: import javax.swing.JComponent;
064: import javax.swing.JMenuItem;
065: import javax.swing.event.ChangeListener;
066: import org.openide.ErrorManager;
067: import org.openide.awt.Actions;
068: import org.openide.awt.DynamicMenuContent;
069: import org.openide.util.HelpCtx;
070: import org.openide.util.Lookup;
071:
072: /**
073: * XXX This should be ideally out of insync, in the designtime/idebridge.
074: * But it has a big architectural flaw, that it needs insync ResultHandler to process tha action.
075: *
076: * Abstract support action encapsulating <code>DisplayAction</code>s
077: * and providing inline presenters for menu and popup.
078: * Subclasses need to implement the <code>getDisplayActions</code>.
079: * <p>
080: * Note: Do not use for toolbars, the presenter is not implemented.
081: * </p>
082: * <p>
083: * Note: XXX There is dependency on the insync (invocation of the action)
084: * which points out incorrect designtime API arch. That should be fixed
085: * before this support class could be moved into designtime/idebridge.
086: * </p>
087: *
088: * @author Peter Zavadsky
089: * @author Tor Norbye (old functionality implementation -> invokeDisplayAction impl)
090: */
091: public abstract class AbstractDisplayActionAction extends
092: AbstractDesignBeanAction {
093:
094: /** Creates a new instance of DisplayActionAction */
095: public AbstractDisplayActionAction() {
096: }
097:
098: protected abstract DisplayAction[] getDisplayActions(
099: DesignBean[] designBeans);
100:
101: protected abstract String getDefaultDisplayName();
102:
103: protected String getDisplayName(DesignBean[] designBeans) {
104: DisplayAction[] displayActions = getDisplayActions(designBeans);
105: if (displayActions.length == 0) {
106: return getDefaultDisplayName();
107: } else {
108: return displayActions[0].getDisplayName();
109: }
110: }
111:
112: protected String getIconBase(DesignBean[] designBeans) {
113: return null;
114: }
115:
116: protected boolean isEnabled(DesignBean[] designBeans) {
117: return getDisplayActions(designBeans).length > 0;
118: }
119:
120: protected void performAction(DesignBean[] designBeans) {
121: DisplayAction[] displayActions = getDisplayActions(designBeans);
122: if (designBeans.length == 0 || displayActions.length == 0) {
123: return;
124: }
125:
126: // XXX Are those always connected?
127: DesignBean designBean = designBeans[0];
128: DisplayAction displayAction = displayActions[0];
129:
130: invokeDisplayAction(displayAction, designBean);
131: }
132:
133: // XXX FIXME This depends on insync internal, why it shouldn't.
134: private static void invokeDisplayAction(
135: DisplayAction displayAction, DesignBean designBean) {
136: DesignContext context = designBean.getDesignContext();
137: // XXX Retrieving the model this way (casting to LiveUnit) smells incorrect architecture.
138: FacesModel facesModel = ((LiveUnit) context).getModel();
139: // webform.getDocument().writeLock("\"" + displayAction.getLabel() + "\""); // NOI18N
140: UndoEvent undoEvent = facesModel.writeLock("\""
141: + displayAction.getDisplayName() + "\""); // NOI18N
142: try {
143: Result result = displayAction.invoke();
144: // XXX FIXME Postprocessing the action invocation makes the API unusable for other clients.
145: ResultHandler.handleResult(result, facesModel);
146: } finally {
147: // webform.getDocument().writeUnlock();
148: facesModel.writeUnlock(undoEvent);
149: }
150: }
151:
152: // Presenters
153: protected JMenuItem getMenuPresenter(Action contextAwareAction,
154: Lookup.Result result) {
155: return new PresenterProvider(PresenterProvider.MENU, this ,
156: result);
157: }
158:
159: protected JMenuItem getPopupPresenter(Action contextAwareAction,
160: Lookup.Result result) {
161: return new PresenterProvider(PresenterProvider.POPUP, this ,
162: result);
163: }
164:
165: // XXX No toolbar presenter, it shouldn't be needed.
166: // protected Component getToolbarPresenter(Action contextAwareAction, DesignBean[] designBeans) {
167: //// return new Actions.ToolbarButton(contextAwareAction);
168: // return new PresenterProvider(PresenterProvider.TOOLBAR, getDisplayActions(designBeans), designBeans[0]);
169: // }
170:
171: private static class PresenterProvider extends JMenuItem
172: /*just a fake*/implements DynamicMenuContent {
173: // FIXME Once moved to jdk5, replace with enum.
174: private static final int MENU = 0;
175: private static final int POPUP = 1;
176: // private static final int TOOLBAR = 2;
177:
178: private final int type;
179: private final AbstractDisplayActionAction delegate;
180: private final Lookup.Result result;
181:
182: public PresenterProvider(int type,
183: AbstractDisplayActionAction delegate,
184: Lookup.Result result) {
185: this .type = type;
186: this .delegate = delegate;
187: this .result = result;
188: }
189:
190: public JComponent[] synchMenuPresenters(JComponent[] items) {
191: if (items.length > 0) {
192: // This is not dynamic.
193: return items;
194: }
195:
196: List components = new ArrayList();
197:
198: DesignBean[] designBeans = getDesignBeans(result);
199: if (designBeans.length > 0) {
200: DesignBean designBean = designBeans[0];
201: DisplayAction[] displayActions = delegate
202: .getDisplayActions(designBeans);
203: for (int i = 0; i < displayActions.length; i++) {
204: components.addAll(Arrays
205: .asList(getPresenterComponents(type,
206: displayActions[i], designBean)));
207: }
208: }
209: return (JComponent[]) components
210: .toArray(new JComponent[components.size()]);
211: }
212:
213: public JComponent[] getMenuPresenters() {
214: return synchMenuPresenters(new JComponent[0]);
215: }
216: } // End of PresenterProvider.
217:
218: private static JComponent[] getPresenterComponents(int type,
219: DisplayAction displayAction, DesignBean designBean) {
220: boolean isMenu;
221: if (PresenterProvider.MENU == type) {
222: isMenu = true;
223: } else if (PresenterProvider.POPUP == type) {
224: isMenu = false;
225: } else {
226: ErrorManager.getDefault().notify(
227: ErrorManager.INFORMATIONAL,
228: new IllegalStateException("Invalid type=" + type)); // NOI18N
229: return new JComponent[0];
230: }
231:
232: if (displayAction instanceof DisplayActionSet) {
233: DisplayActionSet displayActionSet = (DisplayActionSet) displayAction;
234: DisplayAction[] items = displayActionSet
235: .getDisplayActions();
236: // if (items.length == 0) {
237: // return new JComponent[0];
238: // } else if (items.length == 1) {
239: // return getPresenterComponents(type, items[0], designBean);
240: // }
241: if (displayActionSet.isPopup()) {
242: return new JComponent[] { new Actions.SubMenu(
243: new SingleDisplayActionAction(displayAction,
244: designBean),
245: new DisplayActionSetMenuModel(items, designBean),
246: !isMenu) };
247: } else {
248: List components = new ArrayList();
249: for (int i = 0; i < items.length; i++) {
250: components.addAll(Arrays
251: .asList(getPresenterComponents(type,
252: items[0], designBean)));
253: }
254: return (JComponent[]) components
255: .toArray(new JComponent[components.size()]);
256: }
257: } else if (displayAction instanceof CheckedDisplayAction) {
258: CheckedDisplayAction checkedDisplayAction = (CheckedDisplayAction) displayAction;
259: JMenuItem menuItem = new JCheckBoxMenuItem();
260: Actions.connect(menuItem, new SingleDisplayActionAction(
261: displayAction, designBean), !isMenu);
262: menuItem.setSelected(checkedDisplayAction.isChecked());
263: return new JComponent[] { menuItem };
264: } else {
265: return new JComponent[] { new Actions.MenuItem(
266: new SingleDisplayActionAction(displayAction,
267: designBean), isMenu) };
268: }
269: }
270:
271: private static class SingleDisplayActionAction extends
272: AbstractAction {
273: private final DisplayAction displayAction;
274: private final DesignBean designBean;
275:
276: public SingleDisplayActionAction(DisplayAction displayAction,
277: DesignBean designBean) {
278: this .displayAction = displayAction;
279: this .designBean = designBean;
280:
281: putValue(Action.NAME, displayAction.getDisplayName());
282: }
283:
284: public void actionPerformed(ActionEvent evt) {
285: invokeDisplayAction(displayAction, designBean);
286: }
287: } // End of SingleDisplayActionAction.
288:
289: /** Implementation of the actions submenu model.
290: * XXX TODO This model is not recursive, again NB bad support. */
291: private static class DisplayActionSetMenuModel implements
292: Actions.SubMenuModel {
293:
294: private final DisplayAction[] displayActions;
295: private final DesignBean designBean;
296:
297: public DisplayActionSetMenuModel(
298: DisplayAction[] displayActions, DesignBean designBean) {
299: this .displayActions = displayActions;
300: this .designBean = designBean;
301: }
302:
303: public int getCount() {
304: return displayActions.length;
305: }
306:
307: public String getLabel(int i) {
308: return displayActions[i].getDisplayName();
309: }
310:
311: public HelpCtx getHelpCtx(int i) {
312: // XXX Implement?
313: return null;
314: }
315:
316: public void performActionAt(int i) {
317: invokeDisplayAction(displayActions[i], designBean);
318: }
319:
320: public void addChangeListener(ChangeListener changeListener) {
321: // this model is not mutable.
322: }
323:
324: public void removeChangeListener(ChangeListener changeListener) {
325: // this model is not mutable.
326: }
327:
328: } // End of DisplayActionSetMenuModel.
329: }
|