View | Details | Raw Unified | Return to bug 215473 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/ui/editors/text/TextSourceViewerConfiguration.java (-9 / +6 lines)
Lines 16-30 Link Here
16
import java.util.StringTokenizer;
16
import java.util.StringTokenizer;
17
import java.util.Map.Entry;
17
import java.util.Map.Entry;
18
18
19
import org.eclipse.swt.SWT;
20
import org.eclipse.swt.widgets.Shell;
21
22
import org.eclipse.core.runtime.Assert;
19
import org.eclipse.core.runtime.Assert;
23
import org.eclipse.core.runtime.IAdaptable;
20
import org.eclipse.core.runtime.IAdaptable;
24
25
import org.eclipse.jface.action.Action;
21
import org.eclipse.jface.action.Action;
26
import org.eclipse.jface.preference.IPreferenceStore;
22
import org.eclipse.jface.preference.IPreferenceStore;
27
28
import org.eclipse.jface.text.DefaultInformationControl;
23
import org.eclipse.jface.text.DefaultInformationControl;
29
import org.eclipse.jface.text.DefaultTextHover;
24
import org.eclipse.jface.text.DefaultTextHover;
30
import org.eclipse.jface.text.IInformationControl;
25
import org.eclipse.jface.text.IInformationControl;
Lines 34-42 Link Here
34
import org.eclipse.jface.text.ITextViewerExtension2;
29
import org.eclipse.jface.text.ITextViewerExtension2;
35
import org.eclipse.jface.text.IUndoManager;
30
import org.eclipse.jface.text.IUndoManager;
36
import org.eclipse.jface.text.TextViewerUndoManager;
31
import org.eclipse.jface.text.TextViewerUndoManager;
37
import org.eclipse.jface.text.hyperlink.DefaultHyperlinkPresenter;
38
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
32
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
39
import org.eclipse.jface.text.hyperlink.IHyperlinkPresenter;
33
import org.eclipse.jface.text.hyperlink.IHyperlinkPresenter;
34
import org.eclipse.jface.text.hyperlink.MultipleHyperlinkPresenter;
40
import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
35
import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
41
import org.eclipse.jface.text.quickassist.QuickAssistAssistant;
36
import org.eclipse.jface.text.quickassist.QuickAssistAssistant;
42
import org.eclipse.jface.text.reconciler.IReconciler;
37
import org.eclipse.jface.text.reconciler.IReconciler;
Lines 47-53 Link Here
47
import org.eclipse.jface.text.source.IAnnotationHover;
42
import org.eclipse.jface.text.source.IAnnotationHover;
48
import org.eclipse.jface.text.source.ISourceViewer;
43
import org.eclipse.jface.text.source.ISourceViewer;
49
import org.eclipse.jface.text.source.SourceViewerConfiguration;
44
import org.eclipse.jface.text.source.SourceViewerConfiguration;
50
45
import org.eclipse.swt.SWT;
46
import org.eclipse.swt.graphics.RGB;
47
import org.eclipse.swt.widgets.Shell;
51
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
48
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
52
import org.eclipse.ui.texteditor.AnnotationPreference;
49
import org.eclipse.ui.texteditor.AnnotationPreference;
53
import org.eclipse.ui.texteditor.HyperlinkDetectorRegistry;
50
import org.eclipse.ui.texteditor.HyperlinkDetectorRegistry;
Lines 299-307 Link Here
299
	 */
296
	 */
300
	public IHyperlinkPresenter getHyperlinkPresenter(ISourceViewer sourceViewer) {
297
	public IHyperlinkPresenter getHyperlinkPresenter(ISourceViewer sourceViewer) {
301
		if (fPreferenceStore == null)
298
		if (fPreferenceStore == null)
302
			return super.getHyperlinkPresenter(sourceViewer);
299
			return new MultipleHyperlinkPresenter(new RGB(0, 0, 255));
303
300
304
		return new DefaultHyperlinkPresenter(fPreferenceStore);
301
		return new MultipleHyperlinkPresenter(fPreferenceStore);
305
	}
302
	}
