Source Code Cross Referenced for AbstractReconciler.java in  » IDE-Eclipse » jface » org » eclipse » jface » text » reconciler » 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 Eclipse » jface » org.eclipse.jface.text.reconciler 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*******************************************************************************
002:         * Copyright (c) 2000, 2007 IBM Corporation and others.
003:         * All rights reserved. This program and the accompanying materials
004:         * are made available under the terms of the Eclipse Public License v1.0
005:         * which accompanies this distribution, and is available at
006:         * http://www.eclipse.org/legal/epl-v10.html
007:         *
008:         * Contributors:
009:         *     IBM Corporation - initial API and implementation
010:         *******************************************************************************/package org.eclipse.jface.text.reconciler;
011:
012:        import org.eclipse.core.runtime.Assert;
013:        import org.eclipse.core.runtime.IProgressMonitor;
014:
015:        import org.eclipse.jface.text.DocumentEvent;
016:        import org.eclipse.jface.text.IDocument;
017:        import org.eclipse.jface.text.IDocumentListener;
018:        import org.eclipse.jface.text.ITextInputListener;
019:        import org.eclipse.jface.text.ITextViewer;
020:
021:        /**
022:         * Abstract implementation of {@link IReconciler}. The reconciler
023:         * listens to input document changes as well as changes of
024:         * the input document of the text viewer it is installed on. Depending on
025:         * its configuration it manages the received change notifications in a
026:         * queue folding neighboring or overlapping changes together. The reconciler
027:         * processes the dirty regions as a background activity after having waited for further
028:         * changes for the configured duration of time. A reconciler is started using the
029:         * {@link #install(ITextViewer)} method.  As a first step {@link #initialProcess()} is
030:         * executed in the background. Then, the reconciling thread waits for changes that
031:         * need to be reconciled. A reconciler can be resumed by calling {@link #forceReconciling()}
032:         * independent from the existence of actual changes. This mechanism is for subclasses only.
033:         * It is the clients responsibility to stop a reconciler using its {@link #uninstall()}
034:         * method. Unstopped reconcilers do not free their resources.
035:         * <p>
036:         * It is subclass responsibility to specify how dirty regions are processed.
037:         * </p>
038:         *
039:         * @see org.eclipse.jface.text.IDocumentListener
040:         * @see org.eclipse.jface.text.ITextInputListener
041:         * @see org.eclipse.jface.text.reconciler.DirtyRegion
042:         * @since 2.0
043:         */
044:        abstract public class AbstractReconciler implements  IReconciler {
045:
046:            /**
047:             * Background thread for the reconciling activity.
048:             */
049:            class BackgroundThread extends Thread {
050:
051:                /** Has the reconciler been canceled. */
052:                private boolean fCanceled = false;
053:                /** Has the reconciler been reset. */
054:                private boolean fReset = false;
055:                /** Some changes need to be processed. */
056:                private boolean fIsDirty = false;
057:                /** Is a reconciling strategy active. */
058:                private boolean fIsActive = false;
059:
060:                /**
061:                 * Creates a new background thread. The thread
062:                 * runs with minimal priority.
063:                 *
064:                 * @param name the thread's name
065:                 */
066:                public BackgroundThread(String name) {
067:                    super (name);
068:                    setPriority(Thread.MIN_PRIORITY);
069:                    setDaemon(true);
070:                }
071:
072:                /**
073:                 * Returns whether a reconciling strategy is active right now.
074:                 *
075:                 * @return <code>true</code> if a activity is active
076:                 */
077:                public boolean isActive() {
078:                    return fIsActive;
079:                }
080:
081:                /**
082:                 * Returns whether some changes need to be processed.
083:                 *
084:                 * @return <code>true</code> if changes wait to be processed
085:                 * @since 3.0
086:                 */
087:                public synchronized boolean isDirty() {
088:                    return fIsDirty;
089:                }
090:
091:                /**
092:                 * Cancels the background thread.
093:                 */
094:                public void cancel() {
095:                    fCanceled = true;
096:                    IProgressMonitor pm = fProgressMonitor;
097:                    if (pm != null)
098:                        pm.setCanceled(true);
099:                    synchronized (fDirtyRegionQueue) {
100:                        fDirtyRegionQueue.notifyAll();
101:                    }
102:                }
103:
104:                /**
105:                 * Suspends the caller of this method until this background thread has
106:                 * emptied the dirty region queue.
107:                 */
108:                public void suspendCallerWhileDirty() {
109:                    boolean isDirty;
110:                    do {
111:                        synchronized (fDirtyRegionQueue) {
112:                            isDirty = fDirtyRegionQueue.getSize() > 0;
113:                            if (isDirty) {
114:                                try {
115:                                    fDirtyRegionQueue.wait();
116:                                } catch (InterruptedException x) {
117:                                }
118:                            }
119:                        }
120:                    } while (isDirty);
121:                }
122:
123:                /**
124:                 * Reset the background thread as the text viewer has been changed,
125:                 */
126:                public void reset() {
127:
128:                    if (fDelay > 0) {
129:
130:                        synchronized (this ) {
131:                            fIsDirty = true;
132:                            fReset = true;
133:                        }
134:
135:                    } else {
136:
137:                        synchronized (this ) {
138:                            fIsDirty = true;
139:                        }
140:
141:                        synchronized (fDirtyRegionQueue) {
142:                            fDirtyRegionQueue.notifyAll();
143:                        }
144:                    }
145:
146:                    reconcilerReset();
147:                }
148:
149:                /**
150:                 * The background activity. Waits until there is something in the
151:                 * queue managing the changes that have been applied to the text viewer.
152:                 * Removes the first change from the queue and process it.
153:                 * <p>
154:                 * Calls {@link AbstractReconciler#initialProcess()} on entrance.
155:                 * </p>
156:                 */
157:                public void run() {
158:
159:                    synchronized (fDirtyRegionQueue) {
160:                        try {
161:                            fDirtyRegionQueue.wait(fDelay);
162:                        } catch (InterruptedException x) {
163:                        }
164:                    }
165:
166:                    initialProcess();
167:
168:                    while (!fCanceled) {
169:
170:                        synchronized (fDirtyRegionQueue) {
171:                            try {
172:                                fDirtyRegionQueue.wait(fDelay);
173:                            } catch (InterruptedException x) {
174:                            }
175:                        }
176:
177:                        if (fCanceled)
178:                            break;
179:
180:                        if (!isDirty())
181:                            continue;
182:
183:                        synchronized (this ) {
184:                            if (fReset) {
185:                                fReset = false;
186:                                continue;
187:                            }
188:                        }
189:
190:                        DirtyRegion r = null;
191:                        synchronized (fDirtyRegionQueue) {
192:                            r = fDirtyRegionQueue.removeNextDirtyRegion();
193:                        }
194:
195:                        fIsActive = true;
196:
197:                        if (fProgressMonitor != null)
198:                            fProgressMonitor.setCanceled(false);
199:
200:                        process(r);
201:
202:                        synchronized (fDirtyRegionQueue) {
203:                            if (0 == fDirtyRegionQueue.getSize()) {
204:                                synchronized (this ) {
205:                                    fIsDirty = fProgressMonitor != null ? fProgressMonitor
206:                                            .isCanceled()
207:                                            : false;
208:                                }
209:                                fDirtyRegionQueue.notifyAll();
210:                            }
211:                        }
212:
213:                        fIsActive = false;
214:                    }
215:                }
216:            }
217:
218:            /**
219:             * Internal document listener and text input listener.
220:             */
221:            class Listener implements  IDocumentListener, ITextInputListener {
222:
223:                /*
224:                 * @see IDocumentListener#documentAboutToBeChanged(DocumentEvent)
225:                 */
226:                public void documentAboutToBeChanged(DocumentEvent e) {
227:                }
228:
229:                /*
230:                 * @see IDocumentListener#documentChanged(DocumentEvent)
231:                 */
232:                public void documentChanged(DocumentEvent e) {
233:
234:                    if (!fThread.isDirty() && fThread.isAlive()) {
235:                        if (!fIsAllowedToModifyDocument
236:                                && Thread.currentThread() == fThread)
237:                            throw new UnsupportedOperationException(
238:                                    "The reconciler thread is not allowed to modify the document"); //$NON-NLS-1$
239:                        aboutToBeReconciled();
240:                    }
241:
242:                    /*
243:                     * The second OR condition handles the case when the document
244:                     * gets changed while still inside initialProcess().
245:                     */
246:                    if (fProgressMonitor != null
247:                            && (fThread.isActive() || fThread.isDirty()
248:                                    && fThread.isAlive()))
249:                        fProgressMonitor.setCanceled(true);
250:
251:                    if (fIsIncrementalReconciler)
252:                        createDirtyRegion(e);
253:
254:                    fThread.reset();
255:
256:                }
257:
258:                /*
259:                 * @see ITextInputListener#inputDocumentAboutToBeChanged(IDocument, IDocument)
260:                 */
261:                public void inputDocumentAboutToBeChanged(IDocument oldInput,
262:                        IDocument newInput) {
263:
264:                    if (oldInput == fDocument) {
265:
266:                        if (fDocument != null)
267:                            fDocument.removeDocumentListener(this );
268:
269:                        if (fIsIncrementalReconciler) {
270:                            synchronized (fDirtyRegionQueue) {
271:                                fDirtyRegionQueue.purgeQueue();
272:                            }
273:                            if (fDocument != null && fDocument.getLength() > 0) {
274:                                DocumentEvent e = new DocumentEvent(fDocument,
275:                                        0, fDocument.getLength(), ""); //$NON-NLS-1$
276:                                createDirtyRegion(e);
277:                                fThread.reset();
278:                                fThread.suspendCallerWhileDirty();
279:                            }
280:                        }
281:
282:                        fDocument = null;
283:                    }
284:                }
285:
286:                /*
287:                 * @see ITextInputListener#inputDocumentChanged(IDocument, IDocument)
288:                 */
289:                public void inputDocumentChanged(IDocument oldInput,
290:                        IDocument newInput) {
291:
292:                    fDocument = newInput;
293:                    if (fDocument == null)
294:                        return;
295:
296:                    reconcilerDocumentChanged(fDocument);
297:
298:                    fDocument.addDocumentListener(this );
299:
300:                    if (!fThread.isDirty())
301:                        aboutToBeReconciled();
302:
303:                    if (fIsIncrementalReconciler) {
304:                        DocumentEvent e = new DocumentEvent(fDocument, 0, 0,
305:                                fDocument.get());
306:                        createDirtyRegion(e);
307:                    }
308:
309:                    startReconciling();
310:                }
311:            }
312:
313:            /** Queue to manage the changes applied to the text viewer. */
314:            private DirtyRegionQueue fDirtyRegionQueue;
315:            /** The background thread. */
316:            private BackgroundThread fThread;
317:            /** Internal document and text input listener. */
318:            private Listener fListener;
319:            /** The background thread delay. */
320:            private int fDelay = 500;
321:            /** Are there incremental reconciling strategies? */
322:            private boolean fIsIncrementalReconciler = true;
323:            /** The progress monitor used by this reconciler. */
324:            private IProgressMonitor fProgressMonitor;
325:            /**
326:             * Tells whether this reconciler is allowed to modify the document.
327:             * @since 3.2
328:             */
329:            private boolean fIsAllowedToModifyDocument = true;
330:
331:            /** The text viewer's document. */
332:            private IDocument fDocument;
333:            /** The text viewer */
334:            private ITextViewer fViewer;
335:
336:            /**
337:             * Processes a dirty region. If the dirty region is <code>null</code> the whole
338:             * document is consider being dirty. The dirty region is partitioned by the
339:             * document and each partition is handed over to a reconciling strategy registered
340:             * for the partition's content type.
341:             *
342:             * @param dirtyRegion the dirty region to be processed
343:             */
344:            abstract protected void process(DirtyRegion dirtyRegion);
345:
346:            /**
347:             * Hook called when the document whose contents should be reconciled
348:             * has been changed, i.e., the input document of the text viewer this
349:             * reconciler is installed on. Usually, subclasses use this hook to
350:             * inform all their reconciling strategies about the change.
351:             *
352:             * @param newDocument the new reconciler document
353:             */
354:            abstract protected void reconcilerDocumentChanged(
355:                    IDocument newDocument);
356:
357:            /**
358:             * Creates a new reconciler without configuring it.
359:             */
360:            protected AbstractReconciler() {
361:                super ();
362:            }
363:
364:            /**
365:             * Tells the reconciler how long it should wait for further text changes before
366:             * activating the appropriate reconciling strategies.
367:             *
368:             * @param delay the duration in milliseconds of a change collection period.
369:             */
370:            public void setDelay(int delay) {
371:                fDelay = delay;
372:            }
373:
374:            /**
375:             * Tells the reconciler whether any of the available reconciling strategies
376:             * is interested in getting detailed dirty region information or just in the
377:             * fact that the document has been changed. In the second case, the reconciling
378:             * can not incrementally be pursued.
379:             *
380:             * @param isIncremental indicates whether this reconciler will be configured with
381:             *		incremental reconciling strategies
382:             *
383:             * @see DirtyRegion
384:             * @see IReconcilingStrategy
385:             */
386:            public void setIsIncrementalReconciler(boolean isIncremental) {
387:                fIsIncrementalReconciler = isIncremental;
388:            }
389:
390:            /**
391:             * Tells the reconciler whether it is allowed to change the document
392:             * inside its reconciler thread.
393:             * <p>
394:             * If this is set to <code>false</code> an {@link UnsupportedOperationException}
395:             * will be thrown when this restriction will be violated.
396:             * </p>
397:             *
398:             * @param isAllowedToModify indicates whether this reconciler is allowed to modify the document
399:             * @since 3.2
400:             */
401:            public void setIsAllowedToModifyDocument(boolean isAllowedToModify) {
402:                fIsAllowedToModifyDocument = isAllowedToModify;
403:            }
404:
405:            /**
406:             * Sets the progress monitor of this reconciler.
407:             *
408:             * @param monitor the monitor to be used
409:             */
410:            public void setProgressMonitor(IProgressMonitor monitor) {
411:                fProgressMonitor = monitor;
412:            }
413:
414:            /**
415:             * Returns whether any of the reconciling strategies is interested in
416:             * detailed dirty region information.
417:             *
418:             * @return whether this reconciler is incremental
419:             *
420:             * @see IReconcilingStrategy
421:             */
422:            protected boolean isIncrementalReconciler() {
423:                return fIsIncrementalReconciler;
424:            }
425:
426:            /**
427:             * Returns the input document of the text viewer this reconciler is installed on.
428:             *
429:             * @return the reconciler document
430:             */
431:            protected IDocument getDocument() {
432:                return fDocument;
433:            }
434:
435:            /**
436:             * Returns the text viewer this reconciler is installed on.
437:             *
438:             * @return the text viewer this reconciler is installed on
439:             */
440:            protected ITextViewer getTextViewer() {
441:                return fViewer;
442:            }
443:
444:            /**
445:             * Returns the progress monitor of this reconciler.
446:             *
447:             * @return the progress monitor of this reconciler
448:             */
449:            protected IProgressMonitor getProgressMonitor() {
450:                return fProgressMonitor;
451:            }
452:
453:            /*
454:             * @see IReconciler#install(ITextViewer)
455:             */
456:            public void install(ITextViewer textViewer) {
457:
458:                Assert.isNotNull(textViewer);
459:                fViewer = textViewer;
460:
461:                synchronized (this ) {
462:                    if (fThread != null)
463:                        return;
464:                    fThread = new BackgroundThread(getClass().getName());
465:                }
466:
467:                fDirtyRegionQueue = new DirtyRegionQueue();
468:
469:                fListener = new Listener();
470:                fViewer.addTextInputListener(fListener);
471:
472:                // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=67046
473:                // if the reconciler gets installed on a viewer that already has a document
474:                // (e.g. when reusing editors), we force the listener to register
475:                // itself as document listener, because there will be no input change
476:                // on the viewer.
477:                // In order to do that, we simulate an input change.
478:                IDocument document = textViewer.getDocument();
479:                if (document != null) {
480:                    fListener
481:                            .inputDocumentAboutToBeChanged(fDocument, document);
482:                    fListener.inputDocumentChanged(fDocument, document);
483:                }
484:            }
485:
486:            /*
487:             * @see IReconciler#uninstall()
488:             */
489:            public void uninstall() {
490:                if (fListener != null) {
491:
492:                    fViewer.removeTextInputListener(fListener);
493:                    if (fDocument != null) {
494:                        fListener
495:                                .inputDocumentAboutToBeChanged(fDocument, null);
496:                        fListener.inputDocumentChanged(fDocument, null);
497:                    }
498:                    fListener = null;
499:
500:                    synchronized (this ) {
501:                        // http://dev.eclipse.org/bugs/show_bug.cgi?id=19135
502:                        BackgroundThread bt = fThread;
503:                        fThread = null;
504:                        bt.cancel();
505:                    }
506:                }
507:            }
508:
509:            /**
510:             * Creates a dirty region for a document event and adds it to the queue.
511:             *
512:             * @param e the document event for which to create a dirty region
513:             */
514:            private void createDirtyRegion(DocumentEvent e) {
515:                synchronized (fDirtyRegionQueue) {
516:                    if (e.getLength() == 0 && e.getText() != null) {
517:                        // Insert
518:                        fDirtyRegionQueue.addDirtyRegion(new DirtyRegion(e
519:                                .getOffset(), e.getText().length(),
520:                                DirtyRegion.INSERT, e.getText()));
521:
522:                    } else if (e.getText() == null || e.getText().length() == 0) {
523:                        // Remove
524:                        fDirtyRegionQueue.addDirtyRegion(new DirtyRegion(e
525:                                .getOffset(), e.getLength(),
526:                                DirtyRegion.REMOVE, null));
527:
528:                    } else {
529:                        // Replace (Remove + Insert)
530:                        fDirtyRegionQueue.addDirtyRegion(new DirtyRegion(e
531:                                .getOffset(), e.getLength(),
532:                                DirtyRegion.REMOVE, null));
533:                        fDirtyRegionQueue.addDirtyRegion(new DirtyRegion(e
534:                                .getOffset(), e.getText().length(),
535:                                DirtyRegion.INSERT, e.getText()));
536:                    }
537:                }
538:            }
539:
540:            /**
541:             * Hook for subclasses which want to perform some
542:             * action as soon as reconciliation is needed.
543:             * <p>
544:             * Default implementation is to do nothing.
545:             * </p>
546:             *
547:             * @since 3.0
548:             */
549:            protected void aboutToBeReconciled() {
550:            }
551:
552:            /**
553:             * This method is called on startup of the background activity. It is called only
554:             * once during the life time of the reconciler. Clients may reimplement this method.
555:             */
556:            protected void initialProcess() {
557:            }
558:
559:            /**
560:             * Forces the reconciler to reconcile the structure of the whole document.
561:             * Clients may extend this method.
562:             */
563:            protected void forceReconciling() {
564:
565:                if (fDocument != null) {
566:
567:                    if (!fThread.isDirty() && fThread.isAlive())
568:                        aboutToBeReconciled();
569:
570:                    if (fProgressMonitor != null && fThread.isActive())
571:                        fProgressMonitor.setCanceled(true);
572:
573:                    if (fIsIncrementalReconciler) {
574:                        DocumentEvent e = new DocumentEvent(fDocument, 0,
575:                                fDocument.getLength(), fDocument.get());
576:                        createDirtyRegion(e);
577:                    }
578:
579:                    startReconciling();
580:                }
581:            }
582:
583:            /**
584:             * Starts the reconciler to reconcile the queued dirty-regions.
585:             * Clients may extend this method.
586:             */
587:            protected synchronized void startReconciling() {
588:                if (fThread == null)
589:                    return;
590:
591:                if (!fThread.isAlive()) {
592:                    try {
593:                        fThread.start();
594:                    } catch (IllegalThreadStateException e) {
595:                        // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=40549
596:                        // This is the only instance where the thread is started; since
597:                        // we checked that it is not alive, it must be dead already due
598:                        // to a run-time exception or error. Exit.
599:                    }
600:                } else {
601:                    fThread.reset();
602:                }
603:            }
604:
605:            /**
606:             * Hook that is called after the reconciler thread has been reset.
607:             */
608:            protected void reconcilerReset() {
609:            }
610:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.