/[classpath]/classpath/javax/swing/text/DefaultStyledDocument.java
ViewVC logotype

Diff of /classpath/javax/swing/text/DefaultStyledDocument.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.7 by trebligd, Mon Aug 22 11:35:23 2005 UTC revision 1.8 by rabbit78, Tue Sep 13 10:42:03 2005 UTC
# Line 1  Line 1 
1  /* DefaultStyledDocument.java --  /* DefaultStyledDocument.java --
2     Copyright (C) 2004 Free Software Foundation, Inc.     Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3    
4  This file is part of GNU Classpath.  This file is part of GNU Classpath.
5    
# Line 41  package javax.swing.text; Line 41  package javax.swing.text;
41  import java.awt.Color;  import java.awt.Color;
42  import java.awt.Font;  import java.awt.Font;
43  import java.io.Serializable;  import java.io.Serializable;
44    import java.util.Vector;
45    
46  import javax.swing.event.DocumentEvent;  import javax.swing.event.DocumentEvent;
47    
# Line 60  public class DefaultStyledDocument exten Line 61  public class DefaultStyledDocument exten
61    implements StyledDocument    implements StyledDocument
62  {  {
63    /**    /**
64       * Carries specification information for new {@link Element}s that should
65       * be created in {@link ElementBuffer}. This allows the parsing process
66       * to be decoupled from the <code>Element</code> creation process.
67       */
68      public static class ElementSpec
69      {
70        /**
71         * This indicates a start tag. This is a possible value for
72         * {@link #getType}.
73         */
74        public static final short StartTagType = 1;
75    
76        /**
77         * This indicates an end tag. This is a possible value for
78         * {@link #getType}.
79         */
80        public static final short EndTagType = 2;
81    
82        /**
83         * This indicates a content element. This is a possible value for
84         * {@link #getType}.
85         */
86        public static final short ContentType = 3;
87    
88        /**
89         * This indicates that the data associated with this spec should be joined
90         * with what precedes it. This is a possible value for
91         * {@link #getDirection}.
92         */
93        public static final short JoinPreviousDirection = 4;
94    
95        /**
96         * This indicates that the data associated with this spec should be joined
97         * with what follows it. This is a possible value for
98         * {@link #getDirection}.
99         */
100        public static final short JoinNextDirection = 5;
101    
102        /**
103         * This indicates that the data associated with this spec should be used
104         * to create a new element. This is a possible value for
105         * {@link #getDirection}.
106         */
107        public static final short OriginateDirection = 6;
108    
109        /**
110         * This indicates that the data associated with this spec should be joined
111         * to the fractured element. This is a possible value for
112         * {@link #getDirection}.
113         */
114        public static final short JoinFractureDirection = 7;
115    
116        /**
117         * The type of the tag.
118         */
119        short type;
120    
121        /**
122         * The direction of the tag.
123         */
124        short direction;
125    
126        /**
127         * The offset of the content.
128         */
129        int offset;
130    
131        /**
132         * The length of the content.
133         */
134        int length;
135    
136        /**
137         * The actual content.
138         */
139        char[] content;
140    
141        /**
142         * The attributes for the tag.
143         */
144        AttributeSet attributes;
145    
146        /**
147         * Creates a new <code>ElementSpec</code> with no content, length or
148         * offset. This is most useful for start and end tags.
149         *
150         * @param a the attributes for the element to be created
151         * @param type the type of the tag
152         */
153        public ElementSpec(AttributeSet a, short type)
154        {
155          this(a, type, 0);
156        }
157    
158        /**
159         * Creates a new <code>ElementSpec</code> that specifies the length but
160         * not the offset of an element. Such <code>ElementSpec</code>s are
161         * processed sequentially from a known starting point.
162         *
163         * @param a the attributes for the element to be created
164         * @param type the type of the tag
165         * @param len the length of the element
166         */
167        public ElementSpec(AttributeSet a, short type, int len)
168        {
169          this(a, type, null, 0, len);
170        }
171    
172        /**
173         * Creates a new <code>ElementSpec</code> with document content.
174         *
175         * @param a the attributes for the element to be created
176         * @param type the type of the tag
177         * @param txt the actual content
178         * @param offs the offset into the <code>txt</code> array
179         * @param len the length of the element
180         */
181        public ElementSpec(AttributeSet a, short type, char[] txt, int offs,
182                           int len)
183        {
184          attributes = a;
185          this.type = type;
186          offset = offs;
187          length = len;
188          content = txt;
189          direction = OriginateDirection;
190        }
191    
192        /**
193         * Sets the type of the element.
194         *
195         * @param type the type of the element to be set
196         */
197        public void setType(short type)
198        {
199          this.type = type;
200        }
201    
202        /**
203         * Returns the type of the element.
204         *
205         * @return the type of the element
206         */
207        public short getType()
208        {
209          return type;
210        }
211    
212        /**
213         * Sets the direction of the element.
214         *
215         * @param dir the direction of the element to be set
216         */
217        public void setDirection(short dir)
218        {
219          direction = dir;
220        }
221    
222        /**
223         * Returns the direction of the element.
224         *
225         * @return the direction of the element
226         */
227        public short getDirection()
228        {
229          return direction;
230        }
231    
232        /**
233         * Returns the attributes of the element.
234         *
235         * @return the attributes of the element
236         */
237        public AttributeSet getAttributes()
238        {
239          return attributes;
240        }
241    
242        /**
243         * Returns the actual content of the element.
244         *
245         * @return the actual content of the element
246         */
247        public char[] getArray()
248        {
249          return content;
250        }
251    
252        /**
253         * Returns the offset of the content.
254         *
255         * @return the offset of the content
256         */
257        public int getOffset()
258        {
259          return offset;
260        }
261    
262        /**
263         * Returns the length of the content.
264         *
265         * @return the length of the content
266         */
267        public int getLength()
268        {
269          return length;
270        }
271    
272        /**
273         * Returns a String representation of this <code>ElementSpec</code>
274         * describing the type, direction and length of this
275         * <code>ElementSpec</code>.
276         *
277         * @return a String representation of this <code>ElementSpec</code>
278         */
279        public String toString()
280        {
281          StringBuilder b = new StringBuilder();
282          b.append('<');
283          switch (type)
284            {
285            case StartTagType:
286              b.append("StartTag");
287              break;
288            case EndTagType:
289              b.append("EndTag");
290              break;
291            case ContentType:
292              b.append("Content");
293              break;
294            default:
295              b.append("??");
296              break;
297            }
298    
299          b.append(':');
300    
301          switch (direction)
302            {
303            case JoinPreviousDirection:
304              b.append("JoinPrevious");
305              break;
306            case JoinNextDirection:
307              b.append("JoinNext");
308              break;
309            case OriginateDirection:
310              b.append("Originate");
311              break;
312            case JoinFractureDirection:
313              b.append("Fracture");
314              break;
315            default:
316              b.append("??");
317              break;
318            }
319    
320          b.append(':');
321          b.append(length);
322    
323          return b.toString();
324        }
325      }
326    
327      /**
328     * Performs all <em>structural</code> changes to the <code>Element</code>     * Performs all <em>structural</code> changes to the <code>Element</code>
329     * hierarchy.     * hierarchy.
330     */     */
331    public class ElementBuffer    public class ElementBuffer implements Serializable
     implements Serializable  