306
303
307
	/**
304
	/**
(-)src/org/eclipse/jface/text/TextViewer.java (-21 / +18 lines)
Lines 21-27 Link Here
21
import java.util.regex.PatternSyntaxException;
21
import java.util.regex.PatternSyntaxException;
22
22
23
import org.eclipse.core.runtime.Assert;
23
import org.eclipse.core.runtime.Assert;
24
24
import org.eclipse.jface.internal.text.NonDeletingPositionUpdater;
25
import org.eclipse.jface.internal.text.TextUtils;
26
import org.eclipse.jface.text.hyperlink.HyperlinkManager;
27
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
28
import org.eclipse.jface.text.hyperlink.IHyperlinkDetectorExtension;
29
import org.eclipse.jface.text.hyperlink.IHyperlinkPresenter;
30
import org.eclipse.jface.text.hyperlink.HyperlinkManager.DETECTION_STRATEGY;
31
import org.eclipse.jface.text.projection.ChildDocument;
32
import org.eclipse.jface.text.projection.ChildDocumentManager;
33
import org.eclipse.jface.viewers.IPostSelectionProvider;
34
import org.eclipse.jface.viewers.ISelection;
35
import org.eclipse.jface.viewers.ISelectionChangedListener;
36
import org.eclipse.jface.viewers.ISelectionProvider;
37
import org.eclipse.jface.viewers.SelectionChangedEvent;
38
import org.eclipse.jface.viewers.Viewer;
25
import org.eclipse.swt.SWT;
39
import org.eclipse.swt.SWT;
26
import org.eclipse.swt.custom.LineBackgroundEvent;
40
import org.eclipse.swt.custom.LineBackgroundEvent;
27
import org.eclipse.swt.custom.LineBackgroundListener;
41
import org.eclipse.swt.custom.LineBackgroundListener;
Lines 61-80 Link Here
61
import org.eclipse.swt.widgets.Listener;
75
import org.eclipse.swt.widgets.Listener;
62
import org.eclipse.swt.widgets.ScrollBar;
76
import org.eclipse.swt.widgets.ScrollBar;
63
77
64
import org.eclipse.jface.internal.text.NonDeletingPositionUpdater;
65
import org.eclipse.jface.text.hyperlink.HyperlinkManager;
66
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
67
import org.eclipse.jface.text.hyperlink.IHyperlinkDetectorExtension;
68
import org.eclipse.jface.text.hyperlink.IHyperlinkPresenter;
69
import org.eclipse.jface.text.projection.ChildDocument;
70
import org.eclipse.jface.text.projection.ChildDocumentManager;
71
import org.eclipse.jface.viewers.IPostSelectionProvider;
72
import org.eclipse.jface.viewers.ISelection;
73
import org.eclipse.jface.viewers.ISelectionChangedListener;
74
import org.eclipse.jface.viewers.ISelectionProvider;
75
import org.eclipse.jface.viewers.SelectionChangedEvent;
76
import org.eclipse.jface.viewers.Viewer;
77
78
78
79
/**
79
/**
80
 * SWT based implementation of {@link ITextViewer} and its extension interfaces.
80
 * SWT based implementation of {@link ITextViewer} and its extension interfaces.
Lines 3230-3240 Link Here
3230
	 * @return the average character width of this viewer's widget
3230
	 * @return the average character width of this viewer's widget
3231
	 */
3231
	 */
3232
	final protected int getAverageCharWidth() {
3232
	final protected int getAverageCharWidth() {
3233
		GC gc= new GC(fTextWidget);
3233
		return TextUtils.getAverageCharWidth(getTextWidget());
3234
		gc.setFont(fTextWidget.getFont());
3235
		int increment= gc.getFontMetrics().getAverageCharWidth();
3236
		gc.dispose();
3237
		return increment;
3238
	}
3234
	}
3239
3235
3240
	/*
3236
	/*
Lines 5366-5372 Link Here
5366
	 */
5362
	 */
5367
	private void ensureHyperlinkManagerInstalled() {
5363
	private void ensureHyperlinkManagerInstalled() {
5368
		if (fHyperlinkDetectors != null && fHyperlinkDetectors.length > 0 && fHyperlinkPresenter != null && fHyperlinkManager == null) {
5364
		if (fHyperlinkDetectors != null && fHyperlinkDetectors.length > 0 && fHyperlinkPresenter != null && fHyperlinkManager == null) {
5369
			fHyperlinkManager= new HyperlinkManager(HyperlinkManager.FIRST);
5365
			DETECTION_STRATEGY strategy= fHyperlinkPresenter.canShowMultipleHyperlinks() ? HyperlinkManager.ALL : HyperlinkManager.FIRST;
5366
			fHyperlinkManager= new HyperlinkManager(strategy);
5370
			fHyperlinkManager.install(this, fHyperlinkPresenter, fHyperlinkDetectors, fHyperlinkStateMask);
5367
			fHyperlinkManager.install(this, fHyperlinkPresenter, fHyperlinkDetectors, fHyperlinkStateMask);
5371
		}
5368
		}
5372
	}
5369
	}
(-)src/org/eclipse/jface/text/TextViewerHoverManager.java (-55 / +3 lines)
Lines 15-21 Link Here
15
import org.eclipse.core.runtime.IStatus;
15
import org.eclipse.core.runtime.IStatus;
16
import org.eclipse.core.runtime.Platform;
16
import org.eclipse.core.runtime.Platform;
17
import org.eclipse.core.runtime.Status;
17
import org.eclipse.core.runtime.Status;
18
18
import org.eclipse.jface.internal.text.TextUtils;
19
import org.eclipse.jface.text.information.IInformationProviderExtension2;
19
import org.eclipse.swt.custom.StyledText;
20
import org.eclipse.swt.custom.StyledText;
20
import org.eclipse.swt.events.MouseEvent;
21
import org.eclipse.swt.events.MouseEvent;
21
import org.eclipse.swt.events.MouseMoveListener;
22
import org.eclipse.swt.events.MouseMoveListener;
Lines 23-30 Link Here
23
import org.eclipse.swt.graphics.Rectangle;
24
import org.eclipse.swt.graphics.Rectangle;
24
import org.eclipse.swt.widgets.Display;
25
import org.eclipse.swt.widgets.Display;
25
26
26
import org.eclipse.jface.text.information.IInformationProviderExtension2;
27
28
27
29
/**
28
/**
30
 * This manager controls the layout, content, and visibility of an information
29
 * This manager controls the layout, content, and visibility of an information
Lines 145-151 Link Here
145
			return;
144
			return;
146
		}
145
		}
147
146
148
		final Rectangle area= computeArea(region);
147
		final Rectangle area= TextUtils.computeArea(region, fTextViewer);
149
		if (area == null || area.isEmpty()) {
148
		if (area == null || area.isEmpty()) {
150
			setInformation(null, null);
149
			setInformation(null, null);
151
			return;
150
			return;
Lines 277-333 Link Here
277
		}
276
		}
278
	}
277
	}
279
278
280
	/**
281
	 * Determines graphical area covered by the given text region.
282
	 *
283
	 * @param region the region whose graphical extend must be computed
284
	 * @return the graphical extend of the given region
285
	 */
