001: /*
002: * Sun Public License Notice
003: *
004: * The contents of this file are subject to the Sun Public License
005: * Version 1.0 (the "License"). You may not use this file except in
006: * compliance with the License. A copy of the License is available at
007: * http://www.sun.com/
008: *
009: * The Original Code is NetBeans. The Initial Developer of the Original
010: * Code is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
011: * Microsystems, Inc. All Rights Reserved.
012: If you wish your version of this file to be governed by only the CDDL
013: or only the GPL Version 2, indicate your decision by adding
014: "[Contributor] elects to include this software in this distribution
015: under the [CDDL or GPL Version 2] license." If you do not indicate a
016: single choice of license, a recipient has the option to distribute
017: your version of this file under either the CDDL, the GPL Version 2 or
018: to extend the choice of license to its licensees as provided above.
019: However, if you add GPL Version 2 code and therefore, elected the GPL
020: Version 2 license, then the option applies only if the new code is
021: made subject to such option by the copyright holder.
022: If you wish your version of this file to be governed by only the CDDL
023: or only the GPL Version 2, indicate your decision by adding
024: "[Contributor] elects to include this software in this distribution
025: under the [CDDL or GPL Version 2] license." If you do not indicate a
026: single choice of license, a recipient has the option to distribute
027: your version of this file under either the CDDL, the GPL Version 2 or
028: to extend the choice of license to its licensees as provided above.
029: However, if you add GPL Version 2 code and therefore, elected the GPL
030: Version 2 license, then the option applies only if the new code is
031: made subject to such option by the copyright holder.
032: */
033: package org.netbeans.modules.etl.ui;
034:
035: import java.awt.EventQueue;
036: import java.io.IOException;
037: import java.io.Serializable;
038: import java.util.Enumeration;
039: import javax.swing.SwingUtilities;
040: import javax.swing.text.Document;
041: import org.netbeans.core.api.multiview.MultiViewHandler;
042: import org.netbeans.core.api.multiview.MultiViewPerspective;
043: import org.netbeans.core.api.multiview.MultiViews;
044: import org.netbeans.core.spi.multiview.CloseOperationHandler;
045: import org.netbeans.core.spi.multiview.CloseOperationState;
046: import org.netbeans.modules.etl.ui.model.impl.ETLCollaborationModel;
047: import org.openide.ErrorManager;
048: import org.openide.awt.UndoRedo;
049: import org.openide.cookies.CloseCookie;
050: import org.openide.cookies.EditCookie;
051: import org.openide.cookies.EditorCookie;
052: import org.openide.cookies.LineCookie;
053: import org.openide.cookies.OpenCookie;
054: import org.openide.cookies.PrintCookie;
055: import org.openide.filesystems.FileLock;
056: import org.openide.filesystems.FileObject;
057: import org.openide.loaders.DataObject;
058: import org.openide.text.CloneableEditorSupport;
059: import org.openide.text.DataEditorSupport;
060: import org.openide.util.Task;
061: import org.openide.windows.CloneableTopComponent;
062: import org.openide.windows.Mode;
063: import org.openide.windows.TopComponent;
064: import org.openide.windows.WindowManager;
065: import com.sun.sql.framework.exception.BaseException;
066:
067: import java.util.List;
068: import org.netbeans.modules.sql.framework.model.ValidationInfo;
069: import org.openide.awt.StatusDisplayer;
070:
071: /**
072: *
073: * @author Ahimanikya Satapathy
074: */
075: public class ETLEditorSupport extends DataEditorSupport implements
076: OpenCookie, EditCookie, EditorCookie.Observable, LineCookie,
077: CloseCookie, PrintCookie {
078:
079: public ETLEditorSupport(ETLDataObject sobj) {
080: super (sobj, new ETLEditorEnv(sobj));
081: setMIMEType(ETLDataLoader.MIME_TYPE);
082: PRJ_PATH = sobj.getFolder().getPrimaryFile().getParent()
083: .getPath();
084: PRJ_PATH = PRJ_PATH.replace('/', '\\');
085: PRJ_NAME = sobj.getFolder().getPrimaryFile().getParent()
086: .getName();
087: }
088:
089: public ETLEditorEnv getEnv() {
090: return (ETLEditorEnv) env;
091: }
092:
093: @Override
094: protected Pane createPane() {
095: multiviewTC = ETLMultiViewFactory
096: .createMultiView((ETLDataObject) getDataObject());
097: multiviewTC.setName(getDataObject().getPrimaryFile()
098: .getNameExt());
099:
100: Mode editorMode = WindowManager.getDefault().findMode(
101: ETLEditorSupport.EDITOR_MODE);
102: if (editorMode != null) {
103: editorMode.dockInto(multiviewTC);
104: }
105: return (Pane) multiviewTC;
106: }
107:
108: /**
109: * This is called by the multiview elements whenever they are created
110: * (and given a observer knowing their multiview TopComponent). It is
111: * important during deserialization and clonig the multiview - i.e. during
112: * the operations we have no control over. But anytime a multiview is
113: * created, this method gets called.
114: *
115: * @param topComp TopComponent to which we are associated.
116: */
117: public void setTopComponent(TopComponent mvtc) {
118: this .multiviewTC = mvtc;
119:
120: // Force the title to update so the * left over from when the
121: // modified data object was discarded is removed from the title.
122: // It is okay for this to be invoked multiple times.
123: if (!getEnv().getETLDataObject().isModified()) {
124: // Update later to avoid a loop.
125: EventQueue.invokeLater(new Runnable() {
126:
127: public void run() {
128: updateTitles();
129: }
130: });
131: }
132: }
133:
134: public static boolean isLastView(TopComponent tc) {
135:
136: if (!(tc instanceof CloneableTopComponent)) {
137: return false;
138: }
139: boolean oneOrLess = true;
140: Enumeration en = ((CloneableTopComponent) tc).getReference()
141: .getComponents();
142: if (en.hasMoreElements()) {
143: en.nextElement();
144: if (en.hasMoreElements()) {
145: oneOrLess = false;
146: }
147: }
148:
149: return oneOrLess;
150: }
151:
152: @Override
153: protected void updateTitles() {
154: // This method is invoked by DataEditorSupport.DataNodeListener
155: // whenever the DataNode displayName property is changed. It is
156: // also called when the CloneableEditorSupport is (un)modified.
157: // Let the superclass handle the CloneableEditor instances.
158: super .updateTitles();
159:
160: // We need to get the title updated on the MultiViewTopComponent.
161: EventQueue.invokeLater(new Runnable() {
162:
163: public void run() {
164: if (multiviewTC != null) {
165: multiviewTC.setHtmlDisplayName(messageHtmlName());
166: String name = messageName();
167: multiviewTC.setDisplayName(name);
168: multiviewTC.setName(name);
169: multiviewTC.setToolTipText(messageToolTip());
170: }
171: }
172: });
173: }
174:
175: /**
176: * Returns the UndoRedo.Manager instance managed by this editor support.
177: *
178: * @return UndoRedo.Manager instance.
179: */
180: public UndoRedo.Manager getUndoManager() {
181: return super .getUndoRedo();
182: }
183:
184: @Override
185: protected Task reloadDocument() {
186: Task task = super .reloadDocument();
187: EventQueue.invokeLater(new Runnable() {
188:
189: public void run() {
190: // Remove the undo listener only if columns view is showing.
191: if (multiviewTC != null) {
192: MultiViewHandler mvh = MultiViews
193: .findMultiViewHandler(multiviewTC);
194: if (mvh != null) {
195: MultiViewPerspective mvp = mvh
196: .getSelectedPerspective();
197: if (mvp != null) {
198: if (mvp
199: .preferredID()
200: .contains(
201: ETLEditorViewMultiViewDesc.PREFERRED_ID)) {
202: Document doc = getDocument();
203: UndoRedo.Manager urm = getUndoRedo();
204: if (doc != null && urm != null) {
205: doc.removeUndoableEditListener(urm);
206: }
207: }
208: }
209: }
210: }
211: }
212: });
213: return task;
214: }
215:
216: /**
217: * Have the schema model sync with the document.
218: */
219: public void syncModel() {
220: // Only sync the document if the change relates to loss of focus,
221: // which indicates that we are switching from the source view.
222: // Update the tree with the modified text.
223: try {
224: ETLDataObject etlDataObject = (ETLDataObject) getDataObject();
225: ETLCollaborationModel collabModel = etlDataObject
226: .getModel();
227: collabModel.getUndoManager().discardAllEdits();
228:
229: openDocument();
230: String defnContent = getDocument().getText(0,
231: getDocument().getLength());
232: collabModel.reLoad(defnContent);
233: // is below required?
234: collabModel.setReloaded(true);
235: populateCanvas(etlDataObject, collabModel);
236: isFirstTime = false;
237:
238: // Validate the collabModel and update badge
239: updateBadge(etlDataObject);
240: } catch (Throwable ioe) {
241: // The document cannot be parsed
242: ErrorManager.getDefault().notify(ioe);
243: StatusDisplayer.getDefault().setStatusText(
244: "syncModel: " + ioe.getMessage());
245: }
246: }
247:
248: /**
249: * Populates eTL editor canvas using information from given ETLCollaborationModel.
250: *
251: * @param collabModel
252: * @param disableMods
253: * @throws BaseException
254: */
255: private void populateCanvas(final ETLDataObject etlDataObject,
256: final ETLCollaborationModel collabModel)
257: throws BaseException {
258: Runnable run = new Runnable() {
259:
260: public void run() {
261: try {
262: etlDataObject.getETLEditorTopPanel().getGraphView()
263: .clearAll();
264: collabModel.restoreUIState();
265: } catch (Exception ex) {
266: ErrorManager.getDefault().notify(ex);
267: }
268: }
269: };
270:
271: SwingUtilities.invokeLater(run);
272: }
273:
274: public void synchDocument() {
275: //syn source view
276: //TODO: rit we should create etl defininition model based on swing document
277: // and there add document listeber to keeep model in synch with text editing.
278: //all update model incrementally
279: try {
280: ETLDataObject etlDataObject = (ETLDataObject) getDataObject();
281: String content = etlDataObject.getETLDefinition()
282: .toXMLString("");
283: Document doc = getDocument();
284: if (doc != null) {
285: doc.remove(0, getDocument().getLength());
286: doc.insertString(0, content, null);
287: }
288: etlDataObject.getModel().setDirty(false);
289: updateBadge(etlDataObject);
290: } catch (Exception ex) {
291: ErrorManager.getDefault().notify(ex);
292: }
293: }
294:
295: private void updateBadge(ETLDataObject etlDataObject) {
296: try {
297: List<ValidationInfo> list = etlDataObject
298: .getETLDefinition().badgeValidate();
299: int errCount = 0;
300: for (ValidationInfo vInfo : list) {
301: if (vInfo.getValidationType() == ValidationInfo.VALIDATION_ERROR) {
302: errCount++;
303: }
304: }
305: ETLNode node = (ETLNode) etlDataObject.getNodeDelegate();
306:
307: if (errCount > 0) {
308: node.setCollabState(ETLNode.ERROR);
309: } else if (!list.isEmpty()) {
310: node.setCollabState(ETLNode.WARNING);
311: } else {
312: node.setCollabState(ETLNode.VALID);
313: }
314: multiviewTC.setIcon(node.getIcon(0));
315:
316: } catch (Exception ex) {
317: ErrorManager.getDefault().notify(ex);
318: }
319: }
320:
321: /**
322: * Env class extends SchemaEditorSupport.Env.
323: * overrides findSchemaEditorSupport
324: *
325: */
326: protected static class ETLEditorEnv extends DataEditorSupport.Env {
327:
328: static final long serialVersionUID = 1099957785497677206L;
329:
330: public ETLEditorEnv(ETLDataObject obj) {
331: super (obj);
332: }
333:
334: public CloneableEditorSupport findTextEditorSupport() {
335: return getETLDataObject().getETLEditorSupport();
336: }
337:
338: public ETLDataObject getETLDataObject() {
339: return (ETLDataObject) getDataObject();
340: }
341:
342: @Override
343: protected FileObject getFile() {
344: return getDataObject().getPrimaryFile();
345: }
346:
347: @Override
348: protected FileLock takeLock() throws IOException {
349: return getDataObject().getPrimaryFile().lock();
350: }
351: }
352:
353: /**
354: * Implementation of CloseOperationHandler for multiview. Ensures both
355: * column view and xml editor are correctly closed, data saved, etc. Holds
356: * a reference to Schema DataObject only - to be serializable with the
357: * multiview TopComponent without problems.
358: */
359: public static class CloseHandler extends Object implements
360: CloseOperationHandler, Serializable {
361:
362: private CloseHandler() {
363: super ();
364: }
365:
366: public CloseHandler(DataObject schemaDO) {
367: dataObject = schemaDO;
368: }
369:
370: private ETLEditorSupport getETLEditorSupport() {
371: return dataObject != null
372: && dataObject instanceof ETLDataObject ? ((ETLDataObject) dataObject)
373: .getETLEditorSupport()
374: : null;
375: }
376:
377: public boolean resolveCloseOperation(
378: CloseOperationState[] elements) {
379: ETLEditorSupport etlEditor = getETLEditorSupport();
380: if (etlEditor != null) {
381: // This handles saving the document.
382: boolean close = etlEditor.canClose();
383: if (close) {
384: if (dataObject.isValid()) {
385: // In case user discarded edits, need to reload.
386: if (dataObject.isModified()) {
387: // In case user discarded edits, need to reload.
388: etlEditor.reloadDocument().waitFinished();
389: }
390:
391: etlEditor.syncModel();
392: // Need to properly close the support, too.
393: etlEditor.notifyClosed();
394: }
395: }
396: return close;
397: }
398: return true;
399: }
400:
401: private static final long serialVersionUID = -3838395157610633251L;
402: private DataObject dataObject;
403: }
404:
405: /**
406: * The embracing multiview TopComponent (holds the ColumnView and
407: * schema xml editor) - we remeber the last active TopComponent
408: * (not all clones)
409: */
410: private TopComponent multiviewTC;
411: public boolean isFirstTime = true;
412: public static String PRJ_PATH = "";
413: public static String PRJ_NAME = "";
414: }
|