KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > j2ee > ddloaders > common > xmlutils > XMLJ2eeEditorSupport


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.j2ee.ddloaders.common.xmlutils;
21
22 import java.awt.Dialog JavaDoc;
23 import java.io.BufferedReader JavaDoc;
24 import java.io.BufferedWriter JavaDoc;
25 import java.io.ByteArrayOutputStream JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.InputStream JavaDoc;
28 import java.io.InputStreamReader JavaDoc;
29 import java.io.OutputStream JavaDoc;
30 import java.io.OutputStreamWriter JavaDoc;
31 import java.io.Reader JavaDoc;
32 import java.io.UnsupportedEncodingException JavaDoc;
33 import java.io.Writer JavaDoc;
34 import java.nio.charset.Charset JavaDoc;
35 import java.nio.charset.CharsetEncoder JavaDoc;
36 import javax.swing.text.BadLocationException JavaDoc;
37 import javax.swing.text.EditorKit JavaDoc;
38 import javax.swing.text.StyledDocument JavaDoc;
39
40 import org.netbeans.modules.xml.api.EncodingUtil;
41 import org.openide.DialogDescriptor;
42 import org.openide.DialogDisplayer;
43 import org.openide.ErrorManager;
44 import org.openide.NotifyDescriptor;
45 import org.openide.awt.StatusDisplayer;
46 import org.openide.awt.UndoRedo;
47 import org.openide.cookies.CloseCookie;
48 import org.openide.cookies.EditCookie;
49 import org.openide.cookies.EditorCookie;
50 import org.openide.cookies.LineCookie;
51 import org.openide.cookies.PrintCookie;
52 import org.openide.cookies.SaveCookie;
53 import org.openide.filesystems.FileLock;
54 import org.openide.filesystems.FileObject;
55 import org.openide.text.DataEditorSupport;
56 import org.openide.text.NbDocument;
57 import org.openide.util.NbBundle;
58 import org.openide.util.RequestProcessor;
59 import org.openide.windows.CloneableOpenSupport;
60
61 /** Support for editing a XMLJ2eeDataObject as text.
62  *
63  * @author mkuchtiak
64  */