286
	private Rectangle computeArea(IRegion region) {
287
288
		int start= 0;
289
		int end= 0;
290
		IRegion widgetRegion= modelRange2WidgetRange(region);
291
		if (widgetRegion != null) {
292
			start= widgetRegion.getOffset();
293
			end= start + widgetRegion.getLength();
294
		}
295
296
		StyledText styledText= fTextViewer.getTextWidget();
297
		Rectangle bounds;
298
		if (end > 0 && start < end)
299
			bounds= styledText.getTextBounds(start, end - 1);
300
		else {
301
			Point loc= styledText.getLocationAtOffset(start);
302
			bounds= new Rectangle(loc.x, loc.y, fTextViewer.getAverageCharWidth(), styledText.getLineHeight(start));
303
		}
304
		
305
		return new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height);
306
	}
307
308
	/**
309
	 * Translates a given region of the text viewer's document into
310
	 * the corresponding region of the viewer's widget.
311
	 *
312
	 * @param region the document region
313
	 * @return the corresponding widget region
314
	 * @since 2.1
315
	 */
316
	private IRegion modelRange2WidgetRange(IRegion region) {
317
		if (fTextViewer instanceof ITextViewerExtension5) {
318
			ITextViewerExtension5 extension= (ITextViewerExtension5) fTextViewer;
319
			return extension.modelRange2WidgetRange(region);
320
		}
321
322
		IRegion visibleRegion= fTextViewer.getVisibleRegion();
323
		int start= region.getOffset() - visibleRegion.getOffset();
324
		int end= start + region.getLength();
325
		if (end > visibleRegion.getLength())
326
			end= visibleRegion.getLength();
327
328
		return new Region(start, end - start);
329
	}
330
331
	/*
279
	/*
332
	 * @see org.eclipse.jface.text.AbstractInformationControlManager#showInformationControl(org.eclipse.swt.graphics.Rectangle)
280
	 * @see org.eclipse.jface.text.AbstractInformationControlManager#showInformationControl(org.eclipse.swt.graphics.Rectangle)
333
	 */
281
	 */
