Source Code Cross Referenced for FastPartitioner.java in  » IDE-Eclipse » jface » org » eclipse » jface » text » rules » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Eclipse » jface » org.eclipse.jface.text.rules 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*******************************************************************************
002:         * Copyright (c) 2000, 2006 IBM Corporation and others.
003:         * All rights reserved. This program and the accompanying materials
004:         * are made available under the terms of the Eclipse Public License v1.0
005:         * which accompanies this distribution, and is available at
006:         * http://www.eclipse.org/legal/epl-v10.html
007:         *
008:         * Contributors:
009:         *     IBM Corporation - initial API and implementation
010:         *******************************************************************************/package org.eclipse.jface.text.rules;
011:
012:        import java.util.ArrayList;
013:        import java.util.List;
014:
015:        import org.eclipse.core.runtime.Assert;
016:        import org.eclipse.core.runtime.Platform;
017:
018:        import org.eclipse.jface.text.BadLocationException;
019:        import org.eclipse.jface.text.BadPositionCategoryException;
020:        import org.eclipse.jface.text.DefaultPositionUpdater;
021:        import org.eclipse.jface.text.DocumentEvent;
022:        import org.eclipse.jface.text.DocumentRewriteSession;
023:        import org.eclipse.jface.text.IDocument;
024:        import org.eclipse.jface.text.IDocumentPartitioner;
025:        import org.eclipse.jface.text.IDocumentPartitionerExtension;
026:        import org.eclipse.jface.text.IDocumentPartitionerExtension2;
027:        import org.eclipse.jface.text.IDocumentPartitionerExtension3;
028:        import org.eclipse.jface.text.IRegion;
029:        import org.eclipse.jface.text.ITypedRegion;
030:        import org.eclipse.jface.text.Position;
031:        import org.eclipse.jface.text.Region;
032:        import org.eclipse.jface.text.TextUtilities;
033:        import org.eclipse.jface.text.TypedPosition;
034:        import org.eclipse.jface.text.TypedRegion;
035:
036:        /**
037:         * A standard implementation of a document partitioner. It uses an
038:         * {@link IPartitionTokenScanner} to scan the document and to determine the
039:         * document's partitioning. The tokens returned by the scanner must return the
040:         * partition type as their data. The partitioner remembers the document's
041:         * partitions in the document itself rather than maintaining its own data
042:         * structure.
043:         * <p>
044:         * To reduce array creations in {@link IDocument#getPositions(String)}, the
045:         * positions get cached. The cache is cleared after updating the positions in
046:         * {@link #documentChanged2(DocumentEvent)}. Subclasses need to call
047:         * {@link #clearPositionCache()} after modifying the partitioner's positions.
048:         * The cached positions may be accessed through {@link #getPositions()}.
049:         * </p>
050:         *
051:         * @see IPartitionTokenScanner
052:         * @since 3.1
053:         */
054:        public class FastPartitioner implements  IDocumentPartitioner,
055:                IDocumentPartitionerExtension, IDocumentPartitionerExtension2,
056:                IDocumentPartitionerExtension3 {
057:
058:            /**
059:             * The position category this partitioner uses to store the document's partitioning information.
060:             */
061:            private static final String CONTENT_TYPES_CATEGORY = "__content_types_category"; //$NON-NLS-1$
062:            /** The partitioner's scanner */
063:            protected final IPartitionTokenScanner fScanner;
064:            /** The legal content types of this partitioner */
065:            protected final String[] fLegalContentTypes;
066:            /** The partitioner's document */
067:            protected IDocument fDocument;
068:            /** The document length before a document change occurred */
069:            protected int fPreviousDocumentLength;
070:            /** The position updater used to for the default updating of partitions */
071:            protected final DefaultPositionUpdater fPositionUpdater;
072:            /** The offset at which the first changed partition starts */
073:            protected int fStartOffset;
074:            /** The offset at which the last changed partition ends */
075:            protected int fEndOffset;
076:            /**The offset at which a partition has been deleted */
077:            protected int fDeleteOffset;
078:            /**
079:             * The position category this partitioner uses to store the document's partitioning information.
080:             */
081:            private final String fPositionCategory;
082:            /**
083:             * The active document rewrite session.
084:             */
085:            private DocumentRewriteSession fActiveRewriteSession;
086:            /**
087:             * Flag indicating whether this partitioner has been initialized.
088:             */
089:            private boolean fIsInitialized = false;
090:            /**
091:             * The cached positions from our document, so we don't create a new array every time
092:             * someone requests partition information.
093:             */
094:            private Position[] fCachedPositions = null;
095:            /** Debug option for cache consistency checking. */
096:            private static final boolean CHECK_CACHE_CONSISTENCY = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jface.text/debug/FastPartitioner/PositionCache")); //$NON-NLS-1$//$NON-NLS-2$;
097:
098:            /**
099:             * Creates a new partitioner that uses the given scanner and may return
100:             * partitions of the given legal content types.
101:             *
102:             * @param scanner the scanner this partitioner is supposed to use
103:             * @param legalContentTypes the legal content types of this partitioner
104:             */
105:            public FastPartitioner(IPartitionTokenScanner scanner,
106:                    String[] legalContentTypes) {
107:                fScanner = scanner;
108:                fLegalContentTypes = TextUtilities.copy(legalContentTypes);
109:                fPositionCategory = CONTENT_TYPES_CATEGORY + hashCode();
110:                fPositionUpdater = new DefaultPositionUpdater(fPositionCategory);
111:            }
112:
113:            /*
114:             * @see org.eclipse.jface.text.IDocumentPartitionerExtension2#getManagingPositionCategories()
115:             */
116:            public String[] getManagingPositionCategories() {
117:                return new String[] { fPositionCategory };
118:            }
119:
120:            /*
121:             * @see org.eclipse.jface.text.IDocumentPartitioner#connect(org.eclipse.jface.text.IDocument)
122:             */
123:            public final void connect(IDocument document) {
124:                connect(document, false);
125:            }
126:
127:            /**
128:             * {@inheritDoc}
129:             * <p>
130:             * May be extended by subclasses.
131:             * </p>
132:             */
133:            public void connect(IDocument document, boolean delayInitialization) {
134:                Assert.isNotNull(document);
135:                Assert.isTrue(!document
136:                        .containsPositionCategory(fPositionCategory));
137:
138:                fDocument = document;
139:                fDocument.addPositionCategory(fPositionCategory);
140:
141:                fIsInitialized = false;
142:                if (!delayInitialization)
143:                    checkInitialization();
144:            }
145:
146:            /**
147:             * Calls {@link #initialize()} if the receiver is not yet initialized.
148:             */
149:            protected final void checkInitialization() {
150:                if (!fIsInitialized)
151:                    initialize();
152:            }
153:
154:            /**
155:             * Performs the initial partitioning of the partitioner's document.
156:             * <p>
157:             * May be extended by subclasses.
158:             * </p>
159:             */
160:            protected void initialize() {
161:                fIsInitialized = true;
162:                clearPositionCache();
163:                fScanner.setRange(fDocument, 0, fDocument.getLength());
164:
165:                try {
166:                    IToken token = fScanner.nextToken();
167:                    while (!token.isEOF()) {
168:
169:                        String contentType = getTokenContentType(token);
170:
171:                        if (isSupportedContentType(contentType)) {
172:                            TypedPosition p = new TypedPosition(fScanner
173:                                    .getTokenOffset(), fScanner
174:                                    .getTokenLength(), contentType);
175:                            fDocument.addPosition(fPositionCategory, p);
176:                        }
177:
178:                        token = fScanner.nextToken();
179:                    }
180:                } catch (BadLocationException x) {
181:                    // cannot happen as offsets come from scanner
182:                } catch (BadPositionCategoryException x) {
183:                    // cannot happen if document has been connected before
184:                }
185:            }
186:
187:            /**
188:             * {@inheritDoc}
189:             * <p>
190:             * May be extended by subclasses.
191:             * </p>
192:             */
193:            public void disconnect() {
194:
195:                Assert.isTrue(fDocument
196:                        .containsPositionCategory(fPositionCategory));
197:
198:                try {
199:                    fDocument.removePositionCategory(fPositionCategory);
200:                } catch (BadPositionCategoryException x) {
201:                    // can not happen because of Assert
202:                }
203:            }
204:
205:            /**
206:             * {@inheritDoc}
207:             * <p>
208:             * May be extended by subclasses.
209:             * </p>
210:             */
211:            public void documentAboutToBeChanged(DocumentEvent e) {
212:                if (fIsInitialized) {
213:
214:                    Assert.isTrue(e.getDocument() == fDocument);
215:
216:                    fPreviousDocumentLength = e.getDocument().getLength();
217:                    fStartOffset = -1;
218:                    fEndOffset = -1;
219:                    fDeleteOffset = -1;
220:                }
221:            }
222:
223:            /*
224:             * @see IDocumentPartitioner#documentChanged(DocumentEvent)
225:             */
226:            public final boolean documentChanged(DocumentEvent e) {
227:                if (fIsInitialized) {
228:                    IRegion region = documentChanged2(e);
229:                    return (region != null);
230:                }
231:                return false;
232:            }
233:
234:            /**
235:             * Helper method for tracking the minimal region containing all partition changes.
236:             * If <code>offset</code> is smaller than the remembered offset, <code>offset</code>
237:             * will from now on be remembered. If <code>offset  + length</code> is greater than
238:             * the remembered end offset, it will be remembered from now on.
239:             *
240:             * @param offset the offset
241:             * @param length the length
242:             */
243:            private void rememberRegion(int offset, int length) {
244:                // remember start offset
245:                if (fStartOffset == -1)
246:                    fStartOffset = offset;
247:                else if (offset < fStartOffset)
248:                    fStartOffset = offset;
249:
250:                // remember end offset
251:                int endOffset = offset + length;
252:                if (fEndOffset == -1)
253:                    fEndOffset = endOffset;
254:                else if (endOffset > fEndOffset)
255:                    fEndOffset = endOffset;
256:            }
257:
258:            /**
259:             * Remembers the given offset as the deletion offset.
260:             *
261:             * @param offset the offset
262:             */
263:            private void rememberDeletedOffset(int offset) {
264:                fDeleteOffset = offset;
265:            }
266:
267:            /**
268:             * Creates the minimal region containing all partition changes using the
269:             * remembered offset, end offset, and deletion offset.
270:             *
271:             * @return the minimal region containing all the partition changes
272:             */
273:            private IRegion createRegion() {
274:                if (fDeleteOffset == -1) {
275:                    if (fStartOffset == -1 || fEndOffset == -1)
276:                        return null;
277:                    return new Region(fStartOffset, fEndOffset - fStartOffset);
278:                } else if (fStartOffset == -1 || fEndOffset == -1) {
279:                    return new Region(fDeleteOffset, 0);
280:                } else {
281:                    int offset = Math.min(fDeleteOffset, fStartOffset);
282:                    int endOffset = Math.max(fDeleteOffset, fEndOffset);
283:                    return new Region(offset, endOffset - offset);
284:                }
285:            }
286:
287:            /**
288:             * {@inheritDoc}
289:             * <p>
290:             * May be extended by subclasses.
291:             * </p>
292:             */
293:            public IRegion documentChanged2(DocumentEvent e) {
294:
295:                if (!fIsInitialized)
296:                    return null;
297:
298:                try {
299:                    Assert.isTrue(e.getDocument() == fDocument);
300:
301:                    Position[] category = getPositions();
302:                    IRegion line = fDocument.getLineInformationOfOffset(e
303:                            .getOffset());
304:                    int reparseStart = line.getOffset();
305:                    int partitionStart = -1;
306:                    String contentType = null;
307:                    int newLength = e.getText() == null ? 0 : e.getText()
308:                            .length();
309:
310:                    int first = fDocument.computeIndexInCategory(
311:                            fPositionCategory, reparseStart);
312:                    if (first > 0) {
313:                        TypedPosition partition = (TypedPosition) category[first - 1];
314:                        if (partition.includes(reparseStart)) {
315:                            partitionStart = partition.getOffset();
316:                            contentType = partition.getType();
317:                            if (e.getOffset() == partition.getOffset()
318:                                    + partition.getLength())
319:                                reparseStart = partitionStart;
320:                            --first;
321:                        } else if (reparseStart == e.getOffset()
322:                                && reparseStart == partition.getOffset()
323:                                        + partition.getLength()) {
324:                            partitionStart = partition.getOffset();
325:                            contentType = partition.getType();
326:                            reparseStart = partitionStart;
327:                            --first;
328:                        } else {
329:                            partitionStart = partition.getOffset()
330:                                    + partition.getLength();
331:                            contentType = IDocument.DEFAULT_CONTENT_TYPE;
332:                        }
333:                    }
334:
335:                    fPositionUpdater.update(e);
336:                    for (int i = first; i < category.length; i++) {
337:                        Position p = category[i];
338:                        if (p.isDeleted) {
339:                            rememberDeletedOffset(e.getOffset());
340:                            break;
341:                        }
342:                    }
343:                    clearPositionCache();
344:                    category = getPositions();
345:
346:                    fScanner.setPartialRange(fDocument, reparseStart, fDocument
347:                            .getLength()
348:                            - reparseStart, contentType, partitionStart);
349:
350:                    int behindLastScannedPosition = reparseStart;
351:                    IToken token = fScanner.nextToken();
352:
353:                    while (!token.isEOF()) {
354:
355:                        contentType = getTokenContentType(token);
356:
357:                        if (!isSupportedContentType(contentType)) {
358:                            token = fScanner.nextToken();
359:                            continue;
360:                        }
361:
362:                        int start = fScanner.getTokenOffset();
363:                        int length = fScanner.getTokenLength();
364:
365:                        behindLastScannedPosition = start + length;
366:                        int lastScannedPosition = behindLastScannedPosition - 1;
367:
368:                        // remove all affected positions
369:                        while (first < category.length) {
370:                            TypedPosition p = (TypedPosition) category[first];
371:                            if (lastScannedPosition >= p.offset + p.length
372:                                    || (p.overlapsWith(start, length) && (!fDocument
373:                                            .containsPosition(
374:                                                    fPositionCategory, start,
375:                                                    length) || !contentType
376:                                            .equals(p.getType())))) {
377:
378:                                rememberRegion(p.offset, p.length);
379:                                fDocument.removePosition(fPositionCategory, p);
380:                                ++first;
381:
382:                            } else
383:                                break;
384:                        }
385:
386:                        // if position already exists and we have scanned at least the
387:                        // area covered by the event, we are done
388:                        if (fDocument.containsPosition(fPositionCategory,
389:                                start, length)) {
390:                            if (lastScannedPosition >= e.getOffset()
391:                                    + newLength)
392:                                return createRegion();
393:                            ++first;
394:                        } else {
395:                            // insert the new type position
396:                            try {
397:                                fDocument.addPosition(fPositionCategory,
398:                                        new TypedPosition(start, length,
399:                                                contentType));
400:                                rememberRegion(start, length);
401:                            } catch (BadPositionCategoryException x) {
402:                            } catch (BadLocationException x) {
403:                            }
404:                        }
405:
406:                        token = fScanner.nextToken();
407:                    }
408:
409:                    first = fDocument.computeIndexInCategory(fPositionCategory,
410:                            behindLastScannedPosition);
411:
412:                    clearPositionCache();
413:                    category = getPositions();
414:                    TypedPosition p;
415:                    while (first < category.length) {
416:                        p = (TypedPosition) category[first++];
417:                        fDocument.removePosition(fPositionCategory, p);
418:                        rememberRegion(p.offset, p.length);
419:                    }
420:
421:                } catch (BadPositionCategoryException x) {
422:                    // should never happen on connected documents
423:                } catch (BadLocationException x) {
424:                } finally {
425:                    clearPositionCache();
426:                }
427:
428:                return createRegion();
429:            }
430:
431:            /**
432:             * Returns the position in the partitoner's position category which is
433:             * close to the given offset. This is, the position has either an offset which
434:             * is the same as the given offset or an offset which is smaller than the given
435:             * offset. This method profits from the knowledge that a partitioning is
436:             * a ordered set of disjoint position.
437:             * <p>
438:             * May be extended or replaced by subclasses.
439:             * </p>
440:             * @param offset the offset for which to search the closest position
441:             * @return the closest position in the partitioner's category
442:             */
443:            protected TypedPosition findClosestPosition(int offset) {
444:
445:                try {
446:
447:                    int index = fDocument.computeIndexInCategory(
448:                            fPositionCategory, offset);
449:                    Position[] category = getPositions();
450:
451:                    if (category.length == 0)
452:                        return null;
453:
454:                    if (index < category.length) {
455:                        if (offset == category[index].offset)
456:                            return (TypedPosition) category[index];
457:                    }
458:
459:                    if (index > 0)
460:                        index--;
461:
462:                    return (TypedPosition) category[index];
463:
464:                } catch (BadPositionCategoryException x) {
465:                } catch (BadLocationException x) {
466:                }
467:
468:                return null;
469:            }
470:
471:            /**
472:             * {@inheritDoc}
473:             * <p>
474:             * May be replaced or extended by subclasses.
475:             * </p>
476:             */
477:            public String getContentType(int offset) {
478:                checkInitialization();
479:
480:                TypedPosition p = findClosestPosition(offset);
481:                if (p != null && p.includes(offset))
482:                    return p.getType();
483:
484:                return IDocument.DEFAULT_CONTENT_TYPE;
485:            }
486:
487:            /**
488:             * {@inheritDoc}
489:             * <p>
490:             * May be replaced or extended by subclasses.
491:             * </p>
492:             */
493:            public ITypedRegion getPartition(int offset) {
494:                checkInitialization();
495:
496:                try {
497:
498:                    Position[] category = getPositions();
499:
500:                    if (category == null || category.length == 0)
501:                        return new TypedRegion(0, fDocument.getLength(),
502:                                IDocument.DEFAULT_CONTENT_TYPE);
503:
504:                    int index = fDocument.computeIndexInCategory(
505:                            fPositionCategory, offset);
506:
507:                    if (index < category.length) {
508:
509:                        TypedPosition next = (TypedPosition) category[index];
510:
511:                        if (offset == next.offset)
512:                            return new TypedRegion(next.getOffset(), next
513:                                    .getLength(), next.getType());
514:
515:                        if (index == 0)
516:                            return new TypedRegion(0, next.offset,
517:                                    IDocument.DEFAULT_CONTENT_TYPE);
518:
519:                        TypedPosition previous = (TypedPosition) category[index - 1];
520:                        if (previous.includes(offset))
521:                            return new TypedRegion(previous.getOffset(),
522:                                    previous.getLength(), previous.getType());
523:
524:                        int endOffset = previous.getOffset()
525:                                + previous.getLength();
526:                        return new TypedRegion(endOffset, next.getOffset()
527:                                - endOffset, IDocument.DEFAULT_CONTENT_TYPE);
528:                    }
529:
530:                    TypedPosition previous = (TypedPosition) category[category.length - 1];
531:                    if (previous.includes(offset))
532:                        return new TypedRegion(previous.getOffset(), previous
533:                                .getLength(), previous.getType());
534:
535:                    int endOffset = previous.getOffset() + previous.getLength();
536:                    return new TypedRegion(endOffset, fDocument.getLength()
537:                            - endOffset, IDocument.DEFAULT_CONTENT_TYPE);
538:
539:                } catch (BadPositionCategoryException x) {
540:                } catch (BadLocationException x) {
541:                }
542:
543:                return new TypedRegion(0, fDocument.getLength(),
544:                        IDocument.DEFAULT_CONTENT_TYPE);
545:            }
546:
547:            /*
548:             * @see IDocumentPartitioner#computePartitioning(int, int)
549:             */
550:            public final ITypedRegion[] computePartitioning(int offset,
551:                    int length) {
552:                return computePartitioning(offset, length, false);
553:            }
554:
555:            /**
556:             * {@inheritDoc}
557:             * <p>
558:             * May be replaced or extended by subclasses.
559:             * </p>
560:             */
561:            public String[] getLegalContentTypes() {
562:                return TextUtilities.copy(fLegalContentTypes);
563:            }
564:
565:            /**
566:             * Returns whether the given type is one of the legal content types.
567:             * <p>
568:             * May be extended by subclasses.
569:             * </p>
570:             *
571:             * @param contentType the content type to check
572:             * @return <code>true</code> if the content type is a legal content type
573:             */
574:            protected boolean isSupportedContentType(String contentType) {
575:                if (contentType != null) {
576:                    for (int i = 0; i < fLegalContentTypes.length; i++) {
577:                        if (fLegalContentTypes[i].equals(contentType))
578:                            return true;
579:                    }
580:                }
581:
582:                return false;
583:            }
584:
585:            /**
586:             * Returns a content type encoded in the given token. If the token's
587:             * data is not <code>null</code> and a string it is assumed that
588:             * it is the encoded content type.
589:             * <p>
590:             * May be replaced or extended by subclasses.
591:             * </p>
592:             *
593:             * @param token the token whose content type is to be determined
594:             * @return the token's content type
595:             */
596:            protected String getTokenContentType(IToken token) {
597:                Object data = token.getData();
598:                if (data instanceof  String)
599:                    return (String) data;
600:                return null;
601:            }
602:
603:            /* zero-length partition support */
604:
605:            /**
606:             * {@inheritDoc}
607:             * <p>
608:             * May be replaced or extended by subclasses.
609:             * </p>
610:             */
611:            public String getContentType(int offset,
612:                    boolean preferOpenPartitions) {
613:                return getPartition(offset, preferOpenPartitions).getType();
614:            }
615:
616:            /**
617:             * {@inheritDoc}
618:             * <p>
619:             * May be replaced or extended by subclasses.
620:             * </p>
621:             */
622:            public ITypedRegion getPartition(int offset,
623:                    boolean preferOpenPartitions) {
624:                ITypedRegion region = getPartition(offset);
625:                if (preferOpenPartitions) {
626:                    if (region.getOffset() == offset
627:                            && !region.getType().equals(
628:                                    IDocument.DEFAULT_CONTENT_TYPE)) {
629:                        if (offset > 0) {
630:                            region = getPartition(offset - 1);
631:                            if (region.getType().equals(
632:                                    IDocument.DEFAULT_CONTENT_TYPE))
633:                                return region;
634:                        }
635:                        return new TypedRegion(offset, 0,
636:                                IDocument.DEFAULT_CONTENT_TYPE);
637:                    }
638:                }
639:                return region;
640:            }
641:
642:            /**
643:             * {@inheritDoc}
644:             * <p>
645:             * May be replaced or extended by subclasses.
646:             * </p>
647:             */
648:            public ITypedRegion[] computePartitioning(int offset, int length,
649:                    boolean includeZeroLengthPartitions) {
650:                checkInitialization();
651:                List list = new ArrayList();
652:
653:                try {
654:
655:                    int endOffset = offset + length;
656:
657:                    Position[] category = getPositions();
658:
659:                    TypedPosition previous = null, current = null;
660:                    int start, end, gapOffset;
661:                    Position gap = new Position(0);
662:
663:                    int startIndex = getFirstIndexEndingAfterOffset(category,
664:                            offset);
665:                    int endIndex = getFirstIndexStartingAfterOffset(category,
666:                            endOffset);
667:                    for (int i = startIndex; i < endIndex; i++) {
668:
669:                        current = (TypedPosition) category[i];
670:
671:                        gapOffset = (previous != null) ? previous.getOffset()
672:                                + previous.getLength() : 0;
673:                        gap.setOffset(gapOffset);
674:                        gap.setLength(current.getOffset() - gapOffset);
675:                        if ((includeZeroLengthPartitions && overlapsOrTouches(
676:                                gap, offset, length))
677:                                || (gap.getLength() > 0 && gap.overlapsWith(
678:                                        offset, length))) {
679:                            start = Math.max(offset, gapOffset);
680:                            end = Math.min(endOffset, gap.getOffset()
681:                                    + gap.getLength());
682:                            list.add(new TypedRegion(start, end - start,
683:                                    IDocument.DEFAULT_CONTENT_TYPE));
684:                        }
685:
686:                        if (current.overlapsWith(offset, length)) {
687:                            start = Math.max(offset, current.getOffset());
688:                            end = Math.min(endOffset, current.getOffset()
689:                                    + current.getLength());
690:                            list.add(new TypedRegion(start, end - start,
691:                                    current.getType()));
692:                        }
693:
694:                        previous = current;
695:                    }
696:
697:                    if (previous != null) {
698:                        gapOffset = previous.getOffset() + previous.getLength();
699:                        gap.setOffset(gapOffset);
700:                        gap.setLength(fDocument.getLength() - gapOffset);
701:                        if ((includeZeroLengthPartitions && overlapsOrTouches(
702:                                gap, offset, length))
703:                                || (gap.getLength() > 0 && gap.overlapsWith(
704:                                        offset, length))) {
705:                            start = Math.max(offset, gapOffset);
706:                            end = Math.min(endOffset, fDocument.getLength());
707:                            list.add(new TypedRegion(start, end - start,
708:                                    IDocument.DEFAULT_CONTENT_TYPE));
709:                        }
710:                    }
711:
712:                    if (list.isEmpty())
713:                        list.add(new TypedRegion(offset, length,
714:                                IDocument.DEFAULT_CONTENT_TYPE));
715:
716:                } catch (BadPositionCategoryException ex) {
717:                    // Make sure we clear the cache
718:                    clearPositionCache();
719:                } catch (RuntimeException ex) {
720:                    // Make sure we clear the cache
721:                    clearPositionCache();
722:                    throw ex;
723:                }
724:
725:                TypedRegion[] result = new TypedRegion[list.size()];
726:                list.toArray(result);
727:                return result;
728:            }
729:
730:            /**
731:             * Returns <code>true</code> if the given ranges overlap with or touch each other.
732:             *
733:             * @param gap the first range
734:             * @param offset the offset of the second range
735:             * @param length the length of the second range
736:             * @return <code>true</code> if the given ranges overlap with or touch each other
737:             */
738:            private boolean overlapsOrTouches(Position gap, int offset,
739:                    int length) {
740:                return gap.getOffset() <= offset + length
741:                        && offset <= gap.getOffset() + gap.getLength();
742:            }
743:
744:            /**
745:             * Returns the index of the first position which ends after the given offset.
746:             *
747:             * @param positions the positions in linear order
748:             * @param offset the offset
749:             * @return the index of the first position which ends after the offset
750:             */
751:            private int getFirstIndexEndingAfterOffset(Position[] positions,
752:                    int offset) {
753:                int i = -1, j = positions.length;
754:                while (j - i > 1) {
755:                    int k = (i + j) >> 1;
756:                    Position p = positions[k];
757:                    if (p.getOffset() + p.getLength() > offset)
758:                        j = k;
759:                    else
760:                        i = k;
761:                }
762:                return j;
763:            }
764:
765:            /**
766:             * Returns the index of the first position which starts at or after the given offset.
767:             *
768:             * @param positions the positions in linear order
769:             * @param offset the offset
770:             * @return the index of the first position which starts after the offset
771:             */
772:            private int getFirstIndexStartingAfterOffset(Position[] positions,
773:                    int offset) {
774:                int i = -1, j = positions.length;
775:                while (j - i > 1) {
776:                    int k = (i + j) >> 1;
777:                    Position p = positions[k];
778:                    if (p.getOffset() >= offset)
779:                        j = k;
780:                    else
781:                        i = k;
782:                }
783:                return j;
784:            }
785:
786:            /*
787:             * @see org.eclipse.jface.text.IDocumentPartitionerExtension3#startRewriteSession(org.eclipse.jface.text.DocumentRewriteSession)
788:             */
789:            public void startRewriteSession(DocumentRewriteSession session)
790:                    throws IllegalStateException {
791:                if (fActiveRewriteSession != null)
792:                    throw new IllegalStateException();
793:                fActiveRewriteSession = session;
794:            }
795:
796:            /**
797:             * {@inheritDoc}
798:             * <p>
799:             * May be extended by subclasses.
800:             * </p>
801:             */
802:            public void stopRewriteSession(DocumentRewriteSession session) {
803:                if (fActiveRewriteSession == session)
804:                    flushRewriteSession();
805:            }
806:
807:            /**
808:             * {@inheritDoc}
809:             * <p>
810:             * May be extended by subclasses.
811:             * </p>
812:             */
813:            public DocumentRewriteSession getActiveRewriteSession() {
814:                return fActiveRewriteSession;
815:            }
816:
817:            /**
818:             * Flushes the active rewrite session.
819:             */
820:            protected final void flushRewriteSession() {
821:                fActiveRewriteSession = null;
822:
823:                // remove all position belonging to the partitioner position category
824:                try {
825:                    fDocument.removePositionCategory(fPositionCategory);
826:                } catch (BadPositionCategoryException x) {
827:                }
828:                fDocument.addPositionCategory(fPositionCategory);
829:
830:                fIsInitialized = false;
831:            }
832:
833:            /**
834:             * Clears the position cache. Needs to be called whenever the positions have
835:             * been updated.
836:             */
837:            protected final void clearPositionCache() {
838:                if (fCachedPositions != null) {
839:                    fCachedPositions = null;
840:                }
841:            }
842:
843:            /**
844:             * Returns the partitioners positions.
845:             *
846:             * @return the partitioners positions
847:             * @throws BadPositionCategoryException if getting the positions from the
848:             *         document fails
849:             */
850:            protected final Position[] getPositions()
851:                    throws BadPositionCategoryException {
852:                if (fCachedPositions == null) {
853:                    fCachedPositions = fDocument
854:                            .getPositions(fPositionCategory);
855:                } else if (CHECK_CACHE_CONSISTENCY) {
856:                    Position[] positions = fDocument
857:                            .getPositions(fPositionCategory);
858:                    int len = Math.min(positions.length,
859:                            fCachedPositions.length);
860:                    for (int i = 0; i < len; i++) {
861:                        if (!positions[i].equals(fCachedPositions[i]))
862:                            System.err
863:                                    .println("FastPartitioner.getPositions(): cached position is not up to date: from document: " + toString(positions[i]) + " in cache: " + toString(fCachedPositions[i])); //$NON-NLS-1$ //$NON-NLS-2$
864:                    }
865:                    for (int i = len; i < positions.length; i++)
866:                        System.err
867:                                .println("FastPartitioner.getPositions(): new position in document: " + toString(positions[i])); //$NON-NLS-1$
868:                    for (int i = len; i < fCachedPositions.length; i++)
869:                        System.err
870:                                .println("FastPartitioner.getPositions(): stale position in cache: " + toString(fCachedPositions[i])); //$NON-NLS-1$
871:                }
872:                return fCachedPositions;
873:            }
874:
875:            /**
876:             * Pretty print a <code>Position</code>.
877:             *
878:             * @param position the position to format
879:             * @return a formatted string
880:             */
881:            private String toString(Position position) {
882:                return "P[" + position.getOffset() + "+" + position.getLength() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
883:            }
884:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.