65 public class XMLJ2eeEditorSupport extends DataEditorSupport
66         implements EditCookie, EditorCookie.Observable,/* OpenCookie, */LineCookie, CloseCookie, PrintCookie {
67     
68     /** Delay for automatic parsing - in milliseconds */
69     private static final int AUTO_PARSING_DELAY = 2000;
70     private DialogDescriptor dialog;
71     private RequestProcessor.Task parsingDocumentTask;
72     XMLJ2eeDataObject dataObject;
73
74     /** Create a new editor support.
75      * @param obj the data object whose primary file will be edited as text
76      */

77     public XMLJ2eeEditorSupport(XMLJ2eeDataObject obj) {
78         super (obj, new XmlEnv (obj));
79         dataObject=obj;
80         
81         // Set a MIME type as needed, e.g.:
82
setMIMEType ("text/xml"); // NOI18N
83
}
84     
85     /**
86      * Overridden method from CloneableEditorSupport.
87      */

88     protected void saveFromKitToStream (StyledDocument JavaDoc doc, EditorKit JavaDoc kit,
89                                             OutputStream JavaDoc stream)
90                     throws IOException JavaDoc, BadLocationException JavaDoc {
91         // kit and kit() are not accessible so we pretend
92
// to create the kit; actually this should just return kit.
93
EditorKit JavaDoc k = this.createEditorKit();
94         OutputStreamWriter JavaDoc osw = new OutputStreamWriter JavaDoc(stream, "UTF8"); // NOI18N
95
Writer JavaDoc writer = new BufferedWriter JavaDoc(osw);
96         k.write(writer, doc, 0, doc.getLength());
97         writer.close();
98     }
99  
100     /**
101      * Overridden method from CloneableEditorSupport.
102      */

103     protected void loadFromStreamToKit (StyledDocument JavaDoc doc, InputStream JavaDoc stream,
104                                             EditorKit JavaDoc kit)
105                     throws IOException JavaDoc, BadLocationException JavaDoc {
106         // kit and kit() are not accessible so we pretend
107
// to create the kit; actually this should just return kit.
108
EditorKit JavaDoc k = this.createEditorKit();
109         InputStreamReader JavaDoc isr = new InputStreamReader JavaDoc(stream, "UTF8"); // NOI18N
110
Reader JavaDoc reader = new BufferedReader JavaDoc(isr);
111         k.read(reader, doc, 0);
112         reader.close();
113     }
114
115     /** Restart the timer which starts the parser after the specified delay.
116     * @param onlyIfRunning Restarts the timer only if it is already running
117     */

118     public void restartTimer() {
119         //System.out.println("XMLJ2eeEditorSupport:restartTimer "+this.hashCode());
120
dataObject.setDocumentDirty(true);
121         Runnable JavaDoc r = new Runnable JavaDoc() {
122             public void run() {
123                 dataObject.parsingDocument();
124             }
125     };
126         if (parsingDocumentTask==null || parsingDocumentTask.isFinished() ||
127             parsingDocumentTask.cancel()) {
128             parsingDocumentTask = RequestProcessor.getDefault().post(r,100);
129         } else {
130             parsingDocumentTask = RequestProcessor.getDefault().post(r,AUTO_PARSING_DELAY);
131         }
132     }
133
134     /** Called when the document is modified.
135      * Here, adding a save cookie to the object and marking it modified.
136      * @return true if the modification is acceptable
137      */

138     protected boolean notifyModified () {
139         boolean notif = super.notifyModified();
140         if (!notif){
141             return false;
142         }
143         XMLJ2eeDataObject obj = (XMLJ2eeDataObject) getDataObject ();
144         //System.out.println("notifyModified(), nodeDirty="+obj.isNodeDirty());
145
if (obj.getCookie (SaveCookie.class) == null) {
146             obj.addSaveCookie (new Save ());
147         }
148         if (!obj.isNodeDirty()) restartTimer();
149         return true;
150     }
151
152     /** Called when the document becomes unmodified.
153      * Here, removing the save cookie from the object and marking it unmodified.
154      */

155     protected void notifyUnmodified () {
156         super.notifyUnmodified ();
157         XMLJ2eeDataObject obj = (XMLJ2eeDataObject) getDataObject ();
158         obj.removeSaveCookie();
159     }
160
161     /** A save cookie to use for the editor support.
162      * When saved, saves the document to disk and marks the object unmodified.
163      */

164     private class Save implements SaveCookie {
165         
166         public void save () throws IOException JavaDoc {
167             XMLJ2eeDataObject obj = (XMLJ2eeDataObject) getDataObject ();
168             if (obj.isDocumentValid()) {
169                 obj.setSavingDocument(true);
170                 saveDocument();
171             }else {
172                 obj.displayErrorMessage();
173                 dialog = new DialogDescriptor(
174                     NbBundle.getMessage (XMLJ2eeEditorSupport.class, "MSG_invalidXmlWarning"),
175                     NbBundle.getMessage (XMLJ2eeEditorSupport.class, "TTL_invalidXmlWarning"));
176                 Dialog JavaDoc d = DialogDisplayer.getDefault().createDialog(dialog);
177                 d.setVisible(true);
178                 if (dialog.getValue() == DialogDescriptor.OK_OPTION) {
179                     obj.setSavingDocument(true);
180                     saveDocument();
181                 }
182             }
183         }
184     }
185     /*
186      * Save document using encoding declared in XML prolog if possible otherwise
187      * at UTF-8 (in such case it updates the prolog).
188      */

189     public void saveDocument () throws IOException JavaDoc {
190         final StyledDocument JavaDoc doc = getDocument();
191         // dependency on xml/core
192
String JavaDoc enc = EncodingUtil.detectEncoding(doc);
193         if (enc == null) enc = "UTF8"; //!!! // NOI18N
194

195         try {
196             //test encoding on dummy stream
197
new OutputStreamWriter JavaDoc(new ByteArrayOutputStream JavaDoc(1), enc);
198             if (!checkCharsetConversion(enc)) {
199                 return;
200             }
201             super.saveDocument();
202             //moved from Env.save()
203
getDataObject().setModified (false);
204         } catch (UnsupportedEncodingException JavaDoc ex) {
205             // ask user what next?
206
String JavaDoc message = NbBundle.getMessage(XMLJ2eeEditorSupport.class,"TEXT_SAVE_AS_UTF", enc);
207             NotifyDescriptor descriptor = new NotifyDescriptor.Confirmation(message);
208             Object JavaDoc res = DialogDisplayer.getDefault().notify(descriptor);
209
210             if (res.equals(NotifyDescriptor.YES_OPTION)) {
211
212                 // update prolog to new valid encoding
213

214                 try {
215                     final int MAX_PROLOG = 1000;
216                     int maxPrologLen = Math.min(MAX_PROLOG, doc.getLength());
217                     final char prolog[] = doc.getText(0, maxPrologLen).toCharArray();
218                     int prologLen = 0; // actual prolog length
219

220                     //parse prolog and get prolog end
221
if (prolog[0] == '<' && prolog[1] == '?' && prolog[2] == 'x') {
222
223                         // look for delimitting ?>
224
for (int i = 3; i<maxPrologLen; i++) {
225                             if (prolog[i] == '?' && prolog[i+1] == '>') {
226                                 prologLen = i + 1;
227                                 break;
228                             }
229                         }
230                     }
231
232                     final int passPrologLen = prologLen;
233
234                     Runnable JavaDoc edit = new Runnable JavaDoc() {
235                          public void run() {
236                              try {
237
238                                 doc.remove(0, passPrologLen + 1); // +1 it removes exclusive
239
doc.insertString(0, "<?xml version='1.0' encoding='UTF-8' ?> \n<!-- was: " + new String JavaDoc(prolog, 0, passPrologLen + 1) + " -->", null); // NOI18N
240

241                              } catch (BadLocationException JavaDoc e) {
242                                  if (System.getProperty("netbeans.debug.exceptions") != null) // NOI18N
243
e.printStackTrace();
244                              }
245                          }
246                     };
247
248                     NbDocument.runAtomic(doc, edit);
249
250                     super.saveDocument();
251                     //moved from Env.save()
252
getDataObject().setModified (false);
253
254                 } catch (BadLocationException JavaDoc lex) {
255                     ErrorManager.getDefault().notify(lex);
256                 }
257
258             } else { // NotifyDescriptor != YES_OPTION
259
return;
260             }
261         }
262     }
263     
264     private boolean checkCharsetConversion(final String JavaDoc encoding) {
265         boolean value = true;
266         try {
267             CharsetEncoder JavaDoc coder = Charset.forName(encoding).newEncoder();
268             if (!coder.canEncode(getDocument().getText(0, getDocument().getLength()))){
269                 NotifyDescriptor nd = new NotifyDescriptor.Confirmation(
270                         NbBundle.getMessage(XMLJ2eeEditorSupport.class, "MSG_BadCharConversion",
271                         new Object JavaDoc [] { getDataObject().getPrimaryFile().getNameExt(),
272                         encoding}),
273                         NotifyDescriptor.YES_NO_OPTION,
274                         NotifyDescriptor.WARNING_MESSAGE);
275                 nd.setValue(NotifyDescriptor.NO_OPTION);
276                 DialogDisplayer.getDefault().notify(nd);
277                 if(nd.getValue() != NotifyDescriptor.YES_OPTION) {
278                     value = false;
279                 }
280             }
281         } catch (BadLocationException JavaDoc e){
282             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
283         }
284         return value;
285     }
286     
287     public UndoRedo.Manager getUndo(){
288         return getUndoRedo();
289     }
290     
291     /** Constructs message that should be used to name the editor component.
292     *
293     * @return name of the editor
294     */

295     protected String JavaDoc messageName () {
296         String JavaDoc name = super.messageName();
297         int index1 = name.indexOf('[');
298         
299         if (index1>=0) {
300             String JavaDoc prefix = name.substring(0,index1);
301             int index2 = name.lastIndexOf(']');
302             String JavaDoc postfix="";
303             if (index2>=0) postfix = name.substring(index2+1);
304             return prefix+postfix;
305         }
306         return name;
307     }
308
309     /** A description of the binding between the editor support and the object.
310      * Note this may be serialized as part of the window system and so
311      * should be static, and use the transient modifier where needed.
312      */

313     private static class XmlEnv extends DataEditorSupport.Env {
314
315         private static final long serialVersionUID = -800036748848958489L;
316
317         //private static final long serialVersionUID = ...L;
318

319         /** Create a new environment based on the data object.
320          * @param obj the data object to edit
321          */

322         public XmlEnv (XMLJ2eeDataObject obj) {
323             super (obj);
324         }
325
326         /** Get the file to edit.
327          * @return the primary file normally
328          */

329         protected FileObject getFile () {
330             return getDataObject ().getPrimaryFile ();
331         }
332
333         /** Lock the file to edit.
334          * Should be taken from the file entry if possible, helpful during
335          * e.g. deletion of the file.
336          * @return a lock on the primary file normally
337          * @throws IOException if the lock could not be taken
338          */

339         protected FileLock takeLock () throws IOException JavaDoc {
340             return ((XMLJ2eeDataObject) getDataObject ()).getPrimaryEntry ().takeLock ();
341         }
342
343         /** Find the editor support this environment represents.
344          * Note that we have to look it up, as keeping a direct
345          * reference would not permit this environment to be serialized.
346          * @return the editor support
347          */

348         public CloneableOpenSupport findCloneableOpenSupport () {
349             return (XMLJ2eeEditorSupport) getDataObject ().getCookie (XMLJ2eeEditorSupport.class);
350         }
351     }
352 }
353
Popular Tags