(-)src/org/eclipse/jface/internal/text/TextUtils.java (+94 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2007, 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.eclipse.jface.internal.text;
12
13
import org.eclipse.jface.text.IRegion;
14
import org.eclipse.jface.text.ITextViewer;
15
import org.eclipse.jface.text.ITextViewerExtension5;
16
import org.eclipse.jface.text.Region;
17
import org.eclipse.swt.custom.StyledText;
18
import org.eclipse.swt.graphics.GC;
19
import org.eclipse.swt.graphics.Point;
20
import org.eclipse.swt.graphics.Rectangle;
21
22
/**
23
 * @since 3.4
24
 */
25
public class TextUtils {
26
27
	/**
28
	 * Determines graphical area covered by the given text region in
29
	 * the given viewer.
30
	 *
31
	 * @param region the region whose graphical extend must be computed
32
	 * @param textViewer the text viewer containing the region
33
	 * @return the graphical extend of the given region in the given viewer
34
	 */
35
	public static Rectangle computeArea(IRegion region, ITextViewer textViewer) {
36
	
37
		int start= 0;
38
		int end= 0;
39
		IRegion widgetRegion= modelRange2WidgetRange(region, textViewer);
40
		if (widgetRegion != null) {
41
			start= widgetRegion.getOffset();
42
			end= start + widgetRegion.getLength();
43
		}
44
	
45
		StyledText styledText= textViewer.getTextWidget();
46
		Rectangle bounds;
47
		if (end > 0 && start < end)
48
			bounds= styledText.getTextBounds(start, end - 1);
49
		else {
50
			Point loc= styledText.getLocationAtOffset(start);
51
			bounds= new Rectangle(loc.x, loc.y, getAverageCharWidth(textViewer.getTextWidget()), styledText.getLineHeight(start));
52
		}
53
		
54
		return new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height);
55
	}
56
57
	/**
58
	 * Translates a given region of the text viewer's document into
59
	 * the corresponding region of the viewer's widget.
60
	 *
61
	 * @param region the document region
62
	 * @param textViewer the viewer containing the region 
63
	 * @return the corresponding widget region
64
	 * @since 2.1
65
	 */
66
	private static IRegion modelRange2WidgetRange(IRegion region, ITextViewer textViewer) {
67
		if (textViewer instanceof ITextViewerExtension5) {
68
			ITextViewerExtension5 extension= (ITextViewerExtension5) textViewer;
69
			return extension.modelRange2WidgetRange(region);
70
		}
71
	
72
		IRegion visibleRegion= textViewer.getVisibleRegion();
73
		int start= region.getOffset() - visibleRegion.getOffset();
74
		int end= start + region.getLength();
75
		if (end > visibleRegion.getLength())
76
			end= visibleRegion.getLength();
77
	
78
		return new Region(start, end - start);
79
	}
80
81
	/**
82
	 * Returns the average character width of the given widget.
83
	 *
84
	 * @param widget the widget to calculate the average char width for
85
	 * @return the average character width of the given widget
86
	 */
87
	public static int getAverageCharWidth(StyledText widget) {
88
		GC gc= new GC(widget);
89
		gc.setFont(widget.getFont());
90
		int increment= gc.getFontMetrics().getAverageCharWidth();
91
		gc.dispose();
92
		return increment;
93
	}
94
}
(-)src/org/eclipse/jface/text/hyperlink/MultipleHyperlinkPresenter.java (+622 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2007, 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.eclipse.jface.text.hyperlink;
12
13
import org.eclipse.jface.internal.text.TextUtils;
14
import org.eclipse.jface.preference.IPreferenceStore;
15
import org.eclipse.jface.resource.JFaceResources;
16
import org.eclipse.jface.text.AbstractInformationControl;
17
import org.eclipse.jface.text.AbstractInformationControlManager;
18
import org.eclipse.jface.text.IInformationControl;
19
import org.eclipse.jface.text.IInformationControlCreator;
20
import org.eclipse.jface.text.IInformationControlExtension2;
21
import org.eclipse.jface.text.IInformationControlExtension3;
22
import org.eclipse.jface.text.IRegion;
23
import org.eclipse.jface.text.ITextHover;
24
import org.eclipse.jface.text.ITextHoverExtension;
25
import org.eclipse.jface.text.ITextViewer;
26
import org.eclipse.jface.text.IWidgetTokenKeeper;
27
import org.eclipse.jface.text.IWidgetTokenKeeperExtension;
28
import org.eclipse.jface.text.IWidgetTokenOwner;
29
import org.eclipse.jface.text.IWidgetTokenOwnerExtension;
30
import org.eclipse.jface.text.Region;
31
import org.eclipse.jface.util.Geometry;
32
import org.eclipse.swt.SWT;
33
import org.eclipse.swt.custom.ScrolledComposite;
34
import org.eclipse.swt.events.KeyEvent;
35
import org.eclipse.swt.events.KeyListener;
36
import org.eclipse.swt.events.MouseEvent;
37
import org.eclipse.swt.events.MouseListener;
38
import org.eclipse.swt.events.MouseMoveListener;
39
import org.eclipse.swt.graphics.Color;
40
import org.eclipse.swt.graphics.Point;
41
import org.eclipse.swt.graphics.RGB;
42
import org.eclipse.swt.graphics.Rectangle;
43
import org.eclipse.swt.layout.GridData;
44
import org.eclipse.swt.layout.GridLayout;
45
import org.eclipse.swt.widgets.Composite;
46
import org.eclipse.swt.widgets.Control;
47
import org.eclipse.swt.widgets.Display;
48
import org.eclipse.swt.widgets.Event;
49
import org.eclipse.swt.widgets.Label;
50
import org.eclipse.swt.widgets.Listener;
51
import org.eclipse.swt.widgets.ScrollBar;
52
import org.eclipse.swt.widgets.Shell;
53
54
import com.ibm.icu.text.MessageFormat;
55
56
57
/**
58
 * A hyperlink presenter capable of showing multiple hyperlinks in a hover.
59
 * 
60
 * @since 3.4
61
 */
62
public class MultipleHyperlinkPresenter extends DefaultHyperlinkPresenter {
63
	
64
	/**
65
	 * An information control capable of showing a list of hyperlinks. The hyperlinks can be opened.
66
	 */
67
	private static class LinkListInformationControl extends AbstractInformationControl implements IInformationControlExtension2 {
68
		
69
		private IHyperlink[] fInput;
70
		private Composite fParent;
71
		
72
		/**
73
		 * Creates a link list information control with the given shell as parent.
74
		 *
75
		 * @param parentShell the parent shell
76
		 */
77
		public LinkListInformationControl(Shell parentShell) {
78
			super(parentShell, false);
79
			
80
			create();
81
		}
82
		
83
		/* (non-Javadoc)
84
		 * @see org.eclipse.jface.text.IInformationControl#setInformation(java.lang.String)
85
		 */
86
		public void setInformation(String information) {
87
			//replaced by IInformationControlExtension2#setInput(java.lang.Object)
88
		}
89
		
90
		/* (non-Javadoc)
91
		 * @see org.eclipse.jface.text.IInformationControlExtension2#setInput(java.lang.Object)
92
		 */
93
		public void setInput(Object input) {
94
			fInput= (IHyperlink[]) input;
95
			deferredCreateContent(fParent);
96
		}
97
		
98
		/* (non-Javadoc)
99
		 * @see org.eclipse.jface.text.AbstractInformationControl#createContent(org.eclipse.swt.widgets.Composite)
100
		 */
101
		protected void createContent(Composite parent) {
102
			fParent= new Composite(parent, SWT.NONE);
103
			fParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
104
			GridLayout layout= new GridLayout(1, false);
105
			layout.marginHeight= 0;
106
			layout.marginWidth= 0;
107
			fParent.setLayout(layout);
108
		}
109
		
110
		/* (non-Javadoc)
111
		 * @see org.eclipse.jface.text.AbstractInformationControl#computeSizeHint()
112
		 */
113
		public Point computeSizeHint() {
114
			Point minSize= getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
115
			
116
			Point constraints= getSizeConstraints();
117
			if (constraints == null)
118
				return minSize;
119
			
120
			return Geometry.min(minSize, constraints);
121
		}
122
		
123
		private void deferredCreateContent(Composite parent) {
124
			ScrolledComposite scrolledComposite= new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
125
			GridData gridData= new GridData(SWT.FILL, SWT.FILL, true, true);
126
			scrolledComposite.setLayoutData(gridData);
127
			scrolledComposite.setExpandVertical(false);
128
			scrolledComposite.setExpandHorizontal(false);
129
			
130
			Composite composite= createLinks(scrolledComposite);
131
			
132
			scrolledComposite.setContent(composite);
133
			Point point= composite.computeSize(SWT.DEFAULT, SWT.DEFAULT);
134
			composite.setSize(point);
135
			scrolledComposite.setMinSize(point);
136
			
137
			Point contentSize= composite.computeSize(SWT.DEFAULT, SWT.DEFAULT);
138
			Point constraints= getSizeConstraints();
139
			if (constraints != null && contentSize.x < constraints.x) {
140
				ScrollBar horizontalBar= scrolledComposite.getHorizontalBar();
141
				
142
				int scrollBarHeight;
143
				if (horizontalBar == null) {
144
					Point scrollSize= scrolledComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT);
145
					scrollBarHeight= scrollSize.y - contentSize.y;
146
				} else {
147
					scrollBarHeight= horizontalBar.getSize().y;
148
				}
149
				gridData.heightHint= contentSize.y - scrollBarHeight;
150
			}
151
			
152
			if (constraints != null && contentSize.y < constraints.y) {
153
				ScrollBar verticalBar= scrolledComposite.getVerticalBar();
154
				
155
				int scrollBarWidth;
156
				if (verticalBar == null) {
157
					Point scrollSize= scrolledComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT);
158
					scrollBarWidth= scrollSize.x - contentSize.x;
159
				} else {
160
					scrollBarWidth= verticalBar.getSize().x;
161
				}
162
				gridData.widthHint= contentSize.x - scrollBarWidth;
163
			}
164
			
165
		}
166
		
167
		private Composite createLinks(Composite parent) {
168
			Composite composite= new Composite(parent, SWT.NONE);
169
			composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
170
			GridLayout layout= new GridLayout(1, false);
171
			layout.marginWidth= 2;
172
			layout.marginHeight= 2;
173
			layout.verticalSpacing= 0;
174
			composite.setLayout(layout);
175
			composite.setBackground(composite.getDisplay().getSystemColor(SWT.COLOR_WHITE));
176
			
177
			final Composite[] menuEntries= new Composite[fInput.length];
178
			for (int i= 0; i < fInput.length; i++) {
179
				final IHyperlink link= fInput[i];
180
				
181
				final Composite labelComposite= new Composite(composite, SWT.NONE);
182
				labelComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
183
				GridLayout layout2= new GridLayout(1, false);
184
				layout2.marginHeight= 2;
185
				layout2.marginWidth= 2;
186
				labelComposite.setLayout(layout2);
187
				labelComposite.setBackground(composite.getBackground());
188
				menuEntries[i]= labelComposite;
189
				
190
				final Label label= new Label(labelComposite, SWT.NONE);
191
				label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
192
				label.setBackground(labelComposite.getBackground());
193
				
194
				String text= link.getHyperlinkText();
195
				if (text == null)
196
					text= HyperlinkMessages.getString("LinkListInformationControl.unknownLink"); //$NON-NLS-1$
197
					
198
				if (i == 0) {
199
					text= MessageFormat.format(HyperlinkMessages.getString("LinkListInformationControl.defaultLinkPattern"), new Object[] { text }); //$NON-NLS-1$
200
					label.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
201
				}
202
				
203
				label.setText(text);
204
				
205
				label.addMouseListener(new MouseListener() {
206
					public void mouseDoubleClick(MouseEvent e) {
207
					}
208
					
209
					public void mouseDown(MouseEvent e) {
210
					}
211
					
212
					public void mouseUp(MouseEvent e) {
213
						LinkListInformationControl.this.dispose();
214
						link.open();
215
					}
216
				});
217
				label.addMouseMoveListener(new MouseMoveListener() {
218
					public void mouseMove(MouseEvent e) {
219
						Display display= labelComposite.getDisplay();
220
						for (int j= 0; j < menuEntries.length; j++) {
221
							setColor(menuEntries[j], display.getSystemColor(SWT.COLOR_WHITE), display.getSystemColor(SWT.COLOR_BLACK));
222
						}
223
						
224
						setColor(labelComposite, display.getSystemColor(SWT.COLOR_LIST_SELECTION), display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
225
					}
226
					
227
					private void setColor(Control control, Color backColor, Color foreColor) {
228
						control.setBackground(backColor);
229
						control.setForeground(foreColor);
230
						if (control instanceof Composite) {
231
							Control[] children= ((Composite) control).getChildren();
232
							for (int j= 0; j < children.length; j++) {
233
								setColor(children[j], backColor, foreColor);
234
							}
235
						}
236
					}
237
				});
238
			}
239
			
240
			return composite;
241
		}
242
		
243
		/* (non-Javadoc)
244
		 * @see org.eclipse.jface.text.IInformationControlExtension#hasContents()
245
		 */
246
		public boolean hasContents() {
247
			return true;
248
		}
249
	}
250
	
251
	private class MultipleHyperlinkHover implements ITextHover, ITextHoverExtension {
252
		
253
		/**
254
		 * @see org.eclipse.jface.text.ITextHover#getHoverInfo(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion)
255
		 * @deprecated
256
		 */
257
		public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
258
			return null;
259
		}
260
		
261
		/* (non-Javadoc)
262
		 * @see org.eclipse.jface.text.ITextHover#getHoverRegion(org.eclipse.jface.text.ITextViewer, int)
263
		 */
264
		public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
265
			return fSubjectRegion;
266
		}
