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