KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > web > core > jsploader > BaseJspEditorSupport


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.web.core.jsploader;
21 import java.beans.PropertyChangeEvent JavaDoc;
22 import java.beans.PropertyChangeListener JavaDoc;
23 import java.io.Reader JavaDoc;
24 import java.io.InputStreamReader JavaDoc;
25 import java.io.OutputStream JavaDoc;
26 import java.io.OutputStreamWriter JavaDoc;
27 import java.io.Writer JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.io.InputStream JavaDoc;
30 import java.io.ObjectInput JavaDoc;
31 import javax.swing.Timer JavaDoc;
32 import javax.swing.event.CaretListener JavaDoc;
33 import javax.swing.event.CaretEvent JavaDoc;
34 import javax.swing.event.DocumentListener JavaDoc;
35 import javax.swing.event.ChangeListener JavaDoc;
36 import javax.swing.event.DocumentEvent JavaDoc;
37 import javax.swing.event.ChangeEvent JavaDoc;
38 import javax.swing.text.BadLocationException JavaDoc;
39 import javax.swing.text.StyledDocument JavaDoc;
40 import javax.swing.text.EditorKit JavaDoc;
41 import org.netbeans.modules.web.core.palette.JSPPaletteFactory;
42 import org.netbeans.modules.web.jsps.parserapi.JspParserAPI;
43 import org.netbeans.modules.web.jsps.parserapi.JspParserFactory;
44 import org.openide.ErrorManager;
45 import org.openide.filesystems.FileUtil;
46
47 import org.openide.text.DataEditorSupport;
48 import org.openide.filesystems.FileObject;
49 import org.openide.filesystems.FileLock;
50 import org.openide.loaders.MultiDataObject;
51 import org.openide.cookies.*;
52 import org.openide.text.CloneableEditor;
53 import org.openide.util.Lookup;
54 import org.openide.util.TaskListener;
55 import org.openide.util.Task;
56 import org.openide.DialogDisplayer;
57 import org.openide.NotifyDescriptor;
58 import org.openide.util.lookup.AbstractLookup;
59 import org.openide.util.lookup.InstanceContent;
60 import org.openide.util.lookup.Lookups;
61 import org.openide.util.lookup.ProxyLookup;
62 import org.openide.windows.CloneableOpenSupport;
63 import org.openide.nodes.Node;
64 import org.openide.util.NbBundle;
65 //import org.openide.debugger.Debugger;
66
//import org.openide.debugger.Breakpoint;
67

