KickJava   Java API By Example, From Geeks To Geeks.

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


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.awt.Graphics JavaDoc;
23 import java.awt.Shape JavaDoc;
24 import java.awt.event.ActionEvent JavaDoc;
25 import java.awt.event.ActionListener JavaDoc;
26 import java.beans.PropertyChangeListener JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import javax.swing.Timer JavaDoc;
31 import javax.swing.plaf.TextUI JavaDoc;
32 import javax.swing.text.AbstractDocument JavaDoc;
33 import javax.swing.text.Element JavaDoc;
34 import javax.swing.text.JTextComponent JavaDoc;
35 import javax.swing.text.View JavaDoc;
36 import javax.swing.text.ViewFactory JavaDoc;
37 import org.netbeans.api.editor.fold.Fold;
38 import org.netbeans.api.editor.fold.FoldHierarchy;
39 import org.netbeans.api.editor.fold.FoldUtilities;
40 import org.netbeans.api.editor.fold.FoldHierarchyEvent;
41 import org.netbeans.api.editor.fold.FoldHierarchyListener;
42 import org.netbeans.lib.editor.view.GapDocumentView;
43 import org.netbeans.editor.view.spi.LockView;
44
45 /**
46  * View of the whole document supporting the code folding.
47  *
48  * @author Miloslav Metelka
49  */