267
		
268
		/* (non-Javadoc)
269
		 * @see org.eclipse.jface.text.ITextHoverExtension2#getHoverInfo2(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion)
270
		 */
271
		public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
272
			return fHyperlinks;
273
		}
274
		
275
		/* (non-Javadoc)
276
		 * @see org.eclipse.jface.text.ITextHoverExtension#getHoverControlCreator()
277
		 */
278
		public IInformationControlCreator getHoverControlCreator() {
279
			return new IInformationControlCreator() {
280
				public IInformationControl createInformationControl(Shell parent) {
281
					return new LinkListInformationControl(parent);
282
				}
283
			};
284
		}
285
	}
286
	
287
	private static class MultipleHyperlinkHoverManager extends AbstractInformationControlManager implements IWidgetTokenKeeper, IWidgetTokenKeeperExtension {
288
		
289
		private class Closer implements IInformationControlCloser, Listener, KeyListener {
290
			
291
			private Control fSubjectControl;
292
			private Display fDisplay;
293
			private IInformationControl fControl;
294
			private Rectangle fSubjectArea;
295
			
296
			/* (non-Javadoc)
297
			 * @see org.eclipse.jface.text.AbstractInformationControlManager.IInformationControlCloser#setInformationControl(org.eclipse.jface.text.IInformationControl)
298
			 */
299
			public void setInformationControl(IInformationControl control) {
300
				fControl= control;
301
			}
302
			
303
			/* (non-Javadoc)
304
			 * @see org.eclipse.jface.text.AbstractInformationControlManager.IInformationControlCloser#setSubjectControl(org.eclipse.swt.widgets.Control)
305
			 */
306
			public void setSubjectControl(Control subject) {
307
				fSubjectControl= subject;
308
			}
309
			
310
			/* (non-Javadoc)
311
			 * @see org.eclipse.jface.text.AbstractInformationControlManager.IInformationControlCloser#start(org.eclipse.swt.graphics.Rectangle)
312
			 */
313
			public void start(Rectangle subjectArea) {
314
				fSubjectArea= subjectArea;
315
				
316
				fDisplay= fSubjectControl.getDisplay();
317
				if (!fDisplay.isDisposed()) {
318
					fDisplay.addFilter(SWT.FocusOut, this);
319
					fDisplay.addFilter(SWT.MouseMove, this);
320
					fTextViewer.getTextWidget().addKeyListener(this);
321
				}
322
			}
323
			
324
			/* (non-Javadoc)
325
			 * @see org.eclipse.jface.text.AbstractInformationControlManager.IInformationControlCloser#stop()
326
			 */
327
			public void stop() {
328
				if (fDisplay != null && !fDisplay.isDisposed()) {
329
					fDisplay.removeFilter(SWT.FocusOut, this);
330
					fDisplay.removeFilter(SWT.MouseMove, this);
331
					fTextViewer.getTextWidget().removeKeyListener(this);
332
				}
333
				
334
				fSubjectArea= null;
335
			}
336
			
337
			/* (non-Javadoc)
338
			 * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
339
			 */
340
			public void handleEvent(Event event) {
341
				switch (event.type) {
342
					case SWT.FocusOut:
343
						if (!fControl.isFocusControl())
344
							disposeInformationControl();
345
						break;
346
					case SWT.MouseMove:
347
						handleMouseMove(event);
348
						break;
349
				}
350
			}
351
			
352
			/**
353
			 * Handle mouse movement events.
354
			 * 
355
			 * @param event the event
356
			 * @since 3.4
357
			 */
358
			private void handleMouseMove(Event event) {
359
				if (!(event.widget instanceof Control))
360
					return;
361
				Control eventControl= (Control) event.widget;
362
				
363
				//transform coordinates to subject control:
364
				Point mouseLoc= event.display.map(eventControl, fSubjectControl, event.x, event.y);
365
				
366
				if (fSubjectArea.contains(mouseLoc))
367
					return;
368
				
369
				if (inKeepUpZone(mouseLoc.x, mouseLoc.y, ((IInformationControlExtension3) fControl).getBounds()))
370
					return;
371
				
372
				hideInformationControl();
373
			}
374
			
375
			/**
376
			 * Tests whether a given mouse location is within the keep-up zone.
377
			 * The hover should not be hidden as long as the mouse stays inside this zone.
378
			 * 
379
			 * @param x the x coordinate, relative to the <em>subject control</em>
380
			 * @param y the y coordinate, relative to the <em>subject control</em>
381
			 * @param controlBounds the bounds of the current control
382
			 * 
383
			 * @return <code>true</code> iff the mouse event occurred in the keep-up zone
384
			 */
385
			private boolean inKeepUpZone(int x, int y, Rectangle controlBounds) {
386
				Rectangle iControlBounds= fSubjectControl.getDisplay().map(null, fSubjectControl, controlBounds);
387
				Rectangle totalBounds= Geometry.copy(iControlBounds);
388
				
389
				// FIXME: should maybe use convex hull, not bounding box
390
				totalBounds.add(fSubjectArea);
391
				return totalBounds.contains(x, y);
392
			}
393
			
394
			/* (non-Javadoc)
395
			 * @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent)
396
			 */
397
			public void keyPressed(KeyEvent e) {
398
			}
399
			
400
			/* (non-Javadoc)
401
			 * @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent)
402
			 */
403
			public void keyReleased(KeyEvent e) {
404
				hideInformationControl();
405
			}
406
		}
407
		
408
		/**
409
		 * Priority of the hover managed by this manager.
410
		 * Default value: One higher then for the hovers 
411
		 * managed by TextViewerHoverManager.
412
		 */
413
		private static final int WIDGET_TOKEN_PRIORITY= 1;
414
		
415
		private final MultipleHyperlinkHover fHover;
416
		private final ITextViewer fTextViewer;
417
		private Closer fCloser;
418
		
419
		/**
420
		 * Create a new MultipleHyperlinkHoverManager. The MHHM can show and hide
421
		 * the given MultipleHyperlinkHover inside the given ITextViewer.
422
		 * 
423
		 * @param hover the hover to manage 
424
		 * @param viewer the viewer to show the hover in
425
		 */
426
		public MultipleHyperlinkHoverManager(MultipleHyperlinkHover hover, ITextViewer viewer) {
427
			super(hover.getHoverControlCreator());
428
			
429
			fHover= hover;
430
			fTextViewer= viewer;
431
			
432
			fCloser= new Closer();
433
			setCloser(fCloser);
434
		}
435
		
436
		/* (non-Javadoc)
437
		 * @see org.eclipse.jface.text.AbstractInformationControlManager#computeInformation()
438
		 */
439
		protected void computeInformation() {
440
			IRegion region= fHover.getHoverRegion(fTextViewer, -1);
441
			if (region == null) {
442
				setInformation(null, null);
443
				return;
444
			}
445
			
446
			Rectangle area= TextUtils.computeArea(region, fTextViewer);
447
			if (area == null || area.isEmpty()) {
448
				setInformation(null, null);
449
				return;
450
			}
451
			
452
			Object information= fHover.getHoverInfo2(fTextViewer, region);
453
			setCustomInformationControlCreator(fHover.getHoverControlCreator());
454
			setInformation(information, area);
455
		}
456
		
457
		/* (non-Javadoc)
458
		 * @see org.eclipse.jface.text.AbstractInformationControlManager#showInformationControl(org.eclipse.swt.graphics.Rectangle)
459
		 */
460
		protected void showInformationControl(Rectangle subjectArea) {
461
			if (fTextViewer instanceof IWidgetTokenOwnerExtension) {
462
				if (((IWidgetTokenOwnerExtension) fTextViewer).requestWidgetToken(this, WIDGET_TOKEN_PRIORITY))
463
					super.showInformationControl(subjectArea);
464
			} else if (fTextViewer instanceof IWidgetTokenOwner) {
465
				if (((IWidgetTokenOwner) fTextViewer).requestWidgetToken(this))
466
					super.showInformationControl(subjectArea);
467
			} else {
468
				super.showInformationControl(subjectArea);
469
			}
470
		}
471
		
472
		/* (non-Javadoc)
473
		 * @see org.eclipse.jface.text.AbstractInformationControlManager#hideInformationControl()
474
		 */
475
		protected void hideInformationControl() {
476
			super.hideInformationControl();
477
			
478
			if (fTextViewer instanceof IWidgetTokenOwner) {
479
				((IWidgetTokenOwner) fTextViewer).releaseWidgetToken(this);
480
			}
481
		}
482
		
483
		/* (non-Javadoc)
484
		 * @see org.eclipse.jface.text.IWidgetTokenKeeper#requestWidgetToken(org.eclipse.jface.text.IWidgetTokenOwner)
485
		 */
486
		public boolean requestWidgetToken(IWidgetTokenOwner owner) {
487
			hideInformationControl();
488
			return true;
489
		}
490
		
491
		/* (non-Javadoc)
492
		 * @see org.eclipse.jface.text.IWidgetTokenKeeperExtension#requestWidgetToken(org.eclipse.jface.text.IWidgetTokenOwner, int)
493
		 */
494
		public boolean requestWidgetToken(IWidgetTokenOwner owner, int priority) {
495
			if (priority < WIDGET_TOKEN_PRIORITY)
496
				return false;
497
			
498
			hideInformationControl();
499
			return true;
500
		}
501
		
502
		/* (non-Javadoc)
503
		 * @see org.eclipse.jface.text.IWidgetTokenKeeperExtension#setFocus(org.eclipse.jface.text.IWidgetTokenOwner)
504
		 */
505
		public boolean setFocus(IWidgetTokenOwner owner) {
506
			return false;
507
		}
508
	}
