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