42 |
import java.awt.Font; |
import java.awt.Font; |
43 |
import java.io.Serializable; |
import java.io.Serializable; |
44 |
|
|
45 |
|
import javax.swing.event.DocumentEvent; |
46 |
|
|
47 |
/** |
/** |
48 |
* @author Michael Koch (konqueror@gmx.de) |
* @author Michael Koch (konqueror@gmx.de) |
49 |
*/ |
*/ |
54 |
implements Serializable |
implements Serializable |
55 |
{ |
{ |
56 |
private Element root; |
private Element root; |
57 |
|
|
58 |
|
/** Holds the offset for structural changes. */ |
59 |
|
private int offset; |
60 |
|
|
61 |
|
/** Holds the length of structural changes. */ |
62 |
|
private int length; |
63 |
|
|
64 |
public ElementBuffer(Element root) |
public ElementBuffer(Element root) |
65 |
{ |
{ |
66 |
this.root = root; |
this.root = root; |
70 |
{ |
{ |
71 |
return root; |
return root; |
72 |
} |
} |
73 |
|
|
74 |
|
/** |
75 |
|
* Modifies the element structure so that the specified interval starts |
76 |
|
* and ends at an element boundary. Content and paragraph elements |
77 |
|
* are split and created as necessary. |
78 |
|
* |
79 |
|
* This also updates the <code>DefaultDocumentEvent</code> to reflect the |
80 |
|
* structural changes. |
81 |
|
* |
82 |
|
* The bulk work is delegated to {@link #changeUpdate()}. |
83 |
|
* |
84 |
|
* @param offset the start index of the interval to be changed |
85 |
|
* @param length the length of the interval to be changed |
86 |
|
* @param ev the <code>DefaultDocumentEvent</code> describing the change |
87 |
|
*/ |
88 |
|
public void change(int offset, int length, DefaultDocumentEvent ev) |
89 |
|
{ |
90 |
|
this.offset = offset; |
91 |
|
this.length = length; |
92 |
|
changeUpdate(); |
93 |
|
} |
94 |
|
|
95 |
|
/** |
96 |
|
* Performs the actual work for {@link #change}. |
97 |
|
* The elements at the interval boundaries are split up (if necessary) |
98 |
|
* so that the interval boundaries are located at element boundaries. |
99 |
|
*/ |
100 |
|
protected void changeUpdate() |
101 |
|
{ |
102 |
|
// Split up the element at the start offset if necessary. |
103 |
|
Element el = getCharacterElement(offset); |
104 |
|
split(el, offset); |
105 |
|
|
106 |
|
int endOffset = offset + length; |
107 |
|
el = getCharacterElement(endOffset); |
108 |
|
split(el, endOffset); |
109 |
|
} |
110 |
|
|
111 |
|
/** |
112 |
|
* Splits an element if <code>offset</code> is not alread at its boundary. |
113 |
|
* |
114 |
|
* @param el the Element to possibly split |
115 |
|
* @param offset the offset at which to possibly split |
116 |
|
*/ |
117 |
|
void split(Element el, int offset) |
118 |
|
{ |
119 |
|
if (el instanceof AbstractElement) |
120 |
|
{ |
121 |
|
AbstractElement ael = (AbstractElement) el; |
122 |
|
int startOffset = ael.getStartOffset(); |
123 |
|
int endOffset = ael.getEndOffset(); |
124 |
|
int len = endOffset - startOffset; |
125 |
|
if (startOffset != offset && endOffset != offset) |
126 |
|
{ |
127 |
|
Element paragraph = ael.getParentElement(); |
128 |
|
if (paragraph instanceof BranchElement) |
129 |
|
{ |
130 |
|
BranchElement par = (BranchElement) paragraph; |
131 |
|
Element child1 = createLeafElement(par, ael, startOffset, |
132 |
|
offset); |
133 |
|
Element child2 = createLeafElement(par, ael, offset, |
134 |
|
endOffset); |
135 |
|
int index = par.getElementIndex(startOffset); |
136 |
|
par.replace(index, 1, new Element[]{ child1, child2 }); |
137 |
|
} |
138 |
|
} |
139 |
|
else |
140 |
|
throw new AssertionError("paragraph elements are expected to be " |
141 |
|
+ "instances of " |
142 |
|
+ "javax.swing.text.AbstractDocument.BranchElement"); |
143 |
|
} |
144 |
|
else |
145 |
|
throw new AssertionError("content elements are expected to be " |
146 |
|
+ "instances of " |
147 |
|
+ "javax.swing.text.AbstractDocument.AbstractElement"); |
148 |
|
} |
149 |
} |
} |
150 |
|
|
151 |
public static final int BUFFER_SIZE_DEFAULT = 4096; |
public static final int BUFFER_SIZE_DEFAULT = 4096; |
259 |
AttributeSet attributes, |
AttributeSet attributes, |
260 |
boolean replace) |
boolean replace) |
261 |
{ |
{ |
262 |
// FIXME: Implement me. |
DefaultDocumentEvent ev = |
263 |
throw new Error("not implemented"); |
new DefaultDocumentEvent(offset, length, |
264 |
|
DocumentEvent.EventType.CHANGE); |
265 |
|
|
266 |
|
// Modify the element structure so that the interval begins at an element |
267 |
|
// start and ends at an element end. |
268 |
|
buffer.change(offset, length, ev); |
269 |
|
|
270 |
|
Element root = getDefaultRootElement(); |
271 |
|
// Visit all paragraph elements within the specified interval |
272 |
|
int paragraphCount = root.getElementCount(); |
273 |
|
for (int pindex = 0; pindex < paragraphCount; pindex++) |
274 |
|
{ |
275 |
|
Element paragraph = root.getElement(pindex); |
276 |
|
// Skip paragraphs that lie outside the interval. |
277 |
|
if ((paragraph.getStartOffset() > offset + length) |
278 |
|
|| (paragraph.getEndOffset() < offset)) |
279 |
|
continue; |
280 |
|
|
281 |
|
// Visit content elements within this paragraph |
282 |
|
int contentCount = paragraph.getElementCount(); |
283 |
|
for (int cindex = 0; cindex < contentCount; cindex++) |
284 |
|
{ |
285 |
|
Element content = paragraph.getElement(cindex); |
286 |
|
// Skip content that lies outside the interval. |
287 |
|
if ((content.getStartOffset() > offset + length) |
288 |
|
|| (content.getEndOffset() < offset)) |
289 |
|
continue; |
290 |
|
|
291 |
|
if (content instanceof AbstractElement) |
292 |
|
{ |
293 |
|
AbstractElement el = (AbstractElement) content; |
294 |
|
if (replace) |
295 |
|
el.removeAttributes(el); |
296 |
|
el.addAttributes(attributes); |
297 |
|
} |
298 |
|
else |
299 |
|
throw new AssertionError("content elements are expected to be" |
300 |
|
+ "instances of " |
301 |
|
+ "javax.swing.text.AbstractDocument.AbstractElement"); |
302 |
|
} |
303 |
|
} |
304 |
} |
} |
305 |
|
|
306 |
public void setLogicalStyle(int position, Style style) |
public void setLogicalStyle(int position, Style style) |