509
	
510
	private ITextViewer fTextViewer;
511
	
512
	private IHyperlink[] fHyperlinks;
513
	private Region fSubjectRegion;
514
	private MultipleHyperlinkHoverManager fManager;
515
	
516
	/**
517
	 * Creates a new multiple hyperlink presenter which uses
518
	 * {@link #HYPERLINK_COLOR} to read the color from the given preference store.
519
	 *
520
	 * @param store the preference store
521
	 */
522
	public MultipleHyperlinkPresenter(IPreferenceStore store) {
523
		super(store);
524
	}
525
	
526
	/**
527
	 * Creates a new multiple hyperlink presenter.
528
	 *
529
	 * @param color the hyperlink color, to be disposed by the caller
530
	 */
531
	public MultipleHyperlinkPresenter(RGB color) {
532
		super(color);
533
	}
534
	
535
	/* (non-Javadoc)
536
	 * @see org.eclipse.jface.text.hyperlink.DefaultHyperlinkPresenter#install(org.eclipse.jface.text.ITextViewer)
537
	 */
538
	public void install(ITextViewer viewer) {
539
		super.install(viewer);
540
		fTextViewer= viewer;
541
		
542
		fManager= new MultipleHyperlinkHoverManager(new MultipleHyperlinkHover(), fTextViewer);
543
		fManager.install(viewer.getTextWidget());
544
		fManager.setSizeConstraints(100, 12, false, true);
545
	}
