KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > editor > errorstripe > AnnotationViewDataImpl


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.modules.editor.errorstripe;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Collection JavaDoc;
27 import java.util.Collections JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.SortedMap JavaDoc;
31 import java.util.TreeMap JavaDoc;
32 import javax.swing.text.JTextComponent JavaDoc;
33 import org.netbeans.editor.AnnotationDesc;
34 import org.netbeans.editor.AnnotationType;
35 import org.netbeans.editor.AnnotationType.Severity;
36 import org.netbeans.editor.Annotations;
37 import org.netbeans.editor.BaseDocument;
38 import org.netbeans.editor.BaseKit;
39 import org.netbeans.editor.Utilities;
40 import org.netbeans.modules.editor.errorstripe.privatespi.Mark;
41 import org.netbeans.modules.editor.errorstripe.privatespi.MarkProvider;
42 import org.netbeans.modules.editor.errorstripe.privatespi.MarkProviderCreator;
43 import org.netbeans.modules.editor.errorstripe.privatespi.Status;
44 import org.netbeans.spi.editor.errorstripe.UpToDateStatus;
45 import org.netbeans.spi.editor.errorstripe.UpToDateStatusProvider;
46 import org.netbeans.spi.editor.errorstripe.UpToDateStatusProviderFactory;
47 import org.openide.ErrorManager;
48 import org.openide.filesystems.FileObject;
49 import org.openide.filesystems.Repository;
50 import org.openide.loaders.DataFolder;
51 import org.openide.loaders.DataObject;
52 import org.openide.loaders.FolderLookup;
53 import org.openide.util.Lookup;
54 import org.openide.util.Lookup.Result;
55 import org.openide.util.Lookup.Template;
56 import org.openide.util.lookup.ProxyLookup;
57 import org.netbeans.modules.editor.errorstripe.apimodule.SPIAccessor;
58
59 /**
60  *
61  * @author Jan Lahoda
62  */

