001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019: package org.netbeans.modules.xslt.core;
020:
021: import java.awt.EventQueue;
022: import java.io.IOException;
023: import java.io.Serializable;
024: import java.util.ArrayList;
025: import java.util.List;
026: import java.util.Set;
027: import javax.swing.text.AbstractDocument;
028: import javax.swing.text.StyledDocument;
029: import org.netbeans.api.project.Project;
030: import org.netbeans.api.xml.cookies.CookieObserver;
031: import org.netbeans.core.api.multiview.MultiViewHandler;
032: import org.netbeans.core.api.multiview.MultiViews;
033: import org.netbeans.core.spi.multiview.CloseOperationHandler;
034: import org.netbeans.core.spi.multiview.CloseOperationState;
035: import org.netbeans.modules.xml.retriever.catalog.Utilities;
036: import org.netbeans.modules.xml.validation.ShowCookie;
037: import org.netbeans.modules.xml.validation.ui.ValidationAnnotation;
038: import org.netbeans.modules.xml.xam.AbstractModel;
039: import org.netbeans.modules.xml.xam.Component;
040: import org.netbeans.modules.xml.xam.Model.State;
041: import org.netbeans.modules.xml.xam.ModelSource;
042: import org.netbeans.modules.xml.xam.spi.Validator.ResultItem;
043: import org.netbeans.modules.xml.xam.ui.undo.QuietUndoManager;
044: import org.netbeans.modules.xslt.core.multiview.source.XSLTSourceMultiViewElementDesc;
045: import org.netbeans.modules.xslt.core.multiview.XsltMultiViewSupport;
046: import org.netbeans.modules.xslt.core.context.MapperContextFactory;
047: import org.netbeans.modules.xslt.tmap.util.Util;
048: import org.netbeans.modules.xslt.mapper.model.MapperContext;
049: import org.netbeans.modules.xslt.model.XslModel;
050: import org.netbeans.modules.xslt.model.spi.XslModelFactory;
051: import org.openide.ErrorManager;
052: import org.openide.awt.UndoRedo;
053: import org.openide.cookies.EditCookie;
054: import org.openide.cookies.EditorCookie;
055: import org.openide.cookies.LineCookie;
056: import org.openide.cookies.OpenCookie;
057: import org.openide.filesystems.FileLock;
058: import org.openide.filesystems.FileObject;
059: import org.openide.loaders.DataObject;
060: import org.openide.loaders.MultiDataObject;
061: import org.openide.text.CloneableEditor;
062: import org.openide.text.CloneableEditorSupport;
063: import org.openide.text.CloneableEditorSupport.Pane;
064: import org.openide.text.DataEditorSupport;
065: import org.openide.util.Lookup;
066: import org.openide.util.Task;
067: import org.openide.util.TaskListener;
068: import org.openide.windows.Mode;
069: import org.openide.windows.TopComponent;
070: import org.openide.windows.WindowManager;
071: import org.netbeans.modules.soa.ui.UndoRedoManagerProvider;
072:
073: /**
074: *
075: * @author Vitaly Bychkov
076: * @version 1.0
077: *
078: * TODO add ValidateXMLCookie when becomes friend ...
079: */
080: public class XSLTDataEditorSupport extends DataEditorSupport implements
081: OpenCookie, EditCookie, EditorCookie.Observable, ShowCookie,
082: UndoRedoManagerProvider {
083:
084: public XSLTDataEditorSupport(XSLTDataObject dObj) {
085: super (dObj, new XSLTEnv(dObj));
086: setMIMEType(XSLTDataLoader.MIME_TYPE);
087: }
088:
089: // vlv
090: public UndoRedo.Manager getUndoRedoManager() {
091: return getUndoManager();
092: }
093:
094: /** {@inheritDoc} */
095: public void saveDocument() throws IOException {
096: super .saveDocument();
097: syncModel();
098: getDataObject().setModified(false);
099: }
100:
101: /**
102: * Sync Xsl model with source.
103: */
104: public void syncModel() {
105: try {
106: XslModel model = getXslModel();
107: if (model != null) {
108: model.sync();
109: }
110: } catch (IOException e) {
111: ErrorManager.getDefault().notify(
112: ErrorManager.INFORMATIONAL, e);
113: // assert false;
114: }
115: }
116:
117: public QuietUndoManager getUndoManager() {
118: return (QuietUndoManager) getUndoRedo();
119: }
120:
121: /**
122: * @return Xsl Model for this editor.
123: */
124: public XslModel getXslModel() {
125: XSLTDataObject dataObject = getEnv().getXsltDataObject();
126: ModelSource modelSource = Utilities.getModelSource(dataObject
127: .getPrimaryFile(), true);
128: return getModelFactory().getModel(modelSource);
129: }
130:
131: /**
132: * Implements ShowCookie interface used to open editor for the object containing xam Component
133: *
134: * Opens the editor for the file pointed by this resultItem.
135: * @param resultItem Contains the error/warning source, message.
136: */
137: public void show(final ResultItem resultItem) {
138: if (!(resultItem.getModel() instanceof AbstractModel)) {
139: return;
140: }
141:
142: final Component componentEntity = resultItem.getComponents();
143:
144: // Get the edit and line cookies.
145: DataObject d = getDataObject();
146: final LineCookie lc = (LineCookie) d
147: .getCookie(LineCookie.class);
148: final EditCookie ec = (EditCookie) d
149: .getCookie(EditCookie.class);
150: if (lc == null || ec == null) {
151: return;
152: }
153:
154: javax.swing.SwingUtilities.invokeLater(new Runnable() {
155: public void run() {
156: // Opens the editor or brings it into focus
157: // and makes it the activated topcomponent.
158: ec.edit();
159:
160: TopComponent tc = WindowManager.getDefault()
161: .getRegistry().getActivated();
162: MultiViewHandler mvh = MultiViews
163: .findMultiViewHandler(tc);
164:
165: if (mvh == null) {
166: return;
167: }
168:
169: // If model is broken
170: // OR if the resultItem.getComponents() is null which
171: // means the resultItem was generated when the model was broken.
172: // In the above cases switch to the source multiview.
173: if (resultItem.getModel().getState().equals(
174: State.NOT_WELL_FORMED)
175: || resultItem.getComponents() == null) {
176: for (int index1 = 0; index1 < mvh.getPerspectives().length; index1++) {
177: if (mvh.getPerspectives()[index1]
178: .preferredID()
179: .equals(
180: XSLTSourceMultiViewElementDesc.PREFERED_ID))
181: mvh
182: .requestActive(mvh
183: .getPerspectives()[index1]);
184: }
185: }
186:
187: //TODO a
188: // Set annotation or select element in the multiview.
189: // MultiViewPerspective mvp = mvh.getSelectedPerspective();
190: // if (mvp.preferredID().equals("xslt-designer")) {
191: // List<TopComponent> list = getAssociatedTopComponents();
192: // for (TopComponent topComponent : list) {
193: // // Make sure this is a multiview window, and not just
194: // // some
195: // // window that has our DataObject (e.g. Projects,Files).
196: // MultiViewHandler handler = MultiViews
197: // .findMultiViewHandler(topComponent);
198: // if (handler != null && topComponent != null) {
199: // SelectXsltElement selectElement =
200: // (SelectXsltElement) topComponent.getLookup()
201: // .lookup(SelectXsltElement.class);
202: // if (selectElement == null)
203: // return;
204: // selectElement.select(XSLTComponent);
205: // }
206: // }
207: // } else if (mvp.preferredID().equals("xslt-mapper")) {
208: // List<TopComponent> list = getAssociatedTopComponents();
209: // for (TopComponent topComponent : list) {
210: // // Make sure this is a multiview window, and not just
211: // // some
212: // // window that has our DataObject (e.g. Projects,Files).
213: // MultiViewHandler handler = MultiViews
214: // .findMultiViewHandler(topComponent);
215: // if (handler != null && topComponent != null) {
216: // SelectXsltElement selectElement =
217: // (SelectXsltElement) topComponent.getLookup()
218: // .lookup(SelectXsltElement.class);
219: // if (selectElement == null)
220: // return;
221: // selectElement.select(XSLTComponent);
222: // }
223: // }
224: // } else if (mvp.preferredID().equals(
225: // XSLTSourceMultiViewElementDesc.PREFERED_ID)) {
226: //
227: // // Get the line number.
228: // int lineNum;
229: // if(resultItem.getComponents() != null) {
230: // lineNum = getLineNumber((XSLTComponent)resultItem.getComponents());
231: // } else {
232: // lineNum = resultItem.getLineNumber() - 1;
233: // }
234: // if (lineNum < 1) {
235: // return;
236: // }
237: // Line l = lc.getLineSet().getCurrent(lineNum);
238: // l.show(Line.SHOW_GOTO);
239: // annotation.show(l, resultItem.getDescription());
240: //
241: // }
242: }
243: });
244:
245: }
246:
247: /**
248: * Supports one use case for one xsl file
249: * If xslt file is used more than one time than first use case will be returned
250: *
251: * @return MapperContext wrapped first founded use case
252: */
253: public MapperContext getMapperContext() {
254: return getEnv().getMapperContext();
255: }
256:
257: private List<TopComponent> getAssociatedTopComponents() {
258: // Create a list of TopComponents associated with the
259: // editor's schema data object, starting with the the
260: // active TopComponent. Add all open TopComponents in
261: // any mode that are associated with the DataObject.
262: // [Note that EDITOR_MODE does not contain editors in
263: // split mode.]
264: List<TopComponent> associatedTCs = new ArrayList<TopComponent>();
265: DataObject targetDO = getDataObject();
266: TopComponent activeTC = TopComponent.getRegistry()
267: .getActivated();
268: if (activeTC != null
269: && targetDO == (DataObject) activeTC.getLookup()
270: .lookup(DataObject.class)) {
271: associatedTCs.add(activeTC);
272: }
273: Set openTCs = TopComponent.getRegistry().getOpened();
274: for (Object tc : openTCs) {
275: TopComponent tcc = (TopComponent) tc;
276: if (targetDO == (DataObject) tcc.getLookup().lookup(
277: DataObject.class)) {
278: associatedTCs.add(tcc);
279: }
280: }
281: return associatedTCs;
282: }
283:
284: public boolean validateXML(CookieObserver observer) {
285: // TODO a
286: return true;
287: }
288:
289: protected CloneableEditorSupport.Pane createPane() {
290: TopComponent multiview = XsltMultiViewSupport
291: .createMultiView((XSLTDataObject) getDataObject());
292:
293: Mode editorMode = WindowManager.getDefault().findMode(
294: EDITOR_MODE);
295: if (editorMode != null) {
296: editorMode.dockInto(multiview);
297: }
298:
299: return (Pane) multiview;
300: }
301:
302: @Override
303: protected void notifyClosed() {
304: QuietUndoManager undo = getUndoManager();
305: StyledDocument doc = getDocument();
306: synchronized (undo) {
307: // May be null when closing the editor.
308: if (doc != null) {
309: doc.removeUndoableEditListener(undo);
310: undo.endCompound();
311: undo.setDocument(null);
312: }
313:
314: XslModel model = getXslModel();
315: if (model != null) {
316: model.removeUndoableEditListener(undo);
317: }
318: // Must unset the model when no longer listening to it.
319: undo.setModel(null);
320:
321: }
322: super .notifyClosed();
323: getUndoManager().discardAllEdits();
324:
325: // all editors are closed so we don't need to keep this task.
326: prepareTask = null;
327:
328: // getValidationController().detach();
329:
330: }
331:
332: /*
333: * This method is redefined for marking big TopCompenent as modified (
334: * asterik (*) needs to be appended to name of bpel file ). Without this
335: * overriding file will be marked as modified only when source multiview is
336: * edited. Modification in design view will not lead to marking TopComponent
337: * as modified. see bug description for #6421669. (non-Javadoc)
338: *
339: * @see org.openide.text.CloneableEditorSupport#updateTitles()
340: */
341: @Override
342: protected void updateTitles() {
343: /* This method is invoked by DataEditorSupport.DataNodeListener
344: * whenever the DataNode displayName property is changed. It is
345: * also called when the CloneableEditorSupport is (un)modified.
346: */
347:
348: // Let the superclass handle the CloneableEditor instances.
349: super .updateTitles();
350: // We need to get the title updated on the MultiViewTopComponent.
351: EventQueue.invokeLater(new Runnable() {
352:
353: public void run() {
354: List<TopComponent> list = getAssociatedTopComponents();
355: for (TopComponent topComponent : list) {
356: // Make sure this is a multiview window, and not just some
357: // window that has our DataObject (e.g. Projects, Files).
358: MultiViewHandler handler = MultiViews
359: .findMultiViewHandler(topComponent);
360: if (handler != null && topComponent != null) {
361: topComponent
362: .setHtmlDisplayName(messageHtmlName());
363: String name = messageName();
364: topComponent.setDisplayName(name);
365: topComponent.setName(name);
366: topComponent.setToolTipText(messageToolTip());
367: }
368: }
369: }
370: });
371: }
372:
373: protected XSLTEnv getEnv() {
374: return (XSLTEnv) env;
375: }
376:
377: @Override
378: protected UndoRedo.Manager createUndoRedoManager() {
379: // Override so the superclass will use our proxy undo manager
380: // instead of the default, then we can intercept edits.
381: return new QuietUndoManager(super .createUndoRedoManager());
382: // Note we cannot set the document on the undo manager right
383: // now, as CES is probably trying to open the document.
384: }
385:
386: /**
387: * Environment that connects the dataobject and ClonneableEditorSupport
388: */
389: private static class XSLTEnv extends DataEditorSupport.Env {
390:
391: private static final long serialVersionUID = 835762240381934851L;
392:
393: public XSLTEnv(XSLTDataObject dObj) {
394: super (dObj);
395: }
396:
397: public XSLTDataObject getXsltDataObject() {
398: return (XSLTDataObject) getDataObject();
399: }
400:
401: protected FileObject getFile() {
402: return getDataObject().getPrimaryFile();
403: }
404:
405: protected FileLock takeLock() throws IOException {
406: return ((MultiDataObject) getDataObject())
407: .getPrimaryEntry().takeLock();
408: }
409:
410: public MapperContext getMapperContext() {
411: FileObject xsltFo = getFile();
412: Project project = Util.getProject(xsltFo);
413:
414: MapperContext context = null;
415:
416: context = MapperContextFactory.getInstance()
417: .createMapperContext(xsltFo, project);
418:
419: // TODO m | r
420: //// FileObject xsltFo = getFile();
421: //// Project project = Util.getProject(xsltFo);
422: //// FileObject tMapFo = Util.getTMapFo(project);
423: //// FileObject projectRoot = Util.getProjectRoot(xsltFo);
424: //// XslModel xslModel = Util.getXslModel(xsltFo);
425: //// FileObject projectSource = Util.getProjectSource(project);
426: ////
427: //// if (tMapFo == null || projectRoot == null) {
428: //// // TODO m
429: //// try {
430: //// if (tMapFo == null) {
431: //// XmlUtil.createNewXmlFo(
432: //// projectSource.getPath(),
433: //// "transformmap",
434: //// TMapComponent.TRANSFORM_MAP_NS_URI);
435: //// }
436: //// return new MapperContextImpl(xslModel, Util.getTMapModel(tMapFo));
437: //// } catch (IOException ex) {
438: //// ErrorManager.getDefault().notify(ex);
439: //// return null;
440: //// }
441: //// }
442: ////
443: //// TMapModel tMapModel = Util.getTMapModel(tMapFo);
444: //// if (tMapModel == null) {
445: //// // TODO m
446: //// return new MapperContextImpl(xslModel, Util.getTMapModel(tMapFo));
447: //// }
448: ////
449: //// MapperContext mapperContext = null;
450: //// TransformMap root = tMapModel.getTransformMap();
451: //// List<Service> services = root.getServices();
452: //// Operation operation = null;
453: //// if (services != null) {
454: //// for (Service service : services) {
455: //// List<Operation> operations = service.getOperations();
456: //// for (Operation elem : operations) {
457: //// String file = elem.getFile();
458: //// if (file != null && file.equals(xsltFo.getPath().substring(projectSource.getPath().length())) ) {
459: //// operation = elem;
460: //// break;
461: //// }
462: //// }
463: //// if (operation != null) {
464: //// break;
465: //// }
466: //// }
467: //// }
468: ////
469: //// if (operation == null) {
470: //// // TODO m
471: //// return new MapperContextImpl(xslModel, Util.getTMapModel(tMapFo));
472: //// }
473: ////
474: ////
475: //// // TODO m
476: //// AXIComponent sourceComponent = null;//tDesc.getSourceAXIType(projectRoot);
477: //// AXIComponent targetComponent = null;//tDesc.getTargetAXIType(projectRoot);
478: //// // TODO m
479: //// mapperContext = new MapperContextImpl( operation, xslModel, sourceComponent, targetComponent);
480:
481: return context;
482: }
483: }
484:
485: public void initializeCloneableEditor(CloneableEditor editor) {
486: super .initializeCloneableEditor(editor);
487: // Force the title to update so the * left over from when the
488: // modified data object was discarded is removed from the title.
489: if (!getEnv().getXsltDataObject().isModified()) {
490: // Update later to avoid an infinite loop.
491: EventQueue.invokeLater(new Runnable() {
492: public void run() {
493: updateTitles();
494: }
495: });
496: }
497:
498: // TODO a
499: // /*
500: // * I put this code here because it is called each time when
501: // * editor is opened. This can happened omn first open,
502: // * on reopen, on deserialization.
503: // * CTOR of BPELDataEditorSupport is called only once due lifecycle
504: // * data object, so it cannot be used on attach after reopening.
505: // * Method "open" doesn't called after deser-ion.
506: // * But this method is called always on editor opening.
507: // */
508: // getValidationController().attach();
509: }
510:
511: @Override
512: public Task prepareDocument() {
513: Task task = super .prepareDocument();
514: // Avoid listening to the same task more than once.
515: if (task == prepareTask) {
516: return task;
517: }
518: task.addTaskListener(new TaskListener() {
519:
520: public void taskFinished(Task task) {
521: /* The superclass prepareDocument() adds the undo/redo
522: * manager as a listener -- we need to remove it since
523: * the views will add and remove it as needed.
524: */
525: QuietUndoManager undo = (QuietUndoManager) getUndoRedo();
526: StyledDocument doc = getDocument();
527: synchronized (undo) {
528: // Now that the document is ready, pass it to the manager.
529: undo.setDocument((AbstractDocument) doc);
530: if (!undo.isCompound()) {
531: /* The superclass prepareDocument() adds the undo/redo
532: * manager as a listener -- we need to remove it since
533: * we will initially listen to the model instead.
534: */
535: doc.removeUndoableEditListener(undo);
536: // If not listening to document, then listen to model.
537: addUndoManagerToModel(undo);
538: }
539: }
540: }
541: });
542: return task;
543: }
544:
545: @Override
546: public Task reloadDocument() {
547: Task task = super .reloadDocument();
548: task.addTaskListener(new TaskListener() {
549:
550: public void taskFinished(Task task) {
551: EventQueue.invokeLater(new Runnable() {
552:
553: public void run() {
554: QuietUndoManager undo = getUndoManager();
555: StyledDocument doc = getDocument();
556: /* The superclass reloadDocument() adds the undo
557: * manager as an undoable edit listener.
558: */
559: synchronized (undo) {
560: if (!undo.isCompound() && doc != null) {
561: doc.removeUndoableEditListener(undo);
562: }
563: }
564: }
565: });
566: }
567: });
568: return task;
569: }
570:
571: /**
572: * Adds the undo/redo manager to the document as an undoable edit listener,
573: * so it receives the edits onto the queue. The manager will be removed from
574: * the model as an undoable edit listener.
575: * <p>
576: * This method may be called repeatedly.
577: * </p>
578: */
579: public void addUndoManagerToDocument() {
580: /*
581: * This method may be called repeatedly.
582: * Stop the undo manager from listening to the model, as it will
583: * be listening to the document now.
584: */
585: QuietUndoManager undo = getUndoManager();
586: StyledDocument doc = getDocument();
587: synchronized (undo) {
588:
589: removeUndoManagerFromModel();
590:
591: /*
592: * Document may be null if the cloned views are not behaving
593: * correctly.
594: */
595: if (doc != null) {
596: // Ensure the listener is not added twice.
597: doc.removeUndoableEditListener(undo);
598: doc.addUndoableEditListener(undo);
599: /*
600: * Start the compound mode of the undo manager, such that when
601: * we are hidden, we will treat all of the edits as a single
602: * compound edit. This avoids having the user invoke undo
603: * numerous times when in the model view.
604: */
605: undo.beginCompound();
606: }
607: }
608: }
609:
610: /**
611: * Add the undo/redo manager undoable edit listener to the model.
612: * <p>
613: * Caller should synchronize on the undo manager prior to calling this
614: * method, to avoid thread concurrency issues.
615: * </p>
616: *
617: * @param undo
618: * the undo manager.
619: */
620: public void addUndoManagerToModel(QuietUndoManager undo) {
621: XslModel model = getXslModel();
622: if (model != null) {
623: // Ensure the listener is not added twice.
624: removeUndoManagerFromModel();
625: model.addUndoableEditListener(undo);
626: /* Ensure the model is sync'd when undo/redo is invoked,
627: * otherwise the edits are added to the queue and eventually
628: * cause exceptions.
629: */
630: undo.setModel(model);
631:
632: }
633: }
634:
635: /**
636: * Removes the undo/redo manager undoable edit listener from the document,
637: * to stop receiving undoable edits. The manager will be added to the model
638: * as an undoable edit listener.
639: * <p>
640: * This method may be called repeatedly.
641: * </p>
642: */
643: public void removeUndoManagerFromDocument() {
644: // This method may be called repeatedly.
645: QuietUndoManager undo = getUndoManager();
646: StyledDocument doc = getDocument();
647: synchronized (undo) {
648: // May be null when closing the editor.
649: if (doc != null) {
650: doc.removeUndoableEditListener(undo);
651: undo.endCompound();
652: }
653: // Have the undo manager listen to the model when it is not
654: // listening to the document.
655: addUndoManagerToModel(undo);
656: }
657: }
658:
659: /**
660: * Removes the undo/redo manager undoable edit listener from the bpel model,
661: * to stop receiving undoable edits.
662: */
663: private void removeUndoManagerFromModel() {
664: XslModel model = getXslModel();
665: if (model != null) {
666: QuietUndoManager undo = getUndoManager();
667: model.removeUndoableEditListener(undo);
668: // Must unset the model when leaving model view.
669: undo.setModel(null);
670: }
671: }
672:
673: /**
674: * Remove the undo manager from both the model and document, such that
675: * any changes made to either will not be added to the undo queue. The
676: * caller should invoke <code>resumeUndoRedo()</code> once the changes
677: * are completed.
678: *
679: * @return a value that must be passed to <code>resumeUndoRedo()</code>.
680: */
681: public boolean suspendUndoRedo() {
682: QuietUndoManager undo = getUndoManager();
683: boolean compound;
684: synchronized (undo) {
685: compound = undo.isCompound();
686: if (compound) {
687: removeUndoManagerFromDocument();
688: }
689: removeUndoManagerFromModel();
690: }
691: return compound;
692: }
693:
694: /**
695: * Add the undo manager as an undoable edit listener to either the
696: * Swing document or the XAM model, and set up the compound mode if
697: * that was in place previously.
698: *
699: * @param value value returned from <code>suspendUndoRedo()</code>
700: */
701: public void resumeUndoRedo(boolean value) {
702: if (value) {
703: addUndoManagerToDocument();
704: } else {
705: QuietUndoManager undo = getUndoManager();
706: synchronized (undo) {
707: addUndoManagerToModel(undo);
708: }
709: }
710: }
711:
712: private XslModelFactory getModelFactory() {
713: XslModelFactory factory = (XslModelFactory) Lookup.getDefault()
714: .lookup(XslModelFactory.class);
715: return factory;
716: }
717:
718: /**
719: * This method allows the close behavior of CloneableEditorSupport to be
720: * invoked from the SourceMultiViewElement. The close method of
721: * CloneableEditorSupport at least clears the undo queue and releases the
722: * swing document.
723: */
724: public boolean silentClose() {
725: return super .close(false);
726: }
727:
728: /**
729: * Handles closing of the MultiView component globally. Each opened {@link org.netbeans.core.spi.multiview.MultiViewElement}
730: * creates a {@link org.netbeans.core.spi.multiview.CloseOperationState} instance to notify the environment of it's internal state.
731: *
732: */
733: public static class CloseHandler implements CloseOperationHandler,
734: Serializable {
735:
736: private static final long serialVersionUID = -4621077799099893176L;
737:
738: private CloseHandler() {
739: // CTOR for deser
740: }
741:
742: public CloseHandler(XSLTDataObject obj) {
743: myDataObject = obj;
744: }
745:
746: public boolean resolveCloseOperation(
747: CloseOperationState[] elements) {
748: XSLTDataEditorSupport support = myDataObject == null ? null
749: : (XSLTDataEditorSupport) myDataObject
750: .getCookie(XSLTDataEditorSupport.class);
751: if (support == null) {
752: return true;
753: }
754: boolean close = support.canClose();
755: if (close) {
756: if (myDataObject.isValid()) {
757: // In odrer to clear the undo queue of orphaned edits, let's always
758: // reload the document, which discards the edits on the undo queue.
759: // The critical part is that BeforeSaveEdit gets added to the queue.
760: // // In case user discarded edits, need to reload.
761: // if (dataObject.isModified()) {
762: support.reloadDocument().waitFinished();
763: // }
764: }
765:
766: myDataObject.setModified(false); // Issue 85629
767: }
768: return close;
769: }
770:
771: private XSLTDataObject myDataObject;
772: }
773:
774: /** Used for managing the prepareTask listener. */
775: private transient Task prepareTask;
776:
777: private ValidationAnnotation myAnnotation = new ValidationAnnotation();
778: }
|