KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > web > jsf > JSFConfigEditorSupport


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.jsf;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import javax.swing.SwingUtilities JavaDoc;
26 import javax.swing.event.DocumentEvent JavaDoc;
27 import javax.swing.event.DocumentListener JavaDoc;
28 import javax.swing.text.BadLocationException JavaDoc;
29 import org.netbeans.core.spi.multiview.MultiViewDescription;
30 import org.netbeans.core.spi.multiview.MultiViewFactory;
31 import org.netbeans.modules.web.jsf.api.editor.JSFConfigEditorContext;
32 import org.netbeans.modules.xml.api.EncodingUtil;
33 import org.openide.DialogDescriptor;
34 import org.openide.DialogDisplayer;
35 import org.openide.ErrorManager;
36 import org.openide.NotifyDescriptor;
37 import org.openide.awt.UndoRedo;
38 import org.openide.cookies.EditorCookie.Observable;
39 import org.openide.filesystems.FileLock;
40 import org.openide.filesystems.FileObject;
41 import org.openide.nodes.Node.Cookie;
42 import org.openide.text.CloneableEditorSupport.Pane;
43 import org.openide.text.DataEditorSupport;
44 import org.openide.cookies.*;
45 import org.openide.text.CloneableEditorSupport;
46 import org.openide.text.NbDocument;
47 import org.openide.util.NbBundle;
48 import org.openide.util.RequestProcessor;
49 import org.openide.windows.TopComponent;
50
51 /**
52  *
53  * @author Petr Pisl
54  */

