0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.modules.visualweb.project.jsfloader;
0043:
0044: import org.netbeans.modules.visualweb.palette.api.CodeClipDragAndDropHandler;
0045: import org.netbeans.modules.visualweb.palette.api.CodeClipPaletteActions;
0046: import org.netbeans.modules.visualweb.project.jsf.api.JsfProjectUtils;
0047: import org.netbeans.modules.visualweb.spi.designer.jsf.DesignerJsfServiceProvider;
0048: import java.awt.Component;
0049: import java.awt.Cursor;
0050: import java.awt.EventQueue;
0051: import java.io.IOException;
0052: import java.io.Serializable;
0053: import java.io.ObjectInput;
0054: import java.lang.ref.WeakReference;
0055: import java.util.Collections;
0056: import java.util.Enumeration;
0057: import java.util.Set;
0058: import java.util.logging.Logger;
0059: import javax.swing.Action;
0060: import javax.swing.JButton;
0061: import javax.swing.JComponent;
0062: import javax.swing.JEditorPane;
0063: import javax.swing.JFrame;
0064: import javax.swing.JPanel;
0065: import javax.swing.SwingUtilities;
0066: import javax.swing.text.Document;
0067: import org.netbeans.api.project.FileOwnerQuery;
0068: import org.netbeans.api.project.Project;
0069: import org.netbeans.spi.navigator.NavigatorLookupHint;
0070: import org.netbeans.spi.palette.PaletteController;
0071: import org.netbeans.spi.palette.PaletteFactory;
0072:
0073: import org.openide.DialogDisplayer;
0074: import org.openide.ErrorManager;
0075: import org.openide.NotifyDescriptor;
0076: import org.openide.cookies.CloseCookie;
0077: import org.openide.cookies.PrintCookie;
0078: import org.openide.loaders.*;
0079: import org.openide.cookies.EditorCookie;
0080: import org.openide.cookies.PrintCookie;
0081: import org.openide.cookies.SaveCookie;
0082: import org.openide.filesystems.FileObject;
0083: import org.openide.filesystems.FileLock;
0084: import org.openide.nodes.Node;
0085: import org.openide.text.CloneableEditor;
0086: import org.openide.text.CloneableEditorSupport;
0087: import org.openide.text.DataEditorSupport;
0088: import org.openide.text.DataEditorSupport.Env;
0089: import org.openide.util.Lookup;
0090: import org.openide.util.Mutex;
0091: import org.openide.text.NbDocument;
0092: import org.openide.util.NbBundle;
0093: import org.openide.util.Utilities;
0094: import org.openide.util.lookup.Lookups;
0095: import org.openide.util.lookup.ProxyLookup;
0096: import org.openide.windows.CloneableTopComponent;
0097: import org.openide.windows.Mode;
0098: import org.openide.windows.TopComponent;
0099: import org.openide.windows.WindowManager;
0100:
0101: // <multiview>
0102: import org.netbeans.core.api.multiview.MultiViewHandler;
0103: import org.netbeans.core.api.multiview.MultiViews;
0104: import org.netbeans.core.api.multiview.MultiViewPerspective;
0105: import org.netbeans.core.spi.multiview.CloseOperationHandler;
0106: import org.netbeans.core.spi.multiview.CloseOperationState;
0107: import org.netbeans.core.spi.multiview.MultiViewDescription;
0108: import org.netbeans.core.spi.multiview.MultiViewElement;
0109: import org.netbeans.core.spi.multiview.MultiViewElementCallback;
0110: import org.netbeans.core.spi.multiview.MultiViewFactory;
0111:
0112: // </multiview>
0113:
0114: /**
0115: * Editor support for JSF java data objects. The one which provides
0116: * JSF multiiew component.
0117: *
0118: * @author Peter Zavadsky
0119: */
0120: public final class JsfJavaEditorSupport extends DataEditorSupport
0121: implements EditorCookie.Observable, CloseCookie, PrintCookie {
0122:
0123: // <multiview>
0124: static final String MV_ID_DESIGNER = "designer"; // NOI18N
0125: static final String MV_ID_JSP = "jsp"; // NOI18N
0126: static final String MV_ID_JAVA = "java"; // NOI18N
0127:
0128: private static final int ELEMENT_INDEX_DESIGNER = 0;
0129: private static final int ELEMENT_INDEX_JSP = 1;
0130: private static final int ELEMENT_INDEX_JAVA = 2;
0131:
0132: private static final String ICON_PATH_JSF_JSP = "org/netbeans/modules/visualweb/project/jsfloader/resources/jsfJspObject.gif"; // NOI18N
0133:
0134: private static final Logger logger = Logger
0135: .getLogger("org.netbeans.modules.visualweb.project.jsfloader.JsfJavaEditorSupport");
0136:
0137: /** XXX Last created multiview, to be remembered so we can use its ref to update all clones.
0138: * The problem is that allEditors in EditorSupport is not the one plays the role, but the delegated one. */
0139: private CloneableTopComponent lastMultiView;
0140:
0141: /** Constructor. */
0142: JsfJavaEditorSupport(JsfJavaDataObject obj) {
0143: super (obj, new Environment(obj));
0144: }
0145:
0146: public void openDesigner() {
0147: //Bugfix #10688 open() is now run in AWT thread
0148: Mutex.EVENT.writeAccess(new Runnable() {
0149: public void run() {
0150: JFrame mainWin = (JFrame) WindowManager.getDefault()
0151: .getMainWindow();
0152: try {
0153: // show wait cursor using same method as Form editor (see FormEditor.java)
0154: mainWin
0155: .getGlassPane()
0156: .setCursor(
0157: Cursor
0158: .getPredefinedCursor(Cursor.WAIT_CURSOR));
0159: mainWin.getGlassPane().setVisible(true);
0160:
0161: CloneableTopComponent editor = doOpenDesigner();
0162: MultiViewHandler handler = MultiViews
0163: .findMultiViewHandler(editor);
0164: handler
0165: .requestActive(handler.getPerspectives()[ELEMENT_INDEX_DESIGNER]);
0166: } finally {
0167: mainWin.getGlassPane().setCursor(null);
0168: mainWin.getGlassPane().setVisible(false);
0169: }
0170: }
0171: });
0172: }
0173:
0174: CloneableTopComponent doOpenDesigner() {
0175: if (!SwingUtilities.isEventDispatchThread()) {
0176: ErrorManager
0177: .getDefault()
0178: .notify(
0179: ErrorManager.INFORMATIONAL,
0180: new IllegalStateException(
0181: "Assertion failed. WindowsAPI is required to be called from AWT thread only, see " // NOI18N
0182: + "http://www.netbeans.org/download/dev/javadoc/OpenAPIs/org/openide/doc-files/threading.html")); // NOI18N
0183: }
0184:
0185: CloneableTopComponent editor = openCloneableTopComponent();
0186: editor.requestActive();
0187: return editor;
0188: }
0189:
0190: /** Overriding to get java source opened as default, to match the original behaviour. */
0191: @Override
0192: public void open() {
0193: //Bugfix #10688 open() is now run in AWT thread
0194: Mutex.EVENT.writeAccess(new Runnable() {
0195: public void run() {
0196: CloneableTopComponent editor = openCloneableTopComponent();
0197: editor.requestActive();
0198: viewJavaSource(editor);
0199: }
0200: });
0201: }
0202:
0203: protected void openJsp() {
0204: Mutex.EVENT.writeAccess(new Runnable() {
0205: public void run() {
0206: JFrame mainWin = (JFrame) WindowManager.getDefault()
0207: .getMainWindow();
0208: try {
0209: // show wait cursor using same method as Form editor (see FormEditor.java)
0210: mainWin
0211: .getGlassPane()
0212: .setCursor(
0213: Cursor
0214: .getPredefinedCursor(Cursor.WAIT_CURSOR));
0215: mainWin.getGlassPane().setVisible(true);
0216: CloneableTopComponent editor = openCloneableTopComponent();
0217: editor.requestActive();
0218: viewJspSource(editor);
0219: } finally {
0220: mainWin.getGlassPane().setCursor(null);
0221: mainWin.getGlassPane().setVisible(false);
0222: }
0223: }
0224: });
0225: }
0226:
0227: @Override
0228: protected void notifyClosed() {
0229: super .notifyClosed();
0230: lastMultiView = null;
0231: }
0232:
0233: /** Overrides superclass method. Adds updating of display name.
0234: * @return true if the environment accepted being marked as modified
0235: * or false if it has refused and the document should remain unmodified */
0236: @Override
0237: protected boolean notifyModified() {
0238: boolean oldValue = isModified();
0239: boolean ret = super .notifyModified();
0240:
0241: if (ret) {
0242: // XXX Hacks adding save cookie, if there was only the part of jsp save cookie present.
0243: JsfJavaDataObject obj = (JsfJavaDataObject) getDataObject();
0244: if (obj.getPureCookie(SaveCookie.class) == null) {
0245: obj.addSaveCookie(new Save());
0246: obj.setModified(true);
0247: }
0248: }
0249:
0250: if (oldValue != ret) {
0251: updateMultiViewDisplayName();
0252: }
0253:
0254: return ret;
0255: }
0256:
0257: // XXX See above
0258: private class Save implements SaveCookie {
0259: public void save() throws IOException {
0260: saveDocument();
0261: getDataObject().setModified(false);
0262: }
0263: }
0264:
0265: /** Overrides superclass method. Adds removing of save cookie. */
0266: @Override
0267: protected void notifyUnmodified() {
0268: super .notifyUnmodified();
0269:
0270: // Code cloned from super
0271: // Correct way would be to override removeSaveCookie in JsfJavaDataObject,
0272: // BUT removeSaveCookie in JavaDataObject is pacage visible only, so had to
0273: // do this hack
0274: JsfJavaDataObject obj = (JsfJavaDataObject) getDataObject();
0275: SaveCookie save = (SaveCookie) obj
0276: .getPureCookie(SaveCookie.class);
0277: if (save != null) {
0278: obj.removeSaveCookie(save);
0279: obj.setModified(false);
0280: }
0281: updateMultiViewDisplayName();
0282: }
0283:
0284: /** @Override */
0285: @Override
0286: protected void updateTitles() {
0287: // XXX #6486899 Hack to by pass dangerous recursion, see the issue.
0288: // The real problem is in insync,
0289: // which builds the model immediatelly when just creation of the instance is needed.
0290: EventQueue.invokeLater(new Runnable() {
0291: public void run() {
0292: JsfJavaEditorSupport.super .updateTitles();
0293: }
0294: });
0295: }
0296:
0297: /** XXX Heavy hack. Replaces canClose method, used in CloseHandler. */
0298: private static boolean canCloseAll(
0299: JsfJspEditorSupport jsfJspEditorSupport,
0300: JsfJavaEditorSupport jsfJavaEditorSupport) {
0301: // 1st part taken from DataEditorSupport.
0302: if (jsfJavaEditorSupport.env().isModified()
0303: && jsfJavaEditorSupport.isEnvReadOnly()) {
0304: Object result = DialogDisplayer.getDefault().notify(
0305: new NotifyDescriptor.Confirmation(NbBundle
0306: .getMessage(DataObject.class,
0307: "MSG_FileReadOnlyClosing",
0308: // new Object[] {((Env)env).getFileImpl().getNameExt()}),
0309: new Object[] { jsfJavaEditorSupport
0310: .getDataObject()
0311: .getPrimaryFile()
0312: .getNameExt() }),
0313: NotifyDescriptor.OK_CANCEL_OPTION,
0314: NotifyDescriptor.WARNING_MESSAGE));
0315:
0316: return result == NotifyDescriptor.OK_OPTION;
0317: }
0318:
0319: // 2nd part taken from CloneableEditorSupport.
0320: boolean jspModified = jsfJspEditorSupport.env().isModified();
0321: boolean javaModified = jsfJavaEditorSupport.env().isModified();
0322: if (jspModified || javaModified) {
0323: String msg = jsfJavaEditorSupport.messageSave();
0324:
0325: java.util.ResourceBundle bundle = NbBundle
0326: .getBundle(CloneableEditorSupport.class);
0327:
0328: JButton saveOption = new JButton(bundle
0329: .getString("CTL_Save")); // NOI18N
0330: saveOption.getAccessibleContext().setAccessibleDescription(
0331: bundle.getString("ACSD_CTL_Save")); // NOI18N
0332: saveOption.getAccessibleContext().setAccessibleName(
0333: bundle.getString("ACSN_CTL_Save")); // NOI18N
0334: JButton discardOption = new JButton(bundle
0335: .getString("CTL_Discard")); // NOI18N
0336: discardOption.getAccessibleContext()
0337: .setAccessibleDescription(
0338: bundle.getString("ACSD_CTL_Discard")); // NOI18N
0339: discardOption.getAccessibleContext().setAccessibleName(
0340: bundle.getString("ACSN_CTL_Discard")); // NOI18N
0341: discardOption.setMnemonic(bundle.getString(
0342: "CTL_Discard_Mnemonic").charAt(0)); // NOI18N
0343:
0344: NotifyDescriptor nd = new NotifyDescriptor(msg, bundle
0345: .getString("LBL_SaveFile_Title"),
0346: NotifyDescriptor.YES_NO_CANCEL_OPTION,
0347: NotifyDescriptor.QUESTION_MESSAGE, new Object[] {
0348: saveOption, discardOption,
0349: NotifyDescriptor.CANCEL_OPTION },
0350: saveOption);
0351:
0352: Object ret = DialogDisplayer.getDefault().notify(nd);
0353:
0354: if (NotifyDescriptor.CANCEL_OPTION.equals(ret)
0355: || NotifyDescriptor.CLOSED_OPTION.equals(ret)) {
0356: return false;
0357: }
0358:
0359: if (saveOption.equals(ret)) {
0360: if (jspModified) {
0361: try {
0362: jsfJspEditorSupport.saveDocument();
0363: } catch (IOException ioe) {
0364: ErrorManager.getDefault().notify(ioe);
0365: return false;
0366: }
0367: }
0368: if (javaModified) {
0369: try {
0370: jsfJavaEditorSupport.saveDocument();
0371: } catch (IOException ioe) {
0372: ErrorManager.getDefault().notify(ioe);
0373: return false;
0374: }
0375: }
0376: }
0377: }
0378:
0379: return true;
0380: }
0381:
0382: private Env env() {
0383: return (Env) env;
0384: }
0385:
0386: /** Indicates whether the <code>Env</code> is read only. */
0387: private boolean isEnvReadOnly() {
0388: CloneableEditorSupport.Env environment = env();
0389: return environment instanceof Env
0390: && !getDataObject().getPrimaryFile().canWrite();
0391: }
0392:
0393: /** Gets called if jsp editor is opened first via EditCookie. */
0394: @Override
0395: protected CloneableEditorSupport.Pane createPane() {
0396: JsfJavaDataObject jsfJavaDataObject = (JsfJavaDataObject) getDataObject();
0397: JsfJspDataObject jsfJspDataObject = Utils
0398: .findCorrespondingJsfJspDataObject(jsfJavaDataObject
0399: .getPrimaryFile(), false);
0400:
0401: if (jsfJspDataObject == null) {
0402: ErrorManager.getDefault().notify(
0403: ErrorManager.INFORMATIONAL,
0404: new IllegalStateException(
0405: "Can't find jsp data object for "
0406: + getDataObject())); // NOI18N
0407: return super .createPane();
0408: }
0409:
0410: MultiViewDescription[] descs = new MultiViewDescription[] {
0411: new DesignerDesc(jsfJspDataObject),
0412: new JspDesc(jsfJspDataObject),
0413: new JavaDesc(jsfJavaDataObject, jsfJspDataObject) };
0414:
0415: CloneableTopComponent mvtc = MultiViewFactory
0416: .createCloneableMultiView(descs,
0417: descs[ELEMENT_INDEX_DESIGNER],
0418: new CloseHandler(jsfJavaDataObject
0419: .getPrimaryFile()));
0420:
0421: lastMultiView = mvtc;
0422:
0423: // Update display name and tooltip.
0424: SwingUtilities.invokeLater(new Runnable() {
0425: public void run() {
0426: updateMultiViewDisplayName();
0427: updateMultiViewToolTip();
0428: }
0429: });
0430:
0431: // #45665 - dock into editor mode if possible..
0432: Mode editorMode = WindowManager.getDefault().findMode(
0433: EDITOR_MODE);
0434: if (editorMode != null) {
0435: editorMode.dockInto(mvtc);
0436: }
0437: return (CloneableEditorSupport.Pane) mvtc;
0438: }
0439:
0440: void updateMultiViewDisplayName() {
0441: if (SwingUtilities.isEventDispatchThread()) {
0442: doUpdateMultiViewDisplayName();
0443: } else {
0444: SwingUtilities.invokeLater(new Runnable() {
0445: public void run() {
0446: doUpdateMultiViewDisplayName();
0447: }
0448: });
0449: }
0450: }
0451:
0452: private void doUpdateMultiViewDisplayName() {
0453: FileObject jspFileObject = Utils.findJspForJava(getDataObject()
0454: .getPrimaryFile());
0455: if (jspFileObject == null || !jspFileObject.isValid()) {
0456: return;
0457: }
0458:
0459: String displayName;
0460: JsfJspEditorSupport jsfJspEditorSupport = Utils
0461: .findCorrespondingJsfJspEditorSupport(getDataObject()
0462: .getPrimaryFile(), true);
0463: if (jsfJspEditorSupport == null) {
0464: // # 6248373 Probably deleted already.
0465: return;
0466: } else {
0467: displayName = jsfJspEditorSupport.messageName();
0468: }
0469:
0470: Enumeration en = getMultiViews();
0471: while (en.hasMoreElements()) {
0472: TopComponent tc = (TopComponent) en.nextElement();
0473: tc.setDisplayName(displayName);
0474: }
0475: }
0476:
0477: void updateMultiViewToolTip() {
0478: if (SwingUtilities.isEventDispatchThread()) {
0479: doUpdateMultiViewToolTip();
0480: } else {
0481: SwingUtilities.invokeLater(new Runnable() {
0482: public void run() {
0483: doUpdateMultiViewToolTip();
0484: }
0485: });
0486: }
0487: }
0488:
0489: private void doUpdateMultiViewToolTip() {
0490: String toolTip;
0491: JsfJspEditorSupport jsfJspEditorSupport = Utils
0492: .findCorrespondingJsfJspEditorSupport(getDataObject()
0493: .getPrimaryFile(), true);
0494: if (jsfJspEditorSupport == null) {
0495: return;
0496: } else {
0497: toolTip = jsfJspEditorSupport.messageToolTip();
0498: }
0499:
0500: Enumeration<? extends TopComponent> en = getMultiViews();
0501: while (en.hasMoreElements()) {
0502: TopComponent tc = en.nextElement();
0503: tc.setToolTipText(toolTip);
0504: }
0505: }
0506:
0507: /** Gets currently associated multivies, helper method. */
0508: private Enumeration<? extends TopComponent> getMultiViews() {
0509: CloneableTopComponent ctc = lastMultiView;
0510: if (ctc == null) {
0511: Set<TopComponent> emptySet = Collections.emptySet();
0512: return Collections.enumeration(emptySet);
0513: } else {
0514: return ctc.getReference().getComponents();
0515: }
0516: }
0517:
0518: // Helper view methods
0519: private void viewJspSource(final TopComponent jspEditor) {
0520: if (SwingUtilities.isEventDispatchThread()) {
0521: doViewJspSource(jspEditor);
0522: } else {
0523: SwingUtilities.invokeLater(new Runnable() {
0524: public void run() {
0525: doViewJspSource(jspEditor);
0526: }
0527: });
0528: }
0529: }
0530:
0531: private void doViewJspSource(TopComponent jspEditor) {
0532: MultiViewHandler mvh = MultiViews
0533: .findMultiViewHandler(jspEditor);
0534: if (mvh != null) {
0535: MultiViewPerspective[] mvps = mvh.getPerspectives();
0536: for (int i = 0; i < mvps.length; i++) {
0537: if (MV_ID_JSP.equals(mvps[i].preferredID())) {
0538: mvh.requestActive(mvps[i]);
0539: break;
0540: }
0541: }
0542: }
0543: }
0544:
0545: private void viewJavaSource(final TopComponent javaEditor) {
0546: if (SwingUtilities.isEventDispatchThread()) {
0547: doViewJavaSource(javaEditor);
0548: } else {
0549: SwingUtilities.invokeLater(new Runnable() {
0550: public void run() {
0551: doViewJavaSource(javaEditor);
0552: }
0553: });
0554: }
0555: }
0556:
0557: private void doViewJavaSource(TopComponent editor) {
0558: MultiViewHandler mvh = MultiViews.findMultiViewHandler(editor);
0559: if (mvh != null) {
0560: MultiViewPerspective[] mvps = mvh.getPerspectives();
0561: for (int i = 0; i < mvps.length; i++) {
0562: if (MV_ID_JAVA.equals(mvps[i].preferredID())) {
0563: mvh.requestActive(mvps[i]);
0564: break;
0565: }
0566: }
0567: }
0568: }
0569:
0570: private void setLastMultiViewFromChild(Component childComponent) {
0571: if (childComponent == null) {
0572: return;
0573: }
0574:
0575: CloneableTopComponent ctc = (CloneableTopComponent) SwingUtilities
0576: .getAncestorOfClass(CloneableTopComponent.class,
0577: childComponent);
0578: if (ctc != null) {
0579: lastMultiView = ctc;
0580: }
0581: }
0582:
0583: // End of helper view methods.
0584:
0585: // <multiview>
0586: /** A descriptor for the designer editor as an element in multiview. */
0587: private static class DesignerDesc implements MultiViewDescription,
0588: Serializable {
0589:
0590: private static final long serialVersionUID = -3126744316624172415L;
0591:
0592: private JsfJspDataObject jsfJspDataObject;
0593:
0594: public DesignerDesc(JsfJspDataObject jsfJspDataObject) {
0595: this .jsfJspDataObject = jsfJspDataObject;
0596: }
0597:
0598: public MultiViewElement createElement() {
0599: if (jsfJspDataObject.isTemplate()) {
0600: return MultiViewFactory.BLANK_ELEMENT;
0601: }
0602:
0603: final MultiViewElement multiViewElement = DesignerJsfServiceProvider
0604: .getDesignerJsfService()
0605: .createDesignerMultiViewElement(jsfJspDataObject);
0606:
0607: if (multiViewElement != null) {
0608: // XXX Part of workaround for IZ 58136
0609: final MultiViewElement multiViewDelegate;
0610: if (!jsfJspDataObject.isTemplate()) {
0611: multiViewDelegate = new OpenEditOverride.MultiViewDelegate(
0612: multiViewElement, preferredID(),
0613: jsfJspDataObject);
0614: } else {
0615: multiViewDelegate = multiViewElement;
0616: }
0617:
0618: // XXX #6357375 Setting the last multiview, because after deserialization,
0619: // there seems to be no other way how to get it.
0620: EventQueue.invokeLater(new Runnable() {
0621: public void run() {
0622: JsfJavaEditorSupport jsfJavaEditorSupport = Utils
0623: .findCorrespondingJsfJavaEditorSupport(
0624: jsfJspDataObject
0625: .getPrimaryFile(),
0626: false);
0627: if (jsfJavaEditorSupport != null) {
0628: jsfJavaEditorSupport
0629: .setLastMultiViewFromChild(multiViewElement
0630: .getVisualRepresentation());
0631: // #6462651
0632: jsfJavaEditorSupport
0633: .updateMultiViewDisplayName();
0634: jsfJavaEditorSupport
0635: .updateMultiViewToolTip();
0636: }
0637: }
0638: });
0639:
0640: return multiViewDelegate;
0641: }
0642:
0643: return MultiViewFactory.BLANK_ELEMENT;
0644: }
0645:
0646: public String preferredID() {
0647: return MV_ID_DESIGNER;
0648: }
0649:
0650: public org.openide.util.HelpCtx getHelpCtx() {
0651: return org.openide.util.HelpCtx.DEFAULT_HELP;
0652: }
0653:
0654: public java.awt.Image getIcon() {
0655: return Utilities.loadImage(ICON_PATH_JSF_JSP);
0656: }
0657:
0658: public String getDisplayName() {
0659: return NbBundle.getMessage(JsfJavaEditorSupport.class,
0660: "CTL_DesignerTabCaption"); // NOI18N
0661: }
0662:
0663: public int getPersistenceType() {
0664: return TopComponent.PERSISTENCE_NEVER;
0665: }
0666: }
0667:
0668: /** A descriptor for the jsp editor as an element in multiview. */
0669: private static class JspDesc implements MultiViewDescription,
0670: Serializable {
0671:
0672: private static final long serialVersionUID = -3126744316624172415L;
0673:
0674: private JsfJspDataObject jsfJspDataObject;
0675:
0676: public JspDesc(JsfJspDataObject jsfJspDataObject) {
0677: this .jsfJspDataObject = jsfJspDataObject;
0678: }
0679:
0680: public MultiViewElement createElement() {
0681: JsfJspEditorSupport jsfJspEditorSupport = (JsfJspEditorSupport) jsfJspDataObject
0682: .getCookie(JsfJspEditorSupport.class);
0683: if (jsfJspEditorSupport != null) {
0684: jsfJspEditorSupport.prepareDocument();
0685: final MultiViewElement multiViewElement = jsfJspEditorSupport
0686: .createMultiViewElement();
0687:
0688: // XXX Part of workaround for IZ 58136
0689: final MultiViewElement multiViewDelegate;
0690: if (!jsfJspDataObject.isTemplate()) {
0691: multiViewDelegate = new OpenEditOverride.MultiViewDelegate(
0692: multiViewElement, preferredID(),
0693: jsfJspDataObject);
0694: } else {
0695: multiViewDelegate = multiViewElement;
0696: }
0697:
0698: // XXX #6357375 Setting the last multiview, because after deserialization,
0699: // there seems to be no other way how to get it.
0700: EventQueue.invokeLater(new Runnable() {
0701: public void run() {
0702: JsfJavaEditorSupport jsfJavaEditorSupport = Utils
0703: .findCorrespondingJsfJavaEditorSupport(
0704: jsfJspDataObject
0705: .getPrimaryFile(),
0706: false);
0707: if (jsfJavaEditorSupport != null) {
0708: jsfJavaEditorSupport
0709: .setLastMultiViewFromChild((Component) multiViewElement);
0710: // #6462651.
0711: jsfJavaEditorSupport
0712: .updateMultiViewDisplayName();
0713: jsfJavaEditorSupport
0714: .updateMultiViewToolTip();
0715: }
0716: }
0717: });
0718:
0719: return multiViewDelegate;
0720: }
0721: return MultiViewFactory.BLANK_ELEMENT;
0722: }
0723:
0724: public String preferredID() {
0725: return MV_ID_JSP;
0726: }
0727:
0728: public org.openide.util.HelpCtx getHelpCtx() {
0729: return org.openide.util.HelpCtx.DEFAULT_HELP;
0730: }
0731:
0732: public java.awt.Image getIcon() {
0733: return Utilities.loadImage(ICON_PATH_JSF_JSP);
0734: }
0735:
0736: public String getDisplayName() {
0737: return NbBundle.getMessage(JsfJavaEditorSupport.class,
0738: "CTL_JspTabCaption"); // NOI18N
0739: }
0740:
0741: public int getPersistenceType() {
0742: return TopComponent.PERSISTENCE_ONLY_OPENED;
0743: }
0744:
0745: }
0746:
0747: /** A descriptor for the java editor as an element in multiview. */
0748: private static class JavaDesc implements MultiViewDescription,
0749: Serializable {
0750:
0751: private static final long serialVersionUID = -3126744316624172415L;
0752:
0753: private JsfJavaDataObject jsfJavaDataObject;
0754: private JsfJspDataObject jsfJspDataObject;
0755:
0756: public JavaDesc(JsfJavaDataObject jsfJavaDataObject,
0757: JsfJspDataObject jsfJspDataObject) {
0758: this .jsfJavaDataObject = jsfJavaDataObject;
0759: this .jsfJspDataObject = jsfJspDataObject;
0760: }
0761:
0762: public MultiViewElement createElement() {
0763: DataEditorSupport javaEditor = (DataEditorSupport) jsfJavaDataObject
0764: .getCookie(JsfJavaEditorSupport.class);
0765: if (javaEditor != null) {
0766: javaEditor.prepareDocument();
0767: final MultiViewElement multiViewElement = new JavaEditorTopComponent(
0768: javaEditor);
0769:
0770: // XXX Part of workaround for IZ 58136
0771: final MultiViewElement multiViewDelegate;
0772: if (!jsfJspDataObject.isTemplate()) {
0773: multiViewDelegate = new OpenEditOverride.MultiViewDelegate(
0774: multiViewElement, preferredID(),
0775: jsfJspDataObject);
0776: } else {
0777: multiViewDelegate = multiViewElement;
0778: }
0779:
0780: // XXX #6357375 Setting the last multiview, because after deserialization,
0781: // there seems to be no other way how to get it.
0782: EventQueue.invokeLater(new Runnable() {
0783: public void run() {
0784: JsfJavaEditorSupport jsfJavaEditorSupport = (JsfJavaEditorSupport) jsfJavaDataObject
0785: .getCookie(JsfJavaEditorSupport.class);
0786: if (jsfJavaEditorSupport != null) {
0787: jsfJavaEditorSupport
0788: .setLastMultiViewFromChild((Component) multiViewElement);
0789: // #6462651.
0790: jsfJavaEditorSupport
0791: .updateMultiViewDisplayName();
0792: jsfJavaEditorSupport
0793: .updateMultiViewToolTip();
0794: }
0795: }
0796: });
0797:
0798: return multiViewDelegate;
0799: }
0800: return MultiViewFactory.BLANK_ELEMENT;
0801: }
0802:
0803: public String preferredID() {
0804: return MV_ID_JAVA;
0805: }
0806:
0807: public org.openide.util.HelpCtx getHelpCtx() {
0808: return org.openide.util.HelpCtx.DEFAULT_HELP;
0809: }
0810:
0811: public java.awt.Image getIcon() {
0812: return Utilities.loadImage(ICON_PATH_JSF_JSP);
0813: }
0814:
0815: public String getDisplayName() {
0816: return NbBundle.getMessage(JsfJavaEditorSupport.class,
0817: "CTL_JavaTabCaption"); // NOI18N
0818: }
0819:
0820: public int getPersistenceType() {
0821: return TopComponent.PERSISTENCE_ONLY_OPENED;
0822: }
0823:
0824: }
0825:
0826: private static class JavaEditorTopComponent extends CloneableEditor
0827: implements MultiViewElement, CloneableEditorSupport.Pane {
0828: private static final long serialVersionUID = -3126744316624172415L;
0829: private static final NavigatorLookupHint NAVIGATOR_HINT = new NavigatorLookupHint() {
0830: public String getContentType() {
0831: return "text/x-java"; // NOI18N
0832: }
0833: };
0834:
0835: private transient JComponent toolbar;
0836:
0837: private transient MultiViewElementCallback multiViewObserver;
0838:
0839: private PaletteController javaPaletteController;
0840:
0841: JavaEditorTopComponent() {
0842: super ();
0843: }
0844:
0845: JavaEditorTopComponent(CloneableEditorSupport ces) {
0846: super (ces);
0847: initialize();
0848: }
0849:
0850: @Override
0851: public void readExternal(ObjectInput in) throws IOException,
0852: ClassNotFoundException {
0853: //required to do this to make sure cloneableEditorSupport is deserialized.
0854: super .readExternal(in);
0855: initialize();
0856: }
0857:
0858: private void initialize() {
0859: DataObject jsfJavaDataObject = ((JsfJavaEditorSupport) cloneableEditorSupport())
0860: .getDataObject();
0861: if (jsfJavaDataObject != null) {
0862: setActivatedNodes(new Node[] { jsfJavaDataObject
0863: .getNodeDelegate() });
0864: }
0865:
0866: initializePalette();
0867: }
0868:
0869: // XXX PaletteController
0870: private void initializePalette() {
0871:
0872: JsfJavaEditorSupport javaES = (JsfJavaEditorSupport) cloneableEditorSupport();
0873: FileObject primaryFile = javaES.getDataObject()
0874: .getPrimaryFile();
0875: Project project = FileOwnerQuery.getOwner(primaryFile);
0876:
0877: String paletteDirectory;
0878: if (JsfProjectUtils.JAVA_EE_5.equals(JsfProjectUtils
0879: .getJ2eePlatformVersion(project))) {
0880: paletteDirectory = "CreatorJavaPalette5";
0881: } else {
0882: //Later to be renamed with a 1.4
0883: paletteDirectory = "CreatorJavaPalette";
0884: }
0885:
0886: PaletteController controller;
0887: try {
0888: controller = PaletteFactory.createPalette(
0889: paletteDirectory, new CodeClipPaletteActions(
0890: paletteDirectory, this ), null,
0891: new CodeClipDragAndDropHandler()); // NOI18N
0892: } catch (java.io.IOException ex) {
0893: ErrorManager.getDefault().notify(
0894: ErrorManager.INFORMATIONAL, ex);
0895: controller = null;
0896: }
0897: javaPaletteController = controller;
0898: return;
0899:
0900: }
0901:
0902: public JComponent getToolbarRepresentation() {
0903: if (toolbar == null) {
0904: JEditorPane jPane = getEditorPane();
0905: if (jPane != null) {
0906: Document doc = jPane.getDocument();
0907: if (doc instanceof NbDocument.CustomToolbar) {
0908: toolbar = ((NbDocument.CustomToolbar) doc)
0909: .createToolbar(jPane);
0910: }
0911: }
0912: if (toolbar == null) {
0913: // attempt to create own toolbar??
0914: toolbar = new JPanel();
0915: }
0916: }
0917: return toolbar;
0918: }
0919:
0920: public JComponent getVisualRepresentation() {
0921: return this ;
0922: }
0923:
0924: @Override
0925: public void componentDeactivated() {
0926: super .componentDeactivated();
0927: }
0928:
0929: @Override
0930: public void componentActivated() {
0931: super .componentActivated();
0932: }
0933:
0934: public void setMultiViewCallback(
0935: MultiViewElementCallback callback) {
0936: multiViewObserver = callback;
0937: }
0938:
0939: @Override
0940: public void requestVisible() {
0941: if (multiViewObserver != null)
0942: multiViewObserver.requestVisible();
0943: else
0944: super .requestVisible();
0945: }
0946:
0947: @Override
0948: public void requestActive() {
0949: if (multiViewObserver != null)
0950: multiViewObserver.requestActive();
0951: else
0952: super .requestActive();
0953: }
0954:
0955: @Override
0956: public void componentClosed() {
0957: super .componentClosed();
0958: }
0959:
0960: @Override
0961: public void componentShowing() {
0962: super .componentShowing();
0963: }
0964:
0965: @Override
0966: public void componentHidden() {
0967: super .componentHidden();
0968: }
0969:
0970: @Override
0971: public void componentOpened() {
0972: super .componentOpened();
0973: }
0974:
0975: @Override
0976: public void updateName() {
0977: super .updateName();
0978: }
0979:
0980: @Override
0981: protected boolean closeLast() {
0982: return true;
0983: }
0984:
0985: public CloseOperationState canCloseElement() {
0986: // if this is not the last cloned java editor component, closing is OK
0987: if (!isLastView(multiViewObserver.getTopComponent()))
0988: return CloseOperationState.STATE_OK;
0989:
0990: // return a placeholder state - to be sure our CloseHandler is called
0991: return MultiViewFactory.createUnsafeCloseState(
0992: "ID_CLOSING_JAVA", // dummy ID // NOI18N
0993: MultiViewFactory.NOOP_CLOSE_ACTION,
0994: MultiViewFactory.NOOP_CLOSE_ACTION);
0995: }
0996:
0997: private static boolean isLastView(TopComponent tc) {
0998: if (!(tc instanceof CloneableTopComponent))
0999: return false;
1000:
1001: boolean oneOrLess = true;
1002: Enumeration en = ((CloneableTopComponent) tc)
1003: .getReference().getComponents();
1004: if (en.hasMoreElements()) {
1005: en.nextElement();
1006: if (en.hasMoreElements())
1007: oneOrLess = false;
1008: }
1009: return oneOrLess;
1010: }
1011:
1012: @Override
1013: public Action[] getActions() {
1014: // need to delegate to multiview's actions because of the way editor
1015: // constructs actions : NbEditorKit.NbBuildPopupMenuAction
1016: return multiViewObserver != null ? multiViewObserver
1017: .createDefaultActions() : super .getActions();
1018: }
1019:
1020: protected boolean isActiveTC() {
1021: TopComponent selected = getRegistry().getActivated();
1022:
1023: if (selected == null)
1024: return false;
1025: if (selected == this )
1026: return true;
1027:
1028: MultiViewHandler handler = MultiViews
1029: .findMultiViewHandler(selected);
1030: if (handler != null
1031: && MV_ID_JAVA.equals(handler
1032: .getSelectedPerspective().preferredID()))
1033: return true;
1034:
1035: return false;
1036: }
1037:
1038: // XXX Overrides superclass, to fake the display name of the JSF editor,
1039: // in order to prevent overriding of the multiview display name based on multiview SPI impl.
1040: // see NB #57035
1041: @Override
1042: public String getDisplayName() {
1043: JsfJavaEditorSupport javaES = (JsfJavaEditorSupport) cloneableEditorSupport();
1044: JsfJspEditorSupport jes = Utils
1045: .findCorrespondingJsfJspEditorSupport(javaES
1046: .getDataObject().getPrimaryFile(), true);
1047: if (jes == null) {
1048: return null;
1049: } else {
1050: return jes.messageName();
1051: }
1052: }
1053:
1054: private WeakReference<Lookup> lookupWRef = new WeakReference<Lookup>(
1055: null);
1056:
1057: /** Adds <code>NavigatorLookupHint</code> into the original lookup,
1058: * for the navigator. */
1059: @Override
1060: public Lookup getLookup() {
1061: Lookup lookup = lookupWRef.get();
1062:
1063: if (lookup == null) {
1064: Lookup super Lookup = super .getLookup();
1065: if (javaPaletteController == null) {
1066: lookup = new ProxyLookup(new Lookup[] {
1067: super Lookup,
1068: Lookups.singleton(NAVIGATOR_HINT) });
1069: } else {
1070: DataObject dObj = ((JsfJavaEditorSupport) cloneableEditorSupport())
1071: .getDataObject();
1072: lookup = new ProxyLookup(new Lookup[] {
1073: super Lookup,
1074: Lookups.fixed(NAVIGATOR_HINT,
1075: javaPaletteController) });
1076: }
1077: lookupWRef = new WeakReference<Lookup>(lookup);
1078: }
1079: return lookup;
1080: }
1081: }
1082:
1083: // XXX This is a bit strange class? What is a reason of that?
1084: /** Implementation of CloseOperationHandler for multiview. Ensures both form
1085: * and java editor are correctly closed, data saved, etc. Holds a reference
1086: * to jsf DataObject only - to be serializable with the multiview
1087: * TopComponent without problems.
1088: */
1089: private static class CloseHandler implements CloseOperationHandler,
1090: Serializable {
1091: private static final long serialVersionUID = -3126744315424172415L;
1092:
1093: // XXX During deserialization of TopComponent, there might not be recognized the
1094: // JsfJavaDataObject, because the project infra may not be inited yet, thus instead
1095: // of the JsfJavaDataObject it would fall back to JspDataObject.
1096: // Using trick, to operate over the primary file only.
1097: // private JsfJavaDataObject jsfJavaDataObject;
1098: private FileObject primaryJsfFileObject;
1099:
1100: private CloseHandler() {
1101: }
1102:
1103: public CloseHandler(FileObject primaryJsfFileObject) {
1104: this .primaryJsfFileObject = primaryJsfFileObject;
1105: }
1106:
1107: public boolean resolveCloseOperation(
1108: CloseOperationState[] elements) {
1109: if (!primaryJsfFileObject.isValid()) {
1110: // It's not valid, probably deleted already, close it.
1111: return true;
1112: }
1113:
1114: DataObject dobj;
1115: try {
1116: dobj = DataObject.find(primaryJsfFileObject);
1117: } catch (DataObjectNotFoundException dnfe) {
1118: // EAT: The notification of the close is processed AFTER the file is actually deleted, so this error should not
1119: // be an error ?
1120: // ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, dnfe);
1121: return true;
1122: }
1123: JsfJavaDataObject jsfJavaDataObject;
1124: if (dobj instanceof JsfJavaDataObject) {
1125: jsfJavaDataObject = (JsfJavaDataObject) dobj;
1126: } else {
1127: // EAT: The notification of the close is processed AFTER the file is actually deleted, so this error should not
1128: // be an error ?
1129: // ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, new IllegalStateException(
1130: // "JsfJavaDataObject was not found for primary file=" + primaryJsfFileObject + ", instead was found=" + dobj)); // NOI18N
1131: return true;
1132: }
1133: JsfJavaEditorSupport jsfJavaEditorSupport = (JsfJavaEditorSupport) jsfJavaDataObject
1134: .getCookie(JsfJavaEditorSupport.class);
1135:
1136: JsfJspDataObject jsfJspDataObject;
1137: JsfJspEditorSupport jsfJspEditorSupport;
1138: jsfJspDataObject = Utils.findCorrespondingJsfJspDataObject(
1139: jsfJavaDataObject.getPrimaryFile(), true);
1140: if (jsfJspDataObject == null) {
1141: //ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL,
1142: // new IllegalStateException("Can't find jsp data object for " + jsfJavaDataObject)); // NOI18N
1143: jsfJspEditorSupport = null;
1144: } else {
1145: jsfJspEditorSupport = (JsfJspEditorSupport) jsfJspDataObject
1146: .getCookie(JsfJspEditorSupport.class);
1147: }
1148:
1149: boolean ret;
1150: if (jsfJavaEditorSupport != null
1151: && jsfJspEditorSupport != null) {
1152: ret = canCloseAll(jsfJspEditorSupport,
1153: jsfJavaEditorSupport);
1154: } else {
1155: // Some problem occured, log it?
1156: ret = true;
1157: }
1158:
1159: // #6338212 We have to call notifyClose only when the last component
1160: // is about to be closed, otherwise the webform (performance stuff), gets cleared.
1161: // Also that is the correct handling of the notifyClose API.
1162: boolean closingLast;
1163: if (jsfJavaEditorSupport != null) {
1164: int i = 0;
1165: for (Enumeration<? extends TopComponent> en = jsfJavaEditorSupport
1166: .getMultiViews(); en.hasMoreElements();) {
1167: en.nextElement();
1168: i++;
1169: }
1170: if (i > 1) {
1171: closingLast = false;
1172: } else {
1173: closingLast = true;
1174: }
1175: } else {
1176: closingLast = true;
1177: }
1178:
1179: // XXX #6182333 Closing document. Otherwise it is not handled, because of the
1180: // strange impl via original CloneableTopComponent and CloneableEditor.
1181: if (ret && closingLast) {
1182: if (jsfJspEditorSupport != null)
1183: jsfJspEditorSupport.notifyClosed();
1184: if (jsfJavaEditorSupport != null)
1185: jsfJavaEditorSupport.notifyClosed();
1186: }
1187:
1188: return ret;
1189: }
1190: }
1191:
1192: // </multiview>
1193:
1194: /** Nested class. Environment for this support. Extends <code>DataEditorSupport.Env</code> abstract class. */
1195: private static class Environment extends DataEditorSupport.Env {
1196:
1197: private static final long serialVersionUID = 3035543168452715818L;
1198:
1199: /** Constructor. */
1200: public Environment(JsfJavaDataObject obj) {
1201: super (obj);
1202: }
1203:
1204: /** Implements abstract superclass method. */
1205: protected FileObject getFile() {
1206: return getDataObject().getPrimaryFile();
1207: }
1208:
1209: /** Implements abstract superclass method.*/
1210: protected FileLock takeLock() throws IOException {
1211: return getFile().lock();
1212: }
1213: } // End of nested Environment class.
1214: }
|