Source Code Cross Referenced for TextEditorSupport.java in  » IDE-Netbeans » xml » org » netbeans » modules » xml » text » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » xml » org.netbeans.modules.xml.text 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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.xml.text;
042:
043:        import java.io.*;
044:        import java.awt.event.*;
045:        import java.text.*;
046:        import java.util.Enumeration;
047:        import java.lang.ref.WeakReference;
048:        import java.beans.PropertyChangeEvent;
049:
050:        import javax.swing.Timer;
051:        import javax.swing.event.*;
052:        import javax.swing.text.*;
053:
054:        import org.netbeans.modules.xml.api.EncodingUtil;
055:        import org.openide.*;
056:        import org.openide.awt.StatusDisplayer;
057:        import org.openide.text.*;
058:        import org.openide.util.*;
059:        import org.openide.windows.CloneableTopComponent;
060:        import org.openide.windows.CloneableOpenSupport;
061:        import org.openide.loaders.*;
062:        import org.openide.cookies.*;
063:        import org.openide.nodes.*;
064:        import org.openide.filesystems.FileObject;
065:        import org.openide.filesystems.FileLock;
066:
067:        import org.netbeans.modules.xml.*;
068:        import org.netbeans.modules.xml.lib.*;
069:        import org.netbeans.modules.xml.sync.*;
070:        import org.netbeans.modules.xml.cookies.*;
071:
072:        /**
073:         * Text editor support that handles I/O encoding and sync with tree.
074:         * There are two timers a long time and a short time. The long time
075:         * updates tree even in middle of writing text. The short time is restarted
076:         * at every text change..
077:         * <p>
078:         * Listens for: text document change (edit), timers and document status change (loading).
079:         */
080:        public class TextEditorSupport extends DataEditorSupport implements 
081:                EditorCookie.Observable, EditCookie, CloseCookie, PrintCookie {
082:            // ToDo:
083:            // + extend CloneableEditorSupport instead of DataEditorSupport which is associated with DataObject
084:
085:            /**
086:             * Swings document property added by this support.
087:             */
088:            public static final String PROP_DOCUMENT_URL = "doc-url";
089:
090:            /** Timer which countdowns the auto-reparsing time. */
091:            private Timer timer;
092:
093:            /** Used as lock object in close and openCloneableTopComponent. */
094:            private static java.awt.Container awtLock;
095:
096:            private Representation rep; //it is my representation
097:
098:            //
099:            // init
100:            //
101:
102:            /** public jsu for backward compatibility purposes. */
103:            protected TextEditorSupport(XMLDataObjectLook xmlDO, Env env,
104:                    String mime_type) {
105:                super ((DataObject) xmlDO, env);
106:
107:                setMIMEType(mime_type);
108:
109:                initTimer();
110:
111:                initListeners();
112:
113:                //??? why it is not under text module control?
114:                // it must be more lazy, why we must open document
115:                // it looks that Document's StreamDescriptionProperty fits
116:                //        try {
117:                //            if (xmlDO instanceof DataObject) {
118:                //                DataObject dobj = (DataObject) xmlDO;  // we must cast, we cannot as for cookie in cookie <init> that is produced by factory
119:                //                FileObject fo = dobj.getPrimaryFile();
120:                //                URL url = fo.getURL();
121:                //                String system = url.toExternalForm();
122:                //                openDocument().putProperty(PROP_DOCUMENT_URL, system); //openit
123:                //            } else {
124:                //                new RuntimeException("DO expected").printStackTrace();
125:                //            }
126:                //        } catch (Exception ex) {
127:                //            // just let property undefined
128:                //            ex.printStackTrace();
129:                //        }
130:            }
131:
132:            /** public jsu for backward compatibility purposes. */
133:            public TextEditorSupport(XMLDataObjectLook xmlDO, String mime_type) {
134:                this (xmlDO, new Env(xmlDO), mime_type);
135:            }
136:
137:            //
138:            // timer
139:            //
140:
141:            /**
142:             * Initialize timers and handle their ticks.
143:             */
144:            private void initTimer() {
145:                timer = new Timer(0, new java.awt.event.ActionListener() {
146:                    // we are called from the AWT thread so put itno other one
147:                    public void actionPerformed(java.awt.event.ActionEvent e) {
148:                        if (Util.THIS.isLoggable()) /* then */
149:                            Util.THIS
150:                                    .debug("$$ TextEditorSupport::initTimer::actionPerformed: event = "
151:                                            + e);
152:
153:                        RequestProcessor.postRequest(new Runnable() {
154:                            public void run() {
155:                                syncDocument(false);
156:                            }
157:                        });
158:                    }
159:                });
160:
161:                timer.setInitialDelay(getAutoParsingDelay());
162:                timer.setRepeats(false);
163:            }
164:
165:            /*
166:             * Add listeners at Document and document memory status (loading).
167:             */
168:            private void initListeners() {
169:
170:                // create document listener
171:
172:                final DocumentListener docListener = new DocumentListener() {
173:                    public void insertUpdate(DocumentEvent e) {
174:                        if (Util.THIS.isLoggable()) /* then */
175:                            Util.THIS
176:                                    .debug("** TextEditorSupport::DocumentListener::insertUpdate: event = "
177:                                            + e);
178:
179:                        restartTime();
180:                    }
181:
182:                    public void changedUpdate(DocumentEvent e) {
183:                        if (Util.THIS.isLoggable()) /* then */
184:                            Util.THIS
185:                                    .debug("** TextEditorSupport::DocumentListener::changedUpdate: event = "
186:                                            + e);
187:
188:                        // not interested in attribute changes
189:                    }
190:
191:                    public void removeUpdate(DocumentEvent e) {
192:                        if (Util.THIS.isLoggable()) /* then */
193:                            Util.THIS
194:                                    .debug("** TextEditorSupport::DocumentListener::removeUpdate: event = "
195:                                            + e);
196:
197:                        restartTime();
198:                    }
199:
200:                    private void restartTime() {
201:                        if (Util.THIS.isLoggable()) /* then */
202:                            Util.THIS
203:                                    .debug("** TextEditorSupport::DocumentListener::restartTime: isInSync = "
204:                                            + getXMLDataObjectLook()
205:                                                    .getSyncInterface()
206:                                                    .isInSync());
207:
208:                        if (getXMLDataObjectLook().getSyncInterface()
209:                                .isInSync()) {
210:                            return;
211:                        }
212:                        restartTimer(false);
213:                    }
214:                };
215:
216:                // listen for document loading then register to it the docListener as weak
217:
218:                addChangeListener(new ChangeListener() {
219:                    public void stateChanged(ChangeEvent evt) {
220:
221:                        if (isDocumentLoaded()) {
222:
223:                            Document doc = getDocument();
224:                            // when the document is not yet loaded, do nothing
225:                            if (doc == null)
226:                                return;
227:                            doc.addDocumentListener(WeakListeners.document(
228:                                    docListener, doc));
229:
230:                            if (rep == null) {
231:                                XMLDataObjectLook dobj = (XMLDataObjectLook) getDataObject();
232:                                Synchronizator sync = dobj.getSyncInterface();
233:
234:                                //!!! What does this hardcoding mean???
235:                                //[DEPENDENCY] it introduces really ugly core to it's client dependencies!!!
236:                                if (dobj instanceof  org.netbeans.modules.xml.XMLDataObject) {
237:                                    rep = new XMLTextRepresentation(
238:                                            TextEditorSupport.this , sync);
239:                                } else if (dobj instanceof  DTDDataObject) {
240:                                    rep = new DTDTextRepresentation(
241:                                            TextEditorSupport.this , sync);
242:                                } else if (dobj instanceof  EntityDataObject) {
243:                                    rep = new EntityTextRepresentation(
244:                                            TextEditorSupport.this , sync);
245:                                }
246:
247:                                if (rep != null) {
248:                                    sync.addRepresentation(rep);
249:                                }
250:                            }
251:                        }
252:                    }
253:                });
254:
255:            }
256:
257:            /**
258:             * It simply calls super.notifyClosed() for all instances except
259:             * TextEditorSupport.class == this.getClass().
260:             */
261:            protected void notifyClosed() {
262:                super .notifyClosed();
263:
264:                // #15756 following code handles synchronization on text editor closing only!
265:                if (this .getClass() != TextEditorSupport.class)
266:                    return;
267:
268:                XMLDataObjectLook dobj = (XMLDataObjectLook) getDataObject();
269:                Synchronizator sync = dobj.getSyncInterface();
270:                Representation oldRep = rep;
271:                rep = null;
272:                if (oldRep != null) { // because of remove modified document
273:                    sync.removeRepresentation(oldRep);
274:                }
275:
276:                //          if ( isModified() ) { // possible way to remove needless closeDocument followed by open
277:                //              Task reload = reloadDocument();
278:                //              reload.waitFinished();
279:                //          }
280:            }
281:
282:            /**
283:             */
284:            Env getEnv() {
285:                return (Env) env;
286:            }
287:
288:            /**
289:             */
290:            protected XMLDataObjectLook getXMLDataObjectLook() {
291:                return getEnv().getXMLDataObjectLook();
292:            }
293:
294:            /*
295:             * Update presence of SaveCookie on first keystroke.
296:             */
297:            protected boolean notifyModified() {
298:                if (getEnv().isModified()) {
299:                    return true;
300:                }
301:                if (!super .notifyModified()) {
302:                    return false;
303:                }
304:
305:                CookieManagerCookie manager = getEnv().getXMLDataObjectLook()
306:                        .getCookieManager();
307:                manager.addCookie(getEnv());
308:                XMLDataObjectLook obj = (XMLDataObjectLook) getDataObject();
309:                if (obj.getCookie(SaveCookie.class) == null) {
310:                    obj.getCookieManager().addCookie(new SaveCookie() {
311:                        public void save() throws java.io.IOException {
312:                            try {
313:                                saveDocument();
314:                            } catch (UserCancelException e) {
315:                                //just ignore
316:                            }
317:                        }
318:                    });
319:                }
320:
321:                return true;
322:            }
323:
324:            /*
325:             * Update presence of SaveCookie after save.
326:             */
327:            protected void notifyUnmodified() {
328:                if (Util.THIS.isLoggable()) /* then */
329:                    Util.THIS.debug("Notifing unmodified"); // NOI18N
330:
331:                super .notifyUnmodified();
332:                CookieManagerCookie manager = getEnv().getXMLDataObjectLook()
333:                        .getCookieManager();
334:                manager.removeCookie(getEnv());
335:            }
336:
337:            //~~~~~~~~~~~~~~~~~~~~~~~~~ I/O ENCODING HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~
338:
339:            //indicates than document has wrong encoding @see #edit
340:            private volatile boolean encodingErr = false;
341:
342:            /** Read the file from the stream, detect right encoding.
343:             */
344:            protected void loadFromStreamToKit(StyledDocument doc,
345:                    InputStream in, EditorKit kit) throws IOException,
346:                    BadLocationException {
347:                // predetect it to get optimalized XmlReader if utf-8
348:                String enc = EncodingUtil.detectEncoding(in);
349:                if (enc == null) {
350:                    enc = "UTF8"; //!!! // NOI18N
351:                }
352:                try {
353:                    Reader reader = new InputStreamReader(in, enc);
354:                    kit.read(reader, doc, 0);
355:                } catch (CharConversionException ex) {
356:                    if (Util.THIS.isLoggable()) /* then */
357:                        Util.THIS.debug(
358:                                "\n!!! TextEditorSupport.loadFromStreamToKit: enc = '"
359:                                        + enc + "'", ex);
360:
361:                    encodingErr = true;
362:                } catch (UnsupportedEncodingException ex) {
363:                    if (Util.THIS.isLoggable()) /* then */
364:                        Util.THIS.debug(
365:                                "\n!!! TextEditorSupport.loadFromStreamToKit: enc = '"
366:                                        + enc + "'", ex);
367:
368:                    encodingErr = true;
369:                }
370:
371:            }
372:
373:            /** Store the document in proper encoding.
374:             */
375:            protected void saveFromKitToStream(StyledDocument doc,
376:                    EditorKit kit, OutputStream out) throws IOException,
377:                    BadLocationException {
378:                String enc = EncodingUtil.detectEncoding(doc);
379:                if (enc == null) {
380:                    enc = "UTF8"; //!!! // NOI18N
381:                }
382:                try {
383:                    if (Util.THIS.isLoggable()) /* then */
384:                        Util.THIS.debug("Saving using encoding");//, new RuntimeException (enc)); // NOI18N
385:                    if (Util.THIS.isLoggable()) /* then */
386:                        Util.THIS
387:                                .debug("!!! TextEditorSupport::saveFromKitToStream: enc = "
388:                                        + enc);
389:                    //test encoding on dummy stream
390:                    new OutputStreamWriter(new ByteArrayOutputStream(1), enc);
391:                    if (Util.THIS.isLoggable()) /* then */
392:                        Util.THIS
393:                                .debug("!!!                  ::saveFromKitToStream: after first test -> OK");
394:                    Writer writer = new OutputStreamWriter(out, enc);
395:                    if (Util.THIS.isLoggable()) /* then */
396:                        Util.THIS
397:                                .debug("!!!                  ::saveFromKitToStream: writer = "
398:                                        + writer);
399:                    kit.write(writer, doc, 0, doc.getLength());
400:                } catch (UnsupportedEncodingException ex) {
401:                    //!!! just write nothing //?? save say as UTF-8            
402:                    ErrorManager emgr = ErrorManager.getDefault();
403:                    IOException ioex = new IOException("Unsupported encoding "
404:                            + enc); // NOI18N
405:                    emgr.annotate(ioex, Util.THIS.getString(
406:                            "MSG_unsupported_encoding", enc));
407:                    throw ioex;
408:                }
409:            }
410:
411:            /*
412:             * Save document using encoding declared in XML prolog if possible otherwise
413:             * at UTF-8 (in such case it updates the prolog).
414:             */
415:            public void saveDocument() throws IOException {
416:                if (Util.THIS.isLoggable()) /* then */
417:                    Util.THIS.debug("saveDocument()..."); // NOI18N        
418:                final StyledDocument doc = getDocument();
419:                String enc = EncodingUtil.detectEncoding(doc);
420:                if (Util.THIS.isLoggable()) /* then */
421:                    Util.THIS
422:                            .debug("!!! TextEditorSupport::saveDocument: enc = "
423:                                    + enc);
424:                if (enc == null) {
425:                    enc = "UTF8"; //!!! // NOI18N
426:                }
427:                try {
428:                    //test encoding on dummy stream
429:                    new OutputStreamWriter(new ByteArrayOutputStream(1), enc);
430:                    if (!checkCharsetConversion(EncodingUtil
431:                            .getJava2IANAMapping(enc))) {
432:                        if (Util.THIS.isLoggable()) /* then */
433:                            Util.THIS.debug("Let unsaved."); // NOI18N
434:                        return;
435:                    }
436:                    super .saveDocument();
437:                    //moved from Env.save()
438:                    getDataObject().setModified(false);
439:                    getXMLDataObjectLook().getSyncInterface()
440:                            .representationChanged(Document.class);
441:                } catch (UnsupportedEncodingException ex) {
442:                    //ask user what next?
443:                    NotifyDescriptor descriptor = new NotifyDescriptor.Confirmation(
444:                            java.text.MessageFormat.format(Util.THIS
445:                                    .getString("TEXT_SAVE_AS_UTF"),
446:                                    new Object[] { enc }));
447:                    Object res = DialogDisplayer.getDefault()
448:                            .notify(descriptor);
449:                    if (res.equals(NotifyDescriptor.YES_OPTION)) {
450:                        updateDocumentWithNewEncoding(doc);
451:                    } else { // NotifyDescriptor != YES_OPTION
452:                        if (Util.THIS.isLoggable()) /* then */
453:                            Util.THIS.debug("Let unsaved."); // NOI18N
454:                        throw new UserCancelException();
455:                    }
456:                } // of catch UnsupportedEncodingException
457:            }
458:
459:            /**
460:             * update prolog to new valid encoding
461:             */
462:            private void updateDocumentWithNewEncoding(final StyledDocument doc)
463:                    throws IOException {
464:                try {
465:                    final int MAX_PROLOG = 1000;
466:                    int maxPrologLen = Math.min(MAX_PROLOG, doc.getLength());
467:                    final char prolog[] = doc.getText(0, maxPrologLen)
468:                            .toCharArray();
469:                    int prologLen = 0; // actual prolog length
470:                    //parse prolog and get prolog end
471:                    if (prolog[0] == '<' && prolog[1] == '?'
472:                            && prolog[2] == 'x') {
473:                        // look for delimitting ?>
474:                        for (int i = 3; i < maxPrologLen; i++) {
475:                            if (prolog[i] == '?' && prolog[i + 1] == '>') {
476:                                prologLen = i + 1;
477:                                break;
478:                            }
479:                        }
480:                    }
481:                    final int passPrologLen = prologLen;
482:                    Runnable edit = new Runnable() {
483:                        public void run() {
484:                            try {
485:                                doc.remove(0, passPrologLen + 1); // +1 it removes exclusive
486:                                doc.insertString(0,
487:                                        "<?xml version='1.0' encoding='UTF-8' ?> \n<!-- was: "
488:                                                + new String(prolog, 0,
489:                                                        passPrologLen + 1)
490:                                                + " -->", null); // NOI18N
491:                            } catch (BadLocationException e) {
492:                                if (System
493:                                        .getProperty("netbeans.debug.exceptions") != null) // NOI18N
494:                                    e.printStackTrace();
495:                            }
496:                        }
497:                    };
498:                    NbDocument.runAtomic(doc, edit);
499:                    super .saveDocument();
500:                    //moved from Env.save()
501:                    getDataObject().setModified(false);
502:                    getXMLDataObjectLook().getSyncInterface()
503:                            .representationChanged(Document.class);
504:                    if (Util.THIS.isLoggable()) /* then */
505:                        Util.THIS.debug("Saved."); // NOI18N
506:                } catch (BadLocationException lex) {
507:                    ErrorManager.getDefault().notify(lex);
508:                }
509:            }
510:
511:            private boolean checkCharsetConversion(String encoding) /*throws UnsupportedEncodingException*/{
512:                boolean value = true;
513:                try {
514:                    java.nio.charset.CharsetEncoder coder = java.nio.charset.Charset
515:                            .forName(encoding).newEncoder();
516:                    if (!coder.canEncode(getDocument().getText(0,
517:                            getDocument().getLength()))) {
518:                        NotifyDescriptor nd = new NotifyDescriptor.Confirmation(
519:                                NbBundle
520:                                        .getMessage(
521:                                                TextEditorSupport.class,
522:                                                "MSG_BadCharConversion", //NOI18N
523:                                                new Object[] {
524:                                                        getDataObject()
525:                                                                .getPrimaryFile()
526:                                                                .getNameExt(),
527:                                                        encoding }),
528:                                NotifyDescriptor.YES_NO_OPTION,
529:                                NotifyDescriptor.WARNING_MESSAGE);
530:                        nd.setValue(NotifyDescriptor.NO_OPTION);
531:                        DialogDisplayer.getDefault().notify(nd);
532:                        if (nd.getValue() != NotifyDescriptor.YES_OPTION)
533:                            value = false;
534:                    }
535:                } catch (javax.swing.text.BadLocationException e) {
536:                    ErrorManager.getDefault().notify(
537:                            ErrorManager.INFORMATIONAL, e);
538:                }
539:                /*catch (java.nio.charset.UnsupportedCharsetException e){
540:                    throw new UnsupportedEncodingException();
541:                }*/
542:                return value;
543:            }
544:
545:            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SYNC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
546:
547:            /**
548:             * TEXT changed -> update TREE.
549:             */
550:            protected void syncDocument(boolean fromFocus) {
551:                if (Util.THIS.isLoggable()) /* then */
552:                    Util.THIS
553:                            .debug("@@ TextEditorSupport::syncDocument: fromFocus = "
554:                                    + fromFocus);
555:                if (Util.THIS.isLoggable()) /* then */
556:                    Util.THIS
557:                            .debug("@@                  ::syncDocument: timer.isRunning = "
558:                                    + timer.isRunning());
559:
560:                if (fromFocus && !timer.isRunning())
561:                    return;
562:                if (timer.isRunning())
563:                    timer.stop();
564:
565:                XMLDataObjectLook sync = getXMLDataObjectLook();
566:                if (sync != null) { // && isModified()) {
567:                    sync.getSyncInterface().representationChanged(
568:                            Document.class);
569:                }
570:
571:            }
572:
573:            int getAutoParsingDelay() {
574:                return 3000;
575:            }
576:
577:            /** Restart the timer which starts the parser after the specified delay.
578:             * @param onlyIfRunning Restarts the timer only if it is already running
579:             */
580:            void restartTimer(boolean onlyIfRunning) {
581:                if (Util.THIS.isLoggable()) /* then */
582:                    Util.THIS
583:                            .debug("## TextEditorSupport::restartTimer: onlyIfRunning = "
584:                                    + onlyIfRunning);
585:                if (Util.THIS.isLoggable()) /* then */
586:                    Util.THIS
587:                            .debug("##                  ::restartTimer: timer.isRunning = "
588:                                    + timer.isRunning());
589:
590:                if (onlyIfRunning && !timer.isRunning())
591:                    return;
592:
593:                int delay = getAutoParsingDelay();
594:                if (delay > 0) {
595:                    timer.setInitialDelay(delay);
596:                    timer.restart();
597:                }
598:            }
599:
600:            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
601:
602:            /*
603:             * An entry point via EditCookie.
604:             * Delegate to <code>openDocument()</code>.
605:             */
606:            public final void edit() {
607:
608:                try {
609:                    openDocument(); //use sync version of call  - prepare encodingErr
610:                    if (encodingErr) {
611:                        String pattern = Util.THIS
612:                                .getString("TEXT_WRONG_ENCODING");
613:                        String msg = MessageFormat
614:                                .format(
615:                                        pattern,
616:                                        new Object[] { getDataObject()
617:                                                .getPrimaryFile().toString() /*compatibleEntry.getFile().toString()*/});
618:                        DialogDisplayer.getDefault().notify(
619:                                new NotifyDescriptor.Message(msg,
620:                                        NotifyDescriptor.ERROR_MESSAGE));
621:
622:                    } else {
623:                        Mutex.EVENT.writeAccess(new Runnable() {
624:                            public void run() {
625:                                CloneableTopComponent editor = openCloneableEditor();
626:                                editor.requestActive();
627:                            }
628:                        });
629:                    }
630:                } catch (UserQuestionException e) { //this is a hack due to the issue #50701
631:                    open();
632:                    if (isDocumentLoaded()) {
633:                        if (encodingErr) {
634:                            String pattern = Util.THIS
635:                                    .getString("TEXT_WRONG_ENCODING");
636:                            String msg = MessageFormat
637:                                    .format(
638:                                            pattern,
639:                                            new Object[] { getDataObject()
640:                                                    .getPrimaryFile()
641:                                                    .toString() /*compatibleEntry.getFile().toString()*/});
642:                            DialogDisplayer.getDefault().notify(
643:                                    new NotifyDescriptor.Message(msg,
644:                                            NotifyDescriptor.ERROR_MESSAGE));
645:
646:                        } else {
647:                            Mutex.EVENT.writeAccess(new Runnable() {
648:                                public void run() {
649:                                    CloneableTopComponent editor = openCloneableEditor();
650:                                    editor.requestActive();
651:                                }
652:                            });
653:                        }
654:                    }
655:                } catch (IOException ex) {
656:                    String pattern = Util.THIS.getString("TEXT_LOADING_ERROR");
657:                    String msg = MessageFormat
658:                            .format(
659:                                    pattern,
660:                                    new Object[] { getDataObject()
661:                                            .getPrimaryFile().toString() /*compatibleEntry.getFile().toString()*/});
662:                    DialogDisplayer.getDefault().notify(
663:                            new NotifyDescriptor.Message(msg,
664:                                    NotifyDescriptor.ERROR_MESSAGE));
665:                }
666:
667:            }
668:
669:            /*
670:             * Simply open for an cloneable editor. It at first tries to locate
671:             * existing component in <code>allEditors</code> then if it fails create new one
672:             * and registers it with <code>allEditors>/code>.
673:             */
674:            protected final CloneableEditor openCloneableEditor() {
675:
676:                CloneableEditor ret = null;
677:
678:                synchronized (getLock()) {
679:
680:                    String msg = messageOpening();
681:                    if (msg != null) {
682:                        StatusDisplayer.getDefault().setStatusText(msg);
683:                    }
684:
685:                    Enumeration en = allEditors.getComponents();
686:                    while (en.hasMoreElements()) {
687:                        CloneableTopComponent editor = (CloneableTopComponent) en
688:                                .nextElement();
689:                        if (editor instanceof  CloneableEditor) {
690:                            editor.open();
691:                            ret = (CloneableEditor) editor;
692:                        }
693:                    }
694:
695:                    // no opened editor, create a new one
696:
697:                    if (ret == null) {
698:                        CloneableEditor editor = (CloneableEditor) createCloneableTopComponent(); // this is important -- see final createCloneableTopComponent
699:                        editor.setReference(allEditors);
700:                        editor.open();
701:                        ret = editor;
702:                    }
703:
704:                    msg = messageOpened();
705:                    if (msg == null) {
706:                        msg = ""; // NOI18N
707:                    }
708:                    StatusDisplayer.getDefault().setStatusText(msg);
709:
710:                    return ret;
711:                }
712:            }
713:
714:            /**
715:             * Creates lock object used in close and openCloneableTopComponent.
716:             * @return never null
717:             */
718:            protected Object getLock() {
719:                if (awtLock == null) {
720:                    awtLock = new java.awt.Container();
721:                }
722:                return awtLock.getTreeLock();
723:            }
724:
725:            /*
726:             * @return component visualizing this support.
727:             */
728:            protected CloneableEditor createCloneableEditor() {
729:                return new TextEditorComponent(this );
730:            }
731:
732:            // This must call super createCloneableTopComponent because it prepare document, create cloneable editor and initialize it. See super.
733:            protected final CloneableTopComponent createCloneableTopComponent() {
734:                return super .createCloneableTopComponent(); // creates CloneableEditor (calling createCloneableEditor)
735:            }
736:
737:            /**
738:             */
739:            public static final TextEditorSupportFactory findEditorSupportFactory(
740:                    XMLDataObjectLook xmlDO, String mime) {
741:                return new TextEditorSupportFactory(xmlDO, mime);
742:            }
743:
744:            //
745:            // class Env
746:            //
747:
748:            /**
749:             *
750:             */
751:            protected static class Env extends DataEditorSupport.Env implements 
752:                    SaveCookie {
753:
754:                /** Serial Version UID */
755:                private static final long serialVersionUID = -5285524519399090028L;
756:
757:                /** */
758:                public Env(XMLDataObjectLook obj) {
759:                    super ((DataObject) obj);
760:                }
761:
762:                /**
763:                 */
764:                protected XMLDataObjectLook getXMLDataObjectLook() {
765:                    return (XMLDataObjectLook) getDataObject();
766:                }
767:
768:                /**
769:                 */
770:                protected FileObject getFile() {
771:                    return getDataObject().getPrimaryFile();
772:                }
773:
774:                /**
775:                 */
776:                protected FileLock takeLock() throws IOException {
777:                    return ((MultiDataObject) getDataObject())
778:                            .getPrimaryEntry().takeLock();
779:                }
780:
781:                /**
782:                 */
783:                public synchronized void save() throws IOException {
784:                    findTextEditorSupport().saveDocument();
785:                }
786:
787:                /**
788:                 */
789:                public CloneableOpenSupport findCloneableOpenSupport() {
790:                    return findTextEditorSupport();
791:                }
792:
793:                /**
794:                 */
795:                public TextEditorSupport findTextEditorSupport() {
796:                    EditCookie cookie = getDataObject().getCookie(
797:                            EditCookie.class);
798:                    if (cookie instanceof  TextEditorSupport)
799:                        return (TextEditorSupport) cookie;
800:
801:                    return null;
802:                }
803:
804:                // copy pasted, do not get it
805:                public void propertyChange(PropertyChangeEvent ev) {
806:                    if (DataObject.PROP_PRIMARY_FILE.equals(ev
807:                            .getPropertyName())) {
808:                        changeFile();
809:                    }
810:                    super .propertyChange(ev);
811:                }
812:
813:            } // end: class Env
814:
815:            //
816:            // class TextEditorSupportFactory
817:            //
818:
819:            /**
820:             *
821:             */
822:            public static class TextEditorSupportFactory implements 
823:                    CookieSet.Factory {
824:                /** */
825:                private WeakReference editorRef;
826:                /** */
827:                private final XMLDataObjectLook dataObject; // used while creating the editor
828:                /** */
829:                private final String mime; // used while creating the editor
830:
831:                //
832:                // init
833:                //
834:
835:                /** Create new TextEditorSupportFactory. */
836:                public TextEditorSupportFactory(XMLDataObjectLook dobj,
837:                        String mime) {
838:                    this .dataObject = dobj;
839:                    this .mime = mime;
840:                }
841:
842:                /**
843:                 */
844:                protected Class[] supportedCookies() {
845:                    return new Class[] { EditorCookie.class,
846:                            EditorCookie.Observable.class, EditCookie.class,
847:                            CloseCookie.class, PrintCookie.class, };
848:                }
849:
850:                /**
851:                 */
852:                public final void registerCookies(CookieSet cookieSet) {
853:                    Class[] supportedCookies = supportedCookies();
854:                    for (int i = 0; i < supportedCookies.length; i++) {
855:                        cookieSet.add(supportedCookies[i], this );
856:                    }
857:                }
858:
859:                /** Creates a Node.Cookie of given class. The method
860:                 * may be called more than once.
861:                 */
862:                public final Node.Cookie createCookie(Class klass) {
863:                    Class[] supportedCookies = supportedCookies();
864:                    for (int i = 0; i < supportedCookies.length; i++) {
865:                        if (supportedCookies[i].isAssignableFrom(klass)) {
866:                            return createEditor();
867:                        }
868:                    }
869:                    return null;
870:                }
871:
872:                /**
873:                 */
874:                private final synchronized TextEditorSupport createEditor() { // atomic test and set
875:                    TextEditorSupport editorSupport = null;
876:
877:                    if (editorRef != null) {
878:                        editorSupport = (TextEditorSupport) editorRef.get();
879:                    }
880:                    if (editorSupport == null) {
881:                        editorSupport = prepareEditor();
882:                        editorRef = new WeakReference(editorSupport);
883:                    }
884:
885:                    return editorSupport;
886:                }
887:
888:                /**
889:                 */
890:                protected TextEditorSupport prepareEditor() {
891:                    if (Util.THIS.isLoggable()) /* then */
892:                        Util.THIS.debug("Initializing TextEditorSupport ..."); // NOI18N
893:
894:                    return new TextEditorSupport(getDataObject(), getMIMEType());
895:                }
896:
897:                /**
898:                 */
899:                protected final XMLDataObjectLook getDataObject() {
900:                    return dataObject;
901:                }
902:
903:                /**
904:                 */
905:                protected final String getMIMEType() {
906:                    return mime;
907:                }
908:
909:            } // end of class TextEditorSupportFactory
910:
911:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.