55 public class JSFConfigEditorSupport extends DataEditorSupport
56         implements OpenCookie, EditCookie, EditorCookie.Observable, PrintCookie, CloseCookie {
57     
58     /** SaveCookie for this support instance. The cookie is adding/removing
59      * data object's cookie set depending on if modification flag was set/unset. */

60     private final SaveCookie saveCookie = new SaveCookie() {
61         /** Implements <code>SaveCookie</code> interface. */
62         public void save() throws java.io.IOException JavaDoc {
63             JSFConfigDataObject obj = (JSFConfigDataObject) getDataObject();
64             // invoke parsing before save
65
restartTimer();
66             obj.parsingDocument();
67             
68             if (obj.isDocumentValid()) {
69                 saveDocument();
70             }else {
71                 //obj.displayErrorMessage();
72
//StatusDisplayer.getDefault().setStatusText("");
73
DialogDescriptor dialog = new DialogDescriptor(
74                         NbBundle.getMessage(JSFConfigEditorSupport.class, "MSG_invalidXmlWarning"),
75                         NbBundle.getMessage(JSFConfigEditorSupport.class, "TTL_invalidXmlWarning"));
76                 java.awt.Dialog JavaDoc d = org.openide.DialogDisplayer.getDefault().createDialog(dialog);
77                 d.setVisible(true);
78                 if (dialog.getValue() == org.openide.DialogDescriptor.OK_OPTION) {
79                     saveDocument();
80                 }
81                 /*else {
82                     RequestProcessor.getDefault().post(new Runnable() {
83                         public void run(){
84                             StatusDisplayer.getDefault().setStatusText("");
85                         }
86                     },100);
87                 }*/

88             }
89         }
90     };
91     private JSFConfigDataObject dataObject;
92     private RequestProcessor.Task parsingDocumentTask;
93     private TopComponent mvtc;
94     
95     /** Delay for automatic parsing - in miliseconds */
96     private static final int AUTO_PARSING_DELAY = 2000;
97     
98     public JSFConfigEditorSupport(JSFConfigDataObject dobj) {
99         super(dobj,new XmlEnv(dobj));
100         dataObject = dobj;
101         setMIMEType("text/x-jsf+xml"); //NOI18N
102

103         //initialize the listeners on the document
104
initialize();
105     }
106     
107     @Override JavaDoc
108     protected Pane createPane() {
109         //StrutsConfigDataObjectContext context = new StrutsConfigDataObjectContextImpl(getDataObject());
110
JSFConfigEditorContext context = new JSFConfigEditorContextImpl((JSFConfigDataObject)getDataObject());
111         ArrayList JavaDoc<MultiViewDescription> descriptions =
112                 new ArrayList JavaDoc<MultiViewDescription> (JSFConfigEditorViewFactorySupport.createViewDescriptions(context));
113         if (descriptions.size() > 0) {
114             descriptions.add( new JSFConfigMultiviewDescriptor(context));
115             return (CloneableEditorSupport.Pane) MultiViewFactory.createCloneableMultiView(descriptions.toArray(new MultiViewDescription[descriptions.size()]), descriptions.get(0), null);
116         } else {
117             return super.createPane();
118         }
119     }
120     
121     public UndoRedo.Manager getUndoRedoManager() {
122         return super.getUndoRedo();
123     }
124     
125     protected void setMVTC(TopComponent mvtc) {
126         this.mvtc = mvtc;
127         updateDisplayName();
128     }
129     
130     private int click = 0;
131     public void updateDisplayName() {
132         
133         final TopComponent tc = mvtc;
134         if (tc == null)
135             return;
136         
137         SwingUtilities.invokeLater(new Runnable JavaDoc() {
138             public void run() {
139                 String JavaDoc displayName = messageName();
140                 
141                 if (! displayName.equals(tc.getDisplayName())){
142                     tc.setDisplayName(displayName);
143                 }
144                 tc.setToolTipText(dataObject.getPrimaryFile().getPath());
145             }
146         });
147     }
148     
149     private void initialize() {
150         // Create DocumentListener
151
final DocumentListener JavaDoc docListener = new DocumentListener JavaDoc() {
152             public void insertUpdate(DocumentEvent JavaDoc e) { change(e); }
153             public void changedUpdate(DocumentEvent JavaDoc e) { }
154             public void removeUpdate(DocumentEvent JavaDoc e) { change(e); }
155             
156             private void change(DocumentEvent JavaDoc e) {
157                 if (!dataObject.isNodeDirty()) restartTimer();
158             }
159         };
160         // the listener add only when the document is move to memory
161
addPropertyChangeListener(new PropertyChangeListener JavaDoc() {
162             public void propertyChange(PropertyChangeEvent JavaDoc evt) {
163                 if (EditorCookie.Observable.PROP_DOCUMENT.equals(evt.getPropertyName())
164                         && isDocumentLoaded() && getDocument() != null) {
165                     getDocument().addDocumentListener(docListener);
166                 }
167             }
168         });
169     }
170     
171     /*
172      * Save document using encoding declared in XML prolog if possible otherwise
173      * at UTF-8 (in such case it updates the prolog).
174      */

175     public void saveDocument() throws java.io.IOException JavaDoc {
176         final javax.swing.text.StyledDocument JavaDoc doc = getDocument();
177         String JavaDoc defaultEncoding = "UTF-8"; // NOI18N
178
// dependency on xml/core
179
String JavaDoc enc = EncodingUtil.detectEncoding(doc);
180         boolean changeEncodingToDefault = false;
181         if (enc == null) enc = defaultEncoding;
182         
183         //test encoding
184
if (!isSupportedEncoding(enc)){
185             NotifyDescriptor nd = new NotifyDescriptor.Confirmation(
186                     NbBundle.getMessage(JSFConfigEditorSupport.class, "MSG_BadEncodingDuringSave", //NOI18N
187
new Object JavaDoc [] { getDataObject().getPrimaryFile().getNameExt(),
188                     enc,
189                     defaultEncoding} ),
190                     NotifyDescriptor.YES_NO_OPTION,
191                     NotifyDescriptor.WARNING_MESSAGE);
192             nd.setValue(NotifyDescriptor.NO_OPTION);
193             DialogDisplayer.getDefault().notify(nd);
194             if(nd.getValue() != NotifyDescriptor.YES_OPTION) return;
195             changeEncodingToDefault = true;
196         }
197         
198         if (!changeEncodingToDefault){
199             // is it possible to save the document in the encoding?
200
try {
201                 java.nio.charset.CharsetEncoder JavaDoc coder = java.nio.charset.Charset.forName(enc).newEncoder();
202                 if (!coder.canEncode(doc.getText(0, doc.getLength()))){
203                     NotifyDescriptor nd = new NotifyDescriptor.Confirmation(
204                             NbBundle.getMessage(JSFConfigEditorSupport.class, "MSG_BadCharConversion", //NOI18N
205
new Object JavaDoc [] { getDataObject().getPrimaryFile().getNameExt(),
206                             enc}),
207                             NotifyDescriptor.YES_NO_OPTION,
208                             NotifyDescriptor.WARNING_MESSAGE);
209                     nd.setValue(NotifyDescriptor.NO_OPTION);
210                     DialogDisplayer.getDefault().notify(nd);
211                     if(nd.getValue() != NotifyDescriptor.YES_OPTION) return;
212                 }
213             } catch (javax.swing.text.BadLocationException JavaDoc e){
214                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
215             }
216             super.saveDocument();
217             //moved from Env.save()
218
getDataObject().setModified(false);
219         } else {
220             // update prolog to new valid encoding
221

222             try {
223                 final int MAX_PROLOG = 1000;
224                 int maxPrologLen = Math.min(MAX_PROLOG, doc.getLength());
225                 final char prolog[] = doc.getText(0, maxPrologLen).toCharArray();
226                 int prologLen = 0; // actual prolog length
227

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

249                         } catch (BadLocationException JavaDoc e) {
250                             if (System.getProperty("netbeans.debug.exceptions") != null) // NOI18N
251
e.printStackTrace();
252                         }
253                     }
254                 };
255                 
256                 NbDocument.runAtomic(doc, edit);
257                 
258                 super.saveDocument();
259                 //moved from Env.save()
260
getDataObject().setModified(false);
261             } catch (javax.swing.text.BadLocationException JavaDoc e){
262                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
263             }
264         }
265     }
266     
267     private boolean isSupportedEncoding(String JavaDoc encoding){
268         boolean supported;
269         try{
270             supported = java.nio.charset.Charset.isSupported(encoding);
271         } catch (java.nio.charset.IllegalCharsetNameException JavaDoc e){
272             supported = false;
273         }
274         
275         return supported;
276     }
277     
278     
279     /** Restart the timer which starts the parser after the specified delay.
280      * @param onlyIfRunning Restarts the timer only if it is already running
281      */

