1) Moved net.sourceforge.phpeclipse.ui\src\net\sourceforge\phpdt back to net.sourcefo...
[phpeclipse.git] / net.sourceforge.phpeclipse.ui / src / net / sourceforge / phpeclipse / ui / text / rules / MultiViewPartitioner.java
1 /*
2  * Copyright (c) 2002-2004 Widespace, OU and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://solareclipse.sourceforge.net/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     Igor Malinin - initial contribution
10  * 
11  * $Id: MultiViewPartitioner.java,v 1.10 2006-10-21 23:13:53 pombredanne Exp $
12  */
13
14 package net.sourceforge.phpeclipse.ui.text.rules;
15
16 import java.util.ArrayList;
17 import java.util.List;
18
19 //incastrix
20 //import org.eclipse.jface.text.Assert;
21 import org.eclipse.core.runtime.Assert;
22 import org.eclipse.jface.text.BadLocationException;
23 import org.eclipse.jface.text.DocumentEvent;
24 import org.eclipse.jface.text.IDocument;
25 import org.eclipse.jface.text.IDocumentPartitioner;
26 import org.eclipse.jface.text.IDocumentPartitioningListener;
27 import org.eclipse.jface.text.IDocumentPartitioningListenerExtension;
28 import org.eclipse.jface.text.IRegion;
29 import org.eclipse.jface.text.ITypedRegion;
30 import org.eclipse.jface.text.TypedRegion;
31 import org.eclipse.jface.text.rules.IPartitionTokenScanner;
32
33 /**
34  * Advanced partitioner which maintains partitions as views to connected
35  * document. Views have own partitioners themselves. This class is designed as a
36  * base for complex partitioners such as for JSP, PHP, ASP, etc. languages.
37  * 
38  * @author Igor Malinin
39  */
40 public abstract class MultiViewPartitioner extends AbstractPartitioner {
41
42         class ViewListener implements IDocumentPartitioningListener,
43                         IDocumentPartitioningListenerExtension {
44
45                 /*
46                  * @see org.eclipse.jface.text.IDocumentPartitioningListener#documentPartitioningChanged(IDocument)
47                  */
48                 public void documentPartitioningChanged(IDocument document) {
49                         IDocumentView view = (IDocumentView) document;
50
51                         int start = view.getParentOffset(0);
52                         int end = view.getParentOffset(view.getLength());
53
54                         rememberRegion(start, end - start);
55                 }
56
57                 /*
58                  * @see org.eclipse.jface.text.IDocumentPartitioningListenerExtension#documentPartitioningChanged(IDocument,
59                  *      IRegion)
60                  */
61                 public void documentPartitioningChanged(IDocument document,
62                                 IRegion region) {
63                         IDocumentView view = (IDocumentView) document;
64
65                         int offset = region.getOffset();
66
67                         int start = view.getParentOffset(offset);
68                         int end = view.getParentOffset(offset + region.getLength());
69
70                         rememberRegion(start, end - start);
71                 }
72         }
73
74         private ViewListener viewListener = new ViewListener();
75
76         private OuterDocumentView outerDocument;
77
78         private DocumentEvent outerDocumentEvent;
79
80         public MultiViewPartitioner(IPartitionTokenScanner scanner) {
81                 super(scanner);
82         }
83
84         public void setOuterPartitioner(IDocumentPartitioner partitioner) {
85                 if (outerDocument == null) {
86                         if (partitioner == null) {
87                                 return;
88                         }
89
90                         outerDocument = new OuterDocumentView(document, nodes);
91                         outerDocument.addDocumentPartitioningListener(viewListener);
92                 }
93
94                 IDocumentPartitioner old = outerDocument.getDocumentPartitioner();
95                 if (old != null) {
96                         outerDocument.setDocumentPartitioner(null);
97                         old.disconnect();
98                 }
99
100                 if (partitioner != null) {
101                         partitioner.connect(outerDocument);
102                 }
103
104                 outerDocument.setDocumentPartitioner(partitioner);
105
106                 if (partitioner == null) {
107                         outerDocument.removeDocumentPartitioningListener(viewListener);
108                         outerDocument = null;
109                 }
110         }
111
112         /**
113          * Create subpartitioner.
114          * 
115          * @param contentType
116          *            name of inner partition or <code>null</code> for outer
117          *            partition
118          */
119         protected abstract IDocumentPartitioner createPartitioner(String contentType);
120
121         protected void addInnerRegion(FlatNode position) {
122                 if (outerDocument != null) {
123                         if (DEBUG) {
124                                 Assert.isTrue(position.offset >= 0, Integer
125                                                 .toString(position.offset));
126                         }
127                         int outerOffset = outerDocument.getLocalOffset(position.offset);
128                         // axelcl start
129                         DocumentEvent event = null;
130                         if (outerOffset >= 0) {
131                                 // axelcl end
132                                 event = new DocumentEvent(outerDocument, outerOffset,
133                                                 position.length, null);
134
135                                 outerDocument.fireDocumentAboutToBeChanged(event);
136                         }
137                         super.addInnerRegion(position);
138                         // axelcl start
139                         if (event != null) {
140                                 // axelcl end
141                                 outerDocument.fireDocumentChanged(event);
142                         }
143                 } else {
144                         super.addInnerRegion(position);
145                 }
146
147                 if (position instanceof ViewNode) {
148                         // TODO: revisit condition
149                         IDocumentPartitioner partitioner = createPartitioner(position.type);
150                         if (partitioner != null) {
151                                 InnerDocumentView innerDocument = new InnerDocumentView(
152                                                 document, (ViewNode) position);
153
154                                 ((ViewNode) position).view = innerDocument;
155
156                                 partitioner.connect(innerDocument);
157                                 innerDocument.setDocumentPartitioner(partitioner);
158                                 innerDocument.addDocumentPartitioningListener(viewListener);
159                         }
160                 }
161         }
162
163         protected void removeInnerRegion(FlatNode position) {
164                 try {
165                         if (outerDocument != null) {
166                                 DocumentEvent event = null;
167                                 if (position.offset >= 0 && position.length >= 0) {
168                                         int outerOffset = outerDocument
169                                                         .getLocalOffset(position.offset);
170                                         if (outerOffset > 0) {
171                                                 event = new DocumentEvent(outerDocument, outerOffset,
172                                                                 0, document.get(position.offset,
173                                                                                 position.length));
174
175                                                 outerDocument.fireDocumentAboutToBeChanged(event);
176                                         }
177                                 }
178                                 super.removeInnerRegion(position);
179                                 if (position.offset >= 0) {
180                                         if (event != null) {
181                                                 outerDocument.fireDocumentChanged(event);
182                                         }
183                                 }
184                         } else {
185                                 super.removeInnerRegion(position);
186                         }
187
188                         if (position instanceof ViewNode) {
189                                 // TODO: revisit condition
190                                 InnerDocumentView innerDocument = ((ViewNode) position).view;
191                                 if (innerDocument != null) {
192                                         IDocumentPartitioner partitioner = innerDocument
193                                                         .getDocumentPartitioner();
194
195                                         innerDocument
196                                                         .removeDocumentPartitioningListener(viewListener);
197                                         innerDocument.setDocumentPartitioner(null);
198                                         partitioner.disconnect();
199                                 }
200                         }
201                 } catch (BadLocationException e) {
202                 }
203         }
204
205         protected void deleteInnerRegion(FlatNode position) {
206                 super.deleteInnerRegion(position);
207
208                 if (position instanceof ViewNode) {
209                         // TODO: revisit condition
210                         InnerDocumentView innerDocument = ((ViewNode) position).view;
211                         if (innerDocument != null) {
212                                 IDocumentPartitioner partitioner = innerDocument
213                                                 .getDocumentPartitioner();
214
215                                 innerDocument.removeDocumentPartitioningListener(viewListener);
216                                 innerDocument.setDocumentPartitioner(null);
217                                 partitioner.disconnect();
218                         }
219                 }
220         }
221
222         public void connect(IDocument document) {
223                 // outerDocument = new OuterDocumentView(document, innerPositions);
224
225                 super.connect(document);
226
227                 setOuterPartitioner(createPartitioner(null));
228                 // IDocumentPartitioner partitioner =
229                 // partitioner.connect(outerDocument);
230                 // outerDocument.setDocumentPartitioner(partitioner);
231                 // outerDocument.addDocumentPartitioningListener(viewListener);
232         }
233
234         public void disconnect() {
235                 try {
236                         if (outerDocument != null) {
237                                 outerDocument.removeDocumentPartitioningListener(viewListener);
238
239                                 IDocumentPartitioner partitioner = outerDocument
240                                                 .getDocumentPartitioner();
241
242                                 outerDocument.setDocumentPartitioner(null);
243                                 partitioner.disconnect();
244                         }
245                 } finally {
246                         // TODO: cleanup listeners
247                         outerDocument = null;
248                 }
249         }
250
251         /*
252          * @see org.eclipse.jface.text.IDocumentPartitioner#documentAboutToBeChanged(DocumentEvent)
253          */
254         public void documentAboutToBeChanged(DocumentEvent event) {
255                 super.documentAboutToBeChanged(event);
256
257                 outerDocumentEvent = null;
258
259                 int offset = event.getOffset();
260                 int length = event.getLength();
261                 int end = offset + length;
262
263                 // find left partition
264                 int first = computeFlatNodeIndex(offset);
265                 if (first > 0) {
266                         FlatNode p = (FlatNode) nodes.get(first - 1);
267
268                         int right = p.offset + p.length;
269                         if (offset < right) {
270                                 // change overlaps with partition
271                                 InnerDocumentView innerDocument = null;
272                                 if (p instanceof ViewNode) {
273                                         // TODO: revisit condition
274                                         innerDocument = ((ViewNode) p).view;
275                                 }
276
277                                 if (end < right) {
278                                         if (innerDocument != null) {
279                                                 // cahnge completely inside partition
280                                                 int start = innerDocument.getLocalOffset(offset);
281                                                 innerDocument
282                                                                 .fireDocumentAboutToBeChanged(new DocumentEvent(
283                                                                                 innerDocument, start, length, event
284                                                                                                 .getText()));
285                                         }
286
287                                         return;
288                                 }
289
290                                 if (innerDocument != null) {
291                                         // cut partition at right
292                                         int start = innerDocument.getLocalOffset(offset);
293                                         innerDocument
294                                                         .fireDocumentAboutToBeChanged(new DocumentEvent(
295                                                                         innerDocument, start, innerDocument
296                                                                                         .getLength()
297                                                                                         - start, null));
298                                 }
299                         }
300                 }
301
302                 // find right partition
303                 int last = computeFlatNodeIndex(end);
304                 if (last > 0) {
305                         FlatNode p = (FlatNode) nodes.get(last - 1);
306
307                         if (p instanceof ViewNode) {
308                                 // TODO: revisit condition
309                                 InnerDocumentView innerDocument = ((ViewNode) p).view;
310                                 if (innerDocument != null) {
311                                         int right = p.offset + p.length;
312                                         if (end < right) {
313                                                 // cut partition at left
314                                                 int cut = innerDocument.getLocalOffset(end);
315                                                 innerDocument
316                                                                 .fireDocumentAboutToBeChanged(new DocumentEvent(
317                                                                                 innerDocument, 0, cut, null));
318                                         }
319                                 }
320                         }
321                 }
322
323                 if (outerDocument != null) {
324                         int left = outerDocument.getLocalOffset(offset);
325                         int right = outerDocument.getLocalOffset(end);
326
327                         String text = event.getText();
328
329                         if (left >= 0 && (right - left >= 0)) {
330                                 if (left != right || text != null && text.length() > 0) {
331                                         outerDocumentEvent = new DocumentEvent(outerDocument, left,
332                                                         right - left, text);
333
334                                         outerDocument
335                                                         .fireDocumentAboutToBeChanged(outerDocumentEvent);
336                                 }
337                         }
338                 }
339         }
340
341         protected int fixupPartitions(DocumentEvent event) {
342                 int offset = event.getOffset();
343                 int length = event.getLength();
344                 int end = offset + length;
345
346                 // fixup/notify inner views laying on change boundaries
347
348                 int first = computeFlatNodeIndex(offset);
349                 if (first > 0) {
350                         FlatNode p = (FlatNode) nodes.get(first - 1);
351
352                         int right = p.offset + p.length;
353                         if (offset < right) {
354                                 // change overlaps with partition
355                                 if (end < right) {
356                                         // cahnge completely inside partition
357                                         String text = event.getText();
358                                         p.length -= length;
359                                         if (text != null) {
360                                                 p.length += text.length();
361                                         }
362
363                                         if (p instanceof ViewNode) {
364                                                 // TODO: revisit condition
365                                                 InnerDocumentView innerDocument = ((ViewNode) p).view;
366                                                 if (innerDocument != null) {
367                                                         int start = innerDocument.getLocalOffset(offset);
368                                                         innerDocument
369                                                                         .fireDocumentChanged(new DocumentEvent(
370                                                                                         innerDocument, start, length, text));
371                                                 }
372                                         }
373                                 } else {
374                                         // cut partition at right
375                                         int cut = p.offset + p.length - offset;
376                                         p.length -= cut;
377
378                                         if (p instanceof ViewNode) {
379                                                 // TODO: revisit condition
380                                                 InnerDocumentView innerDocument = ((ViewNode) p).view;
381                                                 if (innerDocument != null) {
382                                                         int start = innerDocument.getLocalOffset(offset);
383                                                         // TODO: ???fireDocumentAboutToBeChanged???
384                                                         innerDocument
385                                                                         .fireDocumentChanged(new DocumentEvent(
386                                                                                         innerDocument, start, cut, null));
387                                                 }
388                                         }
389                                 }
390                         }
391                 }
392
393                 int last = computeFlatNodeIndex(end);
394                 if (last > 0 && first != last) {
395                         FlatNode p = (FlatNode) nodes.get(last - 1);
396
397                         int right = p.offset + p.length;
398                         if (end < right) {
399                                 // cut partition at left
400                                 int cut = end - p.offset;
401                                 p.length -= cut;
402                                 p.offset = offset;
403
404                                 String text = event.getText();
405                                 if (text != null) {
406                                         p.offset += text.length();
407                                 }
408
409                                 if (p instanceof ViewNode) {
410                                         // TODO: revisit condition
411                                         InnerDocumentView innerDocument = ((ViewNode) p).view;
412                                         if (innerDocument != null) {
413                                                 // TODO: ???fireDocumentAboutToBeChanged???
414                                                 innerDocument.fireDocumentChanged(new DocumentEvent(
415                                                                 innerDocument, 0, cut, null));
416                                         }
417                                 }
418
419                                 --last;
420                         }
421                 }
422
423                 // fixup inner views laying afrer change
424
425                 String text = event.getText();
426                 if (text != null) {
427                         length -= text.length();
428                 }
429
430                 for (int i = last, size = nodes.size(); i < size; i++) {
431                         ((FlatNode) nodes.get(i)).offset -= length;
432                 }
433
434                 // delete inner views laying completely inside change boundaries
435
436                 if (first < last) {
437                         do {
438                                 deleteInnerRegion((FlatNode) nodes.get(--last));
439                         } while (first < last);
440
441                         rememberRegion(offset, 0);
442                 }
443
444                 // notify outer view
445
446                 if (outerDocumentEvent != null) {
447                         outerDocument.fireDocumentChanged(outerDocumentEvent);
448                 }
449
450                 return first;
451         }
452
453         /*
454          * @see org.eclipse.jface.text.IDocumentPartitioner#computePartitioning(int,
455          *      int)
456          */
457         protected String getContentType(String parent, String view) {
458                 if (view != null) {
459                         return view;
460                 }
461
462                 if (parent != null) {
463                         return parent;
464                 }
465
466                 return IDocument.DEFAULT_CONTENT_TYPE;
467         }
468
469         /*
470          * @see org.eclipse.jface.text.IDocumentPartitioner#computePartitioning(int,
471          *      int)
472          */
473         public ITypedRegion[] computePartitioning(int offset, int length) {
474                 List list = new ArrayList();
475                 // if (DEBUG) {
476                 // if (length>=9400) {
477                 // length--;
478                 // }
479                 // System.out.print("MultiViewPartitioner::computePartitioning - Offset:
480                 // ");
481                 // System.out.print(offset);
482                 // System.out.print(", Length: ");
483                 // System.out.print(length);
484                 // System.out.println("");
485                 // }
486                 int end = offset + length;
487
488                 int index = computeFlatNodeIndex(offset);
489                 while (true) {
490                         FlatNode prev = (index > 0) ? (FlatNode) nodes.get(index - 1)
491                                         : null;
492
493                         if (prev != null) {
494                                 if (prev.overlapsWith(offset, length)) {
495                                         addInnerPartitions(list, offset, length, prev);
496                                 }
497
498                                 if (end <= prev.offset + prev.length) {
499                                         break;
500                                 }
501                         }
502
503                         FlatNode next = (index < nodes.size()) ? (FlatNode) nodes
504                                         .get(index) : null;
505
506                         if (next == null || offset < next.offset) {
507                                 addOuterPartitions(list, offset, length, prev, next);
508                         }
509
510                         if (next == null) {
511                                 break;
512                         }
513
514                         ++index;
515                 }
516                 // if (DEBUG) {
517                 // showList(list);
518                 // }
519
520                 return (TypedRegion[]) list.toArray(new TypedRegion[list.size()]);
521         }
522
523 //      private void showList(List list) {
524 //              try {
525 //                      throw new NullPointerException();
526 //              } catch (Exception e) {
527 //                      e.printStackTrace();
528 //              }
529 //              System.out.println(">>>>>List start");
530 //              TypedRegion temp;
531 //              for (int i = 0; i < list.size(); i++) {
532 //                      temp = (TypedRegion) list.get(i);
533 //                      System.out.print("Offset: ");
534 //                      System.out.print(temp.getOffset());
535 //                      System.out.print(", Length: ");
536 //                      System.out.print(temp.getLength());
537 //                      System.out.print(", Type: ");
538 //                      System.out.print(temp.getType());
539 //                      System.out.println("");
540 //              }
541 //              System.out.println("<<<<<List end");
542 //      }
543
544         private void addOuterPartitions(List list, int offset, int length,
545                         FlatNode prev, FlatNode next) {
546                 // limit region
547                 int start = offset;
548                 int end = offset + length;
549
550                 if (prev != null && start < prev.offset + prev.length) {
551                         start = prev.offset + prev.length;
552                 }
553
554                 if (next != null && next.offset < end) {
555                         end = next.offset;
556                 }
557
558                 if (start == end) {
559                         return;
560                 }
561
562                 if (outerDocument == null) {
563                         // if (DEBUG) {
564                         // if (end - start<0) {
565                         // throw new IndexOutOfBoundsException();
566                         // }
567                         // }
568                         list.add(new TypedRegion(start, end - start, getContentType(null,
569                                         IDocument.DEFAULT_CONTENT_TYPE)));
570                         return;
571                 }
572
573                 try {
574                         // convert to outer offsets
575                         start = outerDocument.getLocalOffset(start);
576                         end = outerDocument.getLocalOffset(end);
577                         int len = end - start;
578                         if (len >= 0) {
579                                 ITypedRegion[] regions = null;
580                                 try {
581                                         regions = outerDocument.computePartitioning(start, len);
582                                 } catch (Exception e) {
583                                         // nasty workaround, which prevents cursor from moveing
584                                         // backwards in the editor
585                                         // but doesn't solve the partitioning problem
586                                         regions = new ITypedRegion[0];
587                                         System.out
588                                                         .println("MultiViewerPartitioner#addOuterPartitions failure\n"
589                                                                         + "start:"
590                                                                         + start
591                                                                         + " length:"
592                                                                         + len
593                                                                         + "\n" + outerDocument.get(start, len));
594                                 }
595                                 for (int i = 0; i < regions.length; i++) {
596                                         ITypedRegion region = regions[i];
597
598                                         // convert back to parent offsets
599                                         start = outerDocument.getParentOffset(region.getOffset());
600                                         end = start + region.getLength();
601
602                                         if (prev != null) {
603                                                 offset = prev.offset + prev.length;
604                                                 if (start < offset) {
605                                                         start = offset;
606                                                 }
607                                         }
608
609                                         if (next != null) {
610                                                 offset = next.offset;
611                                                 if (offset < end) {
612                                                         end = offset;
613                                                 }
614                                         }
615                                         // if (DEBUG) {
616                                         // if (end - start<0) {
617                                         // showList(list);
618                                         // System.out.print("MultiViewPartitioner::addOuterPartitions
619                                         // - Offset: ");
620                                         // System.out.print(offset);
621                                         // System.out.print(", Start: ");
622                                         // System.out.print(start);
623                                         // System.out.print(", End: ");
624                                         // System.out.print(end);
625                                         // System.out.print(", Type: ");
626                                         // System.out.print(region.getType());
627                                         // System.out.println("");
628                                         // throw new IndexOutOfBoundsException();
629                                         // }
630                                         // }
631                                         list.add(new TypedRegion(start, end - start,
632                                                         getContentType(null, region.getType())));
633                                 }
634                         }
635                 } catch (BadLocationException x) {
636                 }
637         }
638
639         private void addInnerPartitions(List list, int offset, int length,
640                         FlatNode position) {
641                 InnerDocumentView innerDocument = null;
642                 if (position instanceof ViewNode) {
643                         // TODO: revisit condition
644                         innerDocument = ((ViewNode) position).view;
645                 }
646
647                 if (innerDocument == null) {
648                         // simple partition
649                         // if (DEBUG) {
650                         // if (position.length<0) {
651                         // throw new IndexOutOfBoundsException();
652                         // }
653                         // }
654                         list.add(new TypedRegion(position.offset, position.length,
655                                         getContentType(position.type, null)));
656                         return;
657                 }
658
659                 // multiplexing to inner view
660                 try {
661                         // limit region
662                         int start = Math.max(offset, position.offset);
663                         int end = Math.min(offset + length, position.offset
664                                         + position.length);
665
666                         // convert to document offsets
667                         length = end - start;
668                         offset = innerDocument.getLocalOffset(start);
669
670                         ITypedRegion[] regions = innerDocument.computePartitioning(offset,
671                                         length);
672
673                         for (int i = 0; i < regions.length; i++) {
674                                 ITypedRegion region = regions[i];
675
676                                 // convert back to parent offsets
677                                 offset = innerDocument.getParentOffset(region.getOffset());
678                                 length = region.getLength();
679                                 // if (DEBUG) {
680                                 // if (length<0) {
681                                 // throw new IndexOutOfBoundsException();
682                                 // }
683                                 // }
684                                 list.add(new TypedRegion(offset, length, getContentType(
685                                                 position.type, region.getType())));
686                         }
687                 } catch (BadLocationException x) {
688                 }
689         }
690
691         /*
692          * @see org.eclipse.jface.text.IDocumentPartitioner#getPartition(int)
693          */
694         public ITypedRegion getPartition(int offset) {
695                 if (nodes.size() == 0) {
696                         return getOuterPartition(offset, null, null);
697                 }
698
699                 int index = computeFlatNodeIndex(offset);
700                 if (index < nodes.size()) {
701                         FlatNode next = (FlatNode) nodes.get(index);
702
703                         if (offset == next.offset) {
704                                 return getInnerPartition(offset, next);
705                         }
706
707                         if (index == 0) {
708                                 return getOuterPartition(offset, null, next);
709                         }
710
711                         FlatNode prev = (FlatNode) nodes.get(index - 1);
712
713                         if (prev.includes(offset)) {
714                                 return getInnerPartition(offset, prev);
715                         }
716
717                         return getOuterPartition(offset, prev, next);
718                 }
719
720                 FlatNode prev = (FlatNode) nodes.get(nodes.size() - 1);
721
722                 if (prev.includes(offset)) {
723                         return getInnerPartition(offset, prev);
724                 }
725
726                 return getOuterPartition(offset, prev, null);
727         }
728
729         protected ITypedRegion getOuterPartition(int offset, FlatNode prev,
730                         FlatNode next) {
731                 try {
732                         int start, end;
733                         String type;
734
735                         if (outerDocument == null) {
736                                 start = 0;
737                                 end = document.getLength();
738                                 type = getContentType(null, IDocument.DEFAULT_CONTENT_TYPE);
739                         } else {
740                                 int outerOffset = outerDocument.getLocalOffset(offset);
741                                 // axelcl start
742                                 if (outerOffset < 0) {
743                                         start = 0;
744                                         end = document.getLength();
745                                         type = getContentType(null, IDocument.DEFAULT_CONTENT_TYPE);
746                                 } else {
747                                         // axelcl end
748                                         ITypedRegion region = outerDocument
749                                                         .getPartition(outerOffset);
750
751                                         start = region.getOffset();
752                                         end = start + region.getLength();
753
754                                         // convert to parent offset
755                                         start = outerDocument.getParentOffset(start);
756                                         end = outerDocument.getParentOffset(end);
757
758                                         type = getContentType(null, region.getType());
759                                 }
760                         }
761
762                         if (prev != null) {
763                                 offset = prev.offset + prev.length;
764                                 if (start < offset) {
765                                         start = offset;
766                                 }
767                         }
768
769                         if (next != null) {
770                                 offset = next.offset;
771                                 if (offset < end) {
772                                         end = offset;
773                                 }
774                         }
775
776                         return new TypedRegion(start, end - start, type);
777                 } catch (BadLocationException x) {
778                         x.printStackTrace();
779                         throw new IllegalArgumentException();
780                 }
781         }
782
783         protected ITypedRegion getInnerPartition(int offset, FlatNode position) {
784                 if (position instanceof ViewNode) {
785                         // TODO: revisit condition
786                         InnerDocumentView innerDocument = ((ViewNode) position).view;
787
788                         if (innerDocument != null) {
789                                 // multiplexing to inner view
790                                 try {
791                                         // convert to inner offset
792                                         ITypedRegion region = innerDocument
793                                                         .getPartition(innerDocument.getLocalOffset(offset));
794
795                                         // convert to parent offset
796                                         offset = innerDocument.getParentOffset(region.getOffset());
797
798                                         return new TypedRegion(offset, region.getLength(),
799                                                         getContentType(position.type, region.getType()));
800                                 } catch (BadLocationException x) {
801                                 }
802                         }
803                 }
804
805                 // simple partition
806                 return new TypedRegion(position.offset, position.length, position.type);
807         }
808 }