Source Code Cross Referenced for FoldHierarchyExecution.java in  » IDE-Netbeans » editor » org » netbeans » modules » editor » fold » 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 » editor » org.netbeans.modules.editor.fold 
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:
042:        package org.netbeans.modules.editor.fold;
043:
044:        import java.beans.PropertyChangeEvent;
045:        import java.beans.PropertyChangeListener;
046:        import java.util.ArrayList;
047:        import java.util.Collection;
048:        import java.util.HashMap;
049:        import java.util.HashSet;
050:        import java.util.Iterator;
051:        import java.util.List;
052:        import java.util.Map;
053:        import java.util.Set;
054:        import javax.swing.SwingUtilities;
055:        import javax.swing.event.DocumentEvent;
056:        import javax.swing.event.DocumentListener;
057:        import javax.swing.event.EventListenerList;
058:        import javax.swing.text.AbstractDocument;
059:        import javax.swing.text.BadLocationException;
060:        import javax.swing.text.Document;
061:        import javax.swing.text.JTextComponent;
062:        import org.netbeans.api.editor.fold.Fold;
063:        import org.netbeans.api.editor.fold.FoldHierarchy;
064:        import org.netbeans.api.editor.fold.FoldHierarchyEvent;
065:        import org.netbeans.api.editor.fold.FoldHierarchyListener;
066:        import org.netbeans.api.editor.fold.FoldStateChange;
067:        import org.netbeans.lib.editor.util.swing.DocumentListenerPriority;
068:        import org.netbeans.lib.editor.util.swing.DocumentUtilities;
069:        import org.netbeans.spi.editor.fold.FoldManager;
070:        import org.netbeans.spi.editor.fold.FoldManagerFactory;
071:        import org.netbeans.spi.editor.fold.FoldOperation;
072:        import org.netbeans.lib.editor.util.PriorityMutex;
073:        import org.openide.ErrorManager;
074:
075:        /**
076:         * Class backing the <code>FoldHierarchy</code> in one-to-one relationship.
077:         * <br>
078:         * The <code>FoldHierarchy</code> delegates all its operations
079:         * to this object.
080:         *
081:         * <p>
082:         * All the changes performed in to the folds are always done
083:         * in terms of a transaction represented by {@link FoldHierarchyTransactionImpl}.
084:         * The transaction can be opened by {@link #openTransaction()}.
085:         *
086:         * <p>
087:         * This class changes its state upon displayability change
088:         * of the associated component by listening on "ancestor" component property.
089:         * <br>
090:         * If the component is not displayable then the list of root folds becomes empty
091:         * while if the component gets displayable the root folds are created
092:         * according to registered managers.
093:         *
094:         * @author Miloslav Metelka
095:         * @version 1.00
096:         */
097:
098:        public final class FoldHierarchyExecution implements  DocumentListener {
099:
100:            private static final String PROPERTY_FOLD_HIERARCHY_MUTEX = "foldHierarchyMutex"; //NOI18N
101:
102:            private static final String PROPERTY_FOLDING_ENABLED = "code-folding-enable"; //NOI18N
103:
104:            private static final boolean debug = Boolean
105:                    .getBoolean("netbeans.debug.editor.fold"); //NOI18N
106:
107:            private static final boolean debugFire = Boolean
108:                    .getBoolean("netbeans.debug.editor.fold.fire"); //NOI18N
109:
110:            private static final FoldOperationImpl[] EMPTY_FOLD_OPERTAION_IMPL_ARRAY = new FoldOperationImpl[0];
111:
112:            static {
113:                // The following call will make sure that the SpiPackageAccessor gets initialized
114:                FoldOperation.isBoundsValid(0, 0, 0, 0);
115:            }
116:
117:            private final JTextComponent component;
118:
119:            private FoldHierarchy hierarchy;
120:
121:            private Fold rootFold;
122:
123:            private FoldOperationImpl[] operations = EMPTY_FOLD_OPERTAION_IMPL_ARRAY;
124:
125:            /**
126:             * Map containing [blocked-fold, blocking-fold] pairs.
127:             */
128:            private Map blocked2block = new HashMap(4);
129:
130:            /**
131:             * Map containing [blocking-fold, blocked-fold-set] pairs.
132:             */
133:            private Map block2blockedSet = new HashMap(4);
134:
135:            /** Whether hierarchy is initialized (root fold etc.) */
136:            private boolean inited;
137:
138:            private AbstractDocument lastDocument;
139:
140:            private PriorityMutex mutex;
141:
142:            private EventListenerList listenerList;
143:
144:            private boolean foldingEnabled;
145:
146:            private FoldHierarchyTransactionImpl activeTransaction;
147:
148:            private PropertyChangeListener componentChangesListener;
149:
150:            public static synchronized FoldHierarchy getOrCreateFoldHierarchy(
151:                    JTextComponent component) {
152:                if (component == null) {
153:                    throw new NullPointerException("component cannot be null"); // NOI18N
154:                }
155:
156:                FoldHierarchyExecution execution = (FoldHierarchyExecution) component
157:                        .getClientProperty(FoldHierarchyExecution.class);
158:
159:                if (execution == null) {
160:                    execution = new FoldHierarchyExecution(component);
161:                    execution.init();
162:
163:                    component.putClientProperty(FoldHierarchyExecution.class,
164:                            execution);
165:                }
166:
167:                return execution.getHierarchy();
168:            }
169:
170:            /**
171:             * Construct new fold hierarchy SPI
172:             *
173:             * @param hierarchy hierarchy for which this SPI gets created.
174:             * @param component comoponent for which this all happens.
175:             */
176:            private FoldHierarchyExecution(JTextComponent component) {
177:                this .component = component;
178:            }
179:
180:            /**
181:             * Initialize this spi by existing hierarchy instance
182:             * (the one for which this spi was created).
183:             * <br>
184:             * This is called lazily upon first attempt to lock
185:             * the hierarchy.
186:             */
187:            private void init() {
188:                // Allow listeners to be added
189:                listenerList = new EventListenerList();
190:
191:                // Assign mutex
192:                mutex = (PriorityMutex) component
193:                        .getClientProperty(PROPERTY_FOLD_HIERARCHY_MUTEX);
194:                if (mutex == null) {
195:                    mutex = new PriorityMutex();
196:                    component.putClientProperty(PROPERTY_FOLD_HIERARCHY_MUTEX,
197:                            mutex);
198:                }
199:
200:                this .hierarchy = ApiPackageAccessor.get().createFoldHierarchy(
201:                        this );
202:
203:                Document doc = component.getDocument();
204:                try {
205:                    rootFold = ApiPackageAccessor.get()
206:                            .createFold(
207:                                    new FoldOperationImpl(this , null,
208:                                            Integer.MAX_VALUE),
209:                                    FoldHierarchy.ROOT_FOLD_TYPE,
210:                                    "root", // NOI18N
211:                                    false, doc, 0,
212:                                    doc.getEndPosition().getOffset(), 0, 0,
213:                                    null);
214:                } catch (BadLocationException e) {
215:                    ErrorManager.getDefault().notify(e);
216:                }
217:
218:                foldingEnabled = getFoldingEnabledSetting();
219:
220:                // Start listening on component changes
221:                startComponentChangesListening();
222:
223:                rebuild();
224:            }
225:
226:            /**
227:             * Get the fold hierarchy associated with this SPI
228:             * in one-to-one relationship.
229:             */
230:            public final FoldHierarchy getHierarchy() {
231:                return hierarchy;
232:            }
233:
234:            /**
235:             * Lock the hierarchy for exclusive use. This method must only
236:             * be used together with {@link #unlock()} in <code>try..finally</code> block.
237:             * <br>
238:             * Prior using this method the document must be locked.
239:             * The document lock can be either readlock
240:             * e.g. by using {@link javax.swing.text.Document#render(Runnable)}
241:             * or writelock
242:             * e.g. when in {@link javax.swing.event.DocumentListener})
243:             * and must be obtained on component's document
244:             * i.e. {@link javax.swing.text.JTextComponent#getDocument()}
245:             * should be used.
246:             *
247:             * <p>
248:             * The <code>FoldHierarchy</code> delegates to this method.
249:             *
250:             * <p>
251:             * <font color="red">
252:             * <b>Note:</b> The clients using this method must ensure that
253:             * they <b>always</b> use this method in the following pattern:<pre>
254:             *
255:             *     lock();
256:             *     try {
257:             *         ...
258:             *     } finally {
259:             *         unlock();
260:             *     }
261:             * </pre>
262:             * </font>
263:             */
264:            public final void lock() {
265:                mutex.lock();
266:            }
267:
268:            /**
269:             * Unlock the hierarchy from exclusive use. This method must only
270:             * be used together with {@link #lock()} in <code>try..finally</code> block.
271:             */
272:            public void unlock() {
273:                mutex.unlock();
274:            }
275:
276:            /**
277:             * Get the text component for which this fold hierarchy was created.
278:             * <br>
279:             * The <code>FoldHierarchy</code> delegates to this method.
280:             *
281:             * @return non-null text component for which this fold hierarchy was created.
282:             */
283:            public JTextComponent getComponent() {
284:                return component;
285:            }
286:
287:            /**
288:             * Get the root fold of this hierarchy.
289:             * <br>
290:             * The <code>FoldHierarchy</code> delegates to this method.
291:             *
292:             * @return root fold of this hierarchy.
293:             *   The root fold covers the whole document and is uncollapsable.
294:             */
295:            public Fold getRootFold() {
296:                return rootFold;
297:            }
298:
299:            /**
300:             * Add listener for changes done in the hierarchy.
301:             * <br>
302:             * The <code>FoldHierarchy</code> delegates to this method.
303:             *
304:             * @param l non-null listener to be added.
305:             */
306:            public void addFoldHierarchyListener(FoldHierarchyListener l) {
307:                synchronized (listenerList) {
308:                    listenerList.add(FoldHierarchyListener.class, l);
309:                }
310:            }
311:
312:            /**
313:             * Remove previously added listener for changes done in the hierarchy.
314:             * <br>
315:             * The <code>FoldHierarchy</code> delegates to this method.
316:             *
317:             * @param l non-null listener to be removed.
318:             */
319:            public void removeFoldHierarchyListener(FoldHierarchyListener l) {
320:                synchronized (listenerList) {
321:                    listenerList.remove(FoldHierarchyListener.class, l);
322:                }
323:            }
324:
325:            void fireFoldHierarchyListener(FoldHierarchyEvent evt) {
326:                if (debugFire) {
327:                    /*DEBUG*/System.err.println("Firing FoldHierarchyEvent:\n"
328:                            + evt); // NOI18N
329:                }
330:
331:                Object[] listeners = listenerList.getListenerList(); // no need to sync
332:                for (int i = listeners.length - 2; i >= 0; i -= 2) {
333:                    if (listeners[i] == FoldHierarchyListener.class) {
334:                        ((FoldHierarchyListener) listeners[i + 1])
335:                                .foldHierarchyChanged(evt);
336:                    }
337:                }
338:
339:            }
340:
341:            /**
342:             * Attempt to add the given fold to the code folding hierarchy.
343:             * The fold will either become part of the hierarchy or it will
344:             * become blocked by another fold present in the hierarchy.
345:             * <br>
346:             * Only folds created by the fold operations of this hierarchy
347:             * can be added.
348:             *
349:             * @param fold fold to be added
350:             * @param transaction transaction under which the fold should be added.
351:             * @return true if the fold was added successfully or false
352:             *  if it became blocked.
353:             */
354:            public boolean add(Fold fold,
355:                    FoldHierarchyTransactionImpl transaction) {
356:                if (fold.getParent() != null || isBlocked(fold)) {
357:                    throw new IllegalStateException("Fold already added: "
358:                            + fold); // NOI18N
359:                }
360:
361:                boolean added = transaction.addFold(fold);
362:
363:                //        checkConsistency();
364:
365:                return added;
366:            }
367:
368:            /**
369:             * Remove the fold that is either present in the hierarchy or blocked
370:             * by another fold.
371:             *
372:             * @param fold fold to be removed
373:             * @param transaction non-null transaction under which the fold should be removed.
374:             */
375:            public void remove(Fold fold,
376:                    FoldHierarchyTransactionImpl transaction) {
377:                transaction.removeFold(fold);
378:
379:                //        checkConsistency();
380:            }
381:
382:            /**
383:             * Check whether the fold is currently present in the hierarchy or blocked.
384:             *
385:             * @return true if the fold is currently present in the hierarchy or blocked
386:             *  or false otherwise.
387:             */
388:            public boolean isAddedOrBlocked(Fold fold) {
389:                return (fold.getParent() != null || isBlocked(fold));
390:            }
391:
392:            /**
393:             * Is the given fold blocked by another fold?
394:             */
395:            public boolean isBlocked(Fold fold) {
396:                return (getBlock(fold) != null);
397:            }
398:
399:            /**
400:             * Get the fold blocking the given fold or null
401:             * if the fold is not blocked.
402:             */
403:            Fold getBlock(Fold fold) {
404:                return (blocked2block.size() > 0) ? (Fold) blocked2block
405:                        .get(fold) : null;
406:            }
407:
408:            /**
409:             * Mark given fold as blocked by the block fold.
410:             */
411:            void markBlocked(Fold blocked, Fold block) {
412:                blocked2block.put(blocked, block);
413:
414:                Set blockedSet = (Set) block2blockedSet.get(block);
415:                if (blockedSet == null) {
416:                    blockedSet = new HashSet();
417:                    block2blockedSet.put(block, blockedSet);
418:                }
419:                if (!blockedSet.add(blocked)) { // already added
420:                    throw new IllegalStateException("fold " + blocked
421:                            + " already blocked"); // NOI18N
422:                }
423:            }
424:
425:            /**
426:             * Remove blocked fold from mappings.
427:             *
428:             * @param blocked fold
429:             * @return fold that blocked the blocked fold.
430:             * @throws IllegalArgumentException if the given blocked fold was not really blocked.
431:             */
432:            Fold unmarkBlocked(Fold blocked) {
433:                // Find block for the given blocked fold
434:                Fold block = (Fold) blocked2block.remove(blocked);
435:                if (block == null) { // not blocked
436:                    throw new IllegalArgumentException("Not blocked: "
437:                            + blocked); // NOI18N
438:                }
439:
440:                // Remove the fold from set of blocked folds of the block
441:                Set blockedSet = (Set) block2blockedSet.get(block);
442:                if (!blockedSet.remove(blocked)) {
443:                    throw new IllegalStateException("Not blocker for "
444:                            + blocked); // NOI18N
445:                }
446:                if (blockedSet.size() == 0) { // Remove the blocker as well
447:                    block2blockedSet.remove(block);
448:                }
449:                return block;
450:            }
451:
452:            /**
453:             * Mark the given block fold to be no longer blocking
454:             * (and mark the folds blocked by the given block fold as not blocked).
455:             *
456:             * @param block the fold blocking others
457:             * @return set of folds blocked by the block or null if the given fold
458:             *  was not block.
459:             */
460:            Set unmarkBlock(Fold block) {
461:                Set blockedSet = (Set) block2blockedSet.remove(block);
462:                if (blockedSet != null) {
463:                    // Remove all items of blocked set
464:                    int size = blocked2block.size();
465:                    blocked2block.keySet().removeAll(blockedSet);
466:                    if (size - blocked2block.size() != blockedSet.size()) { // not all removed
467:                        throw new IllegalStateException("Not all removed: "
468:                                + blockedSet); // NOI18N
469:                    }
470:                }
471:                return blockedSet;
472:            }
473:
474:            /**
475:             * Collapse all folds in the given collection.
476:             * <br>
477:             * The <code>FoldHierarchy</code> delegates to this method.
478:             */
479:            public void collapse(Collection c) {
480:                setCollapsed(c, true);
481:            }
482:
483:            /**
484:             * Expand all folds in the given collection.
485:             * <br>
486:             * The <code>FoldHierarchy</code> delegates to this method.
487:             */
488:            public void expand(Collection c) {
489:                setCollapsed(c, false);
490:            }
491:
492:            private void setCollapsed(Collection c, boolean collapsed) {
493:                FoldHierarchyTransactionImpl transaction = openTransaction();
494:                try {
495:                    for (Iterator it = c.iterator(); it.hasNext();) {
496:                        Fold fold = (Fold) it.next();
497:                        transaction.setCollapsed(fold, collapsed);
498:                    }
499:                } finally {
500:                    transaction.commit();
501:                }
502:            }
503:
504:            /**
505:             * Open a new transaction on the fold hierarchy
506:             * to make a change in the hierarchy.
507:             * <br>
508:             * Transaction is active until commited
509:             * by calling <code>transaction.commit()</code>.
510:             * <br>
511:             * Only one transaction can be active at the time.
512:             * <br>
513:             * There is currently no way to rollback the transaction.
514:             *
515:             * <p>
516:             * <font color="red">
517:             * <b>Note:</b> The clients using this method must ensure that
518:             * they <b>always</b> use this method in the following pattern:<pre>
519:             *
520:             *     FoldHierarchyTransaction transaction = operation.openTransaction();
521:             *     try {
522:             *         ...
523:             *     } finally {
524:             *         transaction.commit();
525:             *     }
526:             * </pre>
527:             * </font>
528:
529:             */
530:            public FoldHierarchyTransactionImpl openTransaction() {
531:                if (activeTransaction != null) {
532:                    throw new IllegalStateException(
533:                            "Active transaction already exists."); // NOI18N
534:                }
535:                activeTransaction = new FoldHierarchyTransactionImpl(this );
536:                return activeTransaction;
537:            }
538:
539:            void clearActiveTransaction() {
540:                if (activeTransaction == null) {
541:                    throw new IllegalStateException(
542:                            "No transaction in progress"); // NOI18N
543:                }
544:                activeTransaction = null;
545:            }
546:
547:            void createAndFireFoldHierarchyEvent(Fold[] removedFolds,
548:                    Fold[] addedFolds, FoldStateChange[] foldStateChanges,
549:                    int affectedStartOffset, int affectedEndOffset) {
550:
551:                // Check correctness
552:                if (affectedStartOffset < 0) {
553:                    throw new IllegalArgumentException("affectedStartOffset=" // NOI18N
554:                            + affectedStartOffset + " < 0"); // NOI18N
555:                }
556:
557:                if (affectedEndOffset < affectedStartOffset) {
558:                    throw new IllegalArgumentException("affectedEndOffset=" // NOI18N
559:                            + affectedEndOffset
560:                            + " < affectedStartOffset="
561:                            + affectedStartOffset); // NOI18N
562:                }
563:
564:                FoldHierarchyEvent evt = ApiPackageAccessor.get()
565:                        .createFoldHierarchyEvent(hierarchy, removedFolds,
566:                                addedFolds, foldStateChanges,
567:                                affectedStartOffset, affectedEndOffset);
568:
569:                fireFoldHierarchyListener(evt);
570:            }
571:
572:            /**
573:             * Rebuild the fold hierarchy - the fold managers will be recreated.
574:             */
575:            public void rebuild() {
576:                // Stop listening on the original document
577:                if (lastDocument != null) {
578:                    // Remove document listener with specific priority
579:                    DocumentUtilities.removeDocumentListener(lastDocument,
580:                            this , DocumentListenerPriority.FOLD_UPDATE);
581:                    lastDocument = null;
582:                }
583:
584:                Document doc = getComponent().getDocument();
585:                AbstractDocument adoc;
586:                boolean releaseOnly; // only release the current hierarchy root folds
587:                if (doc instanceof  AbstractDocument) {
588:                    adoc = (AbstractDocument) doc;
589:                    releaseOnly = false;
590:                } else { // doc is null or non-AbstractDocument => release the hierarchy
591:                    adoc = null;
592:                    releaseOnly = true;
593:                }
594:
595:                if (!foldingEnabled) { // folding not enabled => release
596:                    releaseOnly = true;
597:                }
598:
599:                if (adoc != null) {
600:                    adoc.readLock();
601:
602:                    // Start listening for changes
603:                    if (!releaseOnly) {
604:                        lastDocument = adoc;
605:                        // Add document listener with specific priority
606:                        DocumentUtilities.addDocumentListener(lastDocument,
607:                                this , DocumentListenerPriority.FOLD_UPDATE);
608:                    }
609:                }
610:                try {
611:                    lock();
612:                    try {
613:                        rebuildManagers(releaseOnly);
614:                    } finally {
615:                        unlock();
616:                    }
617:                } finally {
618:                    if (adoc != null) {
619:                        adoc.readUnlock();
620:                    }
621:                }
622:            }
623:
624:            /**
625:             * Rebuild (or release) the root folds of the hierarchy in the event dispatch thread.
626:             *
627:             * @param releaseOnly release the current root folds
628:             *  but make the new root folds array empty.
629:             */
630:            private void rebuildManagers(boolean releaseOnly) {
631:                for (int i = 0; i < operations.length; i++) {
632:                    operations[i].release();
633:                }
634:                operations = EMPTY_FOLD_OPERTAION_IMPL_ARRAY; // really release
635:
636:                // Call all the providers
637:                FoldManagerFactoryProvider provider = !releaseOnly ? FoldManagerFactoryProvider
638:                        .getDefault()
639:                        : FoldManagerFactoryProvider.getEmpty();
640:
641:                List factoryList = provider.getFactoryList(getHierarchy());
642:                int factoryListLength = factoryList.size();
643:
644:                if (debug) {
645:                    /*DEBUG*/System.err.println("FoldHierarchy rebuild():" // NOI18N
646:                            + " FoldManager factory count=" + factoryListLength // NOI18N
647:                    );
648:                }
649:
650:                // Create fold managers
651:                int priority = factoryListLength - 1; // highest priority (till lowest == 0)
652:                boolean ok = false;
653:                try {
654:                    operations = new FoldOperationImpl[factoryListLength];
655:                    for (int i = 0; i < factoryListLength; i++) {
656:                        FoldManagerFactory factory = (FoldManagerFactory) factoryList
657:                                .get(i);
658:                        FoldManager manager = factory.createFoldManager();
659:                        operations[i] = new FoldOperationImpl(this , manager,
660:                                priority);
661:                        priority--;
662:                    }
663:                    ok = true;
664:                } finally {
665:                    if (!ok) {
666:                        operations = EMPTY_FOLD_OPERTAION_IMPL_ARRAY;
667:                    }
668:                }
669:
670:                // Init managers under a local transaction
671:                FoldHierarchyTransactionImpl transaction = openTransaction();
672:                ok = false;
673:                try {
674:                    // Remove all original folds - pass array of all blocked folds
675:                    Fold[] allBlocked = new Fold[blocked2block.size()];
676:                    blocked2block.keySet().toArray(allBlocked);
677:                    transaction.removeAllFolds(allBlocked);
678:
679:                    // Init folds in all fold managers
680:                    // Go from the manager with highest priority (index 0)
681:                    for (int i = 0; i < factoryListLength; i++) {
682:                        operations[i].initFolds(transaction);
683:                    }
684:                    ok = true; // inited successfully
685:                } finally {
686:                    if (!ok) {
687:                        // TODO - remove folds under root fold
688:                        operations = EMPTY_FOLD_OPERTAION_IMPL_ARRAY;
689:                    }
690:                    transaction.commit();
691:                }
692:            }
693:
694:            private void startComponentChangesListening() {
695:                if (componentChangesListener == null) {
696:                    // Start listening on component changes
697:                    componentChangesListener = new PropertyChangeListener() {
698:                        public void propertyChange(PropertyChangeEvent evt) {
699:                            String propName = evt.getPropertyName();
700:                            if ("document".equals(propName)) { //NOI18N
701:                                foldingEnabled = getFoldingEnabledSetting();
702:                                rebuild();
703:                            } else if (PROPERTY_FOLDING_ENABLED
704:                                    .equals(propName)) {
705:                                foldingEnabledSettingChange();
706:                            }
707:                        }
708:                    };
709:
710:                    // Start listening on the component.
711:                    // As the hierarchy instance is stored as a property of the component
712:                    // (and in fact the spi and the reference to the listener as well)
713:                    // the listener does not need to be removed
714:                    getComponent().addPropertyChangeListener(
715:                            componentChangesListener);
716:                }
717:            }
718:
719:            public void insertUpdate(DocumentEvent evt) {
720:                lock();
721:                try {
722:                    FoldHierarchyTransactionImpl transaction = openTransaction();
723:                    try {
724:                        transaction.insertUpdate(evt);
725:
726:                        int operationsLength = operations.length;
727:                        for (int i = 0; i < operationsLength; i++) {
728:                            operations[i].insertUpdate(evt, transaction);
729:                        }
730:                    } finally {
731:                        transaction.commit();
732:                    }
733:                } finally {
734:                    unlock();
735:                }
736:            }
737:
738:            public void removeUpdate(DocumentEvent evt) {
739:                lock();
740:                try {
741:                    FoldHierarchyTransactionImpl transaction = openTransaction();
742:                    try {
743:                        transaction.removeUpdate(evt);
744:
745:                        int operationsLength = operations.length;
746:                        for (int i = 0; i < operationsLength; i++) {
747:                            operations[i].removeUpdate(evt, transaction);
748:                        }
749:                    } finally {
750:                        transaction.commit();
751:                    }
752:                } finally {
753:                    unlock();
754:                }
755:            }
756:
757:            public void changedUpdate(DocumentEvent evt) {
758:                lock();
759:                try {
760:                    FoldHierarchyTransactionImpl transaction = openTransaction();
761:                    try {
762:                        transaction.changedUpdate(evt);
763:
764:                        int operationsLength = operations.length;
765:                        for (int i = 0; i < operationsLength; i++) {
766:                            operations[i].changedUpdate(evt, transaction);
767:                        }
768:                    } finally {
769:                        transaction.commit();
770:                    }
771:                } finally {
772:                    unlock();
773:                }
774:            }
775:
776:            private boolean getFoldingEnabledSetting() {
777:                Boolean b = (Boolean) component
778:                        .getClientProperty(PROPERTY_FOLDING_ENABLED);
779:                return (b != null) ? b.booleanValue() : true;
780:            }
781:
782:            public void foldingEnabledSettingChange() {
783:                boolean origFoldingEnabled = foldingEnabled;
784:                foldingEnabled = getFoldingEnabledSetting();
785:                if (origFoldingEnabled != foldingEnabled) {
786:                    SwingUtilities.invokeLater(new Runnable() {
787:                        public void run() {
788:                            rebuild();
789:                        }
790:                    });
791:                }
792:            }
793:
794:            /**
795:             * Check the internal consistency of the hierarchy
796:             * and its contained folds. This is useful for testing purposes.
797:             *
798:             * @throws IllegalStateException in case an inconsistency is found.
799:             */
800:            public void checkConsistency() {
801:                try {
802:                    checkFoldConsistency(getRootFold());
803:                } catch (RuntimeException e) {
804:                    /*DEBUG*/System.err
805:                            .println("FOLD HIERARCHY INCONSISTENCY FOUND\n"
806:                                    + this ); // NOI18N
807:                    throw e; // rethrow the exception
808:                }
809:            }
810:
811:            private static void checkFoldConsistency(Fold fold) {
812:                int startOffset = fold.getStartOffset();
813:                int endOffset = fold.getEndOffset();
814:                int lastEndOffset = startOffset;
815:
816:                for (int i = 0; i < fold.getFoldCount(); i++) {
817:                    Fold child = fold.getFold(i);
818:                    if (child.getParent() != fold) {
819:                        throw new IllegalStateException(
820:                                "Wrong parent of child=" // NOI18N
821:                                        + child + ": " + child.getParent() // NOI18N
822:                                        + " != " + fold); // NOI18N
823:                    }
824:                    int foldIndex = fold.getFoldIndex(child);
825:                    if (foldIndex != i) {
826:                        throw new IllegalStateException("Fold index "
827:                                + foldIndex // NOI18N
828:                                + " instead of " + i); // NOI18N
829:                    }
830:
831:                    int childStartOffset = child.getStartOffset();
832:                    int childEndOffset = child.getEndOffset();
833:                    if (childStartOffset < lastEndOffset) {
834:                        throw new IllegalStateException("childStartOffset="
835:                                + childStartOffset // NOI18N
836:                                + " < lastEndOffset=" + lastEndOffset); // NOI18N
837:                    }
838:                    if (childStartOffset > childEndOffset) {
839:                        throw new IllegalStateException("childStartOffset="
840:                                + childStartOffset // NOI18N
841:                                + " > childEndOffset=" + childEndOffset); // NOI18N
842:                    }
843:                    lastEndOffset = childEndOffset;
844:
845:                    checkFoldConsistency(child);
846:                }
847:            }
848:
849:            public String toString() {
850:                StringBuffer sb = new StringBuffer();
851:                sb.append("component="); // NOI18N
852:                sb.append(System.identityHashCode(getComponent()));
853:                sb.append('\n');
854:
855:                // Append info about root folds
856:                sb.append(FoldUtilitiesImpl.foldToStringChildren(hierarchy
857:                        .getRootFold(), 0));
858:                sb.append('\n');
859:
860:                // Append info about blocked folds
861:                if (blocked2block != null) {
862:                    sb.append("BLOCKED\n"); // NOI18N
863:                    for (Iterator it = blocked2block.entrySet().iterator(); it
864:                            .hasNext();) {
865:                        Map.Entry entry = (Map.Entry) it.next();
866:                        sb.append("    "); // NOI18N
867:                        sb.append(entry.getKey());
868:                        sb.append(" blocked-by "); // NOI18N
869:                        sb.append(entry.getValue());
870:                        sb.append('\n');
871:                    }
872:                }
873:
874:                // Append info about blockers
875:                if (block2blockedSet != null) {
876:                    sb.append("BLOCKERS\n"); // NOI18N
877:                    for (Iterator it = block2blockedSet.entrySet().iterator(); it
878:                            .hasNext();) {
879:                        Map.Entry entry = (Map.Entry) it.next();
880:                        sb.append("    "); // NOI18N
881:                        sb.append(entry.getKey());
882:                        sb.append('\n');
883:                        Set blockedSet = (Set) entry.getValue();
884:                        for (Iterator it2 = blockedSet.iterator(); it2
885:                                .hasNext();) {
886:                            sb.append("        blocks "); // NOI18N
887:                            sb.append(it2.next());
888:                            sb.append('\n');
889:                        }
890:                    }
891:                }
892:
893:                int operationsLength = operations.length;
894:                if (operationsLength > 0) {
895:                    sb.append("Fold Managers\n"); // NOI18N
896:                    for (int i = 0; i < operationsLength; i++) {
897:                        sb.append("FOLD MANAGER ["); // NOI18N
898:                        sb.append(i);
899:                        sb.append("]:\n"); // NOI18N
900:                        sb.append(operations[i].getManager());
901:                        sb.append("\n"); // NOI18N
902:                    }
903:                }
904:
905:                return sb.toString();
906:            }
907:
908:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.