Source Code Cross Referenced for OffsetsBag.java in  » IDE-Netbeans » editor » org » netbeans » spi » editor » highlighting » support » 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.spi.editor.highlighting.support 
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.spi.editor.highlighting.support;
043:
044:        import java.lang.ref.WeakReference;
045:        import java.util.logging.Level;
046:        import java.util.logging.Logger;
047:        import javax.swing.event.DocumentEvent;
048:        import javax.swing.event.DocumentListener;
049:        import javax.swing.text.AttributeSet;
050:        import javax.swing.text.Document;
051:        import org.netbeans.api.editor.settings.AttributesUtilities;
052:        import org.netbeans.modules.editor.lib2.highlighting.OffsetGapList;
053:        import org.netbeans.spi.editor.highlighting.*;
054:        import org.openide.util.Utilities;
055:
056:        /**
057:         * A bag of highlighted areas specified by their offsets in a document.
058:         *
059:         * <p>The highlighted areas (highlights) are determined by their starting and ending
060:         * offsets in a document and the set of attributes that should be used for rendering
061:         * that area. The highlights can be arbitrarily added to and remove from this bag.
062:         * 
063:         * <p>The <code>OffsetsBag</code> is designed to work over a single
064:         * document, which is passed in to the constructor. All offsets
065:         * accepted by various methods in this class must refer to positions within
066:         * this document. Therefore any offsets passed in to the methods in this class
067:         * have to be equal to or greater than zero and less than or equal to the document
068:         * size.
069:         *
070:         * <p>The <code>OffsetsBag</code> can operate in two modes depending on a
071:         * value passed in its construtor. The mode determines how the bag will treat
072:         * newly added highlights that overlap with existing highlights in the bag.
073:         * 
074:         * <p><b>Trimming mode</b>:
075:         * In the trimming mode the bag will <i>trim</i> any existing highlights that
076:         * would overlap with a newly added highlight. In this mode the newly
077:         * added highlights always replace the existing highlights if they overlap.
078:         * 
079:         * <p><b>Merging mode</b>:
080:         * In the merging mode the bag will <i>merge</i> attributes of the overlapping highlights.
081:         * The area where the new highlight overlaps with some existing highlights will
082:         * then constitute a new highlight, which attributes will be a composition of
083:         * the attributes of both the new and existing highlight. Should there be attributes
084:         * with the same name the attribute values from the newly added highlight will take
085:         * precedence.
086:         *
087:         * @author Vita Stejskal
088:         */
089:        public final class OffsetsBag extends AbstractHighlightsContainer {
090:
091:            private static final Logger LOG = Logger.getLogger(OffsetsBag.class
092:                    .getName());
093:
094:            private Document document;
095:            private OffsetGapList<Mark> marks;
096:            private boolean mergeHighlights;
097:            private long version = 0;
098:            private DocL docListener;
099:
100:            /**
101:             * Creates a new instance of <code>OffsetsBag</code>, which trims highlights
102:             * as they are added. It calls the {@link #OffsetsBag(Document, boolean)} constructor
103:             * passing <code>false</code> as a parameter.
104:             * 
105:             * @param document           The document that should be highlighted.
106:             */
107:            public OffsetsBag(Document document) {
108:                this (document, false);
109:            }
110:
111:            /**
112:             * Creates a new instance of <code>OffsetsBag</code>.
113:             *
114:             * @param document           The document that should be highlighted.
115:             * @param mergeHighlights    Determines whether highlights should be merged
116:             *                           or trimmed.
117:             */
118:            public OffsetsBag(Document document, boolean mergeHighlights) {
119:                this .document = document;
120:                this .mergeHighlights = mergeHighlights;
121:                this .marks = new OffsetGapList<Mark>(true); // do not move 0 offset, #102955
122:                this .docListener = new DocL(this );
123:                this .document.addDocumentListener(docListener);
124:            }
125:
126:            /**
127:             * Discards this <code>OffsetsBag</code>. This method should be called when
128:             * a client stops using the bag. After calling this method no other methods
129:             * should be called. The bag is effectively empty and it is not possible to
130:             * modify it.
131:             */
132:            public void discard() {
133:                synchronized (marks) {
134:                    if (document != null) {
135:                        document.removeDocumentListener(docListener);
136:
137:                        marks.clear();
138:                        version++;
139:                        docListener = null;
140:                        document = null;
141:                    }
142:                }
143:            }
144:
145:            /**
146:             * Adds a highlight to this bag. The highlight is specified by its staring
147:             * and ending offset and by its attributes. Adding a highlight that overlaps
148:             * with one or more existing highlights can have a different result depending
149:             * on the value of the <code>mergingHighlights</code> parameter used for
150:             * constructing this bag.
151:             *
152:             * @param startOffset    The beginning of the highlighted area.
153:             * @param endOffset      The end of the highlighted area.
154:             * @param attributes     The attributes to use for highlighting.
155:             */
156:            public void addHighlight(int startOffset, int endOffset,
157:                    AttributeSet attributes) {
158:                int[] offsets;
159:
160:                synchronized (marks) {
161:                    offsets = addHighlightImpl(startOffset, endOffset,
162:                            attributes);
163:                    if (offsets != null) {
164:                        version++;
165:                    }
166:                }
167:
168:                if (offsets != null) {
169:                    fireHighlightsChange(offsets[0], offsets[1]);
170:                }
171:            }
172:
173:            /**
174:             * Adds all highlights from the bag passed in. This method is equivalent
175:             * to calling <code>addHighlight</code> for all the highlights in the
176:             * <code>bag</code> except that the changes are done atomically.
177:             *
178:             * @param bag    The bag of highlights that will be atomically
179:             *               added to this bag.
180:             */
181:            public void addAllHighlights(HighlightsSequence bag) {
182:                int[] offsets;
183:
184:                synchronized (marks) {
185:                    offsets = addAllHighlightsImpl(bag);
186:                    if (offsets != null) {
187:                        version++;
188:                    }
189:                }
190:
191:                if (offsets != null) {
192:                    fireHighlightsChange(offsets[0], offsets[1]);
193:                }
194:            }
195:
196:            /**
197:             * Resets this bag to use the new set of highlights. This method drops
198:             * all the existing highlights in this bag and adds all highlights from
199:             * the sequence passed in as a parameter. The changes are made atomically.
200:             * The sequence passed in has to be acting on the same <code>Document</code>
201:             * as this bag.
202:             *
203:             * @param seq    New highlights to add.
204:             */
205:            public void setHighlights(HighlightsSequence seq) {
206:                if (seq instanceof  Seq) {
207:                    setHighlights(((Seq) seq).getBag());
208:                    return;
209:                }
210:
211:                int changeStart = Integer.MAX_VALUE;
212:                int changeEnd = Integer.MIN_VALUE;
213:
214:                synchronized (marks) {
215:                    int[] clearedArea = clearImpl();
216:                    int[] populatedArea = addAllHighlightsImpl(seq);
217:
218:                    if (clearedArea != null) {
219:                        changeStart = clearedArea[0];
220:                        changeEnd = clearedArea[1];
221:                    }
222:
223:                    if (populatedArea != null) {
224:                        if (changeStart == Integer.MAX_VALUE
225:                                || changeStart > populatedArea[0]) {
226:                            changeStart = populatedArea[0];
227:                        }
228:                        if (changeEnd == Integer.MIN_VALUE
229:                                || changeEnd < populatedArea[1]) {
230:                            changeEnd = populatedArea[1];
231:                        }
232:                    }
233:
234:                    if (changeStart < changeEnd) {
235:                        version++;
236:                    }
237:                }
238:
239:                if (changeStart < changeEnd) {
240:                    fireHighlightsChange(changeStart, changeEnd);
241:                }
242:            }
243:
244:            /**
245:             * Resets this bag to use the new set of highlights. This method drops
246:             * all the existing highlights in this bag and adds all highlights from
247:             * the bag passed in as a parameter. The changes are made atomically. Both
248:             * bags have to be acting on the same <code>Document</code>.
249:             *
250:             * @param bag    New highlights to add.
251:             */
252:            public void setHighlights(OffsetsBag bag) {
253:                int changeStart = Integer.MAX_VALUE;
254:                int changeEnd = Integer.MIN_VALUE;
255:
256:                synchronized (marks) {
257:                    assert document != null : "Can't modify discarded bag."; //NOI18N
258:
259:                    int[] clearedArea = clearImpl();
260:                    int[] populatedArea = null;
261:
262:                    OffsetGapList<OffsetsBag.Mark> newMarks = bag.getMarks();
263:
264:                    synchronized (newMarks) {
265:                        for (OffsetsBag.Mark mark : newMarks) {
266:                            marks.add(marks.size(), new OffsetsBag.Mark(mark
267:                                    .getOffset(), mark.getAttributes()));
268:                        }
269:
270:                        if (marks.size() > 0) {
271:                            populatedArea = new int[] {
272:                                    marks.get(0).getOffset(),
273:                                    marks.get(marks.size() - 1).getOffset() };
274:                        }
275:                    }
276:
277:                    if (clearedArea != null) {
278:                        changeStart = clearedArea[0];
279:                        changeEnd = clearedArea[1];
280:                    }
281:
282:                    if (populatedArea != null) {
283:                        if (changeStart == Integer.MAX_VALUE
284:                                || changeStart > populatedArea[0]) {
285:                            changeStart = populatedArea[0];
286:                        }
287:                        if (changeEnd == Integer.MIN_VALUE
288:                                || changeEnd < populatedArea[1]) {
289:                            changeEnd = populatedArea[1];
290:                        }
291:                    }
292:
293:                    if (changeStart < changeEnd) {
294:                        version++;
295:                    }
296:                }
297:
298:                if (changeStart < changeEnd) {
299:                    fireHighlightsChange(changeStart, changeEnd);
300:                }
301:            }
302:
303:            /**
304:             * Removes highlights in a specific area of the document. All existing highlights
305:             * that are positioned within the area specified by the <code>startOffset</code> and
306:             * <code>endOffset</code> parameters are removed from this bag. The highlights
307:             * that only partialy overlap with the area are treated according to the value
308:             * of the <code>clip</code> parameter.
309:             * 
310:             * <ul>
311:             * <li>If <code>clip == true</code> : the overlapping highlights will remain
312:             * in this sequence but will be clipped so that they do not overlap anymore
313:             * <li>If <code>clip == false</code> : the overlapping highlights will be
314:             * removed from this sequence
315:             * </ul>
316:             *
317:             * @param startOffset    The beginning of the area to clear.
318:             * @param endOffset      The end of the area to clear.
319:             * @param clip           Whether to clip the partially overlapping highlights.
320:             */
321:            public void removeHighlights(int startOffset, int endOffset,
322:                    boolean clip) {
323:                int changeStart = Integer.MAX_VALUE;
324:                int changeEnd = Integer.MIN_VALUE;
325:
326:                // Ignore empty areas when clipping
327:                if (startOffset == endOffset && clip) {
328:                    return;
329:                } else {
330:                    assert startOffset <= endOffset : "Start offset must be less than or equal to the end offset. startOffset = "
331:                            + startOffset + ", endOffset = " + endOffset; //NOI18N
332:                }
333:
334:                synchronized (marks) {
335:                    assert document != null : "Can't modify discarded bag."; //NOI18N
336:
337:                    if (marks.isEmpty()) {
338:                        return;
339:                    }
340:
341:                    int startIdx = indexBeforeOffset(startOffset);
342:                    int endIdx = indexBeforeOffset(endOffset, startIdx < 0 ? 0
343:                            : startIdx, marks.size() - 1);
344:
345:                    //            System.out.println("removeHighlights(" + startOffset + ", " + endOffset + ", " + clip + ") : startIdx = " + startIdx + ", endIdx = " + endIdx);
346:
347:                    if (clip) {
348:                        if (startIdx == endIdx) {
349:                            if (startIdx != -1
350:                                    && marks.get(startIdx).getAttributes() != null) {
351:                                AttributeSet original = marks.get(startIdx)
352:                                        .getAttributes();
353:
354:                                if (marks.get(startIdx).getOffset() == startOffset) {
355:                                    marks.set(startIdx, new Mark(endOffset,
356:                                            original));
357:                                } else {
358:                                    marks.add(startIdx + 1, new Mark(
359:                                            startOffset, null));
360:                                    marks.add(startIdx + 2, new Mark(endOffset,
361:                                            original));
362:                                }
363:
364:                                changeStart = startOffset;
365:                                changeEnd = endOffset;
366:                            }
367:
368:                            // make sure nothing gets removed
369:                            startIdx = Integer.MAX_VALUE;
370:                            endIdx = Integer.MIN_VALUE;
371:                        } else {
372:                            assert endIdx != -1 : "Invalid range: startIdx = "
373:                                    + startIdx + " endIdx = " + endIdx;
374:
375:                            if (marks.get(endIdx).getAttributes() != null) {
376:                                marks.set(endIdx, new Mark(endOffset, marks
377:                                        .get(endIdx).getAttributes()));
378:                                changeEnd = endOffset;
379:                                endIdx--;
380:                            }
381:
382:                            if (startIdx != -1
383:                                    && marks.get(startIdx).getAttributes() != null) {
384:                                startIdx++;
385:                                if (startIdx <= endIdx) {
386:                                    marks.set(startIdx, new Mark(startOffset,
387:                                            null));
388:                                } else {
389:                                    marks.add(startIdx, new Mark(startOffset,
390:                                            null));
391:                                }
392:                                changeStart = startOffset;
393:                            }
394:                            startIdx++;
395:
396:                        }
397:                    } else {
398:                        if (startIdx == -1
399:                                || marks.get(startIdx).getAttributes() == null) {
400:                            startIdx++;
401:                        }
402:
403:                        if (endIdx != -1
404:                                && marks.get(endIdx).getAttributes() != null) {
405:                            endIdx++;
406:                        }
407:                    }
408:
409:                    if (startIdx <= endIdx) {
410:                        if (changeStart == Integer.MAX_VALUE) {
411:                            changeStart = marks.get(startIdx).getOffset();
412:                        }
413:                        if (changeEnd == Integer.MIN_VALUE) {
414:                            if (endIdx >= marks.size()) { // Logging for #117403
415:                                if (LOG.isLoggable(Level.INFO)) {
416:                                    String logMsg = "Too high endIdx="
417:                                            + endIdx
418:                                            + // NOI18N
419:                                            ", marks.size()="
420:                                            + marks.size()
421:                                            + // NOI18N
422:                                            ", startIdx="
423:                                            + startIdx
424:                                            + // NOI18N
425:                                            ", startOffset=" + startOffset
426:                                            + ", endOffset="
427:                                            + endOffset
428:                                            + // NOI18N
429:                                            ", changeStart="
430:                                            + changeStart
431:                                            + // NOI18N
432:                                            ", document.getLength()="
433:                                            + document.getLength()
434:                                            + // NOI18N
435:                                            ", lastMark="
436:                                            + marks.get(marks.size() - 1); // NOI18N
437:                                    LOG
438:                                            .log(Level.INFO, logMsg,
439:                                                    new Exception());
440:                                }
441:                                endIdx = marks.size() - 1; // Fix the index so that exc. does not occur
442:                            }
443:                            changeEnd = marks.get(endIdx).getOffset();
444:                        }
445:                        marks.remove(startIdx, endIdx - startIdx + 1);
446:                    }
447:
448:                    if (changeStart <= changeEnd) {
449:                        version++;
450:                    }
451:                }
452:
453:                if (changeStart <= changeEnd) {
454:                    fireHighlightsChange(changeStart, changeEnd);
455:                }
456:            }
457:
458:            /**
459:             * Gets highlights from an area of a document. The <code>HighlightsSequence</code> is
460:             * computed using all the highlights present in this bag between the
461:             * <code>startOffset</code> and <code>endOffset</code>.
462:             *
463:             * @param startOffset  The beginning of the area.
464:             * @param endOffset    The end of the area.
465:             *
466:             * @return The <code>HighlightsSequence</code> which iterates through the
467:             *         highlights in the given area of this bag.
468:             */
469:            public HighlightsSequence getHighlights(int startOffset,
470:                    int endOffset) {
471:                if (LOG.isLoggable(Level.FINE) && !(startOffset < endOffset)) {
472:                    LOG
473:                            .fine("startOffset must be less than endOffset: startOffset = "
474:                                    + //NOI18N
475:                                    startOffset + " endOffset = " + endOffset); //NOI18N
476:                }
477:
478:                synchronized (marks) {
479:                    if (document != null) {
480:                        return new Seq(version, startOffset, endOffset);
481:                    } else {
482:                        return HighlightsSequence.EMPTY;
483:                    }
484:                }
485:            }
486:
487:            /**
488:             * Removes all highlights previously added to this bag.
489:             */
490:            public void clear() {
491:                int[] clearedArea;
492:
493:                synchronized (marks) {
494:                    assert document != null : "Can't modify discarded bag."; //NOI18N
495:
496:                    clearedArea = clearImpl();
497:                    if (clearedArea != null) {
498:                        version++;
499:                    }
500:                }
501:
502:                if (clearedArea != null) {
503:                    fireHighlightsChange(clearedArea[0], clearedArea[1]);
504:                }
505:            }
506:
507:            // ----------------------------------------------------------------------
508:            //  Package private API
509:            // ----------------------------------------------------------------------
510:
511:            /* package */OffsetGapList<Mark> getMarks() {
512:                return marks;
513:            }
514:
515:            /* package */Document getDocument() {
516:                return document;
517:            }
518:
519:            // ----------------------------------------------------------------------
520:            //  Private implementation
521:            // ----------------------------------------------------------------------
522:
523:            private int[] addHighlightImpl(int startOffset, int endOffset,
524:                    AttributeSet attributes) {
525:                if (startOffset == endOffset) {
526:                    return null;
527:                } else {
528:                    assert document != null : "Can't modify discarded bag."; //NOI18N
529:                    assert startOffset < endOffset : "Start offset must be before the end offset. startOffset = "
530:                            + startOffset + ", endOffset = " + endOffset; //NOI18N
531:                    assert attributes != null : "Highlight attributes must not be null."; //NOI18N
532:                }
533:
534:                if (mergeHighlights) {
535:                    merge(startOffset, endOffset, attributes);
536:                } else {
537:                    trim(startOffset, endOffset, attributes);
538:                }
539:
540:                return new int[] { startOffset, endOffset };
541:            }
542:
543:            private void merge(int startOffset, int endOffset,
544:                    AttributeSet attributes) {
545:                AttributeSet lastKnownAttributes = null;
546:                int startIdx = indexBeforeOffset(startOffset);
547:                if (startIdx < 0) {
548:                    startIdx = 0;
549:                    marks.add(startIdx, new Mark(startOffset, attributes));
550:                } else {
551:                    Mark mark = marks.get(startIdx);
552:                    AttributeSet markAttribs = mark.getAttributes();
553:                    AttributeSet newAttribs = markAttribs == null ? attributes
554:                            : AttributesUtilities.createComposite(attributes,
555:                                    markAttribs);
556:                    lastKnownAttributes = mark.getAttributes();
557:
558:                    if (mark.getOffset() == startOffset) {
559:                        mark.setAttributes(newAttribs);
560:                    } else {
561:                        startIdx++;
562:                        marks.add(startIdx, new Mark(startOffset, newAttribs));
563:                    }
564:                }
565:
566:                for (int idx = startIdx + 1;; idx++) {
567:                    if (idx < marks.size()) {
568:                        Mark mark = marks.get(idx);
569:
570:                        if (mark.getOffset() < endOffset) {
571:                            lastKnownAttributes = mark.getAttributes();
572:                            mark
573:                                    .setAttributes(lastKnownAttributes == null ? attributes
574:                                            : AttributesUtilities
575:                                                    .createComposite(
576:                                                            attributes,
577:                                                            lastKnownAttributes));
578:                        } else {
579:                            if (mark.getOffset() > endOffset) {
580:                                marks.add(idx, new Mark(endOffset,
581:                                        lastKnownAttributes));
582:                            }
583:                            break;
584:                        }
585:                    } else {
586:                        marks
587:                                .add(idx, new Mark(endOffset,
588:                                        lastKnownAttributes));
589:                        break;
590:                    }
591:                }
592:            }
593:
594:            private void trim(int startOffset, int endOffset,
595:                    AttributeSet attributes) {
596:                int startIdx = indexBeforeOffset(startOffset);
597:                int endIdx = indexBeforeOffset(endOffset, startIdx < 0 ? 0
598:                        : startIdx, marks.size() - 1);
599:
600:                //        System.out.println("trim(" + startOffset + ", " + endOffset + ") : startIdx = " + startIdx + ", endIdx = " + endIdx);
601:
602:                if (startIdx == endIdx) {
603:                    AttributeSet original = null;
604:                    if (startIdx != -1
605:                            && marks.get(startIdx).getAttributes() != null) {
606:                        original = marks.get(startIdx).getAttributes();
607:                    }
608:
609:                    if (startIdx != -1
610:                            && marks.get(startIdx).getOffset() == startOffset) {
611:                        marks.get(startIdx).setAttributes(attributes);
612:                    } else {
613:                        startIdx++;
614:                        marks.add(startIdx, new Mark(startOffset, attributes));
615:                    }
616:
617:                    startIdx++;
618:                    marks.add(startIdx, new Mark(endOffset, original));
619:                } else {
620:                    assert endIdx != -1 : "Invalid range: startIdx = "
621:                            + startIdx + " endIdx = " + endIdx; //NOI81N
622:
623:                    marks.set(endIdx, new Mark(endOffset, marks.get(endIdx)
624:                            .getAttributes()));
625:                    endIdx--;
626:
627:                    startIdx++;
628:                    if (startIdx <= endIdx) {
629:                        marks.set(startIdx, new Mark(startOffset, attributes));
630:                    } else {
631:                        marks.add(startIdx, new Mark(startOffset, attributes));
632:                    }
633:                    startIdx++;
634:
635:                    if (startIdx <= endIdx) {
636:                        marks.remove(startIdx, endIdx - startIdx + 1);
637:                    }
638:                }
639:            }
640:
641:            private int[] addAllHighlightsImpl(HighlightsSequence sequence) {
642:                int changeStart = Integer.MAX_VALUE;
643:                int changeEnd = Integer.MIN_VALUE;
644:
645:                for (; sequence.moveNext();) {
646:                    addHighlightImpl(sequence.getStartOffset(), sequence
647:                            .getEndOffset(), sequence.getAttributes());
648:
649:                    if (changeStart == Integer.MAX_VALUE) {
650:                        changeStart = sequence.getStartOffset();
651:                    }
652:                    changeEnd = sequence.getEndOffset();
653:                }
654:
655:                if (changeStart != Integer.MAX_VALUE
656:                        && changeEnd != Integer.MIN_VALUE) {
657:                    return new int[] { changeStart, changeEnd };
658:                } else {
659:                    return null;
660:                }
661:            }
662:
663:            private int[] clearImpl() {
664:                if (!marks.isEmpty()) {
665:                    int changeStart = marks.get(0).getOffset();
666:                    int changeEnd = marks.get(marks.size() - 1).getOffset();
667:
668:                    marks.clear();
669:
670:                    return new int[] { changeStart, changeEnd };
671:                } else {
672:                    return null;
673:                }
674:            }
675:
676:            private int indexBeforeOffset(int offset, int low, int high) {
677:                int idx = marks.findElementIndex(offset, low, high);
678:                if (idx < 0) {
679:                    idx = -idx - 1; // the insertion point: <0, size()>
680:                    return idx - 1;
681:                } else {
682:                    return idx;
683:                }
684:            }
685:
686:            private int indexBeforeOffset(int offset) {
687:                return indexBeforeOffset(offset, 0, marks.size() - 1);
688:            }
689:
690:            /* package */static final class Mark extends OffsetGapList.Offset {
691:                private AttributeSet attribs;
692:
693:                public Mark(int offset, AttributeSet attribs) {
694:                    super (offset);
695:                    this .attribs = attribs;
696:                }
697:
698:                public AttributeSet getAttributes() {
699:                    return attribs;
700:                }
701:
702:                public void setAttributes(AttributeSet attribs) {
703:                    this .attribs = attribs;
704:                }
705:
706:                @Override
707:                public String toString() {
708:                    return "offset=" + getOffset() + ", attribs=" + attribs; // NOI81N
709:                }
710:
711:            } // End of Mark class
712:
713:            private final class Seq implements  HighlightsSequence {
714:
715:                private long version;
716:                private int startOffset;
717:                private int endOffset;
718:
719:                private int highlightStart;
720:                private int highlightEnd;
721:                private AttributeSet highlightAttributes;
722:
723:                private int idx = -1;
724:
725:                public Seq(long version, int startOffset, int endOffset) {
726:                    this .version = version;
727:                    this .startOffset = startOffset;
728:                    this .endOffset = endOffset;
729:                }
730:
731:                public boolean moveNext() {
732:                    synchronized (OffsetsBag.this .marks) {
733:                        if (checkVersion()) {
734:                            if (idx == -1) {
735:                                idx = indexBeforeOffset(startOffset);
736:                                if (idx == -1 && marks.size() > 0) {
737:                                    idx = 0;
738:                                }
739:                            } else {
740:                                idx++;
741:                            }
742:
743:                            while (isIndexValid(idx)) {
744:                                if (marks.get(idx).getAttributes() != null) {
745:                                    highlightStart = Math.max(marks.get(idx)
746:                                            .getOffset(), startOffset);
747:                                    highlightEnd = Math.min(marks.get(idx + 1)
748:                                            .getOffset(), endOffset);
749:                                    highlightAttributes = marks.get(idx)
750:                                            .getAttributes();
751:                                    return true;
752:                                }
753:
754:                                // Skip any empty areas
755:                                idx++;
756:                            }
757:                        }
758:
759:                        return false;
760:                    }
761:                }
762:
763:                public int getStartOffset() {
764:                    synchronized (OffsetsBag.this .marks) {
765:                        assert idx != -1 : "Sequence not initialized, call moveNext() first."; //NOI18N
766:                        return highlightStart;
767:                    }
768:                }
769:
770:                public int getEndOffset() {
771:                    synchronized (OffsetsBag.this .marks) {
772:                        assert idx != -1 : "Sequence not initialized, call moveNext() first."; //NOI18N
773:                        return highlightEnd;
774:                    }
775:                }
776:
777:                public AttributeSet getAttributes() {
778:                    synchronized (OffsetsBag.this .marks) {
779:                        assert idx != -1 : "Sequence not initialized, call moveNext() first."; //NOI18N
780:                        return highlightAttributes;
781:                    }
782:                }
783:
784:                private boolean isIndexValid(int idx) {
785:                    return idx >= 0 && idx + 1 < marks.size()
786:                            && marks.get(idx).getOffset() < endOffset
787:                            && marks.get(idx + 1).getOffset() > startOffset;
788:                }
789:
790:                private OffsetsBag getBag() {
791:                    return OffsetsBag.this ;
792:                }
793:
794:                private boolean checkVersion() {
795:                    return OffsetsBag.this .version == version;
796:                }
797:            } // End of Seq class
798:
799:            private static final class DocL extends WeakReference<OffsetsBag>
800:                    implements  DocumentListener, Runnable {
801:
802:                private Document document;
803:
804:                public DocL(OffsetsBag bag) {
805:                    super (bag, Utilities.activeReferenceQueue());
806:                    this .document = bag.getDocument();
807:                }
808:
809:                public void insertUpdate(DocumentEvent e) {
810:                    OffsetsBag bag = get();
811:                    if (bag != null) {
812:                        synchronized (bag.marks) {
813:                            if (LOG.isLoggable(Level.FINE)) {
814:                                LOG.fine("OffsetsBag@"
815:                                        + Integer.toHexString(System
816:                                                .identityHashCode(this ))
817:                                        + //NOI18N
818:                                        " insertUpdate: doc="
819:                                        + Integer.toHexString(System
820:                                                .identityHashCode(document))
821:                                        + //NOI18N
822:                                        ", offset=" + e.getOffset()
823:                                        + ", insertLength=" + e.getLength() + //NOI18N
824:                                        ", docLength=" + document.getLength()); //NOI18N
825:                            }
826:                            bag.marks.defaultInsertUpdate(e.getOffset(), e
827:                                    .getLength());
828:                        }
829:                    } else {
830:                        run();
831:                    }
832:                }
833:
834:                public void removeUpdate(DocumentEvent e) {
835:                    OffsetsBag bag = get();
836:                    if (bag != null) {
837:                        synchronized (bag.marks) {
838:                            if (LOG.isLoggable(Level.FINE)) {
839:                                LOG.fine("OffsetsBag@"
840:                                        + Integer.toHexString(System
841:                                                .identityHashCode(this ))
842:                                        + //NOI18N
843:                                        " removeUpdate: doc="
844:                                        + Integer.toHexString(System
845:                                                .identityHashCode(document))
846:                                        + //NOI18N
847:                                        ", offset=" + e.getOffset()
848:                                        + ", removedLength=" + e.getLength() + //NOI18N
849:                                        ", docLength=" + document.getLength()); //NOI18N
850:                            }
851:                            bag.marks.defaultRemoveUpdate(e.getOffset(), e
852:                                    .getLength());
853:                        }
854:                    } else {
855:                        run();
856:                    }
857:                }
858:
859:                public void changedUpdate(DocumentEvent e) {
860:                    // not interested
861:                }
862:
863:                public void run() {
864:                    Document d = document;
865:                    if (d != null) {
866:                        d.removeDocumentListener(this );
867:                        document = null;
868:                    }
869:                }
870:            } // End of DocL class
871:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.