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.api.io.providers;
042:
043: import org.netbeans.core.spi.multiview.MultiViewDescription;
044: import org.netbeans.modules.vmd.api.io.DataEditorView;
045: import org.netbeans.modules.vmd.api.io.DataObjectContext;
046: import org.netbeans.modules.vmd.api.io.ProjectUtils;
047: import org.netbeans.modules.vmd.api.io.serialization.DocumentErrorHandler;
048: import org.netbeans.modules.vmd.api.model.Debug;
049: import org.netbeans.modules.vmd.api.model.DesignDocument;
050: import org.netbeans.modules.vmd.api.model.DocumentInterface;
051: import org.netbeans.modules.vmd.io.CodeResolver;
052: import org.netbeans.modules.vmd.io.DataObjectContextImpl;
053: import org.netbeans.modules.vmd.io.DocumentLoad;
054: import org.netbeans.modules.vmd.io.editor.EditorViewDescription;
055: import org.netbeans.modules.vmd.io.editor.EditorViewElement;
056: import org.netbeans.modules.vmd.io.editor.EditorViewFactorySupport;
057: import org.netbeans.modules.vmd.io.editor.CodeEditorViewDescription;
058: import org.openide.DialogDescriptor;
059: import org.openide.DialogDisplayer;
060: import org.openide.filesystems.FileObject;
061: import org.openide.loaders.DataObject;
062: import org.openide.text.CloneableEditorSupport;
063: import org.openide.util.NbBundle;
064:
065: import javax.swing.*;
066: import java.util.ArrayList;
067: import java.util.Collection;
068: import java.util.WeakHashMap;
069:
070: /**
071: * Custom DataObject used by the IOSupport class must:
072: * <ul>
073: * <li>implement DataObjectInterface
074: * <li>contain CloneableEditorSupport in data object lookup
075: * <li>call notifyDataObjectClosed to notify about editor closing and therefore freeing related structure
076: * <li>optionally call forceUpdateCode to force editor synchronization with design document
077: * </ul>
078: *
079: * @author David Kaspar
080: */
081: public final class IOSupport {
082:
083: private IOSupport() {
084: }
085:
086: private static final WeakHashMap<DataObject, DataObjectContext> contexts = new WeakHashMap<DataObject, DataObjectContext>();
087: private static final WeakHashMap<DataObject, DocumentSerializer> serializers = new WeakHashMap<DataObject, DocumentSerializer>();
088: private static final WeakHashMap<DataObject, CodeResolver> resolvers = new WeakHashMap<DataObject, CodeResolver>();
089: private static final WeakHashMap<DataObject, Boolean> documentUpdating = new WeakHashMap<DataObject, Boolean>();
090:
091: /**
092: * Returns a data object context representing specified data object.
093: * @param dataObject the data object
094: * @return the data object context
095: */
096: public static synchronized DataObjectContext getDataObjectContext(
097: DataObject dataObject) {
098: DataObjectContext context = contexts.get(dataObject);
099: if (context == null) {
100: getDataObjectInteface(dataObject);
101: context = new DataObjectContextImpl(dataObject);
102: contexts.put(dataObject, context);
103: }
104: return context;
105: }
106:
107: /**
108: * Returns a document serializer related to specified data object.
109: * @param dataObject the data object
110: * @return the related document serializer
111: */
112: public static synchronized DocumentSerializer getDocumentSerializer(
113: DataObject dataObject) {
114: DocumentSerializer serializer = serializers.get(dataObject);
115: if (serializer == null) {
116: DataObjectContext context = getDataObjectContext(dataObject);
117: serializer = new DocumentSerializer(context);
118: serializers.put(dataObject, serializer);
119: resolvers.put(dataObject, new CodeResolver(context,
120: serializer));
121: }
122: return serializer;
123: }
124:
125: /**
126: * Force update of code. This is usually invoked immediately after a document is loaded and immediately a document is saved
127: * to keep the generated code synchronized with related design document.
128: * @param dataObject the data object
129: */
130: public static void forceUpdateCode(DataObject dataObject) {
131: CodeResolver resolver = resolvers.get(dataObject);
132: if (resolver != null) {
133: resolver.forceUpdateCode();
134: }
135: }
136:
137: /**
138: * Call this method to free all objects related to the data object that very assigned by the class.
139: * @param dataObject the data object
140: */
141: public static synchronized void notifyDataObjectClosed(
142: DataObject dataObject) {
143: documentUpdating.remove(dataObject);
144: CodeResolver resolver = resolvers.remove(dataObject);
145: if (resolver != null) {
146: resolver.notifyDataObjectClosed();
147: }
148: DocumentSerializer serializer = serializers.remove(dataObject);
149: if (serializer != null) {
150: serializer.notifyDataObjectClosed();
151: }
152: contexts.remove(dataObject);
153: }
154:
155: /**
156: * Returns data object interface for specified data object.
157: * DataObject must implement DataObjectInterface.
158: * @param dataObject the data object
159: * @return the data object interface
160: */
161: public static DataObjectInterface getDataObjectInteface(
162: DataObject dataObject) {
163: if (!(dataObject instanceof DataObjectInterface)) {
164: throw Debug
165: .illegalArgument(
166: "DataObject does not implement DataObjectInterface",
167: dataObject); // NOI18N
168: }
169: return (DataObjectInterface) dataObject;
170: }
171:
172: /**
173: * Returns a cloneable editor lookup for specified data object.
174: * The CloneableEditorSupport has to be in data object lookup.
175: * @param dataObject the data object
176: * @return the cloneable editor support
177: */
178: public static CloneableEditorSupport getCloneableEditorSupport(
179: DataObject dataObject) {
180: CloneableEditorSupport editorSupport = dataObject.getLookup()
181: .lookup(CloneableEditorSupport.class);
182: if (editorSupport == null) {
183: throw Debug
184: .illegalArgument(
185: "Missing CloneableEditorSupport in DataObject lookup",
186: dataObject); // NOI18N
187: }
188: return editorSupport;
189: }
190:
191: /**
192: * Returns the design file of specified data object context.
193: * @param context the data object context
194: * @return the design file object
195: */
196: public static FileObject getDesignFile(DataObjectContext context) {
197: return getDataObjectInteface(context.getDataObject())
198: .getDesignFile();
199: }
200:
201: /**
202: * Creates an array of multi view descriptions for editor support for a specified context.
203: * @param context the data object context
204: * @return the arra of multi view descriptions
205: */
206: public static MultiViewDescription[] createEditorSupportPane(
207: DataObjectContext context) {
208: Collection<DataEditorView> views = EditorViewFactorySupport
209: .createEditorViews(context);
210: ArrayList<EditorViewDescription> descriptions = new ArrayList<EditorViewDescription>();
211: for (DataEditorView view : views)
212: descriptions
213: .add(view.getKind() == DataEditorView.Kind.CODE ? new CodeEditorViewDescription(
214: context, view)
215: : new EditorViewDescription(context, view));
216: return descriptions
217: .toArray(new MultiViewDescription[descriptions.size()]);
218: }
219:
220: /**
221: * Returns data editor view instance assigned to a multi view description.
222: * @param description the description
223: * @return the data editor view
224: */
225: public static DataEditorView getDataEditorView(
226: MultiViewDescription description) {
227: return description instanceof EditorViewDescription ? ((EditorViewDescription) description)
228: .getView()
229: : null;
230: }
231:
232: /**
233: * Returns a data object context for specified document
234: * @param document the design document
235: * @return the data object context
236: */
237: // TODO - should be hidden - used by ProjectUtils.getDataObjectContextForDocument method only
238: public static synchronized DataObjectContext getDataObjectContextForDocumentInterface(
239: DesignDocument document) {
240: assert Debug.isFriend(ProjectUtils.class,
241: "getDataObjectContextForDocument"); // NOI18N
242: DocumentInterface documentInterface = document
243: .getDocumentInterface();
244: for (DataObject dataObject : serializers.keySet()) {
245: if (dataObject == null) {
246: continue;
247: }
248: DocumentSerializer documentSerializer = getDocumentSerializer(dataObject); // TODO - use direct access to serializers field
249: if (documentSerializer
250: .hasDocumentInterface(documentInterface)) {
251: return getDataObjectContext(dataObject);
252: }
253: }
254: return null;
255: }
256:
257: // TODO - should be hidden - used by EditorViewElement.componentActivated method only
258: public static void notifyDataEditorViewActivated(
259: DataEditorView activatedView) {
260: assert Debug.isFriend(EditorViewElement.class,
261: "componentActivated"); // NOI18N
262: if (activatedView == null) {
263: return;
264: }
265: CodeResolver resolver = resolvers.get(activatedView
266: .getContext().getDataObject());
267: resolver.viewActivated(activatedView);
268: }
269:
270: /**
271: * Loads the document and resolves the project type of the document.
272: * @param context the context
273: * @return the project type
274: */
275: public static String resolveProjectType(DataObjectContext context) {
276: return DocumentLoad.loadProjectType(context);
277: }
278:
279: static void resetCodeResolver(DataObject dataObject,
280: DesignDocument document) {
281: CodeResolver resolver = resolvers.get(dataObject);
282: resolver.resetModelModifiedStatus(document);
283: }
284:
285: /**
286: * Returns whether a document updating is enabled.
287: * @param dataObject the data object
288: * @return true, if enabled
289: */
290: public static boolean isDocumentUpdatingEnabled(
291: DataObject dataObject) {
292: Boolean enabled = documentUpdating.get(dataObject);
293: return enabled != null && enabled;
294: }
295:
296: /**
297: * Sets whether a document updating is enabled.
298: * @param dataObject the data object
299: * @param enabled if true, then enabled
300: */
301: public static void setDocumentUpdatingEnabled(
302: DataObject dataObject, boolean enabled) {
303: documentUpdating.put(dataObject, enabled);
304: }
305:
306: }
|