KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > editor > GuardedDocument


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.editor;
21
22 import java.text.MessageFormat JavaDoc;
23 import java.util.Hashtable JavaDoc;
24 import java.util.Enumeration JavaDoc;
25 import java.awt.Color JavaDoc;
26 import java.awt.Font JavaDoc;
27 import javax.swing.text.BadLocationException JavaDoc;
28 import javax.swing.text.StyledDocument JavaDoc;
29 import javax.swing.text.Style JavaDoc;
30 import javax.swing.text.Element JavaDoc;
31 import javax.swing.text.AttributeSet JavaDoc;
32 import javax.swing.text.StyleContext JavaDoc;
33 import javax.swing.event.DocumentEvent JavaDoc;
34 import javax.swing.text.Position JavaDoc;
35 import javax.swing.text.SimpleAttributeSet JavaDoc;
36 import org.openide.util.NbBundle;
37 /**
38 * Extension to the guarded document that implements
39 * StyledDocument interface
40 *
41 * @author Miloslav Metelka
42 * @version 1.00
43 */

44
45 public class GuardedDocument extends BaseDocument
46     implements StyledDocument JavaDoc {
47
48     /** Guarded attribute used for specifying that the inserted block
49     * will be guarded.
50     */

51     public static final String JavaDoc GUARDED_ATTRIBUTE = "guarded"; // NOI18N
52

53     /** AttributeSet with only guarded attribute */
54     public static final SimpleAttributeSet JavaDoc guardedSet = new SimpleAttributeSet JavaDoc();
55
56     /** AttributeSet with only break-guarded attribute */
57     public static final SimpleAttributeSet JavaDoc unguardedSet = new SimpleAttributeSet JavaDoc();
58
59     private static final boolean debugAtomic = Boolean.getBoolean("netbeans.debug.editor.atomic"); // NOI18N
60
private static final boolean debugAtomicStack = Boolean.getBoolean("netbeans.debug.editor.atomic.stack"); // NOI18N
61

62     // Add the attributes to sets
63
static {
64         guardedSet.addAttribute(GUARDED_ATTRIBUTE, Boolean.TRUE);
65         unguardedSet.addAttribute(GUARDED_ATTRIBUTE, Boolean.FALSE);
66     }
67
68     public static final String JavaDoc FMT_GUARDED_INSERT_LOCALE = "FMT_guarded_insert"; // NOI18N
69
public static final String JavaDoc FMT_GUARDED_REMOVE_LOCALE = "FMT_guarded_remove"; // NOI18N
70

71     MarkBlockChain guardedBlockChain;
72
73     /** Break the guarded flag, so inserts/removals over guarded areas will work */
74     boolean breakGuarded;
75
76     boolean atomicAsUser;
77
78     /** Style context to hold the styles */
79     protected StyleContext JavaDoc styles;
80
81     /** Style to layer name mapping */
82     protected Hashtable JavaDoc stylesToLayers;
83
84     /** Name of the normal style. The normal style is used to reset the effect
85     * of all styles applied to the line.
86     */

87     protected String JavaDoc normalStyleName;
88
89     public GuardedDocument(Class JavaDoc kitClass) {
90         this(kitClass, true, new StyleContext JavaDoc());
91     }
92
93     /** Create base document with a specified syntax and style context.
94     * @param kitClass class used to initialize this document with proper settings
95     * category based on the editor kit for which this document is created
96     * @param syntax syntax scanner to use with this document
97     * @param styles style context to use
98     */

99     public GuardedDocument(Class JavaDoc kitClass, boolean addToRegistry, StyleContext JavaDoc styles) {
100         super(kitClass, addToRegistry);
101         this.styles = styles;
102         stylesToLayers = new Hashtable JavaDoc(5);
103         guardedBlockChain = new MarkBlockChain(this) {
104             protected Mark createBlockStartMark() {
105                 MarkFactory.ContextMark startMark = new MarkFactory.ContextMark(Position.Bias.Forward, false);
106                 return startMark;
107             }
108
109             protected Mark createBlockEndMark() {
110                 MarkFactory.ContextMark endMark = new MarkFactory.ContextMark(Position.Bias.Backward, false);
111                 return endMark;
112             }
113         };
114     }
115
116     /** Get the chain of the guarded blocks */
117     public MarkBlockChain getGuardedBlockChain() {
118         return guardedBlockChain;
119     }
120
121     public boolean isPosGuarded(int pos) {
122         int rel = guardedBlockChain.compareBlock(pos, pos) & MarkBlock.IGNORE_EMPTY;
123         return (rel == MarkBlock.INSIDE_BEGIN || rel == MarkBlock.INNER);
124     }
125
126     /** This method is called automatically before the document
127     * is updated as result of removal. This function can throw
128     * BadLocationException or its descendants to stop the ongoing
129     * insert from being actually done.
130     * @param evt document event containing the change including array
131     * of characters that will be inserted
132     */

133     protected void preInsertCheck(int offset, String JavaDoc text, AttributeSet JavaDoc a)
134     throws BadLocationException JavaDoc {
135         super.preInsertCheck(offset, text, a);
136
137         int rel = guardedBlockChain.compareBlock(offset, offset) & MarkBlock.IGNORE_EMPTY;
138
139         if (debugAtomic) {
140             System.err.println("GuardedDocument.beforeInsertUpdate() atomicAsUser=" // NOI18N
141
+ atomicAsUser + ", breakGuarded=" + breakGuarded // NOI18N
142
+ ", inserting text='" + EditorDebug.debugString(text) // NOI18N
143
+ "' at offset=" + Utilities.debugPosition(this, offset)); // NOI18N
144
if (debugAtomicStack) {
145                 Thread.dumpStack();
146             }
147         }
148
149         if (text.length() > 0
150                 && (rel & MarkBlock.OVERLAP) != 0
151                 && rel != MarkBlock.INSIDE_END // guarded blocks have insertAfter endMark
152
&& !(text.charAt(text.length() - 1) == '\n'
153                      && rel == MarkBlock.INSIDE_BEGIN)
154            ) {
155             if (!breakGuarded || atomicAsUser) {
156                 throw new GuardedException(
157                     MessageFormat.format(
158                         NbBundle.getBundle(BaseKit.class).getString(FMT_GUARDED_INSERT_LOCALE),
159                         new Object JavaDoc [] {
160                             new Integer JavaDoc(offset)
161                         }
162                     ),
163                     offset
164                 );
165             }
166         }
167     }
168
169     /** This method is called automatically before the document
170     * is updated as result of removal.
171     */

172     protected void preRemoveCheck(int offset, int len)
173     throws BadLocationException JavaDoc {
174         int rel = guardedBlockChain.compareBlock(offset, offset + len);
175
176         if (debugAtomic) {
177             System.err.println("GuardedDocument.beforeRemoveUpdate() atomicAsUser=" // NOI18N
178
+ atomicAsUser + ", breakGuarded=" + breakGuarded // NOI18N
179
+ ", removing text='" + EditorDebug.debugChars(getChars(offset, len)) // NOI18N
180
+ "'at offset=" + Utilities.debugPosition(this, offset)); // NOI18N
181
if (debugAtomicStack) {
182                 Thread.dumpStack();
183             }
184         }
185
186         if ((rel & MarkBlock.OVERLAP) != 0
187                 || (rel == MarkBlock.CONTINUE_BEGIN
188                     && !(offset == 0 || getChars(offset - 1, 1)[0] == '\n'))
189            ) {
190             if (!breakGuarded || atomicAsUser) {
191                 // test whether the previous char before removed text is '\n'
192
throw new GuardedException(
193                     MessageFormat.format(
194                         NbBundle.getBundle(BaseKit.class).getString(FMT_GUARDED_REMOVE_LOCALE),
195                         new Object JavaDoc [] {
196                             new Integer JavaDoc(offset)
197                         }
198                     ),
199                     offset
200                 );
201             }
202         }
203     }
204
205     public void setCharacterAttributes(int offset, int length, AttributeSet JavaDoc s,
206                                        boolean replace) {
207         if (((Boolean JavaDoc)s.getAttribute(GUARDED_ATTRIBUTE)).booleanValue() == true) {
208             guardedBlockChain.addBlock(offset, offset + length, false); // no concat
209
fireChangedUpdate(createDocumentEvent(offset, length, DocumentEvent.EventType.CHANGE));
210         }
211         if (((Boolean JavaDoc)s.getAttribute(GUARDED_ATTRIBUTE)).booleanValue() == false) {
212             guardedBlockChain.removeBlock(offset, offset + length);
213             fireChangedUpdate(createDocumentEvent(offset, length, DocumentEvent.EventType.CHANGE));
214         }
215     }
216
217     public void runAtomic(Runnable JavaDoc r) {
218         if (debugAtomic) {
219             System.out.println("GuardedDocument.runAtomic() called"); // NOI18N
220
if (debugAtomicStack) {
221                 Thread.dumpStack();
222             }
223         }
224
225         boolean completed = false;
226         atomicLock();
227         boolean origBreakGuarded = breakGuarded;
228         try {
229             breakGuarded = true;
230             r.run();
231             completed = true;
232         } finally {
233             breakGuarded = origBreakGuarded;
234             try {
235                 if (!completed) {
236                     breakAtomicLock();
237                 }
238             } finally {
239                 atomicUnlock();
240             }
241             if (debugAtomic) {
242                 System.out.println("GuardedDocument.runAtomic() finished"); // NOI18N
243
}
244         }
245     }
246
247     public void runAtomicAsUser(Runnable JavaDoc r) {
248         if (debugAtomic) {
249             System.out.println("GuardedDocument.runAtomicAsUser() called"); // NOI18N
250
if (debugAtomicStack) {
251                 Thread.dumpStack();
252             }
253         }
254
255         boolean completed = false;
256         atomicLock();
257         boolean origAtomicAsUser = atomicAsUser;
258         try {
259             atomicAsUser = true;
260             r.run();
261             completed = true;
262         } finally {
263             atomicAsUser = origAtomicAsUser;
264             try {
265                 if (!completed) {
266                     breakAtomicLock();
267                 }
268             } finally {
269                 atomicUnlock();
270             }
271             if (debugAtomic) {
272                 System.out.println("GuardedDocument.runAtomicAsUser() finished"); // NOI18N
273
}
274         }
275     }
276
277     protected BaseDocumentEvent createDocumentEvent(int offset, int length,
278             DocumentEvent.EventType JavaDoc type) {
279         return new GuardedDocumentEvent(this, offset, length, type);
280     }
281
282     /** Adds style to the document */
283     public Style JavaDoc addStyle(String JavaDoc styleName, Style JavaDoc parent) {
284         String JavaDoc layerName = (String JavaDoc)stylesToLayers.get(styleName);
285         if (layerName == null) {
286             layerName = styleName; // same layer name as style name
287
addStyleToLayerMapping(styleName, layerName);
288         }
289
290         Style JavaDoc style = styles.addStyle(styleName, parent);
291         if (findLayer(layerName) == null) { // not created by default
292
try {
293                 extWriteLock();
294                 addStyledLayer(layerName, style);
295             } finally {
296                 extWriteUnlock();
297             }
298         }
299         return style;
300     }
301
302     public void addStyleToLayerMapping(String JavaDoc styleName, String JavaDoc layerName) {
303         stylesToLayers.put(styleName, layerName);
304     }
305
306     /** Removes style from document */
307     public void removeStyle(String JavaDoc styleName) {
308         styles.removeStyle(styleName);
309     }
310
311     /** Fetches style previously added */
312     public Style JavaDoc getStyle(String JavaDoc styleName) {
313         return styles.getStyle(styleName);
314     }
315
316     /** Set the name for normal style. Normal style is used to reset the effect
317     * of all aplied styles.
318     */

319     public void setNormalStyleName(String JavaDoc normalStyleName) {
320         this.normalStyleName = normalStyleName;
321     }
322
323     /** Fetches the list of style names */
324     public Enumeration JavaDoc getStyleNames() {
325         return styles.getStyleNames();
326     }
327
328     /** Change attributes for part of the text. */
329     public void setParagraphAttributes(int offset, int length, AttributeSet JavaDoc s,
330                                        boolean replace) {
331         // !!! implement
332
}
333
334     /**
335      * Sets the logical style to use for the paragraph at the
336      * given position. If attributes aren't explicitly set
337      * for character and paragraph attributes they will resolve
338      * through the logical style assigned to the paragraph, which
339      * in turn may resolve through some hierarchy completely
340      * independent of the element hierarchy in the document.
341      *
342      * @param pos the starting position >= 0
343      * @param s the style to set
344      */

345     public void setLogicalStyle(int pos, Style JavaDoc s) {
346         try {
347             extWriteLock();
348             pos = Utilities.getRowStart(this, pos);
349             String JavaDoc layerName = (String JavaDoc)stylesToLayers.get(s.getName());
350             // remove all applied styles
351
DrawLayer[] layerArray = getDrawLayerList().currentLayers();
352             for (int i = 0; i < layerArray.length; i++) {
353                 if (layerArray[i] instanceof DrawLayerFactory.StyleLayer) {
354                     ((DrawLayerFactory.StyleLayer)layerArray[i]).markChain.removeMark(pos);
355                 }
356             }
357             // now set the requested style
358
DrawLayerFactory.StyleLayer styleLayer
359             = (DrawLayerFactory.StyleLayer)findLayer(layerName);
360             if (styleLayer != null) {
361                 styleLayer.markChain.addMark(pos);
362             }
363             fireChangedUpdate(createDocumentEvent(pos, 0,
364                                                   DocumentEvent.EventType.CHANGE)); // enough to say length 0
365
} catch (BadLocationException JavaDoc e) {
366             // do nothing for invalid positions
367
} finally {
368             extWriteUnlock();
369         }
370     }
371
372     /** Get logical style for position in paragraph */
373     public Style JavaDoc getLogicalStyle(int pos) {
374         try {
375             pos = Utilities.getRowStart(this, pos);
376             DrawLayer[] layerArray = getDrawLayerList().currentLayers();
377             for (int i = 0; i < layerArray.length; i++) {
378                 DrawLayer layer = layerArray[i];
379                 if (layer instanceof DrawLayerFactory.StyleLayer) {
380                     if (((DrawLayerFactory.StyleLayer)layer).markChain.isMark(pos)) {
381                         return ((DrawLayerFactory.StyleLayer)layer).style;
382                     }
383                 }
384             }
385             return getStyle(normalStyleName); // no style found
386
} catch (BadLocationException JavaDoc e) {
387             return null;
388         }
389     }
390
391     /**
392      * Gets the element that represents the character that
393      * is at the given offset within the document.
394      *
395      * @param pos the offset >= 0
396      * @return the element
397      */

398     public Element JavaDoc getCharacterElement(int pos) {
399         return getParagraphElement(pos);
400     }
401
402
403     /**
404      * Takes a set of attributes and turn it into a foreground color
405      * specification. This might be used to specify things
406      * like brighter, more hue, etc.
407      *
408      * @param attr the set of attributes
409      * @return the color
410      */

411     public Color JavaDoc getForeground(AttributeSet JavaDoc attr) {
412         return null; // !!!
413
}
414
415     /**
416      * Takes a set of attributes and turn it into a background color
417      * specification. This might be used to specify things
418      * like brighter, more hue, etc.
419      *
420      * @param attr the set of attributes
421      * @return the color
422      */

423     public Color JavaDoc getBackground(AttributeSet JavaDoc attr) {
424         return null; // !!!
425
}
426
427     /**
428      * Takes a set of attributes and turn it into a font
429      * specification. This can be used to turn things like
430      * family, style, size, etc into a font that is available
431      * on the system the document is currently being used on.
432      *
433      * @param attr the set of attributes
434      * @return the font
435      */

436     public Font JavaDoc getFont(AttributeSet JavaDoc attr) {
437         return new Font JavaDoc("Default",Font.BOLD,12); // NOI18N
438
}
439
440     /**
441      * Using of <code>DrawLayer</code>s has been deprecated.
442      *
443      * @deprecated Please use Highlighting SPI instead, for details see
444      * <a HREF="@org-netbeans-modules-editor-lib2@/overview-summary.html">Editor Library 2</a>.
445      */

446     protected DrawLayer addStyledLayer(String JavaDoc layerName, Style JavaDoc style) {
447         if (layerName != null) {
448             try {
449                 int indColon = layerName.indexOf(':');
450                 int layerVisibility = Integer.parseInt(layerName.substring(indColon + 1));
451                 DrawLayer layer = new DrawLayerFactory.StyleLayer(layerName, this, style);
452
453                 addLayer(layer, layerVisibility);
454                 return layer;
455
456             } catch (NumberFormatException JavaDoc e) {
457                 // wrong name, let it pass
458
}
459         }
460         return null;
461     }
462
463     public String JavaDoc toStringDetail() {
464         return super.toStringDetail()
465                + getDrawLayerList()
466                + ",\nGUARDED blocks:\n" + guardedBlockChain; // NOI18N
467
}
468
469 }
470
Popular Tags