50 class DrawEngineDocView extends GapDocumentView
51 implements FoldHierarchyListener, PropertyChangeListener JavaDoc {
52     
53     private static final boolean debugRebuild
54         = Boolean.getBoolean("netbeans.debug.editor.view.rebuild"); // NOI18N
55

56     private FoldHierarchy foldHierarchy;
57     /** Editor UI listening to */
58     private EditorUI editorUI;
59     
60     private Iterator JavaDoc collapsedFoldIterator;
61     private Fold collapsedFold;
62     private int collapsedFoldStartOffset;
63     private int collapsedFoldEndOffset;
64     
65     private boolean collapsedFoldsInPresentViews;
66     
67     private boolean estimatedSpanResetInitiated;
68     
69     DrawEngineDocView(Element JavaDoc elem) {
70         super(elem);
71         
72         setEstimatedSpan(true);
73     }
74     
75     public void setParent(View JavaDoc parent) {
76         if (parent != null) { // start listening
77
JTextComponent JavaDoc component = (JTextComponent JavaDoc)parent.getContainer();
78             foldHierarchy = FoldHierarchy.get(component);
79             foldHierarchy.addFoldHierarchyListener(this);
80             TextUI JavaDoc tui = component.getUI();
81             if (tui instanceof BaseTextUI){
82                 editorUI = ((BaseTextUI)tui).getEditorUI();
83                 if (editorUI!=null){
84                     editorUI.addPropertyChangeListener(this);
85                 }
86             }
87         }
88
89         super.setParent(parent);
90         
91         if (parent == null) {
92             foldHierarchy.removeFoldHierarchyListener(this);
93             foldHierarchy = null;
94             if (editorUI!=null){
95                 editorUI.removePropertyChangeListener(this);
96                 editorUI = null;
97             }
98         }
99     }
100     
101     protected void attachListeners(){
102         if (foldHierarchy != null) {
103         }
104     }
105     
106     private FoldHierarchy getFoldHierarchy() {
107         return foldHierarchy;
108     }
109     
110     protected boolean useCustomReloadChildren() {
111         return true;
112     }
113
114     /**
115      * Find next collapsed fold in the given offset range.
116      * @param lastCollapsedFold last collapsed fold returned by this method.
117      * @param startOffset starting offset of the area in which the collapsed folds
118      * should be searched.
119      * @param endOffset ending offset of the area in which the collapsed folds
120      * should be searched.
121      */

122     protected Fold nextCollapsedFold() {
123         while (true) {
124             Fold fold = collapsedFoldIterator.hasNext() ? (Fold)collapsedFoldIterator.next() : null;
125
126             // Check whether the fold is not past the doc
127
if (fold != null) {
128                 collapsedFoldStartOffset = fold.getStartOffset();
129                 collapsedFoldEndOffset = fold.getEndOffset();
130                 /* Ignore the empty folds as they would make up
131                  * no visible view anyway.
132                  * Although the fold hierarchy removes the empty views
133                  * automatically it may happen that the document listener
134                  * that the fold hierarchy attaches may not be notified yet.
135                  */

136                 if (collapsedFoldStartOffset == collapsedFoldEndOffset) {
137                     if (debugRebuild) {
138                         /*DEBUG*/System.err.println(
139                             "GapBoxView.nextCollapsedFold(): ignored empty fold " // NOI18N
140
+ fold
141                         );
142                     }
143                     continue; // skip empty fold
144
}
145
146                 if (collapsedFoldEndOffset > getDocument().getLength()) {
147                     /* The fold is past the end of the document.
148                      * If a document is going to be switched in the component
149                      * the view hierarchy may be notified sooner
150                      * than fold hierarchy about that change which
151                      * can lead to this state.
152                      * That fold is ignored together with the rest of the folds
153                      * that would follow it.
154                      */

155                     fold = null;
156                 }
157             }
158
159             if (fold != null) {
160                 collapsedFoldsInPresentViews = true;
161             }
162
163             return fold;
164         }
165     }
166     
167     /**
168      * Extra initialization for custom reload of children.
169      */

170     protected void initCustomReloadChildren(FoldHierarchy hierarchy,
171     int startOffset, int endOffset) {
172         collapsedFoldIterator = FoldUtilities.collapsedFoldIterator(hierarchy, startOffset, endOffset);
173         collapsedFold = nextCollapsedFold();
174     }
175
176     /**
177      * Free any resources required for custom reload of children.
178      */

179     protected void finishCustomReloadChildren(FoldHierarchy hierarchy) {
180         collapsedFoldIterator = null;
181         collapsedFold = null;
182     }
183
184     protected void customReloadChildren(int index, int removeLength, int startOffset, int endOffset) {
185         // if removing all the views reset the flag
186
if (index == 0 && removeLength == getViewCount()) {
187             collapsedFoldsInPresentViews = false; // suppose there will be no folds in line views
188
}
189
190         FoldHierarchy hierarchy = getFoldHierarchy();
191         // Assuming the document lock was already acquired
192
if (hierarchy != null) {
193             hierarchy.lock();
194             try {
195                 initCustomReloadChildren(hierarchy, startOffset, endOffset);
196
197                 super.customReloadChildren(index, removeLength, startOffset, endOffset);
198
199                 finishCustomReloadChildren(hierarchy);
200
201             } finally {
202                 hierarchy.unlock();
203             }
204         }
205     }
206         
207     protected View JavaDoc createCustomView(ViewFactory JavaDoc f,
208     int startOffset, int maxEndOffset, int elementIndex) {
209         if (elementIndex == -1) {
210             throw new IllegalStateException JavaDoc("Need underlying line element structure"); // NOI18N
211
}
212         
213         View JavaDoc view = null;
214
215         Element JavaDoc elem = getElement();
216         Element JavaDoc lineElem = elem.getElement(elementIndex);
217         boolean createCollapsed = (collapsedFold != null);
218
219         if (createCollapsed) { // collapsedFold != null
220
int lineElemEndOffset = lineElem.getEndOffset();
221             createCollapsed = (collapsedFoldStartOffset < lineElemEndOffset);
222             if (createCollapsed) { // need to find end of collapsed area
223
Element JavaDoc firstLineElem = lineElem;
224                 List JavaDoc foldAndEndLineElemList = new ArrayList JavaDoc();
225
226                 while (true) {
227                     int collapsedFoldEndOffset = collapsedFold.getEndOffset();
228                     // Find line element index of the line in which the collapsed fold ends
229
while (collapsedFoldEndOffset > lineElemEndOffset) {
230                         elementIndex++;
231                         lineElem = elem.getElement(elementIndex);
232                         lineElemEndOffset = lineElem.getEndOffset();
233                     }
234
235                     foldAndEndLineElemList.add(collapsedFold);
236                     foldAndEndLineElemList.add(lineElem);
237
238                     collapsedFold = nextCollapsedFold();
239
240                     // No more collapsed or next collapsed does not start on current line
241
if (collapsedFold == null || collapsedFoldStartOffset >= lineElemEndOffset) {
242                         break;
243                     }
244                 }
245                 
246                 // Create the multi-line-view with collapsed fold(s)
247
view = new FoldMultiLineView(firstLineElem, foldAndEndLineElemList);
248             }
249         }
250         
251         if (!createCollapsed) {
252             view = f.create(lineElem);
253         }
254      
255         return view;
256     }
257
258     public void foldHierarchyChanged(FoldHierarchyEvent evt) {
259         LockView lockView = LockView.get(this);
260         lockView.lock();
261         try {
262             layoutLock();
263             try {
264                 FoldHierarchy hierarchy = (FoldHierarchy)evt.getSource();
265                 if (hierarchy.getComponent().getDocument() != lockView.getDocument()) {
266                     // Comonent already has a different document assigned
267
// so this view will be abandoned anyway => do not rebuild
268
// the current chilren because of this change
269
return;
270                 }
271
272                 boolean rebuildViews = true;
273                 int affectedStartOffset = evt.getAffectedStartOffset();
274                 int affectedEndOffset = evt.getAffectedEndOffset();
275
276                 // Check whether it is not a case when there were
277
// no collapsed folds before and no collapsed folds now
278
if (!collapsedFoldsInPresentViews) { // no collapsed folds previously
279
// TODO Could Integer.MAX_VALUE be used?
280
if (FoldUtilities.findCollapsedFold(hierarchy,
281                         affectedStartOffset, affectedEndOffset) == null
282                     ) { // no collapsed folds => no need to rebuild
283
rebuildViews = false;
284                     }
285                 }
286
287                 if (rebuildViews) {
288                     /**
289                      * Check the affected offsets against the current document boundaries
290                      */

291                     int docLength = getDocument().getLength();
292                     int rebuildStartOffset = Math.min(affectedStartOffset, docLength);
293                     int rebuildEndOffset = Math.min(affectedEndOffset, docLength);
294                     offsetRebuild(rebuildStartOffset, rebuildEndOffset);
295                 }
296             } finally {
297                 updateLayout();
298                 layoutUnlock();
299             }
300         } finally {
301             lockView.unlock();
302         }
303     }
304
305     public void paint(Graphics JavaDoc g, Shape JavaDoc allocation) {
306         java.awt.Component JavaDoc c = getContainer();
307         if (c instanceof javax.swing.text.JTextComponent JavaDoc){
308             TextUI JavaDoc textUI = ((javax.swing.text.JTextComponent JavaDoc)c).getUI();
309             if (textUI instanceof BaseTextUI){
310                 ((BaseTextUI) textUI).getEditorUI().paint(g);
311             }
312         }
313
314         super.paint(g, allocation);
315     }
316     
317     public void setSize(float width, float height) {
318         super.setSize(width, height);
319
320         /* #69446 - disabled estimated span reset
321         // Schedule estimated span reset
322         if (!estimatedSpanResetInitiated && isEstimatedSpan()) {
323             estimatedSpanResetInitiated = true;
324             Timer timer = new Timer(4000, new ActionListener() {
325                 public void actionPerformed(ActionEvent evt) {
326                     AbstractDocument doc = (AbstractDocument)getDocument();
327                     if (doc!=null) {
328                         doc.readLock();
329                         try {
330                             LockView lockView = LockView.get(DrawEngineDocView.this);
331                             if (lockView != null) { // if there is no lock view no async layout is done
332                                 lockView.lock();
333                                 try {
334                                     setEstimatedSpan(false);
335                                 } finally {
336                                     lockView.unlock();
337                                 }
338                             }
339                         } finally {
340                             doc.readUnlock();
341                         }
342                     }
343                 }
344             });
345             
346             timer.setRepeats(false);
347             timer.start();
348         }
349          */

350     }
351
352     protected boolean isChildrenResizeDisabled() {
353         return true;
354     }
355     
356     public void propertyChange(java.beans.PropertyChangeEvent JavaDoc evt) {
357         JTextComponent JavaDoc component = (JTextComponent JavaDoc)getContainer();
358         if (component==null || evt==null ||
359             !EditorUI.LINE_HEIGHT_CHANGED_PROP.equals(evt.getPropertyName())) return;
360         
361         AbstractDocument JavaDoc doc = (AbstractDocument JavaDoc)getDocument();
362         if (doc!=null) {
363             doc.readLock();
364             try{
365                 LockView lockView = LockView.get(this);
366                 lockView.lock();
367                 try {
368                     rebuild(0, getViewCount());
369                 } finally {
370                     lockView.unlock();
371                 }
372             } finally {
373                 doc.readUnlock();
374             }
375         component.revalidate();
376         }
377     }
378     
379 }
380
Popular Tags