Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 96331f9804bb1dfd98ec976bc2423d969dfc0563 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/*******************************************************************************
 * Copyright (c) 2008 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jface.internal.text;

import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Shell;

import org.eclipse.jface.util.Geometry;

import org.eclipse.jface.text.AbstractInformationControlManager;
import org.eclipse.jface.text.AbstractReusableInformationControlCreator;
import org.eclipse.jface.text.DefaultInformationControl;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.IInformationControlExtension2;
import org.eclipse.jface.text.IInformationControlExtension3;


/**
 * An information control replacer can replace an {@link AbstractInformationControlManager}'s
 * control.
 * <p>
 * The {@link AbstractInformationControlManager} can be configured with such a replacer by calling
 * <code>setInformationControlReplacer</code>.
 * </p>
 *
 * @since 3.4
 */
public class InformationControlReplacer extends AbstractInformationControlManager {

	/**
	 * Minimal width in pixels.
	 */
	private static final int MIN_WIDTH= 80;
	/**
	 * Minimal height in pixels.
	 */
	private static final int MIN_HEIGHT= 50;

	/**
	 * Default control creator.
	 */
	protected static class DefaultInformationControlCreator extends AbstractReusableInformationControlCreator {
		@Override
		public IInformationControl doCreateInformationControl(Shell shell) {
			return new DefaultInformationControl(shell, true);
		}
	}

	private boolean fIsReplacing;
	private Object fReplacableInformation;
	private boolean fDelayedInformationSet;
	private Rectangle fReplaceableArea;
	private Rectangle fContentBounds;


	/**
	 * Creates a new information control replacer.
	 *
	 * @param creator the default information control creator
	 */
	public InformationControlReplacer(IInformationControlCreator creator) {
		super(creator);
		takesFocusWhenVisible(false);
	}

	/**
	 * Replace the information control.
	 *
	 * @param informationPresenterControlCreator the information presenter control creator
	 * @param contentBounds the bounds of the content area of the information control
	 * @param information the information to show
	 * @param subjectArea the subject area
	 * @param takeFocus <code>true</code> iff the replacing information control should take focus
	 */
	public void replaceInformationControl(IInformationControlCreator informationPresenterControlCreator, Rectangle contentBounds, Object information, final Rectangle subjectArea, boolean takeFocus) {

		try {
			fIsReplacing= true;
			if (! fDelayedInformationSet)
				fReplacableInformation= information;
			else
				takeFocus= true; // delayed input has been set, so the original info control must have been focused
			fContentBounds= contentBounds;
			fReplaceableArea= subjectArea;

			setCustomInformationControlCreator(informationPresenterControlCreator);

			takesFocusWhenVisible(takeFocus);

			showInformation();
		} finally {
			fIsReplacing= false;
			fReplacableInformation= null;
			fDelayedInformationSet= false;
			fReplaceableArea= null;
			setCustomInformationControlCreator(null);
		}
	}

	@Override
	protected void computeInformation() {
		if (fIsReplacing && fReplacableInformation != null) {
			setInformation(fReplacableInformation, fReplaceableArea);
			return;
		}

		if (DEBUG)
			System.out.println("InformationControlReplacer: no active replaceable"); //$NON-NLS-1$
	}

	/**
	 * Opens the information control with the given information and the specified
	 * subject area. It also activates the information control closer.
	 *
	 * @param subjectArea the information area
	 * @param information the information
	 */
	public void showInformationControl(Rectangle subjectArea, Object information) {
		IInformationControl informationControl= getInformationControl();

		Rectangle controlBounds= fContentBounds;
		if (informationControl instanceof IInformationControlExtension3) {
			IInformationControlExtension3 iControl3= (IInformationControlExtension3) informationControl;
			Rectangle trim= iControl3.computeTrim();
			controlBounds= Geometry.add(controlBounds, trim);

			/*
			 * Ensure minimal size. Interacting with a tiny information control
			 * (resizing, selecting text) would be a pain.
			 */
			controlBounds.width= Math.max(controlBounds.width, MIN_WIDTH);
			controlBounds.height= Math.max(controlBounds.height, MIN_HEIGHT);

			getInternalAccessor().cropToClosestMonitor(controlBounds);
		}

		Point location= Geometry.getLocation(controlBounds);
		Point size= Geometry.getSize(controlBounds);

		// Caveat: some IInformationControls fail unless setSizeConstraints(..) is called with concrete values
		informationControl.setSizeConstraints(size.x, size.y);

		if (informationControl instanceof IInformationControlExtension2)
			((IInformationControlExtension2) informationControl).setInput(information);
		else
			informationControl.setInformation(information.toString());

		informationControl.setLocation(location);
		informationControl.setSize(size.x, size.y);

		showInformationControl(subjectArea);
	}

	@Override
	public void hideInformationControl() {
		super.hideInformationControl();
	}

	/**
	 * @param input the delayed input, or <code>null</code> to request cancellation
	 */
	public void setDelayedInput(Object input) {
		fReplacableInformation= input;
		if (! isReplacing()) {
			fDelayedInformationSet= true;
		} else if (getCurrentInformationControl2() instanceof IInformationControlExtension2) {
			((IInformationControlExtension2) getCurrentInformationControl2()).setInput(input);
		} else if (getCurrentInformationControl2() != null) {
			getCurrentInformationControl2().setInformation(input.toString());
		}
	}

	/**
	 * Tells whether the replacer is currently replacing another information control.
	 *
	 * @return <code>true</code> while code from {@link #replaceInformationControl(IInformationControlCreator, Rectangle, Object, Rectangle, boolean)} is run
	 */
	public boolean isReplacing() {
		return fIsReplacing;
	}

	/**
	 * @return the current information control, or <code>null</code> if none available
	 */
	public IInformationControl getCurrentInformationControl2() {
		return getInternalAccessor().getCurrentInformationControl();
	}

	/**
	 * The number of pixels to blow up the keep-up zone.
	 *
	 * @return the margin in pixels
	 */
	public int getKeepUpMargin() {
		return 15;
	}
}

Back to the top