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.compapp.projects.jbi.ui;
043:
044: import javax.swing.event.ChangeEvent;
045: import org.netbeans.api.project.FileOwnerQuery;
046: import org.netbeans.modules.compapp.projects.jbi.JbiProject;
047: import org.netbeans.modules.compapp.projects.jbi.ui.actions.AddProjectAction;
048: import org.netbeans.modules.compapp.projects.jbi.ui.actions.OpenEditorAction;
049: import org.netbeans.modules.compapp.projects.jbi.ui.customizer.JbiProjectProperties;
050: import org.netbeans.modules.compapp.test.ui.TestNode;
051:
052: import org.netbeans.api.project.Project;
053: import org.netbeans.api.project.ProjectUtils;
054:
055: import org.netbeans.spi.java.project.support.ui.BrokenReferencesSupport;
056: import org.netbeans.spi.java.project.support.ui.PackageView;
057: import org.netbeans.spi.project.ActionProvider;
058: import org.netbeans.spi.project.SubprojectProvider;
059: import org.netbeans.spi.project.support.ant.AntProjectHelper;
060: import org.netbeans.spi.project.support.ant.PropertyEvaluator;
061: import org.netbeans.spi.project.support.ant.ReferenceHelper;
062: import org.netbeans.spi.project.ui.LogicalViewProvider;
063: import org.netbeans.spi.project.ui.support.CommonProjectActions;
064: import org.netbeans.spi.project.ui.support.DefaultProjectOperations;
065: import org.netbeans.spi.project.ui.support.ProjectSensitiveActions;
066: import org.openide.filesystems.FileEvent;
067: import org.openide.filesystems.FileRenameEvent;
068:
069: import org.openide.loaders.DataFolder;
070: import org.openide.loaders.DataObject;
071:
072: import org.openide.nodes.*;
073:
074: import org.openide.util.*;
075: import org.openide.util.actions.SystemAction;
076: import org.openide.util.lookup.Lookups;
077: import org.openide.filesystems.FileObject;
078:
079: import java.awt.event.ActionEvent;
080: import java.awt.*;
081:
082: import java.beans.PropertyChangeEvent;
083: import java.beans.PropertyChangeListener;
084:
085: import java.util.*;
086: import java.util.List;
087:
088: import javax.swing.*;
089: import javax.swing.event.ChangeListener;
090: import org.netbeans.modules.compapp.projects.jbi.CasaHelper;
091: import org.netbeans.modules.compapp.projects.jbi.api.*;
092: import org.openide.actions.FindAction;
093: import org.openide.filesystems.FileChangeAdapter;
094: import org.openide.filesystems.FileChangeListener;
095:
096: /**
097: * Support for creating logical views.
098: *
099: * @author Petr Hrebejk
100: */
101: public class JbiLogicalViewProvider implements LogicalViewProvider {
102: // Private innerclasses ----------------------------------------------------
103: private static final String[] BREAKABLE_PROPERTIES = new String[] {
104: JbiProjectProperties.JAVAC_CLASSPATH,
105: JbiProjectProperties.DEBUG_CLASSPATH,
106: JbiProjectProperties.JBI_CONTENT_ADDITIONAL,
107: JbiProjectProperties.SRC_DIR };
108:
109: private final JbiProject project;
110: private final AntProjectHelper helper;
111: private final PropertyEvaluator evaluator;
112: private final SubprojectProvider spp;
113: private final ReferenceHelper resolver;
114:
115: /** The open folder icon */
116: private static Image mIcon = new ImageIcon(
117: JbiLogicalViewProvider.class
118: .getClassLoader()
119: .getResource(
120: "org/netbeans/modules/compapp/projects/jbi/ui/resources/composite_application_project.png"))
121: .getImage(); // NOI18N
122:
123: /** The open folder icon */
124: private static Image mEmpty = new ImageIcon(
125: JbiLogicalViewProvider.class
126: .getClassLoader()
127: .getResource(
128: "org/netbeans/modules/compapp/projects/jbi/ui/resources/brokenProjectBadge.gif"))
129: .getImage(); // NOI18N
130:
131: private static Image mEmptyIcon = mIcon;
132:
133: private JbiLogicalViewRootNode jRoot;
134: private boolean isEmpty = false;
135:
136: /**
137: * Creates a new JbiLogicalViewProvider object.
138: *
139: * @param project DOCUMENT ME!
140: * @param helper DOCUMENT ME!
141: * @param evaluator DOCUMENT ME!
142: * @param spp DOCUMENT ME!
143: * @param resolver DOCUMENT ME!
144: */
145: public JbiLogicalViewProvider(JbiProject project,
146: AntProjectHelper helper, PropertyEvaluator evaluator,
147: SubprojectProvider spp, ReferenceHelper resolver) {
148: this .project = project;
149: assert project != null;
150: this .helper = helper;
151: assert helper != null;
152: this .evaluator = evaluator;
153: assert evaluator != null;
154: this .spp = spp;
155: assert spp != null;
156: this .resolver = resolver;
157:
158: if (mEmpty != null) {
159: mEmptyIcon = Utilities.mergeImages(mIcon, mEmpty, 8, 0);
160: }
161:
162: // isEmpty = isProjectEmpty();
163: }
164:
165: /**
166: * DOCUMENT ME!
167: *
168: * @return DOCUMENT ME!
169: */
170: public Node createLogicalView() {
171: jRoot = new JbiLogicalViewRootNode();
172: Children kids = jRoot.getChildren();
173:
174: final JbiProjectProperties pps = new JbiProjectProperties(
175: project, helper, resolver);
176:
177: try {
178: //helper.addAntProjectListener(epp);
179: kids
180: .add(new Node[] { new JbiModuleViewNode(pps,
181: project) });
182: if (project.getTestDirectory() != null) {
183: kids.add(new Node[] { new TestNode(pps, project) });
184: }
185: } catch (Exception ioe) {
186: org.openide.ErrorManager.getDefault().log(
187: ioe.getLocalizedMessage());
188: }
189:
190: // In case test directory is missing initially and created later (IZ 115285)
191: FileChangeListener fileChangeListener = new FileChangeAdapter() {
192: @Override
193: public void fileFolderCreated(FileEvent fe) {
194: String testDirName = (String) project
195: .getProjectProperties().get(
196: JbiProjectProperties.TEST_DIR);
197: if (fe.getFile().getNameExt().equals(testDirName)) {
198: Children kids = jRoot.getChildren();
199: kids.add(new Node[] { new TestNode(pps, project) });
200: jRoot.refreshNode();
201: }
202: }
203:
204: @Override
205: public void fileRenamed(FileRenameEvent fe) {
206: String oldName = fe.getName();
207: String oldExt = fe.getExt();
208: String oldNameExt = (oldExt == null || oldExt.trim()
209: .equals("")) ? // NOI18N
210: oldName
211: : (oldName + "." + oldExt); // NOI18N
212:
213: String testDirName = (String) project
214: .getProjectProperties().get(
215: JbiProjectProperties.TEST_DIR);
216:
217: if (oldNameExt.equals(testDirName)) {
218: Children kids = jRoot.getChildren();
219: for (Node node : kids.getNodes()) {
220: if (node instanceof TestNode) {
221: kids.remove(new Node[] { node });
222: break;
223: }
224: }
225: }
226:
227: String newNameExt = fe.getFile().getNameExt();
228: if (newNameExt.equals(testDirName)) {
229: Children kids = jRoot.getChildren();
230: kids.add(new Node[] { new TestNode(pps, project) });
231: jRoot.refreshNode();
232: }
233: }
234:
235: // Test dir deletion is automatically taken care of by TestNode
236: };
237: project.getProjectDirectory().addFileChangeListener(
238: fileChangeListener);
239:
240: return jRoot;
241: }
242:
243: /**
244: * DOCUMENT ME!
245: *
246: */
247: public void refreshRootNode() {
248: boolean newEmpty = isProjectEmpty();
249: if (newEmpty != isEmpty) {
250: isEmpty = newEmpty;
251: if (jRoot != null) {
252: jRoot.refreshNode();
253: }
254: }
255: }
256:
257: private boolean isProjectEmpty() {
258: String comps = helper.getStandardPropertyEvaluator()
259: .getProperty(
260: JbiProjectProperties.JBI_CONTENT_ADDITIONAL);
261:
262: if (comps != null && comps.trim().length() > 0) {
263: return false;
264: } else {
265: return !CasaHelper.containsWSDLPort(project);
266: }
267: }
268:
269: // Only used for detecting whether the "Debug (BPEL)" action should be
270: // enabled or not
271: private boolean projectContainsBPELModule() {
272: String comps = helper
273: .getStandardPropertyEvaluator()
274: .getProperty(JbiProjectProperties.JBI_CONTENT_COMPONENT);
275:
276: return comps != null && comps.contains("sun-bpel-engine"); // NOI18N
277: }
278:
279: /**
280: * DOCUMENT ME!
281: *
282: * @param root DOCUMENT ME!
283: * @param target DOCUMENT ME!
284: *
285: * @return DOCUMENT ME!
286: */
287: public Node findPath(Node root, Object target) {
288: Project project = root.getLookup().lookup(Project.class);
289: if (project == null) {
290: return null;
291: }
292:
293: if (target instanceof DataObject) {
294: target = ((DataObject) target).getPrimaryFile();
295: }
296:
297: if (target instanceof FileObject) {
298: FileObject fo = (FileObject) target;
299: Project owner = FileOwnerQuery.getOwner(fo);
300: if (!project.equals(owner)) {
301: return null; // Don't waste time if project does not own the fo
302: }
303:
304: Node[] nodes = root.getChildren().getNodes(true);
305: for (int i = 0; i < nodes.length; i++) {
306: Node result = PackageView.findPath(nodes[i], target);
307: if (result != null) {
308: return result;
309: }
310: }
311: }
312:
313: return null;
314: }
315:
316: private static Lookup createLookup(Project project) {
317: DataFolder rootFolder = DataFolder.findFolder(project
318: .getProjectDirectory());
319:
320: // XXX Remove root folder after FindAction rewrite
321: return Lookups.fixed(new Object[] { project, rootFolder });
322: }
323:
324: /**
325: * DOCUMENT ME!
326: *
327: * @param helper DOCUMENT ME!
328: * @param resolver DOCUMENT ME!
329: *
330: * @return DOCUMENT ME!
331: */
332: public static boolean hasBrokenLinks(AntProjectHelper helper,
333: ReferenceHelper resolver) {
334: return BrokenReferencesSupport.isBroken(helper, resolver,
335: BREAKABLE_PROPERTIES,
336: new String[] { JbiProjectProperties.JAVA_PLATFORM });
337: }
338:
339: /**
340: * Filter node containin additional features for the J2SE physical
341: */
342: private final class JbiLogicalViewRootNode extends AbstractNode {
343: private Action brokenLinksAction;
344: private boolean broken;
345: private SubprojectListener subprojectListener;
346:
347: /**
348: * Creates a new JbiLogicalViewRootNode object.
349: */
350: public JbiLogicalViewRootNode() {
351: super (new JbiViews.LogicalViewChildren(helper, evaluator,
352: project), createLookup(project));
353: setIconBaseWithExtension("org/netbeans/modules/compapp/projects/jbi/ui/resources/composite_application_project.png"); // NOI18N
354: super .setName(ProjectUtils.getInformation(project)
355: .getDisplayName());
356:
357: if (hasBrokenLinks(helper, resolver)) {
358: broken = true;
359: }
360: brokenLinksAction = new BrokenLinksAction();
361: subprojectListener = new SubprojectListener();
362:
363: final SubprojectProvider subprojectProvider = project
364: .getLookup().lookup(SubprojectProvider.class);
365: subprojectProvider.addChangeListener(new ChangeListener() {
366: public void stateChanged(ChangeEvent e) {
367: Project subproject = (Project) e.getSource();
368: FileObject subprojectFO = subproject
369: .getProjectDirectory();
370: if (subprojectProvider.getSubprojects().contains(
371: subproject)) {
372: subprojectFO
373: .addFileChangeListener(subprojectListener);
374: } else {
375: subprojectFO
376: .removeFileChangeListener(subprojectListener);
377: }
378: }
379: });
380:
381: updateSubprojectListeners();
382: }
383:
384: private void updateSubprojectListeners() {
385: SubprojectProvider subprojectProvider = project.getLookup()
386: .lookup(SubprojectProvider.class);
387: for (Project subproject : subprojectProvider
388: .getSubprojects()) {
389: FileObject subprojectFO = subproject
390: .getProjectDirectory();
391: subprojectFO
392: .removeFileChangeListener(subprojectListener);
393: subprojectFO.addFileChangeListener(subprojectListener);
394: }
395: }
396:
397: /**
398: * DOCUMENT ME!
399: *
400: * @return DOCUMENT ME!
401: */
402: public HelpCtx getHelpCtx() {
403: return new HelpCtx(JbiLogicalViewProvider.class);
404: }
405:
406: /**
407: * DOCUMENT ME!
408: *
409: * @param context DOCUMENT ME!
410: *
411: * @return DOCUMENT ME!
412: */
413: public Action[] getActions(boolean context) {
414: if (context) {
415: return super .getActions(true);
416: } else {
417: return getAdditionalActions(context);
418: }
419: }
420:
421: /**
422: * DOCUMENT ME!
423: *
424: * @param type DOCUMENT ME!
425: * @return DOCUMENT ME!
426: */
427: public Image getIcon(int type) {
428: return broken || isEmpty ? mEmptyIcon : mIcon;
429: }
430:
431: public String getHtmlDisplayName() {
432: String dispName = super .getDisplayName();
433: return broken || isEmpty ? "<font color=\"#A40000\">"
434: + dispName + "</font>" : null; // NOI18N
435: }
436:
437: /**
438: * DOCUMENT ME!
439: *
440: * @param type DOCUMENT ME!
441: * @return DOCUMENT ME!
442: */
443: public Image getOpenedIcon(int type) {
444: return getIcon(type);
445: }
446:
447: public void refreshNode() {
448: fireIconChange();
449: fireOpenedIconChange();
450: fireDisplayNameChange(null, null);
451: }
452:
453: /**
454: * DOCUMENT ME!
455: *
456: * @return DOCUMENT ME!
457: */
458: public boolean canRename() {
459: return true;
460: }
461:
462: public void setName(String s) {
463: DefaultProjectOperations.performDefaultRenameOperation(
464: project, s);
465: }
466:
467: // Private methods -------------------------------------------------
468: private Action[] getAdditionalActions(boolean context) {
469: ResourceBundle bundle = NbBundle
470: .getBundle(JbiLogicalViewProvider.class);
471:
472: List<Action> actions = new ArrayList<Action>();
473:
474: actions.add(ProjectSensitiveActions.projectSensitiveAction(
475: new AddProjectAction(), bundle
476: .getString("LBL_AddProjectAction_Name"), // NOI18N
477: null));
478:
479: // Add Actions added by other modules.
480: /*
481: List<CompAppProjectActionPerformer> otherActions =
482: PluggableProjectActionsProvider.getInstance().getProjectActions();
483: if ((otherActions != null) && (otherActions.size() > 0)) {
484: for (CompAppProjectActionPerformer act : otherActions){
485: actions.add(ProjectSensitiveActions.projectSensitiveAction(
486: act, act.getLabel(), act.getIcon()));
487: }
488: }
489: todo: 11/12/07, remove the above code when switching to using project plugins
490: */
491:
492: JbiInstalledProjectPluginInfo plugins = JbiInstalledProjectPluginInfo
493: .getProjectPluginInfo();
494: if (plugins != null) {
495: List<InternalProjectTypePlugin> plist = plugins
496: .getUncategorizedProjectPluginList();
497: for (InternalProjectTypePlugin plugin : plist) {
498: List<JbiProjectActionPerformer> acts = plugin
499: .getProjectActions();
500: for (JbiProjectActionPerformer act : acts) {
501: if (act
502: .getActionType()
503: .equalsIgnoreCase(
504: JbiProjectActionPerformer.ACT_ADD_PROJECT)) {
505: actions
506: .add(ProjectSensitiveActions
507: .projectSensitiveAction(
508: act,
509: act.getLabel(), act
510: .getIcon()));
511: }
512: }
513: }
514: }
515:
516: actions.add(CommonProjectActions.newFileAction());
517:
518: // Create CASA on demand //chikkala: moved to service composition node action.
519:
520: actions.add(null);
521:
522: actions.add(ProjectSensitiveActions.projectCommandAction(
523: JbiProjectConstants.COMMAND_JBIBUILD, bundle
524: .getString("LBL_JbiBuildAction_Name"), // NOI18N
525: null));
526:
527: actions.add(ProjectSensitiveActions.projectCommandAction(
528: JbiProjectConstants.COMMAND_JBICLEANBUILD, bundle
529: .getString("LBL_JbiCleanBuildAction_Name"), // NOI18N
530: null));
531:
532: actions.add(ProjectSensitiveActions.projectCommandAction(
533: ActionProvider.COMMAND_CLEAN, bundle
534: .getString("LBL_CleanAction_Name"), // NOI18N
535: null));
536: actions.add(null);
537:
538: actions.add(ProjectSensitiveActions.projectCommandAction(
539: JbiProjectConstants.COMMAND_DEPLOY, bundle
540: .getString("LBL_DeployAction_Name"), // NOI18N
541: null));
542:
543: actions.add(ProjectSensitiveActions.projectCommandAction(
544: JbiProjectConstants.COMMAND_UNDEPLOY, bundle
545: .getString("LBL_UnDeployAction_Name"), // NOI18N
546: null));
547: // Start Test Framework
548: actions.add(null);
549: Action testAction = ProjectSensitiveActions
550: .projectCommandAction(
551: JbiProjectConstants.COMMAND_TEST, bundle
552: .getString("LBL_TestAction_Name"), // NOI18N
553: null);
554: actions.add(testAction);
555: Action debugAction = ProjectSensitiveActions
556: .projectCommandAction(ActionProvider.COMMAND_DEBUG,
557: bundle.getString("LBL_DebugAction_Name"), // NOI18N
558: null);
559: actions.add(new ActionDecorator(debugAction) {
560: public boolean isEnabled() {
561: return projectContainsBPELModule();
562: }
563: });
564: // End Test Framework
565: actions.add(null);
566: actions.add(CommonProjectActions.setAsMainProjectAction());
567: actions.add(CommonProjectActions.openSubprojectsAction());
568: actions.add(CommonProjectActions.closeProjectAction());
569: actions.add(null);
570:
571: actions.add(CommonProjectActions.renameProjectAction());
572: actions.add(CommonProjectActions.moveProjectAction());
573: actions.add(CommonProjectActions.copyProjectAction());
574: actions.add(CommonProjectActions.deleteProjectAction());
575: actions.add(null);
576: actions.add(SystemAction.get(FindAction.class));
577:
578: // honor 57874 contact
579: addFromLayers(actions, "Projects/Actions"); // NOI18N
580:
581: if (broken) {
582: actions.add(brokenLinksAction);
583: }
584:
585: actions.add(null);
586: actions.add(CommonProjectActions.customizeProjectAction());
587:
588: return actions.toArray(new Action[actions.size()]);
589: }
590:
591: private void addFromLayers(List<Action> actions, String path) {
592: Lookup look = Lookups.forPath(path);
593: for (Object next : look.lookupAll(Object.class)) {
594: if (next instanceof Action) {
595: actions.add((Action) next);
596: } else if (next instanceof JSeparator) {
597: actions.add(null);
598: }
599: }
600: }
601:
602: /**
603: * This action is created only when project has broken references. Once these are resolved
604: * the action is disabled.
605: */
606: private class BrokenLinksAction extends AbstractAction
607: implements PropertyChangeListener {
608: /**
609: * Creates a new BrokenLinksAction object.
610: */
611: public BrokenLinksAction() {
612: evaluator.addPropertyChangeListener(this );
613: putValue(Action.NAME, NbBundle.getMessage(
614: JbiLogicalViewProvider.class,
615: "LBL_Fix_Broken_Links_Action" // NOI18N
616: ));
617: }
618:
619: /**
620: * DOCUMENT ME!
621: *
622: * @param e DOCUMENT ME!
623: */
624: public void actionPerformed(ActionEvent e) {
625: BrokenReferencesSupport
626: .showCustomizer(
627: helper,
628: resolver,
629: BREAKABLE_PROPERTIES,
630: new String[] { JbiProjectProperties.JAVA_PLATFORM });
631:
632: if (!hasBrokenLinks(helper, resolver)) {
633: disable();
634:
635: // Make sure the target component list is not corrupted.
636: project.getProjectProperties()
637: .fixComponentTargetList();
638:
639: // Update ASI.xml which could be corrupted due to the
640: // broken reference.
641: project.getProjectProperties().saveAssemblyInfo();
642: }
643:
644: updateSubprojectListeners();
645:
646: // How to easily update JbiModuleNode?
647: // Children children = jRoot.getChildren();
648: // Node[] childrenNodes = children.getNodes();
649: // for (int i = 0; i < childrenNodes.length; i++) {
650: // if (childrenNodes[i] instanceof JbiModuleViewNode) {
651: // JbiModuleViewNode moduleViewNode = (JbiModuleViewNode) childrenNodes[i];
652: // JbiModuleViewChildren moduleViewChildren =
653: // (JbiModuleViewChildren) moduleViewNode.getChildren();
654: // moduleViewChildren.removeNotify();
655: // moduleViewChildren.addNotify();
656: // break;
657: // }
658: // }
659: }
660:
661: /**
662: * DOCUMENT ME!
663: *
664: * @param evt DOCUMENT ME!
665: */
666: public void propertyChange(PropertyChangeEvent evt) {
667: if (!broken) {
668: disable();
669: return;
670: }
671:
672: broken = hasBrokenLinks(helper, resolver);
673:
674: if (!broken) {
675: disable();
676: }
677: }
678:
679: private void disable() {
680: broken = false;
681: setEnabled(false);
682: evaluator.removePropertyChangeListener(this );
683: fireIconChange();
684: fireOpenedIconChange();
685: fireDisplayNameChange(null, null);
686: }
687: }
688:
689: /**
690: * A file change listener on subproject changes.
691: */
692: private class SubprojectListener extends FileChangeAdapter {
693:
694: public void fileDeleted(FileEvent fe) {
695: checkBrokenLinks();
696: }
697:
698: public void fileRenamed(FileRenameEvent fe) {
699: checkBrokenLinks();
700: }
701:
702: private void checkBrokenLinks() {
703: boolean newBroken = hasBrokenLinks(helper, resolver);
704: if (newBroken != broken) {
705: broken = newBroken;
706: brokenLinksAction.setEnabled(broken);
707: refreshNode();
708: }
709: }
710: }
711: }
712: }
713:
714: /**
715: * Action wrapper.
716: */
717: class ActionDecorator implements Action {
718:
719: private Action realAction;
720:
721: ActionDecorator(Action action) {
722: realAction = action;
723: }
724:
725: public Object getValue(String key) {
726: return realAction.getValue(key);
727: }
728:
729: public void putValue(String key, Object value) {
730: realAction.putValue(key, value);
731: }
732:
733: public void setEnabled(boolean b) {
734: realAction.setEnabled(b);
735: }
736:
737: public boolean isEnabled() {
738: return realAction.isEnabled();
739: }
740:
741: public void addPropertyChangeListener(
742: PropertyChangeListener listener) {
743: realAction.addPropertyChangeListener(listener);
744: }
745:
746: public void removePropertyChangeListener(
747: PropertyChangeListener listener) {
748: realAction.removePropertyChangeListener(listener);
749: }
750:
751: public void actionPerformed(ActionEvent e) {
752: realAction.actionPerformed(e);
753: }
754:
755: }
|