68 import org.openide.loaders.DataObject;
69 import org.netbeans.modules.web.api.webmodule.WebModule;
70 import org.netbeans.spi.palette.PaletteController;
71
72 class BaseJspEditorSupport extends DataEditorSupport implements EditCookie, EditorCookie.Observable, OpenCookie, LineCookie, CloseCookie, PrintCookie {
73     
74     private static final int AUTO_PARSING_DELAY = 2000;//ms
75

76     /** Timer which countdowns the auto-reparsing time. */
77     private Timer JavaDoc timer;
78     
79     /** Cash of encoding of the file */
80     private String JavaDoc encoding;
81     
82     /** When unsupported encoding is set for a jsp file, then defaulEncoding is used for loading
83      * and saving
84      */

85     private static String JavaDoc defaulEncoding = "UTF-8"; // NOI18N
86

87     public BaseJspEditorSupport(JspDataObject obj) {
88         super(obj, new BaseJspEnv(obj));
89         DataObject data = getDataObject();
90         if ((data!=null) && (data instanceof JspDataObject)) {
91             setMIMEType(JspLoader.getMimeType((JspDataObject)data));
92         }
93         initialize();
94     }
95     
96     public boolean close() {
97         //cancel waiting parsing task if there is any
98
//this is largely a workaround for issue #50926
99
TagLibParseSupport sup = (TagLibParseSupport)getDataObject().getCookie(TagLibParseSupport.class);
100         if(sup != null) {
101             sup.cancelParsingTask();
102         }
103         
104         return super.close();
105     }
106     
107     private void initialize() {
108         // initialize timer
109
timer = new Timer JavaDoc(0, new java.awt.event.ActionListener JavaDoc() {
110             public void actionPerformed(java.awt.event.ActionEvent JavaDoc e) {
111                 final TagLibParseSupport sup = (TagLibParseSupport)getDataObject().getCookie(TagLibParseSupport.class);
112                 if (sup != null && WebModule.getWebModule(getDataObject().getPrimaryFile())!= null) {
113                     sup.autoParse().addTaskListener(new TaskListener() {
114                         public void taskFinished(Task t) {
115                             notifyParsingDone(sup);
116                         }
117                     });
118                 }
119             }
120         });
121         timer.setInitialDelay(AUTO_PARSING_DELAY);
122         timer.setRepeats(false);
123         
124         // create document listener
125
final DocumentListener JavaDoc docListener = new DocumentListener JavaDoc() {
126             public void insertUpdate(DocumentEvent JavaDoc e) { change(e); }
127             public void changedUpdate(DocumentEvent JavaDoc e) { }
128             public void removeUpdate(DocumentEvent JavaDoc e) { change(e); }
129             
130             private void change(DocumentEvent JavaDoc e) {
131                 restartTimer(false);
132                 TagLibParseSupport sup = (TagLibParseSupport)getDataObject().getCookie(TagLibParseSupport.class);
133                 if (sup != null) {
134                     sup.setDocumentDirty(true);
135                 }
136             }
137         };
138         
139         // add change listener
140
addChangeListener(new ChangeListener JavaDoc() {
141             public void stateChanged(ChangeEvent JavaDoc evt) {
142                 if (isDocumentLoaded()) {
143                     if (getDocument() != null) {
144                         getDocument().addDocumentListener(docListener);
145                     }
146                 }
147             }
148         });
149     
150         encoding = null;
151         
152         JspParserAccess
153                 .getJspParserWM (getWebModule (getDataObject().getPrimaryFile()))
154                 .addPropertyChangeListener(
155                     new PropertyChangeListener JavaDoc() {
156                         public void propertyChange(java.beans.PropertyChangeEvent JavaDoc evt) {
157                             String JavaDoc propName = evt.getPropertyName();
158                             if (JspParserAPI.WebModule.PROP_LIBRARIES.equals(propName)
159                                 || JspParserAPI.WebModule.PROP_PACKAGE_ROOTS.equals(propName)) {
160                                 // the classpath was changed, need to reparsed
161
restartTimer(false);
162                             }
163                        }
164                     });
165                     
166         
167     }
168     
169     private WebModule getWebModule(FileObject fo){
170         WebModule wm = WebModule.getWebModule(fo);
171         if (wm != null){
172             FileObject wmRoot = wm.getDocumentBase();
173             if (wmRoot != null && (fo == wmRoot || FileUtil.isParentOf(wmRoot, fo))) {
174                 return wm;
175             }
176         }
177         return null;
178     }
179     
180     /** Restart the timer which starts the parser after the specified delay.
181      * @param onlyIfRunning Restarts the timer only if it is already running
182      */

183     private void restartTimer(boolean onlyIfRunning) {
184         if (onlyIfRunning && !timer.isRunning()){
185             return;
186         }
187             
188         
189         int delay = AUTO_PARSING_DELAY;
190         if (delay > 0) {
191             timer.setInitialDelay(delay);
192             timer.restart();
193         }
194     }
195     
196     private boolean isSupportedEncoding(String JavaDoc encoding){
197         boolean supported;
198         try{
199             supported = java.nio.charset.Charset.isSupported(encoding);
200         }
201         catch (java.nio.charset.IllegalCharsetNameException JavaDoc e){
202             supported = false;
203         }
204         
205         return supported;
206     }
207     
208     public void open(){
209         long a = System.currentTimeMillis();
210         encoding = getObjectEncoding(false, false); //use encoding from fileobject & cache it
211

212         if (!isSupportedEncoding(encoding)){
213             NotifyDescriptor nd = new NotifyDescriptor.Confirmation(
214                 NbBundle.getMessage (BaseJspEditorSupport.class, "MSG_BadEncodingDuringLoad", //NOI18N
215
new Object JavaDoc [] { getDataObject().getPrimaryFile().getNameExt(),
216                                     encoding,
217                                     defaulEncoding} ),
218                 NotifyDescriptor.YES_NO_OPTION,
219                 NotifyDescriptor.WARNING_MESSAGE);
220             DialogDisplayer.getDefault().notify(nd);
221             if(nd.getValue() != NotifyDescriptor.YES_OPTION) return;
222         }
223         super.open();
224     }
225     
226     protected void loadFromStreamToKit(StyledDocument JavaDoc doc, InputStream JavaDoc stream, EditorKit JavaDoc kit) throws IOException JavaDoc, BadLocationException JavaDoc {
227
228         Reader JavaDoc reader = null;
229         encoding = getObjectEncoding(false, true);//use encoding from fileobject & cache it
230

231         if (!isSupportedEncoding(encoding)){
232             encoding = defaulEncoding;
233         }
234         try {
235             reader = new InputStreamReader JavaDoc(stream, encoding);
236             kit.read(reader, doc, 0);
237         }
238         finally {
239             if (reader != null)
240                 reader.close();
241         }
242     }
243     
244     protected void saveFromKitToStream(StyledDocument JavaDoc doc, EditorKit JavaDoc kit, OutputStream JavaDoc stream) throws IOException JavaDoc, BadLocationException JavaDoc {
245         Writer JavaDoc wr = null;
246         if (encoding == null) {
247             encoding = getObjectEncoding(false, true);//use encoding from fileobject & cache it
248
}
249         try {
250             if (!isSupportedEncoding(encoding)){
251                 encoding = defaulEncoding;
252             }
253             wr = new OutputStreamWriter JavaDoc(stream, encoding);
254             kit.write(wr, doc, 0, doc.getLength());
255         }
256         finally {
257             if (wr != null)
258                 wr.close();
259         }
260     }
261     
262     /** Notify about the editor closing.
263      */

264     protected void notifyClose() {}
265     
266     /** Notify that parsing task has been finished; some dependent data may now
267      * be refreshed from up-to-date parsing info */

268     protected void notifyParsingDone(TagLibParseSupport sup) {
269         if (sup.isDocumentDirty()) {
270             restartTimer(false);
271         }
272     }
273     
274     protected boolean notifyModified() {
275         boolean notify = super.notifyModified();
276         if (!notify) {
277             return false;
278         }
279         JspDataObject obj = (JspDataObject)getDataObject();
280         if (obj.getCookie(SaveCookie.class) == null) {
281             obj.addSaveCookie(new SaveCookie() {
282                 public void save() throws java.io.IOException JavaDoc {
283                     saveDocument();
284                 }
285             });
286         }
287         return true;
288     }
289     
290     /** Called when the document becomes unmodified.
291      * Here, removing the save cookie from the object and marking it unmodified.
292      */

293     protected void notifyUnmodified() {
294         super.notifyUnmodified();
295         JspDataObject obj = (JspDataObject)getDataObject();
296         obj.removeSaveCookie();
297     }
298     
299     protected String JavaDoc getObjectEncoding(boolean useEditor) {
300         return getObjectEncoding(useEditor, false);
301     }
302     
303     /** Returns encoding of the JSP file.
304      * @param useEditor if <code>true</code> then the encoding is got from the editor
305      * otherwise the encoding is obtained from webmodule parser.
306      * @param useCache if <code>true</code> then the encoding parsed from the webmodule and JSP is
307      * cached. So the next call of this method wont parse the wm and the JSP again until the JSP file is changed.
308      * @return JSP page encoding.
309      */

310     protected String JavaDoc getObjectEncoding(boolean useEditor, boolean useCache) {
311             return ((JspDataObject)getDataObject()).getFileEncoding(!useCache, useEditor).trim();
312     }
313     
314     /** Save the document in this thread and start reparsing it.
315      * @exception IOException on I/O error
316      */

317     public void saveDocument() throws IOException JavaDoc {
318         saveDocument(true, true);
319     }
320     
321     /** Save the document in this thread.
322      * @param parse true if the parser should be started, otherwise false
323      * @exception IOException on I/O error
324      */

325     protected void saveDocumentIfNecessary(boolean parse) throws IOException JavaDoc {
326         saveDocument(parse, false);
327     }
328     
329     /** Save the document in this thread.
330      * @param parse true if the parser should be started, otherwise false
331      * @param forceSave if true save always, otherwise only when is modified
332      * @exception IOException on I/O error
333      */

334     private void saveDocument(boolean parse, boolean forceSave) throws IOException JavaDoc {
335         if (forceSave || isModified()) {
336             encoding = getObjectEncoding(true); //use encoding from editor
337
if (!isSupportedEncoding(encoding)){
338                 NotifyDescriptor nd = new NotifyDescriptor.Confirmation(
339                 NbBundle.getMessage (BaseJspEditorSupport.class, "MSG_BadEncodingDuringSave", //NOI18N
340
new Object JavaDoc [] { getDataObject().getPrimaryFile().getNameExt(),
341                                     encoding,
342                                     defaulEncoding} ),
343                 NotifyDescriptor.YES_NO_OPTION,
344                 NotifyDescriptor.WARNING_MESSAGE);
345                 nd.setValue(NotifyDescriptor.NO_OPTION);
346                 DialogDisplayer.getDefault().notify(nd);
347                 if(nd.getValue() != NotifyDescriptor.YES_OPTION) return;
348             }
349             else {
350                 try {
351                     java.nio.charset.CharsetEncoder JavaDoc coder = java.nio.charset.Charset.forName(encoding).newEncoder();
352                     if (!coder.canEncode(getDocument().getText(0, getDocument().getLength()))){
353                         NotifyDescriptor nd = new NotifyDescriptor.Confirmation(
354                         NbBundle.getMessage (BaseJspEditorSupport.class, "MSG_BadCharConversion", //NOI18N
355
new Object JavaDoc [] { getDataObject().getPrimaryFile().getNameExt(),
356                                         encoding}),
357                             NotifyDescriptor.YES_NO_OPTION,
358                             NotifyDescriptor.WARNING_MESSAGE);
359                             nd.setValue(NotifyDescriptor.NO_OPTION);
360                             DialogDisplayer.getDefault().notify(nd);
361                             if(nd.getValue() != NotifyDescriptor.YES_OPTION) return;
362                     }
363                 }
364                 catch (javax.swing.text.BadLocationException JavaDoc e){
365                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
366                 }
367             }
368             super.saveDocument();
369             if (parse) {
370                 TagLibParseSupport sup = (TagLibParseSupport)getDataObject().getCookie(TagLibParseSupport.class);
371                 if (sup != null) {
372                     sup.prepare();
373                 }
374             }
375         }
376     }
377     
378     /** A method to create a new component. Overridden in subclasses.
379      * @return the {@link BaseJspEditor} for this support
380      */

381     protected CloneableEditor createCloneableEditor() {
382         return new BaseJspEditor(this);
383     }
384     
385     public static class BaseJspEnv extends DataEditorSupport.Env {
386         
387         private static final long serialVersionUID = -800036748848958489L;
388         
389         public BaseJspEnv(JspDataObject obj) {
390             super(obj);
391         }
392         
393         protected FileObject getFile() {
394             return getDataObject().getPrimaryFile();
395         }
396         
397         protected FileLock takeLock() throws IOException JavaDoc {
398             return ((MultiDataObject)getDataObject()).getPrimaryEntry().takeLock();
399         }
400         
401         public CloneableOpenSupport findCloneableOpenSupport() {
402             return (BaseJspEditorSupport)getDataObject().getCookie(BaseJspEditorSupport.class);
403         }
404     }
405     
406     public static class BaseJspEditor extends CloneableEditor {
407         
408         public static final String JavaDoc JSP_MIME_TYPE = "text/x-jsp"; // NOI18N
409
public static final String JavaDoc TAG_MIME_TYPE = "text/x-tag"; // NOI18N
410

411         private TagLibParseSupport taglibParseSupport;
412         private InstanceContent instanceContent;
413         
414         /** Listener on caret movements */
415         CaretListener JavaDoc caretListener;
416         //BaseJspEditorSupport support;
417

418         public BaseJspEditor() {
419             super();
420         }
421         
422         public boolean isXmlSyntax(DataObject dataObject) {
423             
424             FileObject fileObject = (dataObject != null) ? dataObject.getPrimaryFile() : null;
425             if (fileObject == null)
426                 return false;
427             
428             return taglibParseSupport.getCachedOpenInfo(false, false).isXmlSyntax();
429         }
430         
431         void associatePalette(BaseJspEditorSupport s) {
432         
433             DataObject dataObject = s.getDataObject();
434             String JavaDoc mimeType = dataObject.getPrimaryFile().getMIMEType();
435             instanceContent.add(getActionMap());
436             
437             if (dataObject instanceof JspDataObject &&
438                (mimeType.equals(JSP_MIME_TYPE) || mimeType.equals(TAG_MIME_TYPE)) &&
439                 !isXmlSyntax(dataObject))
440             {
441                 try {
442                     PaletteController pc = JSPPaletteFactory.getPalette();
443                     instanceContent.add(pc);
444                 }
445                 catch (IOException JavaDoc ioe) {
446                     //TODO exception handling
447
ioe.printStackTrace();
448                 }
449             }
450         }
451         
452         /** Creates new editor */
453         public BaseJspEditor(BaseJspEditorSupport s) {
454             super(s);
455             initialize();
456         }
457
458         protected void notifyParsingDone() {
459         }
460         
461         private void initialize() {
462             Node nodes[] = {((DataEditorSupport)cloneableEditorSupport()).getDataObject().getNodeDelegate()};
463
464             //init lookup
465
instanceContent = new InstanceContent();
466             associateLookup(new ProxyLookup(new Lookup[] { new AbstractLookup(instanceContent), nodes[0].getLookup()}));
467             
468             setActivatedNodes(nodes);
469             caretListener = new CaretListener JavaDoc() {
470                 public void caretUpdate(CaretEvent JavaDoc e) {
471                     ((BaseJspEditorSupport)cloneableEditorSupport()).restartTimer(true);
472                 }
473             };
474             
475             taglibParseSupport = (TagLibParseSupport)((BaseJspEditorSupport)cloneableEditorSupport()).getDataObject().getCookie(TagLibParseSupport.class);
476
477         }
478         
479         /* This method is called when parent window of this component has focus,
480          * and this component is preferred one in it.
481          */

482         protected void componentActivated() {
483             // Workaround for bug #37188. If the pane is null, don't activate the component.
484
if (getEditorPane() != null){
485                 getEditorPane().addCaretListener(caretListener);
486                 super.componentActivated();
487             }
488             ((BaseJspEditorSupport)cloneableEditorSupport()).restartTimer(false);
489             
490             //allow resumed parser to perform parsing of the webproject
491
taglibParseSupport.setEditorOpened(true);
492             //show up the component palette
493
associatePalette((BaseJspEditorSupport)cloneableEditorSupport());
494             
495         }
496         
497         /*
498          * This method is called when parent window of this component losts focus,
499          * or when this component losts preferrence in the parent window.
500          */

501         protected void componentDeactivated() {
502             getEditorPane().removeCaretListener(caretListener);
503             super.componentDeactivated();
504             taglibParseSupport.setEditorOpened(false);
505         }
506         
507         /* When closing last view, also close the document.
508          * @return <code>true</code> if close succeeded
509          */

510         protected boolean closeLast() {
511             if (!super.closeLast()) return false;
512             ((BaseJspEditorSupport)cloneableEditorSupport()).notifyClose();
513             return true;
514         }
515         
516         /** Deserialize this top component.
517          * @param in the stream to deserialize from
518          */

519         public void readExternal(ObjectInput JavaDoc in) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
520             super.readExternal(in);
521             initialize();
522             associatePalette((BaseJspEditorSupport)cloneableEditorSupport());
523         }
524         
525     } // end of JavaEditorComponent inner class
526

527 }
528
Popular Tags