282     public void restartTimer() {
283         if (parsingDocumentTask==null || parsingDocumentTask.isFinished() ||
284                 parsingDocumentTask.cancel()) {
285             dataObject.setDocumentDirty(true);
286             Runnable JavaDoc r = new Runnable JavaDoc() {
287                 public void run() {
288                     dataObject.parsingDocument();
289                 }
290             };
291             if (parsingDocumentTask != null)
292                 parsingDocumentTask = RequestProcessor.getDefault().post(r, AUTO_PARSING_DELAY);
293             else
294                 parsingDocumentTask = RequestProcessor.getDefault().post(r, 100);
295         }
296     }
297     
298     /**
299      * Overrides superclass method. Adds adding of save cookie if the document has been marked modified.
300      * @return true if the environment accepted being marked as modified
301      * or false if it has refused and the document should remain unmodified
302      */

303     protected boolean notifyModified() {
304         boolean notif = super.notifyModified();
305         if (!notif){
306             return false;
307         }
308         updateDisplayName();
309         addSaveCookie();
310         return true;
311     }
312     
313     /** Overrides superclass method. Adds removing of save cookie. */
314     protected void notifyUnmodified() {
315         super.notifyUnmodified();
316         updateDisplayName();
317         removeSaveCookie();
318     }
319     
320     /** Helper method. Adds save cookie to the data object. */
321     private void addSaveCookie() {
322         // Adds save cookie to the data object.
323
if(dataObject.getCookie(SaveCookie.class) == null) {
324             dataObject.getCookieSet0().add(saveCookie);
325             dataObject.setModified(true);
326         }
327     }
328     
329     /** Helper method. Removes save cookie from the data object. */
330     private void removeSaveCookie() {
331         JSFConfigDataObject obj = (JSFConfigDataObject)getDataObject();
332         
333         // Remove save cookie from the data object.
334
Cookie cookie = obj.getCookie(SaveCookie.class);
335         
336         if(cookie != null && cookie.equals(saveCookie)) {
337             obj.getCookieSet0().remove(saveCookie);
338             obj.setModified(false);
339         }
340     }
341     
342     public void open() {
343         super.open();
344         // parse once after opening the document
345
restartTimer();
346         updateDisplayName();
347     }
348     
349     
350     private static class XmlEnv extends DataEditorSupport.Env {
351         
352         private static final long serialVersionUID = -800036748848958489L;
353         
354         //private static final long serialVersionUID = ...L;
355

356         /** Create a new environment based on the data object.
357          * @param obj the data object to edit
358          */

359         public XmlEnv(JSFConfigDataObject obj) {
360             super(obj);
361         }
362         
363         /** Get the file to edit.
364          * @return the primary file normally
365          */

366         protected FileObject getFile() {
367             return getDataObject().getPrimaryFile();
368         }
369         
370         /** Lock the file to edit.
371          * Should be taken from the file entry if possible, helpful during
372          * e.g. deletion of the file.
373          * @return a lock on the primary file normally
374          * @throws IOException if the lock could not be taken
375          */

376         protected FileLock takeLock() throws java.io.IOException JavaDoc {
377             return ((JSFConfigDataObject) getDataObject()).getPrimaryEntry().takeLock();
378         }
379         
380         /** Find the editor support this environment represents.
381          * Note that we have to look it up, as keeping a direct
382          * reference would not permit this environment to be serialized.
383          * @return the editor support
384          */

385         public org.openide.windows.CloneableOpenSupport findCloneableOpenSupport() {
386             return (JSFConfigEditorSupport) getDataObject().getCookie(JSFConfigEditorSupport.class);
387         }
388     }
389 }
390
Popular Tags