63 final class AnnotationViewDataImpl implements PropertyChangeListener JavaDoc, AnnotationViewData, Annotations.AnnotationsListener {
64     
65     private static final ErrorManager ERR = AnnotationView.ERR;
66     
67     private AnnotationView view;
68     private JTextComponent JavaDoc pane;
69     private BaseDocument document;
70     
71     private List JavaDoc/*<MarkProvider>*/ providers = new ArrayList JavaDoc();
72     private List JavaDoc/*<UpToDateStatusProvider>*/ upToDateStatusProviders = new ArrayList JavaDoc();
73     
74     private List JavaDoc/*<Mark>*/ currentMarks = null;
75     private SortedMap JavaDoc/*<Mark>*/ marksMap = null;
76     
77     /** Creates a new instance of AnnotationViewData */
78     public AnnotationViewDataImpl(AnnotationView view, JTextComponent JavaDoc pane) {
79         this.view = view;
80         this.pane = pane;
81         this.document = null;
82     }
83     
84     public void register(BaseDocument document) {
85         this.document = document;
86         
87         gatherProviders(pane);
88         addListenersToProviders();
89         
90         if (document != null) {
91             document.getAnnotations().addAnnotationsListener(this);
92         }
93         
94         currentMarks = null;
95         marksMap = null;
96     }
97     
98     public void unregister() {
99         if (document != null) {
100             document.getAnnotations().removeAnnotationsListener(this);
101         }
102         
103         removeListenersFromProviders();
104         
105         document = null;
106     }
107     
108     private void gatherProviders(JTextComponent JavaDoc pane) {
109         long start = System.currentTimeMillis();
110         try {
111             BaseKit kit = Utilities.getKit(pane);
112             
113             if (kit == null)
114                 return ;
115             
116             String JavaDoc content = kit.getContentType();
117             BaseDocument document = (BaseDocument) pane.getDocument();
118             FileObject baseFolder = Repository.getDefault().getDefaultFileSystem().findResource("Editors/text/base/UpToDateStatusProvider"); // NOI18N
119
FileObject contentFolder = Repository.getDefault().getDefaultFileSystem().findResource("Editors/" + content + "/UpToDateStatusProvider"); // NOI18N
120

121             if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
122                 ERR.log(ErrorManager.INFORMATIONAL, "baseFolder = " + baseFolder );
123             }
124             
125             DataObject baseDO = baseFolder != null ? DataObject.find(baseFolder) : null;
126             
127             if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
128                 ERR.log(ErrorManager.INFORMATIONAL, "baseDO = " + baseDO );
129             }
130             
131             Lookup baseLookup = baseFolder != null ? new FolderLookup((DataFolder) baseDO).getLookup() : Lookup.EMPTY;
132             
133             if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
134                 ERR.log(ErrorManager.INFORMATIONAL, "contentFolder = " + contentFolder );
135             }
136             
137             DataObject contentDO = contentFolder != null ? DataObject.find(contentFolder) : null;
138             Lookup contentLookup = contentFolder != null ? new FolderLookup((DataFolder) contentDO).getLookup() : Lookup.EMPTY;
139             
140             Lookup lookup = new ProxyLookup(new Lookup[] {baseLookup, contentLookup});
141             
142             Result creators = lookup.lookup(new Template(MarkProviderCreator.class));
143             
144             List JavaDoc markProviders = new ArrayList JavaDoc();
145             
146             for (Iterator JavaDoc i = creators.allInstances().iterator(); i.hasNext(); ) {
147                 MarkProviderCreator creator = (MarkProviderCreator) i.next();
148                 
149                 if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
150                     ERR.log(ErrorManager.INFORMATIONAL, "creator = " + creator );
151                 }
152                 
153                 MarkProvider provider = creator.createMarkProvider(pane);
154                 
155                 if (provider != null)
156                     markProviders.add(provider);
157             }
158             
159             this.providers = markProviders;
160             
161             Result updsCreators = lookup.lookup(new Template(UpToDateStatusProviderFactory.class));
162             List JavaDoc updsProviders = new ArrayList JavaDoc();
163             
164             for (Iterator JavaDoc i = updsCreators.allInstances().iterator(); i.hasNext(); ) {
165                 UpToDateStatusProviderFactory creator = (UpToDateStatusProviderFactory) i.next();
166                 
167                 if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
168                     ERR.log(ErrorManager.INFORMATIONAL, "creator = " + creator );
169                 }
170                 
171                 UpToDateStatusProvider provider = creator.createUpToDateStatusProvider(pane.getDocument());
172                 
173                 if (provider != null)
174                     updsProviders.add(provider);
175             }
176             
177             this.upToDateStatusProviders = updsProviders;
178         } catch (IOException JavaDoc e) {
179             ErrorManager.getDefault().notify(e);
180         }
181         
182         long end = System.currentTimeMillis();
183         
184         if (AnnotationView.TIMING_ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
185             AnnotationView.TIMING_ERR.log(ErrorManager.INFORMATIONAL, "gather providers took: " + (end - start));
186         }
187     }
188     
189     private void addListenersToProviders() {
190         for (Iterator JavaDoc p = upToDateStatusProviders.iterator(); p.hasNext(); ) {
191             UpToDateStatusProvider provider = (UpToDateStatusProvider) p.next();
192             
193             SPIAccessor.getDefault().addPropertyChangeListener(provider, this);
194         }
195         
196         for (Iterator JavaDoc p = providers.iterator(); p.hasNext(); ) {
197             MarkProvider provider = (MarkProvider) p.next();
198             
199             provider.addPropertyChangeListener(this);
200         }
201     }
202
203     private void removeListenersFromProviders() {
204         for (Iterator JavaDoc p = upToDateStatusProviders.iterator(); p.hasNext(); ) {
205             UpToDateStatusProvider provider = (UpToDateStatusProvider) p.next();
206             
207             SPIAccessor.getDefault().removePropertyChangeListener(provider, this);
208         }
209         
210         for (Iterator JavaDoc p = providers.iterator(); p.hasNext(); ) {
211             MarkProvider provider = (MarkProvider) p.next();
212             
213             provider.removePropertyChangeListener(this);
214         }
215     }
216     
217     /*package private*/ static List JavaDoc/*<Mark>*/ createMergedMarks(List JavaDoc/*<MarkProvider>*/ providers) {
218         List JavaDoc result = new ArrayList JavaDoc();
219         
220         for (Iterator JavaDoc p = providers.iterator(); p.hasNext(); ) {
221             MarkProvider provider = (MarkProvider) p.next();
222             
223             result.addAll(provider.getMarks());
224         }
225         
226         return result;
227     }
228     
229     /*package private for tests*/synchronized List JavaDoc/*<Mark>*/ getMergedMarks() {
230         if (currentMarks == null) {
231             currentMarks = createMergedMarks(providers);
232         }
233         
234         return currentMarks;
235     }
236     
237     /*package private*/ static List JavaDoc/*<Mark>*/ getStatusesForLineImpl(int line, SortedMap JavaDoc marks) {
238         List JavaDoc inside = (List JavaDoc) marks.get(new Integer JavaDoc(line));
239         
240         if (inside == null)
241             return Collections.EMPTY_LIST;
242         
243         return inside;
244     }
245     
246     public Mark getMainMarkForBlock(int startLine, int endLine) {
247         Mark m1 = getMainMarkForBlockImpl(startLine, endLine, getMarkMap());
248         Mark m2 = getMainMarkForBlockAnnotations(startLine, endLine);
249         
250         if (m1 == null)
251             return m2;
252         
253         if (m2 == null)
254             return m1;
255         
256         if (isMoreImportant(m1, m2))
257             return m1;
258         else
259             return m2;
260     }
261     
262     /*package private*/ static Mark getMainMarkForBlockImpl(int startLine, int endLine, SortedMap JavaDoc marks) {
263         int current = startLine - 1;
264         Mark found = null;
265         
266         while ((current = findNextUsedLine(current, marks)) != Integer.MAX_VALUE && current <= endLine) {
267             for (Iterator JavaDoc i = getStatusesForLineImpl(/*doc, */current, marks).iterator(); i.hasNext(); ) {
268                 Mark newMark = (Mark) i.next();
269                 
270                 if (found == null || isMoreImportant(newMark, found)) {
271                     found = newMark;
272                 }
273             }
274         }
275         
276         return found;
277     }
278     
279     private static boolean isMoreImportant(Mark m1, Mark m2) {
280         int compared = m1.getStatus().compareTo(m2.getStatus());
281         
282         if (compared == 0)
283             return m1.getPriority() < m2.getPriority();
284         
285         return compared > 0;
286     }
287     
288     private boolean isMoreImportant(AnnotationDesc a1, AnnotationDesc a2) {
289         AnnotationType t1 = a1.getAnnotationTypeInstance();
290         AnnotationType t2 = a2.getAnnotationTypeInstance();
291         
292         int compared = t1.getSeverity().compareTo(t2.getSeverity());
293         
294         if (compared == 0)
295             return t1.getPriority() < t2.getPriority();
296         
297         return compared > 0;
298     }
299     
300     private boolean isValidForErrorStripe(AnnotationDesc a) {
301         return a.getAnnotationTypeInstance().getSeverity() != AnnotationType.Severity.STATUS_NONE;
302     }
303     
304     private Mark getMainMarkForBlockAnnotations(int startLine, int endLine) {
305         int line = startLine;
306         AnnotationDesc foundDesc = null;
307         Annotations annotations = document.getAnnotations();
308         
309         while ((line = annotations.getNextLineWithAnnotation(line)) <= endLine && line != (-1)) {
310             AnnotationDesc desc = annotations.getActiveAnnotation(line);
311             
312             if (desc != null) {
313                 if ((foundDesc == null || isMoreImportant(desc, foundDesc)) && isValidForErrorStripe(desc))
314                     foundDesc = desc;
315             }
316             
317             if (annotations.getNumberOfAnnotations(line) > 1) {
318                 AnnotationDesc[] descriptions = annotations.getPasiveAnnotations(line);
319                 
320                 for (int cntr = 0; cntr < descriptions.length; cntr++) {
321                     if ((foundDesc == null || isMoreImportant(descriptions[cntr], foundDesc)) && isValidForErrorStripe(descriptions[cntr]))
322                         foundDesc = descriptions[cntr];
323                 }
324             }
325             
326             line++;
327         }
328         
329         if (foundDesc != null)
330             return new AnnotationMark(foundDesc);
331         else
332             return null;
333     }
334
335     public int findNextUsedLine(int from) {
336         int line1 = findNextUsedLine(from, getMarkMap());
337         int line2 = document.getAnnotations().getNextLineWithAnnotation(from + 1);
338         
339         if (line2 == (-1))
340             line2 = Integer.MAX_VALUE;
341         
342         return line1 < line2 ? line1 : line2;
343     }
344     
345     /*package private*/ static int findNextUsedLine(int from, SortedMap JavaDoc/*<Mark>*/ marks) {
346         SortedMap JavaDoc next = marks.tailMap(new Integer JavaDoc(from + 1));
347         
348         if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
349             ERR.log("AnnotationView.findNextUsedLine from: " + from);
350             ERR.log("AnnotationView.findNextUsedLine marks: " + marks);
351             ERR.log("AnnotationView.findNextUsedLine next: " + next);
352         }
353         
354         if (next.isEmpty()) {
355             return Integer.MAX_VALUE;
356         }
357         
358         Integer JavaDoc nextLine = (Integer JavaDoc) next.firstKey();
359         
360         return nextLine.intValue();
361     }
362     
363     private void registerMark(Mark mark) {
364         int[] span = mark.getAssignedLines();
365         
366         if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
367             ERR.log("AnnotationView.registerMark mark: " + mark);
368             ERR.log("AnnotationView.registerMark lines from-to: " + span[0] + "-" + span[1]);
369         }
370         
371         for (int line = span[0]; line <= span[1]; line++) {
372             Integer JavaDoc lineInt = new Integer JavaDoc(line);
373             
374             List JavaDoc inside = (List JavaDoc) marksMap.get(lineInt);
375             
376             if (inside == null) {
377                 marksMap.put(lineInt, inside = new ArrayList JavaDoc());
378             }
379             
380             inside.add(mark);
381         }
382     }
383     
384     private void unregisterMark(Mark mark) {
385         int[] span = mark.getAssignedLines();
386         
387         if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
388             ERR.log("AnnotationView.unregisterMark mark: " + mark);
389             ERR.log("AnnotationView.unregisterMark lines from-to: " + span[0] + "-" + span[1]);
390         }
391         
392         for (int line = span[0]; line <= span[1]; line++) {
393             Integer JavaDoc lineInt = new Integer JavaDoc(line);
394             
395             List JavaDoc inside = (List JavaDoc) marksMap.get(lineInt);
396             
397             if (inside != null) {
398                 inside.remove(mark);
399                 
400                 if (inside.size() == 0) {
401                     marksMap.remove(lineInt);
402                 }
403             }
404         }
405     }
406     
407     /*package private for tests*/synchronized SortedMap JavaDoc getMarkMap() {
408         if (marksMap == null) {
409             List JavaDoc/*<Mark>*/ marks = getMergedMarks();
410             marksMap = new TreeMap JavaDoc();
411             
412             for (Iterator JavaDoc i = marks.iterator(); i.hasNext(); ) {
413                 Mark mark = (Mark) i.next();
414                 
415                 registerMark(mark);
416             }
417         }
418         
419         return marksMap;
420     }
421
422     public Status computeTotalStatus() {
423         Status targetStatus = Status.STATUS_OK;
424         Collection JavaDoc/*<Mark>*/ marks = getMergedMarks();
425         
426         for (Iterator JavaDoc m = marks.iterator(); m.hasNext(); ) {
427             Mark mark = (Mark) m.next();
428             Status s = mark.getStatus();
429             
430             targetStatus = Status.getCompoundStatus(s, targetStatus);
431         }
432
433         Annotations annotations = document.getAnnotations();
434         int line = -1;
435         
436         while ((line = annotations.getNextLineWithAnnotation(line)) != (-1)) {
437             AnnotationDesc desc = annotations.getActiveAnnotation(line);
438             
439             if (desc != null) {
440                 Status s = get(desc.getAnnotationTypeInstance());
441                 
442                 if (s != null)
443                     targetStatus = Status.getCompoundStatus(s, targetStatus);
444             }
445             
446             if (annotations.getNumberOfAnnotations(line) > 1) {
447                 AnnotationDesc[] descriptions = annotations.getPasiveAnnotations(line);
448                 
449                 for (int cntr = 0; cntr < descriptions.length; cntr++) {
450                     Status s = get(descriptions[cntr].getAnnotationTypeInstance());
451                     
452                     if (s != null)
453                         targetStatus = Status.getCompoundStatus(s, targetStatus);
454                 }
455             }
456             
457             line++;
458         }
459         
460         return targetStatus;
461     }
462     
463     public UpToDateStatus computeTotalStatusType() {
464         if (upToDateStatusProviders.isEmpty())
465             return UpToDateStatus.UP_TO_DATE_DIRTY;
466         
467         UpToDateStatus statusType = UpToDateStatus.UP_TO_DATE_OK;
468         
469         for (Iterator JavaDoc p = upToDateStatusProviders.iterator(); p.hasNext(); ) {
470             UpToDateStatusProvider provider = (UpToDateStatusProvider) p.next();
471             UpToDateStatus newType = provider.getUpToDate();
472             
473             if (newType.compareTo(statusType) > 0) {
474                 statusType = newType;
475             }
476         }
477         
478         return statusType;
479     }
480
481     public void propertyChange(PropertyChangeEvent JavaDoc evt) {
482         if ("marks".equals(evt.getPropertyName())) {
483             synchronized (this) {
484                 Collection JavaDoc nue = (Collection JavaDoc) evt.getNewValue();
485                 Collection JavaDoc old = (Collection JavaDoc) evt.getOldValue();
486                 
487                 if (nue == null && evt.getSource() instanceof MarkProvider)
488                     nue = ((MarkProvider) evt.getSource()).getMarks();
489                 
490                 if (old != null && nue != null) {
491                     List JavaDoc added = new ArrayList JavaDoc(nue);
492                     List JavaDoc removed = new ArrayList JavaDoc(old);
493                     
494                     added.removeAll(old);
495                     removed.removeAll(nue);
496                     
497                     if (marksMap != null) {
498                         for (Iterator JavaDoc i = removed.iterator(); i.hasNext(); ) {
499                             unregisterMark((Mark) i.next());
500                         }
501                         
502                         for (Iterator JavaDoc i = added.iterator(); i.hasNext(); ) {
503                             registerMark((Mark) i.next());
504                         }
505                     }
506                     
507                     if (currentMarks != null) {
508                         currentMarks.removeAll(removed);
509                         currentMarks.addAll(added);
510                     }
511                     
512                     view.fullRepaint();
513                 } else {
514                     ErrorManager.getDefault().log(ErrorManager.WARNING, "For performance reasons, the providers should fill both old and new value in property changes. Problematic event: " + evt);
515                     clear();
516                     view.fullRepaint();
517                 }
518                 return ;
519             }
520         }
521         
522         if (UpToDateStatusProvider.PROP_UP_TO_DATE.equals(evt.getPropertyName())) {
523             view.fullRepaint(false);
524             return ;
525         }
526     }
527
528     public void clear() {
529         currentMarks = null;
530         marksMap = null;
531     }
532     
533     public int[] computeErrorsAndWarnings() {
534         int errors = 0;
535         int warnings = 0;
536         Collection JavaDoc/*<Mark>*/ marks = getMergedMarks();
537         
538         for (Iterator JavaDoc m = marks.iterator(); m.hasNext(); ) {
539             Mark mark = (Mark) m.next();
540             Status s = mark.getStatus();
541             
542             errors += s == Status.STATUS_ERROR ? 1 : 0;
543             warnings += s == Status.STATUS_WARNING ? 1 : 0;
544         }
545         
546         Annotations annotations = document.getAnnotations();
547         int line = -1;
548         
549         while ((line = annotations.getNextLineWithAnnotation(line)) != (-1)) {
550             AnnotationDesc desc = annotations.getActiveAnnotation(line);
551             
552             if (desc != null) {
553                 Status s = get(desc.getAnnotationTypeInstance());
554                 
555                 if (s != null) {
556                     errors += s == Status.STATUS_ERROR ? 1 : 0;
557                     warnings += s == Status.STATUS_WARNING ? 1 : 0;
558                 }
559             }
560             
561             if (annotations.getNumberOfAnnotations(line) > 1) {
562                 AnnotationDesc[] descriptions = annotations.getPasiveAnnotations(line);
563                 
564                 for (int cntr = 0; cntr < descriptions.length; cntr++) {
565                     Status s = get(descriptions[cntr].getAnnotationTypeInstance());
566                     
567                     if (s != null) {
568                         errors += s == Status.STATUS_ERROR ? 1 : 0;
569                         warnings += s == Status.STATUS_WARNING ? 1 : 0;
570                     }
571                 }
572             }
573             
574             line++;
575         }
576         
577         return new int[] {errors, warnings};
578     }
579     
580     public void changedLine(int Line) {
581         changedAll();
582     }
583     
584     public void changedAll() {
585         view.fullRepaint(false);
586     }
587     
588     static Status get(Severity severity) {
589         if (severity == Severity.STATUS_ERROR)
590             return Status.STATUS_ERROR;
591         if (severity == Severity.STATUS_WARNING)
592             return Status.STATUS_WARNING;
593         if (severity == Severity.STATUS_OK)
594             return Status.STATUS_OK;
595         
596         return null;
597     }
598     
599     static Status get(AnnotationType ann) {
600         return get(ann.getSeverity());
601     }
602 }
603
Popular Tags