1 /*******************************************************************************
2  * Copyright (c) 2000, 2015 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.jface.text.source;
15 
16 import org.eclipse.swt.events.MouseEvent;
17 import org.eclipse.swt.graphics.Color;
18 import org.eclipse.swt.graphics.GC;
19 import org.eclipse.swt.widgets.Composite;
20 import org.eclipse.swt.widgets.Control;
21 
22 import org.eclipse.core.runtime.Assert;
23 
24 import org.eclipse.jface.internal.text.revisions.RevisionPainter;
25 import org.eclipse.jface.internal.text.source.DiffPainter;
26 import org.eclipse.jface.viewers.ISelectionProvider;
27 
28 import org.eclipse.jface.text.revisions.IRevisionListener;
29 import org.eclipse.jface.text.revisions.IRevisionRulerColumn;
30 import org.eclipse.jface.text.revisions.IRevisionRulerColumnExtension;
31 import org.eclipse.jface.text.revisions.RevisionInformation;
32 
33 /**
34  * A vertical ruler column displaying line numbers and serving as a UI for quick diff. Clients
35  * usually instantiate and configure object of this class.
36  *
37  * @since 3.0
38  * @noextend This class is not intended to be subclassed by clients.
39  */
40 public class LineNumberChangeRulerColumn extends LineNumberRulerColumn implements IChangeRulerColumn, IRevisionRulerColumn, IRevisionRulerColumnExtension {
41 	/** The ruler's annotation model. */
42 	private IAnnotationModel fAnnotationModel;
43 	/** <code>true</code> if changes should be displayed using character indications instead of background colors. */
44 	private boolean fCharacterDisplay;
45 	/**
46 	 * The revision painter strategy.
47 	 *
48 	 * @since 3.2
49 	 */
50 	private final RevisionPainter fRevisionPainter;
51 	/**
52 	 * The diff information painter strategy.
53 	 *
54 	 * @since 3.2
55 	 */
56 	private final DiffPainter fDiffPainter;
57 	/**
58 	 * Whether to show number or to behave like a change ruler column.
59 	 * @since 3.3
60 	 */
61 	private boolean fShowNumbers= true;
62 
63 	/**
64 	 * Creates a new instance.
65 	 *
66 	 * @param sharedColors the shared colors provider to use
67 	 */
LineNumberChangeRulerColumn(ISharedTextColors sharedColors)68 	public LineNumberChangeRulerColumn(ISharedTextColors sharedColors) {
69 		Assert.isNotNull(sharedColors);
70 		fRevisionPainter= new RevisionPainter(this, sharedColors);
71 		fDiffPainter= new DiffPainter(this, sharedColors);
72 	}
73 
74 	@Override
createControl(CompositeRuler parentRuler, Composite parentControl)75 	public Control createControl(CompositeRuler parentRuler, Composite parentControl) {
76 		Control control= super.createControl(parentRuler, parentControl);
77 		fRevisionPainter.setParentRuler(parentRuler);
78 		fDiffPainter.setParentRuler(parentRuler);
79 		return control;
80 	}
81 
82 	@Override
getLineOfLastMouseButtonActivity()83 	public int getLineOfLastMouseButtonActivity() {
84 		return getParentRuler().getLineOfLastMouseButtonActivity();
85 	}
86 
87 	@Override
toDocumentLineNumber(int y_coordinate)88 	public int toDocumentLineNumber(int y_coordinate) {
89 		return getParentRuler().toDocumentLineNumber(y_coordinate);
90 	}
91 
92 	@Override
setModel(IAnnotationModel model)93 	public void setModel(IAnnotationModel model) {
94 		setAnnotationModel(model);
95 		fRevisionPainter.setModel(model);
96 		fDiffPainter.setModel(model);
97 		updateNumberOfDigits();
98 		computeIndentations();
99 		layout(true);
100 		postRedraw();
101 	}
102 
setAnnotationModel(IAnnotationModel model)103 	private void setAnnotationModel(IAnnotationModel model) {
104 		if (fAnnotationModel != model)
105 			fAnnotationModel= model;
106 	}
107 
108 
109 	/**
110 	 * Sets the display mode of the ruler. If character mode is set to <code>true</code>, diff
111 	 * information will be displayed textually on the line number ruler.
112 	 *
113 	 * @param characterMode <code>true</code> if diff information is to be displayed textually.
114 	 */
setDisplayMode(boolean characterMode)115 	public void setDisplayMode(boolean characterMode) {
116 		if (characterMode != fCharacterDisplay) {
117 			fCharacterDisplay= characterMode;
118 			updateNumberOfDigits();
119 			computeIndentations();
120 			layout(true);
121 		}
122 	}
123 
124 	@Override
getModel()125 	public IAnnotationModel getModel() {
126 		return fAnnotationModel;
127 	}
128 
129 	@Override
createDisplayString(int line)130 	protected String createDisplayString(int line) {
131 		StringBuilder buffer= new StringBuilder();
132 		if (fShowNumbers)
133 			buffer.append(super.createDisplayString(line));
134 		if (fCharacterDisplay && getModel() != null)
135 			buffer.append(fDiffPainter.getDisplayCharacter(line));
136 		return buffer.toString();
137 	}
138 
139 	@Override
computeNumberOfDigits()140 	protected int computeNumberOfDigits() {
141 		int digits;
142 		if (fCharacterDisplay && getModel() != null) {
143 			if (fShowNumbers)
144 				digits= super.computeNumberOfDigits() + 1;
145 			else
146 				digits= 1;
147 		} else {
148 			if (fShowNumbers)
149 				digits= super.computeNumberOfDigits();
150 			else
151 				digits= 0;
152 		}
153 		if (fRevisionPainter.hasInformation())
154 			digits+= fRevisionPainter.getRequiredWidth();
155 		return digits;
156 	}
157 
158 	@Override
addVerticalRulerListener(IVerticalRulerListener listener)159 	public void addVerticalRulerListener(IVerticalRulerListener listener) {
160 		throw new UnsupportedOperationException();
161 	}
162 
163 	@Override
removeVerticalRulerListener(IVerticalRulerListener listener)164 	public void removeVerticalRulerListener(IVerticalRulerListener listener) {
165 		throw new UnsupportedOperationException();
166 	}
167 
168 	@Override
doPaint(GC gc, ILineRange visibleLines)169 	void doPaint(GC gc, ILineRange visibleLines) {
170 		Color foreground= gc.getForeground();
171 		if (visibleLines != null) {
172 			if (fRevisionPainter.hasInformation()) {
173 				fRevisionPainter.paint(gc, visibleLines);
174 			} else if (fDiffPainter.hasInformation()) { // don't paint quick diff colors if revisions are painted
175 				fDiffPainter.paint(gc, visibleLines);
176 			}
177 		}
178 		gc.setForeground(foreground);
179 		if (fShowNumbers || fCharacterDisplay)
180 			super.doPaint(gc, visibleLines);
181 	}
182 
183 	@Override
getHover()184 	public IAnnotationHover getHover() {
185 		int activeLine= getParentRuler().getLineOfLastMouseButtonActivity();
186 		if (fRevisionPainter.hasHover(activeLine))
187 			return fRevisionPainter.getHover();
188 		if (fDiffPainter.hasHover(activeLine))
189 			return fDiffPainter.getHover();
190 		return null;
191 	}
192 
193 	@Override
setHover(IAnnotationHover hover)194 	public void setHover(IAnnotationHover hover) {
195 		fRevisionPainter.setHover(hover);
196 		fDiffPainter.setHover(hover);
197 	}
198 
199 	@Override
setBackground(Color background)200 	public void setBackground(Color background) {
201 		super.setBackground(background);
202 		fRevisionPainter.setBackground(background);
203 		fDiffPainter.setBackground(background);
204 	}
205 
206 	@Override
setAddedColor(Color addedColor)207 	public void setAddedColor(Color addedColor) {
208 		fDiffPainter.setAddedColor(addedColor);
209 	}
210 
211 	@Override
setChangedColor(Color changedColor)212 	public void setChangedColor(Color changedColor) {
213 		fDiffPainter.setChangedColor(changedColor);
214 	}
215 
216 	@Override
setDeletedColor(Color deletedColor)217 	public void setDeletedColor(Color deletedColor) {
218 		fDiffPainter.setDeletedColor(deletedColor);
219 	}
220 
221 	@Override
setRevisionInformation(RevisionInformation info)222 	public void setRevisionInformation(RevisionInformation info) {
223 		fRevisionPainter.setRevisionInformation(info);
224 		updateNumberOfDigits();
225 		computeIndentations();
226 		layout(true);
227 		postRedraw();
228 	}
229 
230 	@Override
getRevisionSelectionProvider()231 	public ISelectionProvider getRevisionSelectionProvider() {
232 		return fRevisionPainter.getRevisionSelectionProvider();
233 	}
234 
235 	/*
236 	 * @see org.eclipse.jface.text.revisions.IRevisionRulerColumnExtension#setRenderingMode(org.eclipse.jface.text.revisions.IRevisionRulerColumnExtension.RenderingMode)
237 	 * @since 3.3
238 	 */
239 	@Override
setRevisionRenderingMode(RenderingMode renderingMode)240 	public void setRevisionRenderingMode(RenderingMode renderingMode) {
241 		fRevisionPainter.setRenderingMode(renderingMode);
242 	}
243 
244 	/**
245 	 * Sets the line number display mode.
246 	 *
247 	 * @param showNumbers <code>true</code> to show numbers, <code>false</code> to only show
248 	 *        diff / revision info.
249 	 * @since 3.3
250 	 */
showLineNumbers(boolean showNumbers)251 	public void showLineNumbers(boolean showNumbers) {
252 		if (fShowNumbers != showNumbers) {
253 			fShowNumbers= showNumbers;
254 			updateNumberOfDigits();
255 			computeIndentations();
256 			layout(true);
257 		}
258 	}
259 
260 	@Override
getWidth()261 	public int getWidth() {
262 		int width= super.getWidth();
263 		return width > 0 ? width : 8; // minimal width to display quick diff / revisions if no textual info is shown
264 	}
265 
266 	/**
267 	 * Returns <code>true</code> if the ruler is showing line numbers, <code>false</code>
268 	 * otherwise
269 	 *
270 	 * @return <code>true</code> if line numbers are shown, <code>false</code> otherwise
271 	 * @since 3.3
272 	 */
isShowingLineNumbers()273 	public boolean isShowingLineNumbers() {
274 		return fShowNumbers;
275 	}
276 
277 	/**
278 	 * Returns <code>true</code> if the ruler is showing revision information, <code>false</code>
279 	 * otherwise
280 	 *
281 	 * @return <code>true</code> if revision information is shown, <code>false</code> otherwise
282 	 * @since 3.3
283 	 */
isShowingRevisionInformation()284 	public boolean isShowingRevisionInformation() {
285 		return fRevisionPainter.hasInformation();
286 	}
287 
288 	/**
289 	 * Returns <code>true</code> if the ruler is showing change information, <code>false</code>
290 	 * otherwise
291 	 *
292 	 * @return <code>true</code> if change information is shown, <code>false</code> otherwise
293 	 * @since 3.3
294 	 */
isShowingChangeInformation()295 	public boolean isShowingChangeInformation() {
296 		return fDiffPainter.hasInformation();
297 	}
298 
299 	@Override
showRevisionAuthor(boolean show)300 	public void showRevisionAuthor(boolean show) {
301 		fRevisionPainter.showRevisionAuthor(show);
302 		updateNumberOfDigits();
303 		computeIndentations();
304 		layout(true);
305 		postRedraw();
306 	}
307 
308 	@Override
showRevisionId(boolean show)309 	public void showRevisionId(boolean show) {
310 		fRevisionPainter.showRevisionId(show);
311 		updateNumberOfDigits();
312 		computeIndentations();
313 		layout(true);
314 		postRedraw();
315 	}
316 
317 	@Override
addRevisionListener(IRevisionListener listener)318 	public void addRevisionListener(IRevisionListener listener) {
319 		fRevisionPainter.addRevisionListener(listener);
320 	}
321 
322 	@Override
removeRevisionListener(IRevisionListener listener)323 	public void removeRevisionListener(IRevisionListener listener) {
324 		fRevisionPainter.removeRevisionListener(listener);
325 	}
326 
327 	@Override
handleDispose()328 	protected void handleDispose() {
329 		fRevisionPainter.setParentRuler(null);
330 		fRevisionPainter.setModel(null);
331 		fDiffPainter.setParentRuler(null);
332 		fDiffPainter.setModel(null);
333 		super.handleDispose();
334 	}
335 
336 	@Override
handleMouseScrolled(MouseEvent e)337 	void handleMouseScrolled(MouseEvent e) {
338 		if (fRevisionPainter.isWheelHandlerInstalled()) {
339 			return; // scroll event is already handled; don't interfere
340 		}
341 		super.handleMouseScrolled(e);
342 	}
343 }
344