KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > rice > cs > util > swing > HighlightManager


1 /*BEGIN_COPYRIGHT_BLOCK
2  *
3  * This file is part of DrJava. Download the current version of this project from http://www.drjava.org/
4  * or http://sourceforge.net/projects/drjava/
5  *
6  * DrJava Open Source License
7  *
8  * Copyright (C) 2001-2006 JavaPLT group at Rice University (javaplt@rice.edu). All rights reserved.
9  *
10  * Developed by: Java Programming Languages Team, Rice University, http://www.cs.rice.edu/~javaplt/
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13  * documentation files (the "Software"), to deal with the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15  * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16  *
17  * - Redistributions of source code must retain the above copyright notice, this list of conditions and the
18  * following disclaimers.
19  * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
20  * following disclaimers in the documentation and/or other materials provided with the distribution.
21  * - Neither the names of DrJava, the JavaPLT, Rice University, nor the names of its contributors may be used to
22  * endorse or promote products derived from this Software without specific prior written permission.
23  * - Products derived from this software may not be called "DrJava" nor use the term "DrJava" as part of their
24  * names without prior written permission from the JavaPLT group. For permission, write to javaplt@rice.edu.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
27  * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * WITH THE SOFTWARE.
31  *
32  *END_COPYRIGHT_BLOCK*/