546
	
547
	/* (non-Javadoc)
548
	 * @see org.eclipse.jface.text.hyperlink.DefaultHyperlinkPresenter#uninstall()
549
	 */
550
	public void uninstall() {
551
		super.uninstall();
552
		
553
		if (fTextViewer != null) {
554
			fManager.dispose();
555
			
556
			fTextViewer= null;
557
		}
558
	}
559
	
560
	/* (non-Javadoc)
561
	 * @see org.eclipse.jface.text.hyperlink.DefaultHyperlinkPresenter#canShowMultipleHyperlinks()
562
	 */
563
	public boolean canShowMultipleHyperlinks() {
564
		return true;
565
	}
566
	
567
	/* (non-Javadoc)
568
	 * @see org.eclipse.jface.text.hyperlink.DefaultHyperlinkPresenter#hideHyperlinks()
569
	 */
570
	public void hideHyperlinks() {
571
		super.hideHyperlinks();
572
		
573
		fHyperlinks= null;
574
	}
575
	
576
	/* (non-Javadoc)
577
	 * @see org.eclipse.jface.text.hyperlink.DefaultHyperlinkPresenter#showHyperlinks(org.eclipse.jface.text.hyperlink.IHyperlink[])
578
	 */
579
	public void showHyperlinks(final IHyperlink[] hyperlinks) {
580
		super.showHyperlinks(new IHyperlink[] { hyperlinks[0] });
581
		
582
		if (equals(fHyperlinks, hyperlinks))
583
			return;
584
		
585
		fManager.disposeInformationControl();
586
		fSubjectRegion= null;
587
		fHyperlinks= hyperlinks;
588
		
589
		if (hyperlinks.length == 1)
590
			return;
591
		
592
		int start= hyperlinks[0].getHyperlinkRegion().getOffset();
593
		int end= start + hyperlinks[0].getHyperlinkRegion().getLength();
594
		
595
		for (int i= 1; i < hyperlinks.length; i++) {
596
			int hstart= hyperlinks[i].getHyperlinkRegion().getOffset();
597
			int hend= hstart + hyperlinks[i].getHyperlinkRegion().getLength();
598
			
599
			start= Math.min(start, hstart);
600
			end= Math.max(end, hend);
601
		}
602
		
603
		fSubjectRegion= new Region(start, end - start);
604
		
605
		fManager.showInformation();
606
	}
607
	
608
	private boolean equals(IHyperlink[] oldLinks, IHyperlink[] newLinks) {
609
		if (oldLinks == null)
610
			return false;
611
		
612
		if (oldLinks.length != newLinks.length)
613
			return false;
614
		
615
		for (int i= 0; i < newLinks.length; i++) {
616
			if (!oldLinks[i].getHyperlinkRegion().equals(newLinks[i].getHyperlinkRegion()))
617
				return false;
618
		}
619
		
620
		return true;
621
	}
622
}

Return to bug 215473