Mercurial > projects > dwt-addons
comparison dwtx/jface/text/source/LineChangeHover.d @ 129:eb30df5ca28b
Added JFace Text sources
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 23 Aug 2008 19:10:48 +0200 |
parents | |
children | c4fb132a086c |
comparison
equal
deleted
inserted
replaced
128:8df1d4193877 | 129:eb30df5ca28b |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2000, 2008 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 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module dwtx.jface.text.source.LineChangeHover; | |
14 | |
15 import dwt.dwthelper.utils; | |
16 | |
17 import java.util.Iterator; | |
18 import java.util.LinkedList; | |
19 import java.util.List; | |
20 | |
21 import dwt.graphics.Point; | |
22 import dwt.widgets.Shell; | |
23 import dwtx.jface.action.ToolBarManager; | |
24 import dwtx.jface.text.DefaultInformationControl; | |
25 import dwtx.jface.text.IDocument; | |
26 import dwtx.jface.text.IInformationControl; | |
27 import dwtx.jface.text.IInformationControlCreator; | |
28 import dwtx.jface.text.information.IInformationProviderExtension2; | |
29 | |
30 | |
31 /** | |
32 * A hover for line oriented diffs. It determines the text to show as hover for a certain line in the | |
33 * document. | |
34 * | |
35 * @since 3.0 | |
36 */ | |
37 public class LineChangeHover : IAnnotationHover, IAnnotationHoverExtension, IInformationProviderExtension2 { | |
38 | |
39 /* | |
40 * @see dwtx.jface.text.source.IAnnotationHover#getHoverInfo(dwtx.jface.text.source.ISourceViewer, int) | |
41 */ | |
42 public String getHoverInfo(ISourceViewer sourceViewer, int lineNumber) { | |
43 return null; | |
44 } | |
45 | |
46 /** | |
47 * Formats the source w/ syntax coloring etc. This implementation replaces tabs with spaces. | |
48 * May be overridden by subclasses. | |
49 * | |
50 * @param content the hover content | |
51 * @return <code>content</code> reformatted | |
52 */ | |
53 protected String formatSource(String content) { | |
54 if (content !is null) { | |
55 StringBuffer sb= new StringBuffer(content); | |
56 final String tabReplacement= getTabReplacement(); | |
57 for (int pos= 0; pos < sb.length(); pos++) { | |
58 if (sb.charAt(pos) is '\t') | |
59 sb.replace(pos, pos + 1, tabReplacement); | |
60 } | |
61 return sb.toString(); | |
62 } | |
63 return content; | |
64 } | |
65 | |
66 /** | |
67 * Returns a replacement for the tab character. The default implementation | |
68 * returns a tabulator character, but subclasses may override to specify a | |
69 * number of spaces. | |
70 * | |
71 * @return a whitespace String that will be substituted for the tabulator | |
72 * character | |
73 */ | |
74 protected String getTabReplacement() { | |
75 return "\t"; //$NON-NLS-1$ | |
76 } | |
77 | |
78 /** | |
79 * Computes the content of the hover for the document contained in <code>viewer</code> on | |
80 * line <code>line</code>. | |
81 * | |
82 * @param viewer the connected viewer | |
83 * @param first the first line in <code>viewer</code>'s document to consider | |
84 * @param last the last line in <code>viewer</code>'s document to consider | |
85 * @param maxLines the max number of lines | |
86 * @return The hover content corresponding to the parameters | |
87 * @see #getHoverInfo(ISourceViewer, int) | |
88 * @see #getHoverInfo(ISourceViewer, ILineRange, int) | |
89 */ | |
90 private String computeContent(ISourceViewer viewer, int first, int last, int maxLines) { | |
91 ILineDiffer differ= getDiffer(viewer); | |
92 if (differ is null) | |
93 return null; | |
94 | |
95 final List lines= new LinkedList(); | |
96 for (int l= first; l <= last; l++) { | |
97 ILineDiffInfo info= differ.getLineInfo(l); | |
98 if (info !is null) | |
99 lines.add(info); | |
100 } | |
101 | |
102 return decorateText(lines, maxLines); | |
103 } | |
104 | |
105 /** | |
106 * Takes a list of <code>ILineDiffInfo</code>s and computes a hover of at most <code>maxLines</code>. | |
107 * Added lines are prefixed with a <code>'+'</code>, changed lines with <code>'>'</code> and | |
108 * deleted lines with <code>'-'</code>. | |
109 * <p>Deleted and added lines can even each other out, so that a number of deleted lines get | |
110 * displayed where - in the current document - the added lines are. | |
111 * | |
112 * @param diffInfos a <code>List</code> of <code>ILineDiffInfo</code> | |
113 * @param maxLines the maximum number of lines. Note that adding up all annotations might give | |
114 * more than that due to deleted lines. | |
115 * @return a <code>String</code> suitable for hover display | |
116 */ | |
117 protected String decorateText(List diffInfos, int maxLines) { | |
118 /* maxLines controls the size of the hover (not more than what fits into the display are of | |
119 * the viewer). | |
120 * added controls how many lines are added - added lines are | |
121 */ | |
122 String text= ""; //$NON-NLS-1$ | |
123 int added= 0; | |
124 for (Iterator it= diffInfos.iterator(); it.hasNext();) { | |
125 ILineDiffInfo info= (ILineDiffInfo)it.next(); | |
126 String[] original= info.getOriginalText(); | |
127 int type= info.getChangeType(); | |
128 int i= 0; | |
129 if (type is ILineDiffInfo.ADDED) | |
130 added++; | |
131 else if (type is ILineDiffInfo.CHANGED) { | |
132 text += "> " + (original.length > 0 ? original[i++] : ""); //$NON-NLS-1$ //$NON-NLS-2$ | |
133 maxLines--; | |
134 } else if (type is ILineDiffInfo.UNCHANGED) { | |
135 maxLines++; | |
136 } | |
137 if (maxLines is 0) | |
138 return trimTrailing(text); | |
139 for (; i < original.length; i++) { | |
140 text += "- " + original[i]; //$NON-NLS-1$ | |
141 added--; | |
142 if (--maxLines is 0) | |
143 return trimTrailing(text); | |
144 } | |
145 } | |
146 text= text.trim(); | |
147 if (text.length() is 0 && added-- > 0 && maxLines-- > 0) | |
148 text += "+ "; //$NON-NLS-1$ | |
149 while (added-- > 0 && maxLines-- > 0) | |
150 text += "\n+ "; //$NON-NLS-1$ | |
151 return text; | |
152 } | |
153 | |
154 /** | |
155 * Trims trailing spaces | |
156 * | |
157 * @param text a <code>String</code> | |
158 * @return a copy of <code>text</code> with trailing spaces removed | |
159 */ | |
160 private String trimTrailing(String text) { | |
161 int pos= text.length() - 1; | |
162 while (pos >= 0 && Character.isWhitespace(text.charAt(pos))) { | |
163 pos--; | |
164 } | |
165 return text.substring(0, pos + 1); | |
166 } | |
167 | |
168 /** | |
169 * Extracts the line differ - if any - from the viewer's document's annotation model. | |
170 * @param viewer the viewer | |
171 * @return a line differ for the document displayed in viewer, or <code>null</code>. | |
172 */ | |
173 private ILineDiffer getDiffer(ISourceViewer viewer) { | |
174 IAnnotationModel model= viewer.getAnnotationModel(); | |
175 | |
176 if (model is null) | |
177 return null; | |
178 | |
179 if (model instanceof IAnnotationModelExtension) { | |
180 IAnnotationModel diffModel= ((IAnnotationModelExtension)model).getAnnotationModel(IChangeRulerColumn.QUICK_DIFF_MODEL_ID); | |
181 if (diffModel !is null) | |
182 model= diffModel; | |
183 } | |
184 if (model instanceof ILineDiffer) { | |
185 if (model instanceof ILineDifferExtension2 && ((ILineDifferExtension2)model).isSuspended()) | |
186 return null; | |
187 return (ILineDiffer)model; | |
188 } | |
189 return null; | |
190 } | |
191 | |
192 /** | |
193 * Computes the block of lines which form a contiguous block of changes covering <code>line</code>. | |
194 * | |
195 * @param viewer the source viewer showing | |
196 * @param line the line which a hover is displayed for | |
197 * @param min the first line in <code>viewer</code>'s document to consider | |
198 * @param max the last line in <code>viewer</code>'s document to consider | |
199 * @return the selection in the document displayed in <code>viewer</code> containing <code>line</code> | |
200 * that is covered by the hover information returned by the receiver. | |
201 */ | |
202 protected Point computeLineRange(ISourceViewer viewer, int line, int min, int max) { | |
203 /* Algorithm: | |
204 * All lines that have changes to themselves (added, changed) are taken that form a | |
205 * contiguous block of lines that includes <code>line</code>. | |
206 * | |
207 * If <code>line</code> is itself unchanged, if there is a deleted line either above or | |
208 * below, or both, the lines +/- 1 from <code>line</code> are included in the search as well, | |
209 * without applying this last rule to them, though. (I.e., if <code>line</code> is unchanged, | |
210 * but has a deleted line above, this one is taken in. If the line above has changes, the block | |
211 * is extended from there. If the line has no changes itself, the search stops). | |
212 * | |
213 * The block never extends the visible line range of the viewer. | |
214 */ | |
215 | |
216 ILineDiffer differ= getDiffer(viewer); | |
217 if (differ is null) | |
218 return new Point(-1, -1); | |
219 | |
220 // backward search | |
221 | |
222 int l= line; | |
223 ILineDiffInfo info= differ.getLineInfo(l); | |
224 // search backwards until a line has no changes to itself | |
225 while (l >= min && info !is null && (info.getChangeType() is ILineDiffInfo.CHANGED || info.getChangeType() is ILineDiffInfo.ADDED)) { | |
226 info= differ.getLineInfo(--l); | |
227 } | |
228 | |
229 int first= Math.min(l + 1, line); | |
230 | |
231 // forward search | |
232 | |
233 l= line; | |
234 info= differ.getLineInfo(l); | |
235 // search forward until a line has no changes to itself | |
236 while (l <= max && info !is null && (info.getChangeType() is ILineDiffInfo.CHANGED || info.getChangeType() is ILineDiffInfo.ADDED)) { | |
237 info= differ.getLineInfo(++l); | |
238 } | |
239 | |
240 int last= Math.max(l - 1, line); | |
241 | |
242 return new Point(first, last); | |
243 } | |
244 | |
245 /* | |
246 * @see dwtx.jface.text.source.IAnnotationHoverExtension#getHoverInfo(dwtx.jface.text.source.ISourceViewer, dwtx.jface.text.source.ILineRange, int) | |
247 */ | |
248 public Object getHoverInfo(ISourceViewer sourceViewer, ILineRange lineRange, int visibleLines) { | |
249 int first= adaptFirstLine(sourceViewer, lineRange.getStartLine()); | |
250 int last= adaptLastLine(sourceViewer, lineRange.getStartLine() + lineRange.getNumberOfLines() - 1); | |
251 String content= computeContent(sourceViewer, first, last, visibleLines); | |
252 return formatSource(content); | |
253 } | |
254 | |
255 /** | |
256 * Adapts the start line to the implementation of <code>ILineDiffInfo</code>. | |
257 * | |
258 * @param viewer the source viewer | |
259 * @param startLine the line to adapt | |
260 * @return <code>startLine - 1</code> if that line exists and is an | |
261 * unchanged line followed by deletions, <code>startLine</code> | |
262 * otherwise | |
263 */ | |
264 private int adaptFirstLine(ISourceViewer viewer, int startLine) { | |
265 ILineDiffer differ= getDiffer(viewer); | |
266 if (differ !is null && startLine > 0) { | |
267 int l= startLine - 1; | |
268 ILineDiffInfo info= differ.getLineInfo(l); | |
269 if (info !is null && info.getChangeType() is ILineDiffInfo.UNCHANGED && info.getRemovedLinesBelow() > 0) | |
270 return l; | |
271 } | |
272 return startLine; | |
273 } | |
274 | |
275 /** | |
276 * Adapts the last line to the implementation of <code>ILineDiffInfo</code>. | |
277 * | |
278 * @param viewer the source viewer | |
279 * @param lastLine the line to adapt | |
280 * @return <code>lastLine - 1</code> if that line exists and is an | |
281 * unchanged line followed by deletions, <code>startLine</code> | |
282 * otherwise | |
283 */ | |
284 private int adaptLastLine(ISourceViewer viewer, int lastLine) { | |
285 ILineDiffer differ= getDiffer(viewer); | |
286 if (differ !is null && lastLine > 0) { | |
287 ILineDiffInfo info= differ.getLineInfo(lastLine); | |
288 if (info !is null && info.getChangeType() is ILineDiffInfo.UNCHANGED) | |
289 return lastLine - 1; | |
290 } | |
291 return lastLine; | |
292 } | |
293 | |
294 /* | |
295 * @see dwtx.jface.text.source.IAnnotationHoverExtension#getHoverLineRange(dwtx.jface.text.source.ISourceViewer, int) | |
296 */ | |
297 public ILineRange getHoverLineRange(ISourceViewer viewer, int lineNumber) { | |
298 IDocument document= viewer.getDocument(); | |
299 if (document !is null) { | |
300 Point range= computeLineRange(viewer, lineNumber, 0, Math.max(0, document.getNumberOfLines() - 1)); | |
301 if (range.x !is -1 && range.y !is -1) | |
302 return new LineRange(range.x, range.y - range.x + 1); | |
303 } | |
304 return null; | |
305 } | |
306 | |
307 /* | |
308 * @see dwtx.jface.text.source.IAnnotationHoverExtension#canHandleMouseCursor() | |
309 */ | |
310 public bool canHandleMouseCursor() { | |
311 return false; | |
312 } | |
313 | |
314 /* | |
315 * @see dwtx.jface.text.source.IAnnotationHoverExtension#getHoverControlCreator() | |
316 */ | |
317 public IInformationControlCreator getHoverControlCreator() { | |
318 return null; | |
319 } | |
320 | |
321 /* | |
322 * @see dwtx.jface.text.information.IInformationProviderExtension2#getInformationPresenterControlCreator() | |
323 * @since 3.2 | |
324 */ | |
325 public IInformationControlCreator getInformationPresenterControlCreator() { | |
326 return new IInformationControlCreator() { | |
327 public IInformationControl createInformationControl(Shell parent) { | |
328 return new DefaultInformationControl(parent, (ToolBarManager)null, null); | |
329 } | |
330 }; | |
331 } | |
332 } |