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-2006 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: package org.netbeans.modules.vmd.io;
042:
043: import org.netbeans.api.editor.fold.Fold;
044: import org.netbeans.api.editor.fold.FoldHierarchy;
045: import org.netbeans.modules.vmd.api.io.*;
046: import org.netbeans.modules.vmd.api.io.providers.DocumentSerializer;
047: import org.netbeans.modules.vmd.api.io.providers.IOSupport;
048: import org.netbeans.modules.vmd.api.model.DesignDocument;
049: import org.openide.DialogDisplayer;
050: import org.openide.NotifyDescriptor;
051: import org.openide.util.Lookup;
052: import org.openide.util.NbBundle;
053:
054: import javax.swing.*;
055: import java.util.HashMap;
056:
057: /**
058: * @author David Kaspar
059: */
060: public class CodeResolver implements DesignDocumentAwareness {
061:
062: private static final Lookup.Result<CodeGenerator> result = Lookup
063: .getDefault().lookupResult(CodeGenerator.class);
064:
065: private DataObjectContext context;
066: private DocumentSerializer serializer;
067: private volatile DesignDocument document;
068: private volatile long documentState = Long.MIN_VALUE;
069: private volatile DataEditorView.Kind viewKind;
070:
071: public CodeResolver(DataObjectContext context,
072: DocumentSerializer serializer) {
073: this .context = context;
074: this .serializer = serializer;
075: this .serializer.addDesignDocumentAwareness(this );
076: }
077:
078: public void resetModelModifiedStatus(DesignDocument document) {
079: if (this .document == null && document != null) {
080: this .document = document;
081: this .documentState = document.getListenerManager()
082: .getDocumentState();
083: }
084: }
085:
086: public void setDesignDocument(final DesignDocument designDocument) {
087: DataEditorView activeView = ActiveViewSupport.getDefault()
088: .getActiveView();
089: if (activeView == null)
090: return;
091: if (activeView.getContext() != context)
092: return;
093: update(designDocument, activeView.getKind());
094: }
095:
096: public void viewActivated(DataEditorView view) {
097: update(serializer.getDocument(), view.getKind());
098: }
099:
100: public void forceUpdateCode() {
101: update(serializer.getDocument(), null);
102: }
103:
104: private void update(final DesignDocument document,
105: final DataEditorView.Kind kind) {
106: if (document == null)
107: return;
108: if (kind != null && kind.equals(DataEditorView.Kind.NONE))
109: return;
110:
111: synchronized (this ) {
112: if (kind != null && kind.equals(viewKind))
113: return;
114:
115: boolean modelModified = CodeResolver.this .document != document
116: || CodeResolver.this .documentState != document
117: .getListenerManager().getDocumentState();
118: boolean editorSupportModified = IOSupport
119: .getCloneableEditorSupport(context.getDataObject())
120: .isModified();
121: boolean switchedFromModelToCode = kind != null
122: && kind.equals(DataEditorView.Kind.CODE)
123: && viewKind != null
124: && viewKind.equals(DataEditorView.Kind.MODEL);
125: final boolean switchedFromCodeToModel = kind != null
126: && kind.equals(DataEditorView.Kind.MODEL)
127: && viewKind != null
128: && viewKind.equals(DataEditorView.Kind.CODE);
129: final boolean regenerateSourceCode = editorSupportModified
130: && modelModified
131: && (switchedFromModelToCode || kind == null);
132:
133: if (!IOSupport.isDocumentUpdatingEnabled(context
134: .getDataObject())) {
135: if (regenerateSourceCode)
136: SwingUtilities.invokeLater(new Runnable() {
137: public void run() {
138: String lckFile = ".LCK"
139: + context.getDataObject()
140: .getPrimaryFile()
141: .getNameExt() + "~"; // NOI18N
142: DialogDisplayer
143: .getDefault()
144: .notifyLater(
145: new NotifyDescriptor.Message(
146: NbBundle
147: .getMessage(
148: CodeResolver.class,
149: "CodeResolver.locked",
150: lckFile) // NOI18N
151: ));
152: }
153: });
154: if (kind != null)
155: CodeResolver.this .viewKind = kind;
156: return;
157: }
158:
159: JEditorPane pane = null;
160: FoldHierarchy foldHierarchy = null;
161: HashMap<String, Boolean> foldStates = null;
162:
163: if (regenerateSourceCode) {
164: pane = findEditorPane();
165: if (pane != null) {
166: foldHierarchy = FoldHierarchy.get(pane);
167: foldStates = new HashMap<String, Boolean>();
168: }
169: }
170:
171: if (pane != null) {
172: storeFoldStates(foldHierarchy.getRootFold(), foldStates);
173: }
174:
175: final long eventID = document.getTransactionManager()
176: .writeAccess(new Runnable() {
177: public void run() {
178: if (regenerateSourceCode)
179: for (CodeGenerator generator : result
180: .allInstances())
181: generator
182: .validateModelForCodeGeneration(
183: context, document);
184:
185: if (switchedFromCodeToModel
186: || regenerateSourceCode)
187: for (CodeGenerator generator : result
188: .allInstances())
189: generator.updateModelFromCode(
190: context, document);
191: }
192: });
193:
194: CodeResolver.this .document = document;
195: if (regenerateSourceCode)
196: CodeResolver.this .documentState = eventID;
197: if (kind != null)
198: CodeResolver.this .viewKind = kind;
199:
200: if (regenerateSourceCode)
201: document.getTransactionManager().readAccess(
202: new Runnable() {
203: public void run() {
204: for (CodeGenerator generator : result
205: .allInstances())
206: generator.updateCodeFromModel(
207: context, document);
208: }
209: });
210:
211: if (pane != null)
212: loadFoldStates(foldHierarchy, foldHierarchy
213: .getRootFold(), foldStates);
214: }
215: }
216:
217: private void storeFoldStates(Fold fold,
218: HashMap<String, Boolean> foldStates) {
219: String description = fold.getDescription();
220: if ("custom-fold".equals(fold.getType().toString())
221: && description != null) // NOI18N
222: foldStates.put(description, fold.isCollapsed());
223: for (int a = 0; a < fold.getFoldCount(); a++)
224: storeFoldStates(fold.getFold(a), foldStates);
225: }
226:
227: private void loadFoldStates(FoldHierarchy foldHierarchy, Fold fold,
228: HashMap<String, Boolean> foldStates) {
229: String description = fold.getDescription();
230: if ("custom-fold".equals(fold.getType().toString())
231: && description != null) { // NOI18N
232: Boolean state = foldStates.get(description);
233: if (state != null && state != fold.isCollapsed()) {
234: if (state)
235: foldHierarchy.collapse(fold);
236: else
237: foldHierarchy.expand(fold);
238: }
239: }
240: for (int a = 0; a < fold.getFoldCount(); a++)
241: loadFoldStates(foldHierarchy, fold.getFold(a), foldStates);
242: }
243:
244: private JEditorPane findEditorPane() {
245: if (!SwingUtilities.isEventDispatchThread()) {
246: // Debug.warning ("Fold states cannot be restored since the code is invoke outside of AWT-thread"); // NOI18N
247: return null;
248: }
249: JEditorPane[] panes = context.getCloneableEditorSupport()
250: .getOpenedPanes();
251: if (panes == null || panes.length < 1) {
252: // Debug.warning ("No editor pane found for", context); // NOI18N
253: return null;
254: }
255: // else if (panes.length > 1)
256: // Debug.warning ("Multiple editor panes found for", context, "taking first one"); // NOI18N
257: return panes[0];
258: }
259:
260: public void notifyDataObjectClosed() {
261: serializer.removeDesignDocumentAwareness(this);
262: serializer = null;
263: context = null;
264: }
265:
266: }
|