33
34 package edu.rice.cs.util.swing;
35
36 import java.util.Stack JavaDoc;
37 import java.util.Vector JavaDoc;
38
39 import javax.swing.text.JTextComponent JavaDoc;
40 import javax.swing.text.Highlighter JavaDoc;
41 import javax.swing.text.BadLocationException JavaDoc;
42 import javax.swing.text.Position JavaDoc;
43
44 import edu.rice.cs.util.UnexpectedException;
45
46 /** This class has synchronized public methods because it is accessed outside of the event thread. */
47 public class HighlightManager {
48
49     //private Hashtable<HighlightPosition, Stack<HighlightInfo>> _highlights;
50

51   /** An unsorted Vector of Stack<HighlightInfo>, each of which corresponds to a unique
52     * region in the document. All HighlightInfo objects within a given stack must correspond
53     * to the same region but must have unique Highlighter.HighlightPainters.
54     * Each stack is ordered so the most recent highlight is at the top.
55     */

56     private Vector JavaDoc<Stack JavaDoc<HighlightInfo>> _highlights;
57
58     /** The component necessary for creating positions in in the document, which is also
59      * contained within this component.
60      */

61     private JTextComponent JavaDoc _component;
62
63     /** Constructor
64      * @param jtc the component whose document will have positions created therein.
65      */

66     public HighlightManager(JTextComponent JavaDoc jtc) {
67       _component = jtc;
68       _highlights = new Vector JavaDoc<Stack JavaDoc<HighlightInfo>>();
69     }
70     
71     /** Overrides to toString() to support unit testing */
72
73     public String JavaDoc toString() { return "HighLightManager(" + _highlights + ")"; }
74     
75     /** Size of highlight stack; used only for unit testing */
76     
77     public int size() { return _highlights.size(); }
78
79     /** Adds a highlight using the supplied painter to the vector element(Stack) that exactly corresponds to the
80      * specified bounds. The most recently added highlights over a given range appear on top of the older highlights.
81      * All highlights in a given range(Stack) must be unique, that is, each must use a different painter--redundant
82      * highlights are shifted to the top of the stack, but not added twice.
83      * @param startOffset the offset at which the highlight is to begin.
84      * @param endOffset the offset at which the highlight is to end.
85      * @param p the Highlighter.HighlightPainter for painting
86      * @return HighlightInfo the HighlightInfo object, for keeping a tag of a given highlight
87      */

88     public synchronized HighlightInfo addHighlight(int startOffset, int endOffset, Highlighter.HighlightPainter JavaDoc p) {
89
90       HighlightInfo newLite = new HighlightInfo(startOffset,endOffset,p);
91
92 // Utilities.showDebug("Adding highlight from "+startOffset+" to "+endOffset);
93
Stack JavaDoc<HighlightInfo> lineStack = _getStackAt(newLite);
94
95       if (lineStack != null) {
96         int searchResult = lineStack.search(newLite);
97         if (searchResult == 1) return lineStack.peek();
98         if (searchResult > 1) {
99           lineStack.remove(newLite);
100         }
101       }
102       else {
103         //add a new Stack to the empty place in the hashtable
104
lineStack = new Stack JavaDoc<HighlightInfo>();
105         _highlights.add(lineStack);
106       }
107
108       try {
109         Object JavaDoc highlightTag = _component.getHighlighter().addHighlight(startOffset,endOffset,p);
110         newLite.setHighlightTag(highlightTag);
111         lineStack.push(newLite);
112         return newLite;
113       }
114       catch (BadLocationException JavaDoc ble) {
115         //if adding a highlight failed, remove any empty stack
116
if (lineStack.isEmpty()) {
117           _highlights.remove(lineStack);
118         }
119         throw new UnexpectedException(ble);
120       }
121     }
122
123     /**
124      * Returning the Stack corresponding to the given region in the document, or null
125      * if there is none. Requires every Stack in the vector to have a unique region.
126      * @param h the descriptor for the desired region.
127      * @return the corresponding Stack, or null
128      */

129     private Stack JavaDoc<HighlightInfo> _getStackAt (HighlightInfo h) {
130
131       for (Stack JavaDoc<HighlightInfo> stack : _highlights) {
132         if (stack.get(0).matchesRegion(h)) {
133           return stack;
134         }
135       }
136       //if here, no corresponding stack, so return null
137
return null;
138     }
139
140     /**
141      * Convenience method for removing a highlight with the specified start/end offsets and the given
142      * painter.
143      * @param startOffset the offset at which the desired highlight should start.
144      * @param endOffset the offset at which the desired highlight shoud end.
145      * @param p the Highlighter.HighlightPainter for painting
146      */

147     public synchronized void removeHighlight(int startOffset, int endOffset, Highlighter.HighlightPainter JavaDoc p) {
148       HighlightInfo newLite = new HighlightInfo(startOffset,endOffset,p);
149       removeHighlight(newLite);
150     }
151
152     /**
153      * Removes a given highlight (HighlightInfo) from the highlighter
154      * @param newLite the HighlightInfo object corresponding to the highlight needed to be removed
155      */

156     public void removeHighlight (HighlightInfo newLite) {
157
158
159 // int startOffset = newLite.getStartOffset();
160
// int endOffset = newLite.getEndOffset();
161

162       Stack JavaDoc<HighlightInfo> lineStack = _getStackAt(newLite);
163
164       if (lineStack== null) {
165         //System.out.println("Error! No stack to access in region from " + startOffset+ " to "+ endOffset);
166
return;
167       }
168
169       int searchResult = lineStack.search(newLite);
170       //System.out.println("searchResult: "+searchResult);
171

172       if (searchResult == 1) {
173         HighlightInfo liteToRemove = lineStack.pop();
174         _component.getHighlighter().removeHighlight(liteToRemove.getHighlightTag());
175         //System.out.println("Removed highlight @ "+startOffset);
176
}
177       else if (searchResult > 1) {
178         //System.out.println("Removing old instance...");
179
lineStack.remove(newLite);
180         _component.getHighlighter().removeHighlight(newLite.getHighlightTag());
181       }
182
183       if (lineStack.isEmpty()) {
184         //System.out.println("Removing empty stack...");
185
//remove the lineStack
186
_highlights.remove(lineStack);
187       }
188
189     }
190
191     /** The public inner class defining a "smart" highlight, which can return the value of its start and end
192      * offsets for comparison with other highlights. Also keeps a tag to its actual highlight in the
193      * component's highlighter for easy removal.
194      */

195     public class HighlightInfo {
196       private Object JavaDoc _highlightTag;
197       private Position JavaDoc _startPos;
198       private Position JavaDoc _endPos;
199       private Highlighter.HighlightPainter JavaDoc _painter;
200
201       /** Constructor takes the bounds and the painter for a highlighter
202        * @param from the offset at which the new highlight will start.
203        * @param to the offset at which the new highlight will end.
204        * @param p the Highlighter.HighlightPainter for painting
205        */

206       public HighlightInfo(int from, int to, Highlighter.HighlightPainter JavaDoc p) {
207
208         _highlightTag = null;
209         try {
210           _startPos = _component.getDocument().createPosition(from);
211           _endPos = _component.getDocument().createPosition(to);
212         }
213         catch (BadLocationException JavaDoc ble) {
214           throw new UnexpectedException(ble);
215         }
216
217         _painter = p;
218       }
219
220       /** Set the highlight tag for later access to the highlight as it is stored in the components highlighter.
221        * @param highlightTag the Object for keeping track of a stored highlight
222        */

223       public void setHighlightTag ( Object JavaDoc highlightTag) { _highlightTag = highlightTag; }
224
225       /** Tests equivalency of one HighlightInfo object with this HighlightInfo object. Compares start
226        * and end offsets, and the Highlighter.HighlightPainter -- returns true, if they are the same in both.
227        * @param o the other HighlightInfo object to compare to this one.
228        * @return boolean true, if equivalent; false otherwise.
229        */

230       public boolean equals( Object JavaDoc o) {
231         
232         if (o == null) return false;
233
234         if (o instanceof HighlightInfo) {
235
236           HighlightInfo obj = (HighlightInfo)o;
237           /*
238            //System.out.println("p0: "+p0+" obj.p0: "+obj.p0);
239            //System.out.println("p1: "+p1+" obj.p1: "+obj.p1);
240            //System.out.println("p: "+p+" obj.p: "+obj.p);
241            */

242           boolean result = getStartOffset() == obj.getStartOffset() &&
243             getEndOffset() == obj.getEndOffset() &&
244             getPainter() == obj.getPainter();
245
246           //System.out.println("HighlightInfo.equals() = "+result);
247
return result;
248         }
249         else return false;
250       }
251       
252       /** Overrides hashCode() for consistency with override of equals(...) */
253       public int hashCode() { return getPainter().hashCode() ^ getStartOffset() ^ getEndOffset(); }
254
255       public void remove() { removeHighlight(this); }
256
257       /** Accessor for the highlight tag
258        * @return the highlight tag which might be null
259        */

260       public Object JavaDoc getHighlightTag() { return _highlightTag; }
261
262       /** Accessor for the painter
263        * @return the painter
264        */

265       public Highlighter.HighlightPainter JavaDoc getPainter() { return _painter; }
266
267       /** Accessor for the starting offset of this highlight
268        * @return the start offset
269        */

270       public int getStartOffset() { return _startPos.getOffset(); }
271
272       /** Accessor for the ending offset of this highlight
273        * @return the end offset
274        */

275       public int getEndOffset() { return _endPos.getOffset(); }
276
277       /** Tests to see if the given offsets correspond to the offsets specified within this highlight.
278        * @param h a HighlightInfo object given the start and end offsets
279        * @return true, if the supplied offsets are the same as those of this highlight.
280        */

281       public boolean matchesRegion(HighlightInfo h) {
282         return (getStartOffset() == h.getStartOffset() && getEndOffset() == h.getEndOffset());
283       }
284       
285       /** Refreshes this HighlightInfo object, obtaining a new Highlighter. */
286       public void refresh (Highlighter.HighlightPainter JavaDoc p ) {
287
288         this.remove();
289         HighlightInfo newHighlight = addHighlight(getStartOffset(), getEndOffset(), p);
290         
291         _painter = p;
292         // turn this HighlightInfo object into the newHighlight
293
_highlightTag = newHighlight.getHighlightTag();
294       }
295     }
296 }
297
Popular Tags