Source Code Cross Referenced for SourceUnit.java in  » IDE-Netbeans » visualweb.api.designer » org » netbeans » modules » visualweb » insync » 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 » visualweb.api.designer » org.netbeans.modules.visualweb.insync 
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-2007 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.visualweb.insync;
042:
043:        import java.beans.PropertyChangeEvent;
044:        import java.beans.PropertyChangeListener;
045:        import java.io.BufferedWriter;
046:        import java.io.OutputStream;
047:        import java.io.OutputStreamWriter;
048:        import java.io.PrintWriter;
049:        import java.io.StringWriter;
050:        import java.io.Writer;
051:        import java.io.IOException;
052:        import java.util.Date;
053:        import java.util.HashSet;
054:        import java.util.Iterator;
055:        import java.util.concurrent.atomic.AtomicBoolean;
056:
057:        import javax.swing.event.DocumentEvent;
058:        import javax.swing.event.DocumentListener;
059:        import javax.swing.event.UndoableEditEvent;
060:        import javax.swing.event.UndoableEditListener;
061:        import javax.swing.text.StyledDocument;
062:
063:        import org.openide.ErrorManager;
064:        import org.openide.cookies.EditorCookie;
065:        import org.openide.filesystems.FileAttributeEvent;
066:        import org.openide.filesystems.FileChangeListener;
067:        import org.openide.filesystems.FileEvent;
068:        import org.openide.filesystems.FileObject;
069:        import org.openide.filesystems.FileRenameEvent;
070:        import org.openide.filesystems.FileUtil;
071:        import org.openide.loaders.DataObject;
072:        import org.openide.text.CloneableEditorSupport;
073:        import org.openide.text.NbDocument;
074:        import org.openide.cookies.SaveCookie;
075:
076:        import org.netbeans.modules.visualweb.extension.openide.util.Trace;
077:
078:        /**
079:         * A partial Unit implementation that provides common functionality for all source-based Units.
080:         * @author Carl Quinn
081:         */
082:        public abstract class SourceUnit implements  Unit, DocumentListener,
083:                UndoableEditListener, PropertyChangeListener,
084:                FileChangeListener {
085:
086:            // Information about this unit
087:            protected FileObject fobj; // may be null, e.g. for testsuite & stand-alone use
088:            protected StyledDocument styledDocument;
089:            protected UndoManager undoManager;
090:            private DataObject dataObject = null;
091:            private EditorCookie ec = null;
092:
093:            protected Date lastModified;
094:            private FileChangeListener lastModifiedTracker;
095:
096:            protected Date lastModelDirty;
097:
098:            private AtomicBoolean documentListenerAdded = new AtomicBoolean(
099:                    false);
100:            private AtomicBoolean undoableEditListenerAdded = new AtomicBoolean(
101:                    false);
102:
103:            //--------------------------------------------------------------------------------- Construction
104:
105:            /**
106:             * Construct a SourceUnit from an existing source Document
107:             * @param dobj
108:             */
109:            protected SourceUnit(FileObject fobj, UndoManager undoManager) {
110:                this .fobj = fobj;
111:                // Cache the data object. If the data object is not cached
112:                // then diffrent CloneableEditorSupport may be created for
113:                // the FileObject on request and our added listener may be lost.
114:
115:                try {
116:                    dataObject = DataObject.find(fobj);
117:                } catch (Exception exc) {
118:                    ErrorManager.getDefault().notify(exc);
119:                }
120:                this .undoManager = undoManager;
121:                //Trace.enableTraceCategory("insync");
122:
123:                state = State.SOURCEDIRTY; // need to perform initial read of source into model
124:
125:                // Listen for the editor closing the document so that we can release it
126:                ec = (EditorCookie) Util.getCookie(fobj, EditorCookie.class);
127:                if (ec instanceof  CloneableEditorSupport)
128:                    ((CloneableEditorSupport) ec)
129:                            .addPropertyChangeListener(this );
130:
131:                styledDocument = ec.getDocument(); // get if open. Do not block
132:
133:                if (styledDocument != null) {
134:                    addDocumentListener();
135:                    addUndoableEditListener();
136:                } else {
137:
138:                    // Add listener to the File Object so that we can listen to the FileObject modification
139:                    // When the StyledDocument is obtained, the listener will be removed and then on we listen
140:                    // only to the StyledDocument events.
141:                    fobj.addFileChangeListener(this );
142:                }
143:                lastModified = fobj.lastModified();
144:                lastModifiedTracker = new FileChangeListener() {
145:                    public void fileAttributeChanged(FileAttributeEvent fe) {
146:                    }
147:
148:                    public void fileChanged(FileEvent fe) {
149:                        lastModified = SourceUnit.this .fobj.lastModified();
150:                    }
151:
152:                    public void fileDataCreated(FileEvent fe) {
153:                    }
154:
155:                    public void fileDeleted(FileEvent fe) {
156:                    }
157:
158:                    public void fileFolderCreated(FileEvent fe) {
159:                    }
160:
161:                    public void fileRenamed(FileRenameEvent fe) {
162:                        lastModified = SourceUnit.this .fobj.lastModified();
163:                    }
164:                };
165:                fobj.addFileChangeListener(lastModifiedTracker);
166:            }
167:
168:            /*
169:             * @see org.netbeans.modules.visualweb.insync.Unit#destroy()
170:             */
171:            public void destroy() {
172:                releaseDocument();
173:                // Make sure FileObject listener is also removed that was added by the
174:                // above releaseDocument() call
175:                if (fobj != null) {
176:                    fobj.removeFileChangeListener(this );
177:                    fobj.removeFileChangeListener(lastModifiedTracker);
178:                }
179:                listeners = null;
180:
181:                if (ec instanceof  CloneableEditorSupport) {
182:                    ((CloneableEditorSupport) ec)
183:                            .removePropertyChangeListener(this );
184:                    ec = null;
185:                }
186:                undoManager = null;
187:            }
188:
189:            //----------------------------------- Implementation of file change listener ------------------
190:
191:            public void fileFolderCreated(FileEvent fe) {
192:            }
193:
194:            public void fileDataCreated(FileEvent fe) {
195:            }
196:
197:            public void fileChanged(FileEvent fe) {
198:                // If both the model and the disk copy have been changed,
199:                // take the model.
200:                if (state != State.MODELDIRTY) {
201:                    setSourceDirty();
202:                }
203:            }
204:
205:            public void fileDeleted(FileEvent fe) {
206:            }
207:
208:            public void fileRenamed(FileRenameEvent fe) {
209:            }
210:
211:            public void fileAttributeChanged(FileAttributeEvent fe) {
212:            }
213:
214:            //---------------------------------------------------------------------------- Document handling
215:
216:            /**
217:             * Release the current document and all listener hooks. The document will have to be grabbed 
218:             * again before use.
219:             */
220:            protected void releaseDocument() {
221:                if (styledDocument != null) {
222:                    removeDocumentListener();
223:                    removeUndoableEditListener();
224:                    styledDocument = null;
225:
226:                    //need to tell the undo manager to clear events on the Undo/Redo stack
227:                    if (undoManager != null) { // XXX Prevent NPE from leaked unit?
228:                        undoManager.notifyBufferEdited(this );
229:                    }
230:
231:                    // Add back the FileObject change listener, now that we no longer 
232:                    // listen to the StyledDocument changes
233:                    if (fobj != null) { // XXX Prevent NPE from leaked unit?
234:                        fobj.addFileChangeListener(this );
235:                    }
236:                }
237:            }
238:
239:            /*
240:             * Looks like the editor is getting a new document--release our grip on it for now.
241:             * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
242:             */
243:            public void propertyChange(PropertyChangeEvent event) {
244:                if (EditorCookie.Observable.PROP_DOCUMENT.equals(event
245:                        .getPropertyName())) {
246:                    if (event.getNewValue() == null) {
247:                        // Check if the model was dirtied after opening or last saving
248:                        try {
249:                            if (lastModelDirty != null
250:                                    && lastModified.before(lastModelDirty)) {
251:                                setSourceDirty();
252:                            }
253:                        } finally {
254:                            lastModified = fobj.lastModified();
255:                            lastModelDirty = null;
256:                            releaseDocument();
257:                        }
258:                    }
259:                    if ((event.getNewValue() != null)
260:                            && (event.getOldValue() == null)) {
261:                        // Remove the FileObject change listener, now that we start
262:                        // listening to the StyledDocument changes
263:                        fobj.removeFileChangeListener(this );
264:                        styledDocument = (StyledDocument) event.getNewValue();
265:                        addDocumentListener();
266:                        addUndoableEditListener();
267:                    }
268:
269:                } else if (EditorCookie.Observable.PROP_MODIFIED.equals(event
270:                        .getPropertyName())) {
271:                    // TODO !EAT: Take a look at cleaning up the need for listeners ?
272:                    Boolean newValue = (Boolean) event.getNewValue();
273:                    if (newValue != null && newValue.equals(Boolean.FALSE)) {
274:                        fireSaved();
275:                    }
276:                }
277:            }
278:
279:            //------------------------------------------------------------------------------- State tracking
280:
281:            State state = State.CLEAN;
282:
283:            /*
284:             * @see org.netbeans.modules.visualweb.insync.Unit#getState()
285:             */
286:            public State getState() {
287:                return state;
288:            }
289:
290:            /*
291:             * @see org.netbeans.modules.visualweb.insync.Unit#getErrors()
292:             */
293:            public ParserAnnotation[] getErrors() {
294:                return ParserAnnotation.EMPTY_ARRAY;
295:            }
296:
297:            /**
298:             * Called by various subclasses when they actually mutate their model
299:             */
300:            public void setModelDirty() {
301:                // Record model dirty timestamp
302:                lastModelDirty = new Date();
303:                //This would be good, but many sync() handlers would need a lock and cant place it with source dirty...
304:                //if (writerCount == 0)
305:                //    throw new IllegalStateException("Illegal model modification without a lock " + name);
306:                if (state == State.SOURCEDIRTY)
307:                    throw new IllegalStateException(
308:                            "Illegal model modification with dirty source "
309:                                    + getName());
310:                if (state == State.MODELDIRTY)
311:                    return; // Already dirty
312:                // We know that this is just a temporary state and that a flush will be coming soon anyway
313:                //markDocumentModified();
314:                if (state == State.CLEAN) {
315:                    assert Trace.trace("insync",
316:                            "SU.setModelDirty UpToDate => ModelDirty");
317:                    state = State.MODELDIRTY;
318:                    fireModelDirtied();
319:                }
320:            }
321:
322:            /**
323:             * Called by document listeners to let us know that our buffer is dirty and needs re-syncing
324:             */
325:            public void setSourceDirty() {
326:                if (state == State.MODELDIRTY) {
327:                    // When a file is moved, it is copied to new destination, and old file is deleted.
328:                    // We could be notified of the copy being created prior to the delete, in that case
329:                    // I will still be listening on document events that do not pertain to me anymore, so
330:                    // ignore that case.
331:                    if (fobj != null && !fobj.isValid())
332:                        return;
333:                    throw new IllegalStateException(
334:                            "Illegal source modification with dirty model "
335:                                    + getName());
336:                }
337:                if (state != State.SOURCEDIRTY) {
338:                    // See above, breaking it out so test is not always done
339:                    if (fobj != null && !fobj.isValid())
340:                        return;
341:                    if (state == State.CLEAN) {
342:                        assert Trace.trace("insync",
343:                                "SU.setModelDirty Clean => SourceDirty");
344:                        state = State.SOURCEDIRTY;
345:                    } else if (state == State.BUSTED) {
346:                        assert Trace.trace("insync",
347:                                "SU.setModelDirty Busted => SourceDirty");
348:                        state = State.SOURCEDIRTY;
349:                    }
350:                    fireSourceDirtied();
351:                }
352:            }
353:
354:            /**
355:             * Return true if my state is busted.
356:             * @return
357:             */
358:            public boolean isBusted() {
359:                return state.isBusted();
360:            }
361:
362:            /**
363:             * Mark the source as being busted - e.g. cannot be parsed.
364:             * @todo Provide notification of invalid state changes?
365:             */
366:            public void setBusted() {
367:                if (state == State.BUSTED)
368:                    return; // Already busted
369:                if (state == State.SOURCEDIRTY) {
370:                    assert Trace.trace("insync",
371:                            "SU.setInvalid SourceDirty => Busted");
372:                    state = State.BUSTED;
373:                } else { // should only be called during a sync - from source dirty state
374:                    throw new IllegalStateException(
375:                            "Illegal source busting from " + state + " "
376:                                    + getName());
377:                }
378:            }
379:
380:            /**
381:             *
382:             */
383:            public void setClean() {
384:                //Note: applying a model brings you up to date but not saved - don't
385:                // call notifyUnmodified
386:                if (state == State.SOURCEDIRTY)
387:                    assert Trace.trace("insync",
388:                            "SU.setSourceUpToDate SourceDirty => Clean");
389:                else if (state == State.BUSTED)
390:                    assert Trace.trace("insync",
391:                            "SU.setSourceUpToDate Busted => Clean");
392:                else if (state == State.MODELDIRTY)
393:                    assert Trace.trace("insync",
394:                            "SU.setSourceUpToDate ModelDirty => Clean");
395:                state = State.CLEAN;
396:            }
397:
398:            //----------------------------------------------------------------------------- DocumentListener
399:
400:            /*
401:             * @see javax.swing.event.DocumentListener#changedUpdate(javax.swing.event.DocumentEvent)
402:             */
403:            public void changedUpdate(DocumentEvent e) {
404:                assert Trace.trace("insync-listener", "SU.changedUpdate");
405:                //setSourceDirty();  // these are usually non-substantial changes but things
406:                // like editor annotations uses attributes so just adding a breakpoint to
407:                // a line will cause a changedUpdate which we definitely don't want to treat
408:                // as an insert/delete/source dirty operation
409:            }
410:
411:            /*
412:             * @see javax.swing.event.DocumentListener#insertUpdate(javax.swing.event.DocumentEvent)
413:             */
414:            public void insertUpdate(DocumentEvent e) {
415:                assert Trace.trace("insync-listener", "SU.insertUpdate");
416:                undoManager.notifyBufferEdited(this );
417:                setSourceDirty();
418:            }
419:
420:            /*
421:             * @see javax.swing.event.DocumentListener#removeUpdate(javax.swing.event.DocumentEvent)
422:             */
423:            public void removeUpdate(DocumentEvent e) {
424:                assert Trace.trace("insync-listener", "SU.removeUpdate");
425:                undoManager.notifyBufferEdited(this );
426:                setSourceDirty();
427:            }
428:
429:            /*
430:             * @see javax.swing.event.UndoableEditListener#undoableEditHappened(javax.swing.event.UndoableEditEvent)
431:             */
432:            public void undoableEditHappened(UndoableEditEvent e) {
433:                if (undoManager != null) {
434:                    undoManager.notifyUndoableEditEvent(this );
435:                }
436:            }
437:
438:            //-------------------------------------------------------------------------------------- Locking
439:
440:            int readerCount;
441:            int writerCount;
442:            Thread writingThread;
443:
444:            /**
445:             * Fetches the current writing thread if there is one. This can be used to distinguish whether a
446:             * method is being called as part of an existing modification or if a lock needs to be acquired
447:             * and a new transaction started.
448:             *
449:             * @return the thread actively modifying the document or <code>null</code> if there are no
450:             *         modifications in progress
451:             */
452:            protected synchronized final Thread getWritingThread() {
453:                return writingThread;
454:            }
455:
456:            /*
457:             * @see org.netbeans.modules.visualweb.insync.Unit#writeLock(org.netbeans.modules.visualweb.insync.UndoEvent)
458:             */
459:            public synchronized final void writeLock(UndoEvent event) {
460:                //if (state == State.SOURCEDIRTY)
461:                //    throw new IllegalStateException("SU.writeLock attempt to writeLock a model with dirty source");
462:                //if (state == State.BUSTED) {
463:                //    throw new IllegalStateException("SU.writeLock attempt to writeLock a model with busted source");
464:                //}
465:                try {
466:                    while (readerCount > 0 || writingThread != null) {
467:                        if (Thread.currentThread() == writingThread) {
468:                            /*
469:                            if (notifyingListeners) {
470:                                // Assuming one doesn't do something wrong in a subclass this should only
471:                                // happen if a UnitListener tries to mutate the unit.
472:                                throw new IllegalStateException("Attempt to mutate in notification");
473:                            }*/
474:                            writerCount++;
475:                            return;
476:                        }
477:                        wait();
478:                    }
479:                    writingThread = Thread.currentThread();
480:                    writerCount = 1;
481:                    firstWriteLock();
482:                    //if (doc instanceof BaseDocument)
483:                    //    ((BaseDocument)doc).atomicLock();
484:                    // or even:
485:                    // doc.writeLock();
486:                } catch (InterruptedException e) {
487:                    throw new UnsupportedOperationException(
488:                            "Interrupted attempt to aquire write lock");
489:                }
490:                return;
491:            }
492:
493:            /*
494:             * @see org.netbeans.modules.visualweb.insync.Unit#writeUnlock(org.netbeans.modules.visualweb.insync.UndoEvent)
495:             */
496:            public synchronized final boolean writeUnlock(UndoEvent event) {
497:                if (--writerCount <= 0) {
498:                    //if (doc instanceof BaseDocument)
499:                    //    ((BaseDocument)doc).atomicUnlock();
500:                    // or even:
501:                    // doc.writeUnlock();
502:                    writerCount = 0;
503:                    flush();
504:                    writingThread = null;
505:                    lastWriteUnlock();
506:                    notifyAll();
507:                    return true;
508:                }
509:                return false;
510:            }
511:
512:            /*
513:             * @see org.netbeans.modules.visualweb.insync.Unit#isWriteLocked()
514:             */
515:            public boolean isWriteLocked() {
516:                return writerCount > 0;
517:            }
518:
519:            /*
520:             * @see org.netbeans.modules.visualweb.insync.Unit#readLock()
521:             */
522:            public synchronized final void readLock() {
523:                try {
524:                    while (writingThread != null) {
525:                        if (writingThread == Thread.currentThread()) {
526:                            // writer has full read access.... may try to acquire
527:                            // lock in notification
528:                            return;
529:                        }
530:                        wait();
531:                    }
532:                    readerCount += 1;
533:                } catch (InterruptedException e) {
534:                    throw new UnsupportedOperationException(
535:                            "Interrupted attempt to aquire read lock");
536:                }
537:            }
538:
539:            /*
540:             * @see org.netbeans.modules.visualweb.insync.Unit#readUnlock()
541:             */
542:            public synchronized final void readUnlock() {
543:                if (writingThread == Thread.currentThread()) {
544:                    // writer has full read access.... may try to acquire
545:                    // lock in notification
546:                    return;
547:                }
548:                if (readerCount <= 0)
549:                    throw new IllegalStateException("BAD_LOCK_STATE");
550:                readerCount -= 1;
551:                notify();
552:            }
553:
554:            //---------------------------------------------------------------------------------------- Input
555:
556:            /**
557:             * Read the actual characters from the source document's content. Concrete subclasses must
558:             * override this method to process the buffer characters into the model.
559:             */
560:            protected abstract void read(char[] cbuf, int len);
561:
562:            /**
563:             * Load the document into buf
564:             */
565:            private final Util.BufferResult loadBuf() {
566:                Util.BufferResult bufferResult;
567:                if (styledDocument == null) {
568:                    bufferResult = Util.loadFileObjectBuffer(fobj);
569:                } else {
570:                    bufferResult = Util.loadDocumentBuffer(styledDocument);
571:                }
572:                return bufferResult;
573:            }
574:
575:            /**
576:             * Implicit read. Read the document supplied during construction into this model.
577:             *
578:             * @return whether or not the read affected the model.
579:             */
580:            public boolean sync() {
581:                // make sure it is necessary & ok to read.
582:                //assert Trace.trace("insync", "SU.sync of " + getName() + " state:" + state + " len:" + styledDocument.getLength());
583:                if (state == State.CLEAN)
584:                    return false;
585:                if (state == State.MODELDIRTY) {
586:                    assert Trace
587:                            .trace("insync",
588:                                    "SU.sync attempt to read source into a dirty model");
589:                    //Trace.printStackTrace();
590:                    return false;
591:                }
592:
593:                Util.BufferResult bufferResult = loadBuf();
594:                read(bufferResult.getBuffer(), bufferResult.getSize());
595:
596:                if (state == State.SOURCEDIRTY) // read() may have set an error, if so don't do to Clean
597:                    setClean(); //state = State.CLEAN;
598:
599:                return true;
600:            }
601:
602:            //--------------------------------------------------------------------------------------- Output
603:
604:            /**
605:             * @param w
606:             * @throws java.io.IOException
607:             */
608:            public abstract void writeTo(Writer w) throws java.io.IOException;
609:
610:            /**
611:             * @param out
612:             * @throws java.io.IOException
613:             */
614:            public void writeTo(OutputStream out) throws java.io.IOException {
615:                Writer w = new BufferedWriter(new OutputStreamWriter(out));
616:                writeTo(w);
617:                w.flush();
618:            }
619:
620:            /**
621:             * @param out
622:             */
623:            public final void dumpTo(OutputStream out) {
624:                PrintWriter w = new PrintWriter(new BufferedWriter(
625:                        new OutputStreamWriter(out)));
626:                dumpTo(w);
627:                w.flush();
628:            }
629:
630:            /**
631:             * Internal routine for performing the smallest single update operation to the document given an
632:             * old document and a new text string.
633:             *
634:             * @param newText  The new document text contents.
635:             */
636:            protected boolean minimalReplace(String newText) {
637:                try {
638:                    Util.BufferResult bufferResult = loadBuf();
639:                    char[] buf = bufferResult.getBuffer();
640:                    int end = styledDocument.getLength();
641:                    int newEnd = newText.length();
642:                    int start = 0;
643:                    while (start < end && start < newEnd
644:                            && buf[start] == newText.charAt(start))
645:                        start++;
646:                    while (end > start && newEnd > start
647:                            && buf[end - 1] == newText.charAt(newEnd - 1)) {
648:                        end--;
649:                        newEnd--;
650:                    }
651:                    if (end > start || newEnd > start) {
652:                        String newSeg = (start > 0 || newEnd < newText.length()) ? newText
653:                                .substring(start, newEnd)
654:                                : newText;
655:                        styledDocument.remove(start, end - start);
656:                        styledDocument.insertString(start, newSeg, null);
657:                        return true;
658:                    }
659:                } catch (javax.swing.text.BadLocationException e) {
660:                    // we know the location we passed is good...
661:                    assert Trace.trace("insync",
662:                            "Unexpected error in SU.flush: " + e);
663:                }
664:                return false;
665:            }
666:
667:            /**
668:             * Flush this unit to its document, writing changes as needed and updating flags.
669:             *
670:             * @see #writeLock
671:             * @return true iff the document was written to by the operation public abstract boolean
672:             *         flush();
673:             */
674:            public boolean flush() {
675:                // make sure it is necessary & ok to write.
676:                Trace.trace("insync", "SU.flush of " + getName() + " state:"
677:                        + state);
678:                if (state == State.CLEAN)
679:                    return false;
680:
681:                // these two should not happen since we should have caught this at writeLock time
682:                if (state == State.SOURCEDIRTY) {
683:                    assert Trace
684:                            .trace("insync",
685:                                    "SU.flush attempt to flush a model with dirty source");
686:                    assert Trace.printStackTrace();
687:                    return false;
688:                }
689:                if (state == State.BUSTED) {
690:                    assert Trace
691:                            .trace("insync",
692:                                    "SU.flush attempt to flush a model with busted source");
693:                    return false;
694:                }
695:
696:                //grabDocument(State.MODELDIRTY, true);  // if the disk copy was dirty, too bad: nothing we can do
697:                if (styledDocument == null) {
698:                    styledDocument = Util.retrieveDocument(fobj, true);
699:                }
700:
701:                final boolean[] didReplace = new boolean[1];
702:
703:                // Flush to the document if the document exists
704:                if (styledDocument != null) {
705:                    //            System.out.println("SU.flush of " + getName() + " state:" + state + "Mode: Document");
706:                    // Seems no op
707:                    startFlush();
708:                    try {
709:                        // Stop listening to doc while it is us doing the writing
710:                        removeDocumentListener();
711:
712:                        // Lock the document atomically
713:                        // !TN TODO: BaseDocument.replace() should do this automatically;
714:                        // investigating that now
715:                        NbDocument.runAtomic(styledDocument, new Runnable() {
716:                            public void run() {
717:                                try {
718:                                    Writer w = new StringWriter();
719:                                    writeTo(w);
720:                                    didReplace[0] = minimalReplace(w.toString());
721:                                } catch (java.io.IOException e) {
722:                                    //!CQ TODO: log this better
723:                                    assert Trace.trace("insync",
724:                                            "Unexpected error in SU.flush: "
725:                                                    + e);
726:                                    ErrorManager.getDefault().notify(e);
727:                                }
728:                            }
729:                        });
730:                    } finally {
731:                        // Start listening again
732:                        addDocumentListener();
733:                        // Seems no op
734:                        endFlush(didReplace[0]);
735:                    }
736:                }
737:
738:                // Flush file documents -- used for testing
739:                if (styledDocument instanceof  FileDocument) {
740:                    FileDocument fdoc = (FileDocument) styledDocument;
741:                    try {
742:                        fdoc.write(); // flush to file
743:                    } catch (java.io.IOException e) {
744:                        assert Trace.trace("insync", "Can't write file: "
745:                                + getName());
746:                    }
747:                }
748:
749:                //state = State.CLEAN;
750:                setClean();
751:                return didReplace[0];
752:            }
753:
754:            /**
755:             * Saves the owning file using project apis
756:             */
757:            public void save() {
758:                DataObject dataObject = getDataObject();
759:                if (dataObject != null && state == State.CLEAN) {
760:                    SaveCookie cookie = (SaveCookie) dataObject
761:                            .getCookie(SaveCookie.class);
762:                    if (cookie != null) {
763:                        try {
764:                            cookie.save();
765:                        } catch (IOException e) {
766:                            throw new RuntimeException(e);
767:                        }
768:                    }
769:                }
770:            }
771:
772:            /**
773:             * Writer implementation to assist with brute-force output position rtacking.
774:             * @author cquinn
775:             */
776:            public class CountingWriter extends Writer {
777:                public int pos;
778:
779:                public void close() {
780:                }
781:
782:                public void flush() {
783:                    //System.err.flush();
784:                }
785:
786:                public void write(char[] buf) {
787:                    //System.err.print("("+pos+")");
788:                    //System.err.print(buf);
789:                    pos += buf.length;
790:                }
791:
792:                public void write(char[] buf, int off, int len) {
793:                    //System.err.print("("+pos+")");
794:                    //System.err.print(new String(buf).substring(off, len));
795:                    pos += len;
796:                }
797:
798:                public void write(int c) {
799:                    //System.err.print("("+pos+")");
800:                    //System.err.print(c);
801:                    pos += 1;
802:                }
803:
804:                public void write(String str) {
805:                    //System.err.print("("+pos+")");
806:                    //System.err.print(str);
807:                    pos += str.length();
808:                }
809:
810:                public void write(String str, int off, int len) {
811:                    //System.err.print("("+pos+")");
812:                    //System.err.print(str.substring(off, len));
813:                    pos += len;
814:                }
815:            }
816:
817:            //------------------------------------------------------------------------------------ Accessors
818:
819:            /**
820:             * @return
821:             */
822:            public String getName() {
823:                return FileUtil.toFile(fobj).getAbsolutePath();
824:            }
825:
826:            /**
827:             * @return
828:             */
829:            public StyledDocument getSourceDocument() {
830:                if (styledDocument == null) {
831:                    styledDocument = Util.retrieveDocument(fobj, true);
832:                }
833:                if (state != State.MODELDIRTY) {
834:                    state = State.CLEAN;
835:                }
836:                return styledDocument;
837:            }
838:
839:            /**
840:             * @return
841:             */
842:            public FileObject getFileObject() {
843:                return fobj;
844:            }
845:
846:            /**
847:             * @return
848:             */
849:            public DataObject getDataObject() {
850:                if (fobj != null && !fobj.isValid())
851:                    return null;
852:                return Util.findDataObject(fobj);
853:            }
854:
855:            protected HashSet listeners = null;
856:
857:            public void addListener(SourceUnitListener listener) {
858:                if (listeners == null)
859:                    listeners = new HashSet();
860:                listeners.add(listener);
861:            }
862:
863:            public void removeListener(SourceUnitListener listener) {
864:                if (listeners == null)
865:                    return;
866:                listeners.remove(listener);
867:            }
868:
869:            /**
870:             * Notify my listeners of the fact that my model has been made dirty.
871:             *
872:             */
873:            protected void fireModelDirtied() {
874:                if (listeners == null)
875:                    return;
876:                for (Iterator iterator = listeners.iterator(); iterator
877:                        .hasNext();) {
878:                    SourceUnitListener listener = (SourceUnitListener) iterator
879:                            .next();
880:                    listener.sourceUnitModelDirtied(this );
881:                }
882:            }
883:
884:            /**
885:             * Notify my listeners of the fact that my source has been made dirty.
886:             *
887:             */
888:            protected void fireSourceDirtied() {
889:                if (listeners == null)
890:                    return;
891:                for (Iterator iterator = listeners.iterator(); iterator
892:                        .hasNext();) {
893:                    SourceUnitListener listener = (SourceUnitListener) iterator
894:                            .next();
895:                    listener.sourceUnitSourceDirtied(this );
896:                }
897:            }
898:
899:            protected void fireSaved() {
900:                if (listeners == null)
901:                    return;
902:                for (Iterator iterator = listeners.iterator(); iterator
903:                        .hasNext();) {
904:                    SourceUnitListener listener = (SourceUnitListener) iterator
905:                            .next();
906:                    listener.sourceUnitSaved(this );
907:                }
908:            }
909:
910:            /**
911:             * Improve the readability of String display in debugger's variable inspector.
912:             */
913:            public String toString() {
914:                StringBuffer sb = new StringBuffer(30);
915:                sb.append("["); // NOI18N
916:                toString(sb);
917:                sb.append("]");
918:                return sb.toString();
919:            }
920:
921:            /**
922:             * Subclasses should override to Improve the readability of String display in debugger's variable inspector.
923:             */
924:            protected void toString(StringBuffer sb) {
925:                sb.append(getClass().getName().substring(
926:                        getClass().getPackage().getName().length() + 1));
927:                sb.append(" fobj: ");
928:                if (fobj == null) {
929:                    sb.append("null");
930:                } else {
931:                    sb.append(fobj.getNameExt());
932:                }
933:            }
934:
935:            protected void startFlush() {
936:            }
937:
938:            protected void endFlush(boolean madeDirty) {
939:            }
940:
941:            protected synchronized void firstWriteLock() {
942:                //nop
943:            }
944:
945:            protected synchronized void lastWriteUnlock() {
946:                //nop
947:            }
948:
949:            // Methods to prevent repeated registration of listeners
950:            private void addDocumentListener() {
951:                if (styledDocument != null
952:                        && documentListenerAdded.compareAndSet(false, true)) {
953:                    styledDocument.addDocumentListener(this );
954:                }
955:            }
956:
957:            private void removeDocumentListener() {
958:                if (styledDocument != null
959:                        && documentListenerAdded.compareAndSet(true, false)) {
960:                    styledDocument.removeDocumentListener(this );
961:                }
962:            }
963:
964:            private void addUndoableEditListener() {
965:                if (styledDocument != null
966:                        && undoableEditListenerAdded.compareAndSet(false, true)) {
967:                    styledDocument.addUndoableEditListener(this );
968:                }
969:            }
970:
971:            private void removeUndoableEditListener() {
972:                if (styledDocument != null
973:                        && undoableEditListenerAdded.compareAndSet(true, false)) {
974:                    styledDocument.removeUndoableEditListener(this);
975:                }
976:            }
977:
978:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.