KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > editor > view > spi > LockView


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.view.spi;
21
22 import java.awt.Graphics JavaDoc;
23 import java.awt.Shape JavaDoc;
24 import javax.swing.event.DocumentEvent JavaDoc;
25 import javax.swing.text.AbstractDocument JavaDoc;
26 import javax.swing.text.AttributeSet JavaDoc;
27 import javax.swing.text.BadLocationException JavaDoc;
28 import javax.swing.text.Document JavaDoc;
29 import javax.swing.text.Element JavaDoc;
30 import javax.swing.text.JTextComponent JavaDoc;
31 import javax.swing.text.Position JavaDoc;
32 import javax.swing.text.View JavaDoc;
33 import javax.swing.text.ViewFactory JavaDoc;
34 import org.netbeans.lib.editor.util.PriorityMutex;
35
36 /**
37  * View that allow to lock the view hierarchy.
38  * It's a filter view that is being installed under the root view.
39  *
40  * @author Miloslav Metelka
41  * @version 1.00
42  */

43
44 public class LockView extends View JavaDoc {
45     
46     private static final String JavaDoc PROPERTY_VIEW_HIERARCHY_MUTEX = "viewHierarchyMutex"; // NOI18N
47
// Note: FoldHierarchyExecution has the same property
48
private static final String JavaDoc PROPERTY_FOLD_HIERARCHY_MUTEX = "foldHierarchyMutex"; // NOI18N
49

50     private View JavaDoc view;
51     
52     private PriorityMutex mutex;
53     
54     private AbstractDocument JavaDoc doc;
55     
56     /**
57      * Get mutex used to lock the view hierarchy.
58      * All the services manipulating the view hierarchy
59      * or providing data for the view hierarchy
60      * may choose to lock on this mutex
61      * rather having its own locking mechanism
62      * to simplify their locking model
63      * and eliminate possibility of deadlocks
64      * because of counter-locking.
65      * <br>
66      * The <code>LockView</code> itself uses this mutex
67      * as well as the code folding hierarchy.
68      */

69     public static synchronized PriorityMutex getViewHierarchyMutex(JTextComponent JavaDoc component) {
70         // A single mutex instance must be shared by view and fold hierarchies
71
PriorityMutex mutex = (PriorityMutex)component.getClientProperty(PROPERTY_FOLD_HIERARCHY_MUTEX);
72         if (mutex == null) {
73             mutex = new PriorityMutex();
74             component.putClientProperty(PROPERTY_FOLD_HIERARCHY_MUTEX, mutex);
75         }
76         component.putClientProperty(PROPERTY_VIEW_HIERARCHY_MUTEX, mutex);
77         
78         return mutex;
79     }
80
81     /**
82      * Find the <code>LockView</code> instance in a view hierarchy
83      * by traversing it up to the root view.
84      *
85      * @param view view in the view hierarchy. <code>null</code> is accepted too.
86      * @return valid instance of <code>LockView</code> or null
87      * if there is no <code>LockView</code> instance present
88      * in the view hierarchy of the view is no longer
89      * part of the view hierarchy.
90      */

91     public static LockView get(View JavaDoc view) {
92         while (view != null && !(view instanceof LockView)) {
93             view = view.getParent();
94         }
95         
96         return (LockView)view;
97     }
98     
99     public LockView(View JavaDoc view) {
100         super(null);
101
102         this.view = view;
103 // System.out.println("LockView instance created " + System.identityHashCode(this));
104
}
105     
106     public void setParent(View JavaDoc parent) {
107     
108         View JavaDoc origParent = getParent();
109         if (origParent != null && parent != null) {
110             /* This is not truly an errorneous situation
111              * but this does not normally happen
112              * as for complex changes in the text component (e.g. a document replacement)
113              * the whole view hierarchy starting with RootView in TextUI
114              * is being thrown away and recreated.
115              * So this special state is reported
116              * to make sure that this situation will be handled
117              * before this constraint will be removed.
118              */

119             throw new IllegalStateException JavaDoc("Unexpected state occurred when" // NOI18N
120
+ " trying to set non-null parent to LockView with non-null" // NOI18N
121
+ " parent already set." // NOI18N
122
);
123         }
124
125         // Assign the mutex variable if necessary
126
// May be desirable to be synced with getMutex() if necessary
127
if (mutex == null && parent != null) {
128             JTextComponent JavaDoc c = (JTextComponent JavaDoc)parent.getContainer();
129             if (c != null) {
130                 mutex = getViewHierarchyMutex(c);
131             }
132         }
133
134         if (parent != null) {
135             // Check that AbstractDocument is being used.
136
Document JavaDoc maybeAbstractDoc = parent.getDocument();
137             if (!(maybeAbstractDoc instanceof AbstractDocument JavaDoc)) {
138                 /**
139                  * Although LockView could possibly be changed
140                  * to work with just the Document interface
141                  * there are bunch of other view implementations
142                  * in the editor that expect the AbstractDocument as well
143                  * mainly due to the presence of AbstractDocument.readLock()
144                  * instead of just the Document.render().
145                  * If working with non-AbstractDocument instances
146                  * would be a strong requirement the editor's
147                  * view implementations would have to be reviewed
148                  * before this constraint can be removed.
149                  */

150                 throw new IllegalStateException JavaDoc("Currently the LockView" // NOI18N
151
+ " is designed to work with AbstractDocument instances only." // NOI18N
152
);
153             }
154             
155             /**
156              * Remember the document for which this LockView and underlying
157              * view hierarchy was created.
158              * If any of the childviews would delegate its getDocument()
159              * to parent and it would end up here then the remembered
160              * document will be returned instead of possibly delegating
161              * to the parent RootView which delegates to component.getDocument().
162              * The component.getDocument() always brings the most fresh
163              * document. However that can be problematic e.g. in the following
164              * case:
165              * <ol>
166              * <li> ViewLayoutQueue executes a task in Layout-Thread
167              * <li> The task properly locks document and then view hierarchy
168              * <li> In AWT thread someone calls JTextComponent.setDocument()
169              * before the task in Layout-Tread finishes
170              * <li> Task calls JTextComponent.getDocument()
171              * and attempts to do doc.readLock().
172              * Normally it should be noop as the document
173              * was already read-locked previously however
174              * here it's a different document so looking from
175              * the new document's perspective the locking order
176              * is exactly opposite than it should be
177              * i.e. first the view hierarchy is locked
178              * and then the (new) document is locked.
179              * This situation may lead to deadlock from counter-locking.
180              * <br>
181              * Remembering of the document here and consistent
182              * use of the view.getDocument() instead of
183              * component.getDocument() in the tasks
184              * executed in the Layout-Thread
185              * should avoid this type of deadlock.
186              * </ol>
187              */

188             this.doc = (AbstractDocument JavaDoc)maybeAbstractDoc;
189         }
190
191         /* First read-lock the document to prevent deadlocks
192          * from counter-locking.
193          */

194         this.doc.readLock();
195         try {
196             lock();
197             try {
198
199                 setParentLocked(parent);
200
201             } finally {
202                 unlock();
203             }
204                 
205         } finally {
206             this.doc.readUnlock();
207         }
208     }
209     
210     protected void setParentLocked(View JavaDoc parent) {
211         // possibly first clear parent in child than in this view
212
// so that getContainer() remains usable
213
if (parent == null && view != null) {
214             view.setParent(null);
215         }
216         
217         super.setParent(parent);
218
219         // Update child for non-null parent here
220
if (parent != null && view != null) {
221             view.setParent(this);
222         }
223     }
224
225     /**
226      * Set a new single child of this view.
227      */

228     public void setView(View JavaDoc v) {
229         lock();
230         try {
231             
232             if (view != null) {
233                 // get rid of back reference so that the old
234
// hierarchy can be garbage collected.
235
view.setParent(null);
236             }
237             view = v;
238             if (view != null) {
239                 view.setParent(this);
240             }
241             
242         } finally {
243             unlock();
244         }
245     }
246     
247     public void lock() {
248         if (mutex != null) {
249             mutex.lock();
250         }
251     }
252     
253     public void unlock() {
254         mutex.unlock(); // should always proceed if a previous lock() succeeded
255
}
256     
257     public boolean isPriorityThreadWaiting() {
258         return mutex.isPriorityThreadWaiting();
259     }
260     
261     /**
262      * Return the thread that holds a lock on the view hierarchy.
263      * <br>
264      * This method is intended for diagnostic purposes only to determine
265      * an intruder thread that entered the view hierarchy without obtaining
266      * the lock first.
267      *
268      * @return thread that currently holds a lock on the hierarchy or null
269      * if there is currently no thread holding a lock on the hierarchy.
270      */

271     public Thread JavaDoc getLockThread() {
272         return mutex.getLockThread();
273     }
274     
275     public void render(Runnable JavaDoc r) {
276         lock();
277         try {
278             
279             r.run();
280             
281         } finally {
282             unlock();
283         }
284     }
285
286     /**
287      * Fetches the attributes to use when rendering. At this level
288      * there are no attributes. If an attribute is resolved
289      * up the view hierarchy this is the end of the line.
290      */

291     public AttributeSet JavaDoc getAttributes() {
292         return null;
293     }
294
295     public float getPreferredSpan(int axis) {
296         lock();
297         try {
298             
299             if (view != null) {
300                 return view.getPreferredSpan(axis);
301             }
302             return 10;
303
304         } finally {
305             unlock();
306         }
307     }
308
309     public float getMinimumSpan(int axis) {
310         lock();
311         try {
312             
313             if (view != null) {
314                 return view.getMinimumSpan(axis);
315             }
316             return 10;
317
318         } finally {
319             unlock();
320         }
321     }
322
323     public float getMaximumSpan(int axis) {
324         lock();
325         try {
326             
327             if (view != null) {
328                 return view.getMaximumSpan(axis);
329             }
330             return Integer.MAX_VALUE;
331
332         } finally {
333             unlock();
334         }
335     }
336
337     public void preferenceChanged(View JavaDoc child, boolean width, boolean height) {
338         View JavaDoc parent = getParent();
339         if (parent != null) {
340             parent.preferenceChanged(this, width, height);
341         }
342     }
343
344     public float getAlignment(int axis) {
345         lock();
346         try {
347             
348             if (view != null) {
349                 return view.getAlignment(axis);
350             }
351             return 0;
352
353         } finally {
354             unlock();
355         }
356     }
357
358     public void paint(Graphics JavaDoc g, Shape JavaDoc allocation) {
359         lock();
360         try {
361             
362             if (view != null) {
363                 view.paint(g, allocation);
364             }
365
366         } finally {
367             unlock();
368         }
369     }
370
371     public int getViewCount() {
372         return 1;
373     }
374
375     /**
376      * Gets the n-th view in this container.
377      *
378      * @param n the number of the view to get
379      * @return the view
380      */

381     public View JavaDoc getView(int n) {
382         return view;
383     }
384
385     public int getViewIndex(int pos, Position.Bias JavaDoc b) {
386         return 0;
387     }
388
389     public Shape JavaDoc getChildAllocation(int index, Shape JavaDoc a) {
390         return a;
391     }
392
393     public Shape JavaDoc modelToView(int pos, Shape JavaDoc a, Position.Bias JavaDoc b) throws BadLocationException JavaDoc {
394         lock();
395         try {
396             
397             if (view != null) {
398                 return view.modelToView(pos, a, b);
399             }
400             return null;
401
402         } finally {
403             unlock();
404         }
405     }
406
407     public Shape JavaDoc modelToView(int p0, Position.Bias JavaDoc b0, int p1, Position.Bias JavaDoc b1, Shape JavaDoc a) throws BadLocationException JavaDoc {
408         lock();
409         try {
410             
411             if (view != null) {
412                 return view.modelToView(p0, b0, p1, b1, a);
413             }
414             return null;
415
416         } finally {
417             unlock();
418         }
419     }
420
421     public int viewToModel(float x, float y, Shape JavaDoc a, Position.Bias JavaDoc[] bias) {
422         lock();
423         try {
424             
425             if (view != null) {
426                 return view.viewToModel(x, y, a, bias);
427             }
428             return -1;
429
430         } finally {
431             unlock();
432         }
433     }
434
435     public int getNextVisualPositionFrom(int pos, Position.Bias JavaDoc b, Shape JavaDoc a,
436     int direction, Position.Bias JavaDoc[] biasRet) throws BadLocationException JavaDoc {
437
438         lock();
439         try {
440             
441             if(view != null) {
442                 return view.getNextVisualPositionFrom(pos, b, a, direction, biasRet);
443             }
444             return -1;
445
446         } finally {
447             unlock();
448         }
449     }
450
451     public void insertUpdate(DocumentEvent JavaDoc e, Shape JavaDoc a, ViewFactory JavaDoc f) {
452         lock();
453         try {
454             
455             if (view != null) {
456                 view.insertUpdate(e, a, f);
457             }
458
459         } finally {
460             unlock();
461         }
462     }
463
464     public void removeUpdate(DocumentEvent JavaDoc e, Shape JavaDoc a, ViewFactory JavaDoc f) {
465         lock();
466         try {
467             
468             if (view != null) {
469                 view.removeUpdate(e, a, f);
470             }
471
472         } finally {
473             unlock();
474         }
475     }
476
477     public void changedUpdate(DocumentEvent JavaDoc e, Shape JavaDoc a, ViewFactory JavaDoc f) {
478         lock();
479         try {
480             
481             if (view != null) {
482                 view.changedUpdate(e, a, f);
483             }
484
485         } finally {
486             unlock();
487         }
488     }
489
490     public String JavaDoc getToolTipText(float x, float y, Shape JavaDoc allocation) {
491         lock();
492         try {
493             
494             return (view != null)
495                 ? view.getToolTipText(x, y, allocation)
496                 : null;
497
498         } finally {
499             unlock();
500         }
501     }
502
503     public Document JavaDoc getDocument() {
504         return doc;
505     }
506
507     public int getStartOffset() {
508         if (view != null) {
509             return view.getStartOffset();
510         }
511         Element JavaDoc elem = getElement();
512         return (elem != null) ? elem.getStartOffset() : 0;
513     }
514
515     public int getEndOffset() {
516         if (view != null) {
517             return view.getEndOffset();
518         }
519         Element JavaDoc elem = getElement();
520         return (elem != null) ? elem.getEndOffset() : 0;
521     }
522
523     public Element JavaDoc getElement() {
524         if (view != null) {
525             return view.getElement();
526         }
527         Document JavaDoc doc = getDocument();
528         return (doc != null) ? doc.getDefaultRootElement() : null;
529     }
530
531     public View JavaDoc breakView(int axis, float len, Shape JavaDoc a) {
532         throw new Error JavaDoc("Can't break lock view"); // NOI18N
533
}
534
535     public int getResizeWeight(int axis) {
536         lock();
537         try {
538             
539             if (view != null) {
540                 return view.getResizeWeight(axis);
541             }
542             return 0;
543
544         } finally {
545             unlock();
546         }
547     }
548
549     public void setSize(float width, float height) {
550         lock();
551         try {
552             
553             if (view != null) {
554                 view.setSize(width, height);
555             }
556
557         } finally {
558             unlock();
559         }
560     }
561
562 }
563
Popular Tags