KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jface > text > source > LineChangeHover


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jface.text.source;
12
13 import java.util.Iterator JavaDoc;
14 import java.util.LinkedList JavaDoc;
15 import java.util.List JavaDoc;
16
17 import org.eclipse.swt.SWT;
18 import org.eclipse.swt.graphics.Point;
19 import org.eclipse.swt.widgets.Shell;
20
21 import org.eclipse.jface.text.DefaultInformationControl;
22 import org.eclipse.jface.text.IDocument;
23 import org.eclipse.jface.text.IInformationControl;
24 import org.eclipse.jface.text.IInformationControlCreator;
25 import org.eclipse.jface.text.information.IInformationProviderExtension2;
26
27
28 /**
29  * A hover for line oriented diffs. It determines the text to show as hover for a certain line in the
30  * document.
31  *
32  * @since 3.0
33  */

34 public class LineChangeHover implements IAnnotationHover, IAnnotationHoverExtension, IInformationProviderExtension2 {
35
36     /*
37      * @see org.eclipse.jface.text.source.IAnnotationHover#getHoverInfo(org.eclipse.jface.text.source.ISourceViewer, int)
38      */

39     public String JavaDoc getHoverInfo(ISourceViewer sourceViewer, int lineNumber) {
40         return null;
41     }
42
43     /**
44      * Formats the source w/ syntax coloring etc. This implementation replaces tabs with spaces.
45      * May be overridden by subclasses.
46      *
47      * @param content the hover content
48      * @return <code>content</code> reformatted
49      */

50     protected String JavaDoc formatSource(String JavaDoc content) {
51         if (content != null) {
52             StringBuffer JavaDoc sb= new StringBuffer JavaDoc(content);
53             final String JavaDoc tabReplacement= getTabReplacement();
54             for (int pos= 0; pos < sb.length(); pos++) {
55                 if (sb.charAt(pos) == '\t')
56                     sb.replace(pos, pos + 1, tabReplacement);
57             }
58             return sb.toString();
59         }
60         return content;
61     }
62
63     /**
64      * Returns a replacement for the tab character. The default implementation
65      * returns a tabulator character, but subclasses may override to specify a
66      * number of spaces.
67      *
68      * @return a whitespace String that will be substituted for the tabulator
69      * character
70      */

71     protected String JavaDoc getTabReplacement() {
72         return "\t"; //$NON-NLS-1$
73
}
74
75     /**
76      * Computes the content of the hover for the document contained in <code>viewer</code> on
77      * line <code>line</code>.
78      *
79      * @param viewer the connected viewer
80      * @param first the first line in <code>viewer</code>'s document to consider
81      * @param last the last line in <code>viewer</code>'s document to consider
82      * @param maxLines the max number of lines
83      * @return The hover content corresponding to the parameters
84      * @see #getHoverInfo(ISourceViewer, int)
85      * @see #getHoverInfo(ISourceViewer, ILineRange, int)
86      */

87     private String JavaDoc computeContent(ISourceViewer viewer, int first, int last, int maxLines) {
88         ILineDiffer differ= getDiffer(viewer);
89         if (differ == null)
90             return null;
91
92         final List JavaDoc lines= new LinkedList JavaDoc();
93         for (int l= first; l <= last; l++) {
94             ILineDiffInfo info= differ.getLineInfo(l);
95             if (info != null)
96                 lines.add(info);
97         }
98
99         return decorateText(lines, maxLines);
100     }
101
102     /**
103      * Takes a list of <code>ILineDiffInfo</code>s and computes a hover of at most <code>maxLines</code>.
104      * Added lines are prefixed with a <code>'+'</code>, changed lines with <code>'>'</code> and
105      * deleted lines with <code>'-'</code>.
106      * <p>Deleted and added lines can even each other out, so that a number of deleted lines get
107      * displayed where - in the current document - the added lines are.
108      *
109      * @param diffInfos a <code>List</code> of <code>ILineDiffInfo</code>
110      * @param maxLines the maximum number of lines. Note that adding up all annotations might give
111      * more than that due to deleted lines.
112      * @return a <code>String</code> suitable for hover display
113      */

114     protected String JavaDoc decorateText(List JavaDoc diffInfos, int maxLines) {
115         /* maxLines controls the size of the hover (not more than what fits into the display are of
116          * the viewer).
117          * added controls how many lines are added - added lines are
118          */

119         String JavaDoc text= ""; //$NON-NLS-1$
120
int added= 0;
121         for (Iterator JavaDoc it= diffInfos.iterator(); it.hasNext();) {
122             ILineDiffInfo info= (ILineDiffInfo)it.next();
123             String JavaDoc[] original= info.getOriginalText();
124             int type= info.getChangeType();
125             int i= 0;
126             if (type == ILineDiffInfo.ADDED)
127                 added++;
128             else if (type == ILineDiffInfo.CHANGED) {
129                 text += "> " + (original.length > 0 ? original[i++] : ""); //$NON-NLS-1$ //$NON-NLS-2$
130
maxLines--;
131             } else if (type == ILineDiffInfo.UNCHANGED) {
132                 maxLines++;
133             }
134             if (maxLines == 0)
135                 return trimTrailing(text);
136             for (; i < original.length; i++) {
137                 text += "- " + original[i]; //$NON-NLS-1$
138
added--;
139                 if (--maxLines == 0)
140                     return trimTrailing(text);
141             }
142         }
143         text= text.trim();
144         if (text.length() == 0 && added-- > 0 && maxLines-- > 0)
145             text += "+ "; //$NON-NLS-1$
146
while (added-- > 0 && maxLines-- > 0)
147             text += "\n+ "; //$NON-NLS-1$
148
return text;
149     }
150
151     /**
152      * Trims trailing spaces
153      *
154      * @param text a <code>String</code>
155      * @return a copy of <code>text</code> with trailing spaces removed
156      */

157     private String JavaDoc trimTrailing(String JavaDoc text) {
158         int pos= text.length() - 1;
159         while (pos >= 0 && Character.isWhitespace(text.charAt(pos))) {
160             pos--;
161         }
162         return text.substring(0, pos + 1);
163     }
164
165     /**
166      * Extracts the line differ - if any - from the viewer's document's annotation model.
167      * @param viewer the viewer
168      * @return a line differ for the document displayed in viewer, or <code>null</code>.
169      */

170     private ILineDiffer getDiffer(ISourceViewer viewer) {
171         IAnnotationModel model= viewer.getAnnotationModel();
172
173         if (model == null)
174             return null;
175
176         if (model instanceof IAnnotationModelExtension) {
177             IAnnotationModel diffModel= ((IAnnotationModelExtension)model).getAnnotationModel(IChangeRulerColumn.QUICK_DIFF_MODEL_ID);
178             if (diffModel != null)
179                 model= diffModel;
180         }
181         if (model instanceof ILineDiffer)
182             return (ILineDiffer)model;
183         return null;
184     }
185
186     /**
187      * Computes the block of lines which form a contiguous block of changes covering <code>line</code>.
188      *
189      * @param viewer the source viewer showing
190      * @param line the line which a hover is displayed for
191      * @param min the first line in <code>viewer</code>'s document to consider
192      * @param max the last line in <code>viewer</code>'s document to consider
193      * @return the selection in the document displayed in <code>viewer</code> containing <code>line</code>
194      * that is covered by the hover information returned by the receiver.
195      */

196     protected Point computeLineRange(ISourceViewer viewer, int line, int min, int max) {
197         /* Algorithm:
198          * All lines that have changes to themselves (added, changed) are taken that form a
199          * contiguous block of lines that includes <code>line</code>.
200          *
201          * If <code>line</code> is itself unchanged, if there is a deleted line either above or
202          * below, or both, the lines +/- 1 from <code>line</code> are included in the search as well,
203          * without applying this last rule to them, though. (I.e., if <code>line</code> is unchanged,
204          * but has a deleted line above, this one is taken in. If the line above has changes, the block
205          * is extended from there. If the line has no changes itself, the search stops).
206          *
207          * The block never extends the visible line range of the viewer.
208          */

209
210         ILineDiffer differ= getDiffer(viewer);
211         if (differ == null)
212             return new Point(-1, -1);
213
214         // backward search
215

216         int l= line;
217         ILineDiffInfo info= differ.getLineInfo(l);
218         // search backwards until a line has no changes to itself
219
while (l >= min && info != null && (info.getChangeType() == ILineDiffInfo.CHANGED || info.getChangeType() == ILineDiffInfo.ADDED)) {
220             info= differ.getLineInfo(--l);
221         }
222
223         int first= Math.min(l + 1, line);
224
225         // forward search
226

227         l= line;
228         info= differ.getLineInfo(l);
229         // search forward until a line has no changes to itself
230
while (l <= max && info != null && (info.getChangeType() == ILineDiffInfo.CHANGED || info.getChangeType() == ILineDiffInfo.ADDED)) {
231             info= differ.getLineInfo(++l);
232         }
233
234         int last= Math.max(l - 1, line);
235
236         return new Point(first, last);
237     }
238
239     /*
240      * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverInfo(org.eclipse.jface.text.source.ISourceViewer, org.eclipse.jface.text.source.ILineRange, int)
241      */

242     public Object JavaDoc getHoverInfo(ISourceViewer sourceViewer, ILineRange lineRange, int visibleLines) {
243         int first= adaptFirstLine(sourceViewer, lineRange.getStartLine());
244         int last= adaptLastLine(sourceViewer, lineRange.getStartLine() + lineRange.getNumberOfLines() - 1);
245         String JavaDoc content= computeContent(sourceViewer, first, last, visibleLines);
246         return formatSource(content);
247     }
248
249     /**
250      * Adapts the start line to the implementation of <code>ILineDiffInfo</code>.
251      *
252      * @param viewer the source viewer
253      * @param startLine the line to adapt
254      * @return <code>startLine - 1</code> if that line exists and is an
255      * unchanged line followed by deletions, <code>startLine</code>
256      * otherwise
257      */

258     private int adaptFirstLine(ISourceViewer viewer, int startLine) {
259         ILineDiffer differ= getDiffer(viewer);
260         if (differ != null && startLine > 0) {
261             int l= startLine - 1;
262             ILineDiffInfo info= differ.getLineInfo(l);
263             if (info != null && info.getChangeType() == ILineDiffInfo.UNCHANGED && info.getRemovedLinesBelow() > 0)
264                 return l;
265         }
266         return startLine;
267     }
268
269     /**
270      * Adapts the last line to the implementation of <code>ILineDiffInfo</code>.
271      *
272      * @param viewer the source viewer
273      * @param lastLine the line to adapt
274      * @return <code>lastLine - 1</code> if that line exists and is an
275      * unchanged line followed by deletions, <code>startLine</code>
276      * otherwise
277      */

278     private int adaptLastLine(ISourceViewer viewer, int lastLine) {
279         ILineDiffer differ= getDiffer(viewer);
280         if (differ != null && lastLine > 0) {
281             ILineDiffInfo info= differ.getLineInfo(lastLine);
282             if (info != null && info.getChangeType() == ILineDiffInfo.UNCHANGED)
283                 return lastLine - 1;
284         }
285         return lastLine;
286     }
287
288     /*
289      * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverLineRange(org.eclipse.jface.text.source.ISourceViewer, int)
290      */

291     public ILineRange getHoverLineRange(ISourceViewer viewer, int lineNumber) {
292         IDocument document= viewer.getDocument();
293         if (document != null) {
294             Point range= computeLineRange(viewer, lineNumber, 0, Math.max(0, document.getNumberOfLines() - 1));
295             if (range.x != -1 && range.y != -1)
296                 return new LineRange(range.x, range.y - range.x + 1);
297         }
298         return null;
299     }
300
301     /*
302      * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#canHandleMouseCursor()
303      */

304     public boolean canHandleMouseCursor() {
305         return false;
306     }
307
308     /*
309      * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverControlCreator()
310      */

311     public IInformationControlCreator getHoverControlCreator() {
312         return null;
313     }
314
315     /*
316      * @see org.eclipse.jface.text.information.IInformationProviderExtension2#getInformationPresenterControlCreator()
317      * @since 3.2
318      */

319     public IInformationControlCreator getInformationPresenterControlCreator() {
320         return new IInformationControlCreator() {
321             public IInformationControl createInformationControl(Shell parent) {
322                 int shellStyle= SWT.RESIZE | SWT.TOOL;
323                 int style= SWT.V_SCROLL | SWT.H_SCROLL;
324                 return new DefaultInformationControl(parent, shellStyle, style, null);
325             }
326         };
327     }
328 }
329
Popular Tags