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:
042: package threaddemo.data;
043:
044: import java.beans.PropertyChangeListener;
045: import java.beans.VetoableChangeListener;
046: import java.io.ByteArrayInputStream;
047: import java.io.ByteArrayOutputStream;
048: import java.io.IOException;
049: import java.io.InputStream;
050: import java.io.OutputStream;
051: import java.util.Date;
052: import org.openide.cookies.CloseCookie;
053: import org.openide.cookies.EditorCookie;
054: import org.openide.cookies.OpenCookie;
055: import org.openide.cookies.PrintCookie;
056: import org.openide.cookies.SaveCookie;
057: import org.openide.text.CloneableEditorSupport;
058: import org.openide.util.Task;
059: import org.openide.util.TaskListener;
060: import org.openide.windows.CloneableOpenSupport;
061: import threaddemo.model.Phadhail;
062:
063: /**
064: * An editor for phadhails.
065: * @author Jesse Glick
066: */
067: final class PhadhailEditorSupport extends CloneableEditorSupport
068: implements OpenCookie, CloseCookie, EditorCookie.Observable,
069: PrintCookie {
070:
071: private final Phadhail ph;
072: private SaveCookie modified = null;
073:
074: public PhadhailEditorSupport(Phadhail ph) {
075: this (ph, new PhadhailEnv(ph));
076: }
077:
078: private PhadhailEditorSupport(Phadhail ph, PhadhailEnv env) {
079: super (env);
080: if (ph.hasChildren())
081: throw new IllegalArgumentException();
082: this .ph = ph;
083: env.associate(this );
084: }
085:
086: protected String messageName() {
087: // XXX should listen for PhadhailNameEvent too
088: String n = ph.getName();
089: if (modified != null) {
090: n += " *";
091: }
092: return n;
093: }
094:
095: protected String messageOpened() {
096: return "Opened " + ph.getPath() + ".";
097: }
098:
099: protected String messageOpening() {
100: return "Opening " + ph.getPath() + "...";
101: }
102:
103: protected String messageSave() {
104: return "Saved " + ph.getPath() + ".";
105: }
106:
107: protected String messageToolTip() {
108: return ph.getPath();
109: }
110:
111: /**
112: * Same as default behavior in CES except solves a deadlock.
113: * The problem arises e.g. when first calling openDocument while
114: * holding a write lock: the prepareDocument task is posted to RP,
115: * where it starts to run but then Env.inputStream blocks getting
116: * a read lock.
117: */
118: public Task prepareDocument() {
119: // XXX hack no longer works after patch to CES; pD() not called from oD() + gD()
120: ((PhadhailEnv) env).preloadInputStream();
121: Task t = super .prepareDocument();
122: t.addTaskListener(new TaskListener() {
123: public void taskFinished(Task t) {
124: ((PhadhailEnv) env).forgetPreloadedInputStream();
125: }
126: });
127: return t;
128: }
129:
130: private static final class PhadhailEnv implements
131: CloneableEditorSupport.Env {
132:
133: private final Phadhail ph;
134: private PhadhailEditorSupport supp;
135: private final long createTime;
136: private byte[] preloadedContents = null;
137:
138: public PhadhailEnv(Phadhail ph) {
139: this .ph = ph;
140: createTime = System.currentTimeMillis();
141: }
142:
143: void associate(PhadhailEditorSupport supp) {
144: this .supp = supp;
145: }
146:
147: public CloneableOpenSupport findCloneableOpenSupport() {
148: return supp;
149: }
150:
151: public String getMimeType() {
152: return "text/plain";
153: }
154:
155: public Date getTime() {
156: return new Date(createTime);
157: }
158:
159: public void preloadInputStream() {
160: if (preloadedContents == null) {
161: try {
162: InputStream is = ph.getInputStream();
163: ByteArrayOutputStream baos = new ByteArrayOutputStream(
164: is.available());
165: byte[] buf = new byte[4096];
166: int read;
167: while ((read = is.read(buf)) != -1) {
168: baos.write(buf, 0, read);
169: }
170: preloadedContents = baos.toByteArray();
171: } catch (IOException e) {
172: // ignore, will show up later
173: e.printStackTrace();
174: }
175: }
176: }
177:
178: public void forgetPreloadedInputStream() {
179: preloadedContents = null;
180: }
181:
182: public InputStream inputStream() throws IOException {
183: if (preloadedContents != null) {
184: return new ByteArrayInputStream(preloadedContents);
185: } else {
186: return ph.getInputStream();
187: }
188: }
189:
190: public OutputStream outputStream() throws IOException {
191: return ph.getOutputStream();
192: }
193:
194: public boolean isModified() {
195: return supp.modified != null;
196: }
197:
198: public boolean isValid() {
199: // XXX a better model for Phadhail would have an isValid method
200: // and deleting it would set it to false...
201: return true;
202: }
203:
204: public void addPropertyChangeListener(PropertyChangeListener l) {
205: }
206:
207: public void addVetoableChangeListener(VetoableChangeListener l) {
208: }
209:
210: public void removePropertyChangeListener(
211: PropertyChangeListener l) {
212: }
213:
214: public void removeVetoableChangeListener(
215: VetoableChangeListener l) {
216: }
217:
218: public void markModified() throws IOException {
219: // For some mysterious reason this can be called repeatedly?
220: //assert supp.modified == null;
221: if (supp.modified == null) {
222: supp.modified = new Save();
223: PhadhailLookups.modified(ph, supp.modified);
224: }
225: }
226:
227: private final class Save implements SaveCookie {
228:
229: public void save() throws IOException {
230: supp.saveDocument();
231: }
232:
233: public String toString() {
234: return "Save[" + ph + "]";
235: }
236:
237: }
238:
239: public void unmarkModified() {
240: if (supp.modified != null) {
241: PhadhailLookups.saved(ph, supp.modified);
242: supp.modified = null;
243: }
244: }
245:
246: }
247:
248: }
|