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 | *******************************************************************************/ |
---|
11 | package org.modelica.mdt.ui.hover; |
---|
12 | |
---|
13 | import java.util.ArrayList; |
---|
14 | import java.util.Iterator; |
---|
15 | import java.util.List; |
---|
16 | |
---|
17 | import org.eclipse.swt.SWT; |
---|
18 | import org.eclipse.swt.custom.StyleRange; |
---|
19 | import org.eclipse.swt.custom.StyledText; |
---|
20 | import org.eclipse.swt.events.DisposeEvent; |
---|
21 | import org.eclipse.swt.events.DisposeListener; |
---|
22 | import org.eclipse.swt.events.FocusListener; |
---|
23 | import org.eclipse.swt.events.MenuEvent; |
---|
24 | import org.eclipse.swt.events.MenuListener; |
---|
25 | import org.eclipse.swt.events.MouseAdapter; |
---|
26 | import org.eclipse.swt.events.MouseEvent; |
---|
27 | import org.eclipse.swt.events.MouseTrackAdapter; |
---|
28 | import org.eclipse.swt.events.MouseTrackListener; |
---|
29 | import org.eclipse.swt.events.PaintEvent; |
---|
30 | import org.eclipse.swt.events.PaintListener; |
---|
31 | import org.eclipse.swt.graphics.Color; |
---|
32 | import org.eclipse.swt.graphics.Cursor; |
---|
33 | import org.eclipse.swt.graphics.Point; |
---|
34 | import org.eclipse.swt.graphics.Rectangle; |
---|
35 | import org.eclipse.swt.layout.GridData; |
---|
36 | import org.eclipse.swt.layout.GridLayout; |
---|
37 | import org.eclipse.swt.widgets.Canvas; |
---|
38 | import org.eclipse.swt.widgets.Composite; |
---|
39 | import org.eclipse.swt.widgets.Control; |
---|
40 | import org.eclipse.swt.widgets.Display; |
---|
41 | import org.eclipse.swt.widgets.Event; |
---|
42 | import org.eclipse.swt.widgets.Layout; |
---|
43 | import org.eclipse.swt.widgets.Listener; |
---|
44 | import org.eclipse.swt.widgets.Menu; |
---|
45 | import org.eclipse.swt.widgets.Shell; |
---|
46 | import org.eclipse.swt.widgets.Widget; |
---|
47 | |
---|
48 | import org.eclipse.jface.viewers.IDoubleClickListener; |
---|
49 | |
---|
50 | import org.eclipse.jface.text.AbstractInformationControlManager; |
---|
51 | import org.eclipse.jface.text.DefaultInformationControl; |
---|
52 | import org.eclipse.jface.text.IInformationControl; |
---|
53 | import org.eclipse.jface.text.IInformationControlCreator; |
---|
54 | import org.eclipse.jface.text.IInformationControlExtension; |
---|
55 | import org.eclipse.jface.text.IInformationControlExtension2; |
---|
56 | import org.eclipse.jface.text.IInformationControlExtension5; |
---|
57 | import org.eclipse.jface.text.IRegion; |
---|
58 | import org.eclipse.jface.text.IViewportListener; |
---|
59 | import org.eclipse.jface.text.Position; |
---|
60 | import org.eclipse.jface.text.Region; |
---|
61 | import org.eclipse.jface.text.TextViewer; |
---|
62 | import org.eclipse.jface.text.source.Annotation; |
---|
63 | import org.eclipse.jface.text.source.IAnnotationAccess; |
---|
64 | import org.eclipse.jface.text.source.IAnnotationAccessExtension; |
---|
65 | import org.eclipse.jface.text.source.IAnnotationModel; |
---|
66 | import org.eclipse.jface.text.source.ISourceViewer; |
---|
67 | import org.eclipse.jface.text.source.IVerticalRulerInfo; |
---|
68 | import org.eclipse.jface.text.source.IVerticalRulerListener; |
---|
69 | import org.eclipse.jface.text.source.VerticalRulerEvent; |
---|
70 | |
---|
71 | |
---|
72 | /** |
---|
73 | * A control that can display a number of annotations. The control can decide how it layouts the |
---|
74 | * annotations to present them to the user. |
---|
75 | * <p> |
---|
76 | * This class got moved here form Platform Text since it was not used there |
---|
77 | * and caused discouraged access warnings. It will be moved down again once |
---|
78 | * annotation roll-over support is provided by Platform Text. |
---|
79 | * </p> |
---|
80 | * <p>Each annotation can have its custom context menu and hover.</p> |
---|
81 | * |
---|
82 | * @since 3.2 |
---|
83 | */ |
---|
84 | public class AnnotationExpansionControl implements IInformationControl, IInformationControlExtension, IInformationControlExtension2, IInformationControlExtension5 { |
---|
85 | |
---|
86 | |
---|
87 | public interface ICallback { |
---|
88 | void run(IInformationControlExtension2 control); |
---|
89 | } |
---|
90 | |
---|
91 | /** |
---|
92 | * Input used by the control to display the annotations. |
---|
93 | * TODO move to top-level class |
---|
94 | * TODO encapsulate fields |
---|
95 | * |
---|
96 | * @since 3.0 |
---|
97 | */ |
---|
98 | public static class AnnotationHoverInput { |
---|
99 | public Annotation[] fAnnotations; |
---|
100 | public ISourceViewer fViewer; |
---|
101 | public IVerticalRulerInfo fRulerInfo; |
---|
102 | public IVerticalRulerListener fAnnotationListener; |
---|
103 | public IDoubleClickListener fDoubleClickListener; |
---|
104 | public ICallback redoAction; |
---|
105 | public IAnnotationModel model; |
---|
106 | } |
---|
107 | |
---|
108 | private final class Item { |
---|
109 | Annotation fAnnotation; |
---|
110 | Canvas canvas; |
---|
111 | StyleRange[] oldStyles; |
---|
112 | |
---|
113 | public void selected() { |
---|
114 | Display disp= fShell.getDisplay(); |
---|
115 | canvas.setCursor(fHandCursor); |
---|
116 | // TODO: shade - for now: set grey background |
---|
117 | canvas.setBackground(getSelectionColor(disp)); |
---|
118 | |
---|
119 | // highlight the viewer background at its position |
---|
120 | oldStyles= setViewerBackground(fAnnotation); |
---|
121 | |
---|
122 | // set the selection |
---|
123 | fSelection= this; |
---|
124 | |
---|
125 | if (fHoverManager != null) |
---|
126 | fHoverManager.showInformation(); |
---|
127 | |
---|
128 | if (fInput.fAnnotationListener != null) { |
---|
129 | VerticalRulerEvent event= new VerticalRulerEvent(fAnnotation); |
---|
130 | fInput.fAnnotationListener.annotationSelected(event); |
---|
131 | } |
---|
132 | |
---|
133 | } |
---|
134 | |
---|
135 | public void defaultSelected() { |
---|
136 | if (fInput.fAnnotationListener != null) { |
---|
137 | VerticalRulerEvent event= new VerticalRulerEvent(fAnnotation); |
---|
138 | fInput.fAnnotationListener.annotationDefaultSelected(event); |
---|
139 | } |
---|
140 | |
---|
141 | dispose(); |
---|
142 | } |
---|
143 | |
---|
144 | public void showContextMenu(Menu menu) { |
---|
145 | if (fInput.fAnnotationListener != null) { |
---|
146 | VerticalRulerEvent event= new VerticalRulerEvent(fAnnotation); |
---|
147 | fInput.fAnnotationListener.annotationContextMenuAboutToShow(event, menu); |
---|
148 | } |
---|
149 | } |
---|
150 | |
---|
151 | public void deselect() { |
---|
152 | // hide the popup |
---|
153 | // fHoverManager.disposeInformationControl(); |
---|
154 | |
---|
155 | // deselect |
---|
156 | fSelection= null; |
---|
157 | |
---|
158 | resetViewerBackground(oldStyles); |
---|
159 | oldStyles= null; |
---|
160 | |
---|
161 | Display disp= fShell.getDisplay(); |
---|
162 | canvas.setCursor(null); |
---|
163 | // TODO: remove shading - for now: set standard background |
---|
164 | canvas.setBackground(disp.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); |
---|
165 | |
---|
166 | } |
---|
167 | |
---|
168 | } |
---|
169 | |
---|
170 | /** |
---|
171 | * Disposes of an item |
---|
172 | */ |
---|
173 | private final static class MyDisposeListener implements DisposeListener { |
---|
174 | /* |
---|
175 | * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent) |
---|
176 | */ |
---|
177 | public void widgetDisposed(DisposeEvent e) { |
---|
178 | Item item= (Item) ((Widget) e.getSource()).getData(); |
---|
179 | item.deselect(); |
---|
180 | item.canvas= null; |
---|
181 | item.fAnnotation= null; |
---|
182 | item.oldStyles= null; |
---|
183 | |
---|
184 | ((Widget) e.getSource()).setData(null); |
---|
185 | } |
---|
186 | } |
---|
187 | |
---|
188 | /** |
---|
189 | * Listener on context menu invocation on the items |
---|
190 | */ |
---|
191 | private final class MyMenuDetectListener implements Listener { |
---|
192 | /* |
---|
193 | * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event) |
---|
194 | */ |
---|
195 | public void handleEvent(Event event) { |
---|
196 | if (event.type == SWT.MenuDetect) { |
---|
197 | // TODO: show per-item menu |
---|
198 | // for now: show ruler context menu |
---|
199 | if (fInput != null) { |
---|
200 | Control ruler= fInput.fRulerInfo.getControl(); |
---|
201 | if (ruler != null && !ruler.isDisposed()) { |
---|
202 | Menu menu= ruler.getMenu(); |
---|
203 | if (menu != null && !menu.isDisposed()) { |
---|
204 | menu.setLocation(event.x, event.y); |
---|
205 | menu.addMenuListener(new MenuListener() { |
---|
206 | |
---|
207 | public void menuHidden(MenuEvent e) { |
---|
208 | dispose(); |
---|
209 | } |
---|
210 | |
---|
211 | public void menuShown(MenuEvent e) { |
---|
212 | } |
---|
213 | |
---|
214 | }); |
---|
215 | menu.setVisible(true); |
---|
216 | } |
---|
217 | } |
---|
218 | } |
---|
219 | } |
---|
220 | } |
---|
221 | } |
---|
222 | |
---|
223 | |
---|
224 | /** |
---|
225 | * Listener on mouse events on the items. |
---|
226 | */ |
---|
227 | private final class MyMouseListener extends MouseAdapter { |
---|
228 | /* |
---|
229 | * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) |
---|
230 | */ |
---|
231 | public void mouseDoubleClick(MouseEvent e) { |
---|
232 | Item item= (Item) ((Widget) e.getSource()).getData(); |
---|
233 | if (e.button == 1 && item.fAnnotation == fInput.fAnnotations[0] && fInput.fDoubleClickListener != null) { |
---|
234 | fInput.fDoubleClickListener.doubleClick(null); |
---|
235 | // special code for JDT to renew the annotation set. |
---|
236 | if (fInput.redoAction != null) |
---|
237 | fInput.redoAction.run(AnnotationExpansionControl.this); |
---|
238 | } |
---|
239 | // dispose(); |
---|
240 | // TODO special action to invoke double-click action on the vertical ruler |
---|
241 | // how about |
---|
242 | // Canvas can= (Canvas) e.getSource(); |
---|
243 | // Annotation a= (Annotation) can.getData(); |
---|
244 | // if (a != null) { |
---|
245 | // a.getDoubleClickAction().run(); |
---|
246 | // } |
---|
247 | } |
---|
248 | |
---|
249 | /* |
---|
250 | * Using mouseDown as mouseUp isn't fired on some Platforms, for |
---|
251 | * details see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=165533 |
---|
252 | * |
---|
253 | * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent) |
---|
254 | */ |
---|
255 | public void mouseDown(MouseEvent e) { |
---|
256 | Item item= (Item) ((Widget) e.getSource()).getData(); |
---|
257 | // TODO for now, to make double click work: disable single click on the first item |
---|
258 | // disable later when the annotationlistener selectively handles input |
---|
259 | if (item != null && e.button == 1) // && item.fAnnotation != fInput.fAnnotations[0]) |
---|
260 | item.defaultSelected(); |
---|
261 | } |
---|
262 | |
---|
263 | } |
---|
264 | |
---|
265 | /** |
---|
266 | * Listener on mouse track events on the items. |
---|
267 | */ |
---|
268 | private final class MyMouseTrackListener implements MouseTrackListener { |
---|
269 | /* |
---|
270 | * @see org.eclipse.swt.events.MouseTrackListener#mouseEnter(org.eclipse.swt.events.MouseEvent) |
---|
271 | */ |
---|
272 | public void mouseEnter(MouseEvent e) { |
---|
273 | Item item= (Item) ((Widget) e.getSource()).getData(); |
---|
274 | if (item != null) |
---|
275 | item.selected(); |
---|
276 | } |
---|
277 | |
---|
278 | /* |
---|
279 | * @see org.eclipse.swt.events.MouseTrackListener#mouseExit(org.eclipse.swt.events.MouseEvent) |
---|
280 | */ |
---|
281 | public void mouseExit(MouseEvent e) { |
---|
282 | |
---|
283 | Item item= (Item) ((Widget) e.getSource()).getData(); |
---|
284 | if (item != null) |
---|
285 | item.deselect(); |
---|
286 | |
---|
287 | // if the event lies outside the entire popup, dispose |
---|
288 | org.eclipse.swt.graphics.Region region= fShell.getRegion(); |
---|
289 | Canvas can= (Canvas) e.getSource(); |
---|
290 | Point p= can.toDisplay(e.x, e.y); |
---|
291 | if (region == null) { |
---|
292 | Rectangle bounds= fShell.getBounds(); |
---|
293 | // p= fShell.toControl(p); |
---|
294 | if (!bounds.contains(p)) |
---|
295 | dispose(); |
---|
296 | } else { |
---|
297 | p= fShell.toControl(p); |
---|
298 | if (!region.contains(p)) |
---|
299 | dispose(); |
---|
300 | } |
---|
301 | |
---|
302 | |
---|
303 | } |
---|
304 | |
---|
305 | /* |
---|
306 | * @see org.eclipse.swt.events.MouseTrackListener#mouseHover(org.eclipse.swt.events.MouseEvent) |
---|
307 | */ |
---|
308 | public void mouseHover(MouseEvent e) { |
---|
309 | if (fHoverManager == null) { |
---|
310 | fHoverManager= new HoverManager(); |
---|
311 | fHoverManager.takesFocusWhenVisible(false); |
---|
312 | fHoverManager.install(fComposite); |
---|
313 | fHoverManager.showInformation(); |
---|
314 | } |
---|
315 | } |
---|
316 | } |
---|
317 | |
---|
318 | |
---|
319 | /** |
---|
320 | * @since 3.0 |
---|
321 | */ |
---|
322 | public class LinearLayouter { |
---|
323 | |
---|
324 | private static final int ANNOTATION_SIZE= 14; |
---|
325 | private static final int BORDER_WIDTH= 2; |
---|
326 | |
---|
327 | public Layout getLayout(int itemCount) { |
---|
328 | // simple layout: a row of items |
---|
329 | GridLayout layout= new GridLayout(itemCount, true); |
---|
330 | layout.horizontalSpacing= 1; |
---|
331 | layout.verticalSpacing= 0; |
---|
332 | layout.marginHeight= 1; |
---|
333 | layout.marginWidth= 1; |
---|
334 | return layout; |
---|
335 | } |
---|
336 | |
---|
337 | public Object getLayoutData() { |
---|
338 | GridData gridData= new GridData(ANNOTATION_SIZE + 2 * BORDER_WIDTH, ANNOTATION_SIZE + 2 * BORDER_WIDTH); |
---|
339 | gridData.horizontalAlignment= GridData.CENTER; |
---|
340 | gridData.verticalAlignment= GridData.CENTER; |
---|
341 | return gridData; |
---|
342 | } |
---|
343 | |
---|
344 | public int getAnnotationSize() { |
---|
345 | return ANNOTATION_SIZE; |
---|
346 | } |
---|
347 | |
---|
348 | public int getBorderWidth() { |
---|
349 | return BORDER_WIDTH; |
---|
350 | } |
---|
351 | |
---|
352 | /** |
---|
353 | * Gets the shell region for the given number of items. |
---|
354 | * |
---|
355 | * @param itemCount the item count |
---|
356 | * @return the shell region |
---|
357 | */ |
---|
358 | public org.eclipse.swt.graphics.Region getShellRegion(int itemCount) { |
---|
359 | // no special region - set to null for default shell size |
---|
360 | return null; |
---|
361 | } |
---|
362 | |
---|
363 | } |
---|
364 | |
---|
365 | |
---|
366 | /** |
---|
367 | * Listener on paint events on the items. Paints the annotation image on the given <code>GC</code>. |
---|
368 | */ |
---|
369 | private final class MyPaintListener implements PaintListener { |
---|
370 | /* |
---|
371 | * @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent) |
---|
372 | */ |
---|
373 | public void paintControl(PaintEvent e) { |
---|
374 | Canvas can= (Canvas) e.getSource(); |
---|
375 | Annotation a= ((Item) can.getData()).fAnnotation; |
---|
376 | if (a != null) { |
---|
377 | Rectangle rect= new Rectangle(fLayouter.getBorderWidth(), fLayouter.getBorderWidth(), fLayouter.getAnnotationSize(), fLayouter.getAnnotationSize()); |
---|
378 | if (fAnnotationAccessExtension != null) |
---|
379 | fAnnotationAccessExtension.paint(a, e.gc, can, rect); |
---|
380 | } |
---|
381 | } |
---|
382 | } |
---|
383 | |
---|
384 | /** |
---|
385 | * Our own private hover manager used to shop per-item pop-ups. |
---|
386 | */ |
---|
387 | private final class HoverManager extends AbstractInformationControlManager { |
---|
388 | |
---|
389 | /** |
---|
390 | * |
---|
391 | */ |
---|
392 | public HoverManager() { |
---|
393 | super(new IInformationControlCreator() { |
---|
394 | public IInformationControl createInformationControl(Shell parent) { |
---|
395 | return new DefaultInformationControl(parent); |
---|
396 | } |
---|
397 | }); |
---|
398 | |
---|
399 | setMargins(5, 10); |
---|
400 | setAnchor(ANCHOR_BOTTOM); |
---|
401 | setFallbackAnchors(new Anchor[] {ANCHOR_BOTTOM, ANCHOR_LEFT, ANCHOR_RIGHT} ); |
---|
402 | } |
---|
403 | |
---|
404 | /* |
---|
405 | * @see org.eclipse.jface.text.AbstractInformationControlManager#computeInformation() |
---|
406 | */ |
---|
407 | protected void computeInformation() { |
---|
408 | if (fSelection != null) { |
---|
409 | Rectangle subjectArea= fSelection.canvas.getBounds(); |
---|
410 | Annotation annotation= fSelection.fAnnotation; |
---|
411 | String msg; |
---|
412 | if (annotation != null) |
---|
413 | msg= annotation.getText(); |
---|
414 | else |
---|
415 | msg= null; |
---|
416 | |
---|
417 | setInformation(msg, subjectArea); |
---|
418 | } |
---|
419 | } |
---|
420 | |
---|
421 | |
---|
422 | } |
---|
423 | |
---|
424 | /** Model data. */ |
---|
425 | protected AnnotationHoverInput fInput; |
---|
426 | /** The control's shell */ |
---|
427 | private Shell fShell; |
---|
428 | /** The composite combining all the items. */ |
---|
429 | protected Composite fComposite; |
---|
430 | /** The hand cursor. */ |
---|
431 | private Cursor fHandCursor; |
---|
432 | /** The currently selected item, or <code>null</code> if none is selected. */ |
---|
433 | private Item fSelection; |
---|
434 | /** The hover manager for the per-item hovers. */ |
---|
435 | private HoverManager fHoverManager; |
---|
436 | /** The annotation access extension. */ |
---|
437 | private IAnnotationAccessExtension fAnnotationAccessExtension; |
---|
438 | |
---|
439 | |
---|
440 | /* listener legion */ |
---|
441 | private final MyPaintListener fPaintListener; |
---|
442 | private final MyMouseTrackListener fMouseTrackListener; |
---|
443 | private final MyMouseListener fMouseListener; |
---|
444 | private final MyMenuDetectListener fMenuDetectListener; |
---|
445 | private final DisposeListener fDisposeListener; |
---|
446 | private final IViewportListener fViewportListener; |
---|
447 | |
---|
448 | private LinearLayouter fLayouter; |
---|
449 | |
---|
450 | /** |
---|
451 | * Creates a new control. |
---|
452 | * |
---|
453 | * @param parent |
---|
454 | * @param shellStyle |
---|
455 | * @param access |
---|
456 | */ |
---|
457 | public AnnotationExpansionControl(Shell parent, int shellStyle, IAnnotationAccess access) { |
---|
458 | fPaintListener= new MyPaintListener(); |
---|
459 | fMouseTrackListener= new MyMouseTrackListener(); |
---|
460 | fMouseListener= new MyMouseListener(); |
---|
461 | fMenuDetectListener= new MyMenuDetectListener(); |
---|
462 | fDisposeListener= new MyDisposeListener(); |
---|
463 | fViewportListener= new IViewportListener() { |
---|
464 | |
---|
465 | public void viewportChanged(int verticalOffset) { |
---|
466 | dispose(); |
---|
467 | } |
---|
468 | |
---|
469 | }; |
---|
470 | fLayouter= new LinearLayouter(); |
---|
471 | |
---|
472 | if (access instanceof IAnnotationAccessExtension) |
---|
473 | fAnnotationAccessExtension= (IAnnotationAccessExtension) access; |
---|
474 | |
---|
475 | fShell= new Shell(parent, shellStyle | SWT.NO_FOCUS | SWT.ON_TOP); |
---|
476 | Display display= fShell.getDisplay(); |
---|
477 | fShell.setBackground(display.getSystemColor(SWT.COLOR_BLACK)); |
---|
478 | fComposite= new Composite(fShell, SWT.NO_FOCUS | SWT.NO_REDRAW_RESIZE | SWT.NO_TRIM); |
---|
479 | // fComposite= new Composite(fShell, SWT.NO_FOCUS | SWT.NO_REDRAW_RESIZE | SWT.NO_TRIM | SWT.V_SCROLL); |
---|
480 | |
---|
481 | GridLayout layout= new GridLayout(1, true); |
---|
482 | layout.marginHeight= 0; |
---|
483 | layout.marginWidth= 0; |
---|
484 | fShell.setLayout(layout); |
---|
485 | |
---|
486 | GridData data= new GridData(GridData.FILL_BOTH); |
---|
487 | data.heightHint= fLayouter.getAnnotationSize() + 2 * fLayouter.getBorderWidth() + 4; |
---|
488 | fComposite.setLayoutData(data); |
---|
489 | fComposite.addMouseTrackListener(new MouseTrackAdapter() { |
---|
490 | |
---|
491 | public void mouseExit(MouseEvent e) { |
---|
492 | if (fComposite == null) |
---|
493 | return; |
---|
494 | Control[] children= fComposite.getChildren(); |
---|
495 | Rectangle bounds= null; |
---|
496 | for (int i= 0; i < children.length; i++) { |
---|
497 | if (bounds == null) |
---|
498 | bounds= children[i].getBounds(); |
---|
499 | else |
---|
500 | bounds.add(children[i].getBounds()); |
---|
501 | if (bounds.contains(e.x, e.y)) |
---|
502 | return; |
---|
503 | } |
---|
504 | |
---|
505 | // if none of the children contains the event, we leave the popup |
---|
506 | dispose(); |
---|
507 | } |
---|
508 | |
---|
509 | }); |
---|
510 | |
---|
511 | // fComposite.getVerticalBar().addListener(SWT.Selection, new Listener() { |
---|
512 | // |
---|
513 | // public void handleEvent(Event event) { |
---|
514 | // Rectangle bounds= fShell.getBounds(); |
---|
515 | // int x= bounds.x - fLayouter.getAnnotationSize() - fLayouter.getBorderWidth(); |
---|
516 | // int y= bounds.y; |
---|
517 | // fShell.setBounds(x, y, bounds.width, bounds.height); |
---|
518 | // } |
---|
519 | // |
---|
520 | // }); |
---|
521 | |
---|
522 | fHandCursor= new Cursor(display, SWT.CURSOR_HAND); |
---|
523 | fShell.setCursor(fHandCursor); |
---|
524 | fComposite.setCursor(fHandCursor); |
---|
525 | |
---|
526 | setInfoSystemColor(); |
---|
527 | } |
---|
528 | |
---|
529 | private void setInfoSystemColor() { |
---|
530 | Display display= fShell.getDisplay(); |
---|
531 | setForegroundColor(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND)); |
---|
532 | setBackgroundColor(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); |
---|
533 | } |
---|
534 | |
---|
535 | /* |
---|
536 | * @see org.eclipse.jface.text.IInformationControl#setInformation(java.lang.String) |
---|
537 | */ |
---|
538 | public void setInformation(String information) { |
---|
539 | setInput(null); |
---|
540 | } |
---|
541 | |
---|
542 | |
---|
543 | /* |
---|
544 | * @see org.eclipse.jface.text.IInformationControlExtension2#setInput(java.lang.Object) |
---|
545 | */ |
---|
546 | public void setInput(Object input) { |
---|
547 | if (fInput != null && fInput.fViewer != null) |
---|
548 | fInput.fViewer.removeViewportListener(fViewportListener); |
---|
549 | |
---|
550 | if (input instanceof AnnotationHoverInput) |
---|
551 | fInput= (AnnotationHoverInput) input; |
---|
552 | else |
---|
553 | fInput= null; |
---|
554 | |
---|
555 | inputChanged(fInput, null); |
---|
556 | } |
---|
557 | |
---|
558 | /** |
---|
559 | * Internal hook method called when the input is |
---|
560 | * initially set or subsequently changed. |
---|
561 | * |
---|
562 | * @param newInput the new input |
---|
563 | * @param newSelection the new selection |
---|
564 | */ |
---|
565 | protected void inputChanged(Object newInput, Object newSelection) { |
---|
566 | refresh(); |
---|
567 | } |
---|
568 | |
---|
569 | protected void refresh() { |
---|
570 | adjustItemNumber(); |
---|
571 | |
---|
572 | if (fInput == null) |
---|
573 | return; |
---|
574 | |
---|
575 | if (fInput.fAnnotations == null) |
---|
576 | return; |
---|
577 | |
---|
578 | if (fInput.fViewer != null) |
---|
579 | fInput.fViewer.addViewportListener(fViewportListener); |
---|
580 | |
---|
581 | fShell.setRegion(fLayouter.getShellRegion(fInput.fAnnotations.length)); |
---|
582 | |
---|
583 | Layout layout= fLayouter.getLayout(fInput.fAnnotations.length); |
---|
584 | fComposite.setLayout(layout); |
---|
585 | |
---|
586 | Control[] children= fComposite.getChildren(); |
---|
587 | for (int i= 0; i < fInput.fAnnotations.length; i++) { |
---|
588 | Canvas canvas= (Canvas) children[i]; |
---|
589 | Item item= new Item(); |
---|
590 | item.canvas= canvas; |
---|
591 | item.fAnnotation= fInput.fAnnotations[i]; |
---|
592 | canvas.setData(item); |
---|
593 | canvas.redraw(); |
---|
594 | } |
---|
595 | |
---|
596 | } |
---|
597 | |
---|
598 | protected void adjustItemNumber() { |
---|
599 | if (fComposite == null) |
---|
600 | return; |
---|
601 | |
---|
602 | Control[] children= fComposite.getChildren(); |
---|
603 | int oldSize= children.length; |
---|
604 | int newSize= fInput == null ? 0 : fInput.fAnnotations.length; |
---|
605 | |
---|
606 | Display display= fShell.getDisplay(); |
---|
607 | |
---|
608 | // add missing items |
---|
609 | for (int i= oldSize; i < newSize; i++) { |
---|
610 | Canvas canvas= new Canvas(fComposite, SWT.NONE); |
---|
611 | Object gridData= fLayouter.getLayoutData(); |
---|
612 | canvas.setLayoutData(gridData); |
---|
613 | canvas.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); |
---|
614 | |
---|
615 | canvas.addPaintListener(fPaintListener); |
---|
616 | |
---|
617 | canvas.addMouseTrackListener(fMouseTrackListener); |
---|
618 | |
---|
619 | canvas.addMouseListener(fMouseListener); |
---|
620 | |
---|
621 | canvas.addListener(SWT.MenuDetect, fMenuDetectListener); |
---|
622 | |
---|
623 | canvas.addDisposeListener(fDisposeListener); |
---|
624 | } |
---|
625 | |
---|
626 | // dispose of exceeding resources |
---|
627 | for (int i= oldSize; i > newSize; i--) { |
---|
628 | Item item= (Item) children[i - 1].getData(); |
---|
629 | item.deselect(); |
---|
630 | children[i - 1].dispose(); |
---|
631 | } |
---|
632 | |
---|
633 | } |
---|
634 | |
---|
635 | /* |
---|
636 | * @see IInformationControl#setVisible(boolean) |
---|
637 | */ |
---|
638 | public void setVisible(boolean visible) { |
---|
639 | fShell.setVisible(visible); |
---|
640 | } |
---|
641 | |
---|
642 | /* |
---|
643 | * @see IInformationControl#dispose() |
---|
644 | */ |
---|
645 | public void dispose() { |
---|
646 | if (fShell != null) { |
---|
647 | if (!fShell.isDisposed()) |
---|
648 | fShell.dispose(); |
---|
649 | fShell= null; |
---|
650 | fComposite= null; |
---|
651 | if (fHandCursor != null) |
---|
652 | fHandCursor.dispose(); |
---|
653 | fHandCursor= null; |
---|
654 | if (fHoverManager != null) |
---|
655 | fHoverManager.dispose(); |
---|
656 | fHoverManager= null; |
---|
657 | fSelection= null; |
---|
658 | } |
---|
659 | } |
---|
660 | |
---|
661 | /* |
---|
662 | * @see org.eclipse.jface.text.IInformationControlExtension#hasContents() |
---|
663 | */ |
---|
664 | public boolean hasContents() { |
---|
665 | return fInput.fAnnotations != null && fInput.fAnnotations.length > 0; |
---|
666 | } |
---|
667 | |
---|
668 | /* |
---|
669 | * @see org.eclipse.jface.text.IInformationControl#setSizeConstraints(int, int) |
---|
670 | */ |
---|
671 | public void setSizeConstraints(int maxWidth, int maxHeight) { |
---|
672 | //fMaxWidth= maxWidth; |
---|
673 | //fMaxHeight= maxHeight; |
---|
674 | } |
---|
675 | |
---|
676 | /* |
---|
677 | * @see org.eclipse.jface.text.IInformationControl#computeSizeHint() |
---|
678 | */ |
---|
679 | public Point computeSizeHint() { |
---|
680 | return fShell.computeSize(SWT.DEFAULT, SWT.DEFAULT); |
---|
681 | } |
---|
682 | |
---|
683 | /* |
---|
684 | * @see IInformationControl#setLocation(Point) |
---|
685 | */ |
---|
686 | public void setLocation(Point location) { |
---|
687 | fShell.setLocation(location); |
---|
688 | } |
---|
689 | |
---|
690 | /* |
---|
691 | * @see IInformationControl#setSize(int, int) |
---|
692 | */ |
---|
693 | public void setSize(int width, int height) { |
---|
694 | fShell.setSize(width, height); |
---|
695 | } |
---|
696 | |
---|
697 | /* |
---|
698 | * @see IInformationControl#addDisposeListener(DisposeListener) |
---|
699 | */ |
---|
700 | public void addDisposeListener(DisposeListener listener) { |
---|
701 | fShell.addDisposeListener(listener); |
---|
702 | } |
---|
703 | |
---|
704 | /* |
---|
705 | * @see IInformationControl#removeDisposeListener(DisposeListener) |
---|
706 | */ |
---|
707 | public void removeDisposeListener(DisposeListener listener) { |
---|
708 | fShell.removeDisposeListener(listener); |
---|
709 | } |
---|
710 | |
---|
711 | /* |
---|
712 | * @see IInformationControl#setForegroundColor(Color) |
---|
713 | */ |
---|
714 | public void setForegroundColor(Color foreground) { |
---|
715 | fComposite.setForeground(foreground); |
---|
716 | } |
---|
717 | |
---|
718 | /* |
---|
719 | * @see IInformationControl#setBackgroundColor(Color) |
---|
720 | */ |
---|
721 | public void setBackgroundColor(Color background) { |
---|
722 | fComposite.setBackground(background); |
---|
723 | } |
---|
724 | |
---|
725 | /* |
---|
726 | * @see IInformationControl#isFocusControl() |
---|
727 | */ |
---|
728 | public boolean isFocusControl() { |
---|
729 | return fShell.getDisplay().getActiveShell() == fShell; |
---|
730 | } |
---|
731 | |
---|
732 | /* |
---|
733 | * @see IInformationControl#setFocus() |
---|
734 | */ |
---|
735 | public void setFocus() { |
---|
736 | fShell.forceFocus(); |
---|
737 | } |
---|
738 | |
---|
739 | /* |
---|
740 | * @see IInformationControl#addFocusListener(FocusListener) |
---|
741 | */ |
---|
742 | public void addFocusListener(FocusListener listener) { |
---|
743 | fShell.addFocusListener(listener); |
---|
744 | } |
---|
745 | |
---|
746 | /* |
---|
747 | * @see IInformationControl#removeFocusListener(FocusListener) |
---|
748 | */ |
---|
749 | public void removeFocusListener(FocusListener listener) { |
---|
750 | fShell.removeFocusListener(listener); |
---|
751 | } |
---|
752 | |
---|
753 | private StyleRange[] setViewerBackground(Annotation annotation) { |
---|
754 | StyledText text= fInput.fViewer.getTextWidget(); |
---|
755 | if (text == null || text.isDisposed()) |
---|
756 | return null; |
---|
757 | |
---|
758 | Display disp= text.getDisplay(); |
---|
759 | |
---|
760 | Position pos= fInput.model.getPosition(annotation); |
---|
761 | if (pos == null) |
---|
762 | return null; |
---|
763 | |
---|
764 | IRegion region= ((TextViewer)fInput.fViewer).modelRange2WidgetRange(new Region(pos.offset, pos.length)); |
---|
765 | if (region == null) |
---|
766 | return null; |
---|
767 | |
---|
768 | StyleRange[] ranges= text.getStyleRanges(region.getOffset(), region.getLength()); |
---|
769 | |
---|
770 | List undoRanges= new ArrayList(ranges.length); |
---|
771 | for (int i= 0; i < ranges.length; i++) { |
---|
772 | undoRanges.add(ranges[i].clone()); |
---|
773 | } |
---|
774 | |
---|
775 | int offset= region.getOffset(); |
---|
776 | StyleRange current= undoRanges.size() > 0 ? (StyleRange) undoRanges.get(0) : null; |
---|
777 | int curStart= current != null ? current.start : region.getOffset() + region.getLength(); |
---|
778 | int curEnd= current != null ? current.start + current.length : -1; |
---|
779 | int index= 0; |
---|
780 | |
---|
781 | // fill no-style regions |
---|
782 | while (curEnd < region.getOffset() + region.getLength()) { |
---|
783 | // add empty range |
---|
784 | if (curStart > offset) { |
---|
785 | StyleRange undoRange= new StyleRange(offset, curStart - offset, null, null); |
---|
786 | undoRanges.add(index, undoRange); |
---|
787 | index++; |
---|
788 | } |
---|
789 | |
---|
790 | // step |
---|
791 | index++; |
---|
792 | if (index < undoRanges.size()) { |
---|
793 | offset= curEnd; |
---|
794 | current= (StyleRange) undoRanges.get(index); |
---|
795 | curStart= current.start; |
---|
796 | curEnd= current.start + current.length; |
---|
797 | } else if (index == undoRanges.size()) { |
---|
798 | // last one |
---|
799 | offset= curEnd; |
---|
800 | current= null; |
---|
801 | curStart= region.getOffset() + region.getLength(); |
---|
802 | curEnd= -1; |
---|
803 | } else |
---|
804 | curEnd= region.getOffset() + region.getLength(); |
---|
805 | } |
---|
806 | |
---|
807 | // create modified styles (with background) |
---|
808 | List shadedRanges= new ArrayList(undoRanges.size()); |
---|
809 | for (Iterator it= undoRanges.iterator(); it.hasNext(); ) { |
---|
810 | StyleRange range= (StyleRange) ((StyleRange) it.next()).clone(); |
---|
811 | shadedRanges.add(range); |
---|
812 | range.background= getHighlightColor(disp); |
---|
813 | } |
---|
814 | |
---|
815 | // set the ranges one by one |
---|
816 | for (Iterator iter= shadedRanges.iterator(); iter.hasNext(); ) { |
---|
817 | text.setStyleRange((StyleRange) iter.next()); |
---|
818 | |
---|
819 | } |
---|
820 | |
---|
821 | return (StyleRange[]) undoRanges.toArray(undoRanges.toArray(new StyleRange[0])); |
---|
822 | } |
---|
823 | |
---|
824 | private void resetViewerBackground(StyleRange[] oldRanges) { |
---|
825 | |
---|
826 | if (oldRanges == null) |
---|
827 | return; |
---|
828 | |
---|
829 | if (fInput == null) |
---|
830 | return; |
---|
831 | |
---|
832 | StyledText text= fInput.fViewer.getTextWidget(); |
---|
833 | if (text == null || text.isDisposed()) |
---|
834 | return; |
---|
835 | |
---|
836 | // set the ranges one by one |
---|
837 | for (int i= 0; i < oldRanges.length; i++) { |
---|
838 | text.setStyleRange(oldRanges[i]); |
---|
839 | } |
---|
840 | } |
---|
841 | |
---|
842 | private Color getHighlightColor(Display disp) { |
---|
843 | return disp.getSystemColor(SWT.COLOR_GRAY); |
---|
844 | } |
---|
845 | |
---|
846 | private Color getSelectionColor(Display disp) { |
---|
847 | return disp.getSystemColor(SWT.COLOR_GRAY); |
---|
848 | } |
---|
849 | |
---|
850 | /* |
---|
851 | * @see org.eclipse.jface.text.IInformationControlExtension5#computeSizeConstraints(int, int) |
---|
852 | * @since 3.4 |
---|
853 | */ |
---|
854 | public Point computeSizeConstraints(int widthInChars, int heightInChars) { |
---|
855 | return null; |
---|
856 | } |
---|
857 | |
---|
858 | /* |
---|
859 | * @see org.eclipse.jface.text.IInformationControlExtension5#containsControl(org.eclipse.swt.widgets.Control) |
---|
860 | * @since 3.4 |
---|
861 | */ |
---|
862 | public boolean containsControl(Control control) { |
---|
863 | do { |
---|
864 | if (control == fShell) |
---|
865 | return true; |
---|
866 | if (control instanceof Shell) |
---|
867 | return false; |
---|
868 | control= control.getParent(); |
---|
869 | } while (control != null); |
---|
870 | return false; |
---|
871 | } |
---|
872 | |
---|
873 | /* |
---|
874 | * @see org.eclipse.jface.text.IInformationControlExtension5#getInformationPresenterControlCreator() |
---|
875 | * @since 3.4 |
---|
876 | */ |
---|
877 | public IInformationControlCreator getInformationPresenterControlCreator() { |
---|
878 | return null; |
---|
879 | } |
---|
880 | |
---|
881 | /* |
---|
882 | * @see org.eclipse.jface.text.IInformationControlExtension5#isVisible() |
---|
883 | */ |
---|
884 | public boolean isVisible() { |
---|
885 | return fShell != null && !fShell.isDisposed() && fShell.isVisible(); |
---|
886 | } |
---|
887 | |
---|
888 | } |
---|