332    {    {
333        /** The serialization UID (compatible with JDK1.5). */
334        private static final long serialVersionUID = 1688745877691146623L;
335    
336      /** The root element of the hierarchy. */      /** The root element of the hierarchy. */
337      private Element root;      private Element root;
338    
# Line 76  public class DefaultStyledDocument exten Line 343  public class DefaultStyledDocument exten
343      private int length;      private int length;
344    
345      /**      /**
346         * Holds fractured elements during insertion of end and start tags.
347         * Inserting an end tag may lead to fracturing of the current paragraph
348         * element. The elements that have been cut off may be added to the
349         * next paragraph that is created in the next start tag.
350         */
351        Element[] fracture;
352    
353        /**
354         * The ElementChange that describes the latest changes.
355         */
356        DefaultDocumentEvent documentEvent;
357    
358        /**
359       * Creates a new <code>ElementBuffer</code> for the specified       * Creates a new <code>ElementBuffer</code> for the specified
360       * <code>root</code> element.       * <code>root</code> element.
361       *       *
# Line 114  public class DefaultStyledDocument exten Line 394  public class DefaultStyledDocument exten
394      {      {
395        this.offset = offset;        this.offset = offset;
396        this.length = length;        this.length = length;
397          documentEvent = ev;
398        changeUpdate();        changeUpdate();
399      }      }
400    
# Line 158  public class DefaultStyledDocument exten Line 439  public class DefaultStyledDocument exten
439                    Element child2 = createLeafElement(par, ael, offset,                    Element child2 = createLeafElement(par, ael, offset,
440                                                       endOffset);                                                       endOffset);
441                    int index = par.getElementIndex(startOffset);                    int index = par.getElementIndex(startOffset);
442                    par.replace(index, 1, new Element[]{ child1, child2 });            Element[] add = new Element[]{ child1, child2 };
443                      par.replace(index, 1, add);
444              documentEvent.addEdit(new ElementEdit(par, index,
445                                                    new Element[]{ el },
446                                                    add));
447                  }                  }
448                else                else
449                  throw new AssertionError("paragraph elements are expected to "                  throw new AssertionError("paragraph elements are expected to "
# Line 171  public class DefaultStyledDocument exten Line 456  public class DefaultStyledDocument exten
456                                   + "instances of "                                   + "instances of "
457                          + "javax.swing.text.AbstractDocument.AbstractElement");                          + "javax.swing.text.AbstractDocument.AbstractElement");
458      }      }
459    
460        /**
461         * Inserts new <code>Element</code> in the document at the specified
462         * position.
463         *
464         * Most of the work is done by {@link #insertUpdate}, after some fields
465         * have been prepared for it.
466         *
467         * @param offset the location in the document at which the content is
468         *        inserted
469         * @param length the length of the inserted content
470         * @param data the element specifications for the content to be inserted
471         * @param ev the document event that is updated to reflect the structural
472         *        changes
473         */
474        public void insert(int offset, int length, ElementSpec[] data,
475                           DefaultDocumentEvent ev)
476        {
477          this.offset = offset;
478          this.length = length;
479          documentEvent = ev;
480          insertUpdate(data);
481        }
482    
483        /**
484         * Performs the actual structural change for {@link #insert}. This
485         * creates a bunch of {@link Element}s as specified by <code>data</code>
486         * and inserts it into the document as specified in the arguments to
487         * {@link #insert}.
488         *
489         * @param data the element specifications for the elements to be inserte
490         */
491        protected void insertUpdate(ElementSpec[] data)
492        {
493          for (int i = 0; i < data.length; i++)
494            {
495              switch (data[i].getType())
496                {
497                case ElementSpec.StartTagType:
498                  insertStartTag(data[i]);
499                  break;
500                case ElementSpec.EndTagType:
501                  insertEndTag(data[i]);
502                  break;
503                default:
504                  insertContentTag(data[i]);
505                  break;
506                }
507              BranchElement root = (BranchElement) getDefaultRootElement();
508            }
509        }
510    
511        /**
512         * Insert a new paragraph after the paragraph at the current position.
513         *
514         * @param tag the element spec that describes the element to be inserted
515         */
516        void insertStartTag(ElementSpec tag)
517        {
518          BranchElement root = (BranchElement) getDefaultRootElement();
519          int index = root.getElementIndex(offset);
520          if (index == -1)
521            index = 0;
522    
523          BranchElement newParagraph =
524            (BranchElement) createBranchElement(root, tag.getAttributes());
525    
526          // Add new paragraph into document structure.
527          Element[] added = new Element[]{newParagraph};
528          root.replace(index + 1, 0, added);
529          ElementEdit edit = new ElementEdit(root, index + 1, new Element[0],
530                                             added);
531          documentEvent.addEdit(edit);
532    
533          // Maybe add fractured elements.
534          if (tag.getDirection() == ElementSpec.JoinFractureDirection)
535            {
536              Element[] newFracture = new Element[fracture.length];
537              for (int i = 0; i < fracture.length; i++)
538                {
539                  Element oldLeaf = fracture[i];
540                  Element newLeaf = createLeafElement(newParagraph,
541                                                      oldLeaf.getAttributes(),
542                                                      oldLeaf.getStartOffset(),
543                                                      oldLeaf.getEndOffset());
544                  newFracture[i] = newLeaf;
545                }
546              newParagraph.replace(0, 0, newFracture);
547              edit = new ElementEdit(newParagraph, 0, new Element[0],
548                                     fracture);
549              documentEvent.addEdit(edit);
550              fracture = new Element[0];
551            }
552        }
553    
554        /**
555         * Inserts an end tag into the document structure. This cuts of the
556         * current paragraph element, possibly fracturing it's child elements.
557         * The fractured elements are saved so that they can be joined later
558         * with a new paragraph element.
559         */
560        void insertEndTag(ElementSpec tag)
561        {
562          BranchElement root = (BranchElement) getDefaultRootElement();
563          int parIndex = root.getElementIndex(offset);
564          BranchElement paragraph = (BranchElement) root.getElement(parIndex);
565    
566          int index = paragraph.getElementIndex(offset);
567          LeafElement content = (LeafElement) paragraph.getElement(index);
568          // We might have to split the element at offset.
569          split(content, offset);
570          index = paragraph.getElementIndex(offset);
571    
572          int count = paragraph.getElementCount();
573          // Store fractured elements.
574          fracture = new Element[count - index];
575          for (int i = index; i < count; ++i)
576            fracture[i - index] = paragraph.getElement(i);
577    
578          // Delete fractured elements.
579          paragraph.replace(index, count - index, new Element[0]);
580    
581          // Add this action to the document event.
582          ElementEdit edit = new ElementEdit(paragraph, index, fracture,
583                                             new Element[0]);
584          documentEvent.addEdit(edit);
585        }
586    
587        /**
588         * Inserts a content element into the document structure.
589         *
590         * @param tag the element spec
591         */
592        void insertContentTag(ElementSpec tag)
593        {
594          int len = tag.getLength();
595          int dir = tag.getDirection();
596          if (dir == ElementSpec.JoinPreviousDirection)
597            {
598              Element prev = getCharacterElement(offset);
599              BranchElement prevParent = (BranchElement) prev.getParentElement();
600              Element join = createLeafElement(prevParent, tag.getAttributes(),
601                                               prev.getStartOffset(),
602                                               Math.max(prev.getEndOffset(),
603                                                        offset + len));
604              int ind = prevParent.getElementIndex(offset);
605              if (ind == -1)
606                ind = 0;
607              Element[] add = new Element[]{join};
608              prevParent.replace(ind, 1, add);
609    
610              // Add this action to the document event.
611              ElementEdit edit = new ElementEdit(prevParent, ind,
612                                                 new Element[]{prev}, add);
613              documentEvent.addEdit(edit);
614            }
615          else if (dir == ElementSpec.JoinNextDirection)
616            {
617              Element next = getCharacterElement(offset + len);
618              BranchElement nextParent = (BranchElement) next.getParentElement();
619              Element join = createLeafElement(nextParent, tag.getAttributes(),
620                                               offset,
621                                               next.getEndOffset());
622              int ind = nextParent.getElementIndex(offset + len);
623              if (ind == -1)
624                ind = 0;
625              Element[] add = new Element[]{join};
626              nextParent.replace(ind, 1, add);
627    
628              // Add this action to the document event.
629              ElementEdit edit = new ElementEdit(nextParent, ind,
630                                                 new Element[]{next}, add);
631              documentEvent.addEdit(edit);
632            }
633          else
634            {
635              BranchElement par = (BranchElement) getParagraphElement(offset);
636    
637              int ind = par.getElementIndex(offset);
638    
639              // Make room for the element.
640              // Cut previous element.
641              Element prev = par.getElement(ind);
642              if (prev != null && prev.getStartOffset() < offset)
643                {
644                  Element cutPrev = createLeafElement(par, prev.getAttributes(),
645                                                      prev.getStartOffset(),
646                                                      offset);
647                  Element[] remove = new Element[]{prev};
648                  Element[] add = new Element[]{cutPrev};
649                  if (prev.getEndOffset() > offset + len)
650                    {
651                      Element rem = createLeafElement(par, prev.getAttributes(),
652                                                      offset + len,
653                                                      prev.getEndOffset());
654                      add = new Element[]{cutPrev, rem};
655                    }
656    
657                  par.replace(ind, 1, add);
658                  documentEvent.addEdit(new ElementEdit(par, ind, remove, add));
659                  ind++;
660                }
661              // ind now points to the next element.
662    
663              // Cut next element if necessary.
664              Element next = par.getElement(ind);
665              if (next != null && next.getStartOffset() < offset + len)
666                {
667                  Element cutNext = createLeafElement(par, next.getAttributes(),
668                                                      offset + len,
669                                                      next.getEndOffset());
670                  Element[] remove = new Element[]{next};
671                  Element[] add = new Element[]{cutNext};
672                  par.replace(ind, 1, add);
673                  documentEvent.addEdit(new ElementEdit(par, ind, remove,
674                                                        add));
675                }
676    
677              // Insert new element.
678              Element newEl = createLeafElement(par, tag.getAttributes(),
679                                                offset, offset + len);
680              Element[] added = new Element[]{newEl};
681              par.replace(ind, 0, added);
682              // Add this action to the document event.
683              ElementEdit edit = new ElementEdit(par, ind, new Element[0],
684                                                 added);
685              documentEvent.addEdit(edit);
686            }
687          offset += len;
688        }
689    }    }
690    
691    /**    /**
692       * An element type for sections. This is a simple BranchElement with
693       * a unique name.
694       */
695      protected class SectionElement extends BranchElement
696      {
697        /**
698         * Creates a new SectionElement.
699         */
700        public SectionElement()
701        {
702          super(null, null);
703        }
704    
705        /**
706         * Returns the name of the element. This method always returns
707         * &quot;section&quot;.
708         *
709         * @return the name of the element
710         */
711        public String getName()
712        {
713          return "section";
714        }
715      }
716    
717      /** The serialization UID (compatible with JDK1.5). */
718      private static final long serialVersionUID = 940485415728614849L;
719    
720      /**
721     * The default size to use for new content buffers.     * The default size to use for new content buffers.
722     */     */
723    public static final int BUFFER_SIZE_DEFAULT = 4096;    public static final int BUFFER_SIZE_DEFAULT = 4096;
# Line 250  public class DefaultStyledDocument exten Line 794  public class DefaultStyledDocument exten
794      Element[] tmp;      Element[] tmp;
795      // FIXME: Create a SecionElement here instead of a BranchElement.      // FIXME: Create a SecionElement here instead of a BranchElement.
796      // Use createBranchElement() and createLeafElement instead.      // Use createBranchElement() and createLeafElement instead.
797      BranchElement section = new BranchElement(null, null);      SectionElement section = new SectionElement();
798        
799      BranchElement paragraph = new BranchElement(section, null);      BranchElement paragraph = new BranchElement(section, null);
800      tmp = new Element[1];      tmp = new Element[1];
801      tmp[0] = paragraph;      tmp[0] = paragraph;
# Line 261  public class DefaultStyledDocument exten Line 805  public class DefaultStyledDocument exten
805      tmp = new Element[1];      tmp = new Element[1];
806      tmp[0] = leaf;      tmp[0] = leaf;
807      paragraph.replace(0, 0, tmp);      paragraph.replace(0, 0, tmp);
808        
809      return section;      return section;
810    }    }
811    
# Line 360  public class DefaultStyledDocument exten Line 904  public class DefaultStyledDocument exten
904     */     */
905    public Element getParagraphElement(int position)    public Element getParagraphElement(int position)
906    {    {
907      Element element = getCharacterElement(position);      BranchElement root = (BranchElement) getDefaultRootElement();
908      return element.getParentElement();      Element par = root.positionToElement(position);
909        return par;
910    }    }
911    
912    /**    /**
# Line 445  public class DefaultStyledDocument exten Line 990  public class DefaultStyledDocument exten
990                         + "javax.swing.text.AbstractDocument.AbstractElement");                         + "javax.swing.text.AbstractDocument.AbstractElement");
991            }            }
992        }        }
993    
994        fireChangedUpdate(ev);
995    }    }
996        
997    /**    /**
# Line 482  public class DefaultStyledDocument exten Line 1029  public class DefaultStyledDocument exten
1029      // FIXME: Implement me.      // FIXME: Implement me.
1030      throw new Error("not implemented");      throw new Error("not implemented");
1031    }    }
1032    
1033      /**
1034       * Called in response to content insert actions. This is used to
1035       * update the element structure.
1036       *
1037       * @param ev the <code>DocumentEvent</code> describing the change
1038       * @param attr the attributes for the change
1039       */
1040      protected void insertUpdate(DefaultDocumentEvent ev, AttributeSet attr)
1041      {
1042        super.insertUpdate(ev, attr);
1043        int offset = ev.getOffset();
1044        int length = ev.getLength();
1045        int endOffset = offset + length;
1046        Segment txt = new Segment();
1047        try
1048          {
1049            getText(offset, length, txt);
1050          }
1051        catch (BadLocationException ex)
1052          {
1053            throw new AssertionError("BadLocationException must not be thrown "
1054                                     + "here.");
1055          }
1056    
1057        int len = 0;
1058        Vector specs = new Vector();
1059    
1060        Element prev = getCharacterElement(offset);
1061        Element next = getCharacterElement(endOffset);
1062    
1063        for (int i = offset; i < endOffset; ++i)
1064          {
1065            len++;
1066            if (txt.array[i] == '\n')
1067              {
1068                ElementSpec spec = new ElementSpec(attr, ElementSpec.ContentType,
1069                                                   len);
1070    
1071                // If we are at the last index, then check if we could probably be
1072                // joined with the next element.
1073                if (i == endOffset - 1)
1074                  {
1075                    if (attr.isEqual(next.getAttributes()))
1076                      spec.setDirection(ElementSpec.JoinNextDirection);
1077                  }
1078                // If we are at the first new element, then check if it could be
1079                // joined with the previous element.
1080                else if (specs.size() == 0)
1081                  {
1082                    if (attr.isEqual(prev.getAttributes()))
1083                        spec.setDirection(ElementSpec.JoinPreviousDirection);
1084                  }
1085    
1086                specs.add(spec);
1087    
1088                // Add ElementSpecs for the newline.
1089                ElementSpec endTag = new ElementSpec(null, ElementSpec.EndTagType);
1090                specs.add(endTag);
1091                ElementSpec startTag = new ElementSpec(null,
1092                                                       ElementSpec.StartTagType);
1093                startTag.setDirection(ElementSpec.JoinFractureDirection);
1094                specs.add(startTag);
1095    
1096                len = 0;
1097                offset += len;
1098              }
1099          }
1100    
1101        // Create last element if last character hasn't been a newline.
1102        if (len > 0)
1103          {
1104            ElementSpec spec = new ElementSpec(attr, ElementSpec.ContentType, len);
1105            // If we are at the first new element, then check if it could be
1106            // joined with the previous element.
1107            if (specs.size() == 0)
1108              {
1109                if (attr.isEqual(prev.getAttributes()))
1110                  spec.setDirection(ElementSpec.JoinPreviousDirection);
1111              }
1112            // Check if we could probably be joined with the next element.
1113            else if (attr.isEqual(next.getAttributes()))
1114              spec.setDirection(ElementSpec.JoinNextDirection);
1115    
1116            specs.add(spec);
1117          }
1118    
1119        ElementSpec[] elSpecs =
1120          (ElementSpec[]) specs.toArray(new ElementSpec[specs.size()]);
1121    
1122        buffer.insert(offset, length, elSpecs, ev);
1123      }  
1124  }  }

Legend:
Removed from v.1.7  
changed lines
  Added in v.1.8

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26