Mercurial > projects > dwt-addons
annotate dwtx/jface/text/information/InformationPresenter.d @ 133:7d818bd32d63
Fix ctors to this with gvim regexp
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 24 Aug 2008 01:29:22 +0200 |
parents | c4fb132a086c |
children | 51e6e63f930e |
rev | line source |
---|---|
129 | 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 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module dwtx.jface.text.information.InformationPresenter; | |
14 | |
131 | 15 import dwtx.jface.text.information.IInformationProvider; // packageimport |
16 import dwtx.jface.text.information.IInformationProviderExtension; // packageimport | |
17 import dwtx.jface.text.information.IInformationPresenterExtension; // packageimport | |
18 import dwtx.jface.text.information.IInformationProviderExtension2; // packageimport | |
19 import dwtx.jface.text.information.IInformationPresenter; // packageimport | |
20 | |
21 | |
129 | 22 import dwt.dwthelper.utils; |
23 | |
24 import java.util.HashMap; | |
25 import java.util.Map; | |
26 | |
27 import dwt.custom.StyledText; | |
28 import dwt.events.ControlEvent; | |
29 import dwt.events.ControlListener; | |
30 import dwt.events.FocusEvent; | |
31 import dwt.events.FocusListener; | |
32 import dwt.events.KeyEvent; | |
33 import dwt.events.KeyListener; | |
34 import dwt.events.MouseEvent; | |
35 import dwt.events.MouseListener; | |
36 import dwt.graphics.Point; | |
37 import dwt.graphics.Rectangle; | |
38 import dwt.widgets.Control; | |
39 import dwt.widgets.Display; | |
40 import dwtx.core.runtime.Assert; | |
41 import dwtx.jface.text.AbstractInformationControlManager; | |
42 import dwtx.jface.text.BadLocationException; | |
43 import dwtx.jface.text.IDocumentExtension3; | |
44 import dwtx.jface.text.IInformationControl; | |
45 import dwtx.jface.text.IInformationControlCreator; | |
46 import dwtx.jface.text.IRegion; | |
47 import dwtx.jface.text.ITextViewer; | |
48 import dwtx.jface.text.ITextViewerExtension5; | |
49 import dwtx.jface.text.IViewportListener; | |
50 import dwtx.jface.text.IWidgetTokenKeeper; | |
51 import dwtx.jface.text.IWidgetTokenKeeperExtension; | |
52 import dwtx.jface.text.IWidgetTokenOwner; | |
53 import dwtx.jface.text.IWidgetTokenOwnerExtension; | |
54 import dwtx.jface.text.Region; | |
55 import dwtx.jface.text.TextUtilities; | |
56 | |
57 | |
58 /** | |
59 * Standard implementation of <code>IInformationPresenter</code>. | |
60 * This implementation extends <code>AbstractInformationControlManager</code>. | |
61 * The information control is made visible on request by calling | |
62 * {@link #showInformationControl(Rectangle)}. | |
63 * <p> | |
64 * Usually, clients instantiate this class and configure it before using it. The configuration | |
65 * must be consistent: This means the used {@link dwtx.jface.text.IInformationControlCreator} | |
66 * must create an information control expecting information in the same format the configured | |
67 * {@link dwtx.jface.text.information.IInformationProvider}s use to encode the information they provide. | |
68 * </p> | |
69 * | |
70 * @since 2.0 | |
71 */ | |
72 public class InformationPresenter : AbstractInformationControlManager , IInformationPresenter, IInformationPresenterExtension, IWidgetTokenKeeper, IWidgetTokenKeeperExtension { | |
73 | |
74 | |
75 /** | |
76 * Priority of the info controls managed by this information presenter. | |
77 * Default value: <code>5</code>. | |
78 * | |
79 * @since 3.0 | |
80 */ | |
81 /* | |
82 * 5 as value has been chosen in order to beat the hovers of {@link dwtx.jface.text.TextViewerHoverManager} | |
83 */ | |
84 public static final int WIDGET_PRIORITY= 5; | |
85 | |
86 | |
87 /** | |
88 * Internal information control closer. Listens to several events issued by its subject control | |
89 * and closes the information control when necessary. | |
90 */ | |
91 class Closer : IInformationControlCloser, ControlListener, MouseListener, FocusListener, IViewportListener, KeyListener { | |
92 | |
93 /** The subject control. */ | |
94 private Control fSubjectControl; | |
95 /** The information control. */ | |
96 private IInformationControl fInformationControlToClose; | |
97 /** Indicates whether this closer is active. */ | |
98 private bool fIsActive= false; | |
99 | |
100 /* | |
101 * @see IInformationControlCloser#setSubjectControl(Control) | |
102 */ | |
103 public void setSubjectControl(Control control) { | |
104 fSubjectControl= control; | |
105 } | |
106 | |
107 /* | |
108 * @see IInformationControlCloser#setInformationControl(IInformationControl) | |
109 */ | |
110 public void setInformationControl(IInformationControl control) { | |
111 fInformationControlToClose= control; | |
112 } | |
113 | |
114 /* | |
115 * @see IInformationControlCloser#start(Rectangle) | |
116 */ | |
117 public void start(Rectangle informationArea) { | |
118 | |
119 if (fIsActive) | |
120 return; | |
121 fIsActive= true; | |
122 | |
123 if (fSubjectControl !is null && !fSubjectControl.isDisposed()) { | |
124 fSubjectControl.addControlListener(this); | |
125 fSubjectControl.addMouseListener(this); | |
126 fSubjectControl.addFocusListener(this); | |
127 fSubjectControl.addKeyListener(this); | |
128 } | |
129 | |
130 if (fInformationControlToClose !is null) | |
131 fInformationControlToClose.addFocusListener(this); | |
132 | |
133 fTextViewer.addViewportListener(this); | |
134 } | |
135 | |
136 /* | |
137 * @see IInformationControlCloser#stop() | |
138 */ | |
139 public void stop() { | |
140 | |
141 if (!fIsActive) | |
142 return; | |
143 fIsActive= false; | |
144 | |
145 fTextViewer.removeViewportListener(this); | |
146 | |
147 if (fInformationControlToClose !is null) | |
148 fInformationControlToClose.removeFocusListener(this); | |
149 | |
150 if (fSubjectControl !is null && !fSubjectControl.isDisposed()) { | |
151 fSubjectControl.removeControlListener(this); | |
152 fSubjectControl.removeMouseListener(this); | |
153 fSubjectControl.removeFocusListener(this); | |
154 fSubjectControl.removeKeyListener(this); | |
155 } | |
156 } | |
157 | |
158 /* | |
159 * @see ControlListener#controlResized(ControlEvent) | |
160 */ | |
161 public void controlResized(ControlEvent e) { | |
162 hideInformationControl(); | |
163 } | |
164 | |
165 /* | |
166 * @see ControlListener#controlMoved(ControlEvent) | |
167 */ | |
168 public void controlMoved(ControlEvent e) { | |
169 hideInformationControl(); | |
170 } | |
171 | |
172 /* | |
173 * @see MouseListener#mouseDown(MouseEvent) | |
174 */ | |
175 public void mouseDown(MouseEvent e) { | |
176 hideInformationControl(); | |
177 } | |
178 | |
179 /* | |
180 * @see MouseListener#mouseUp(MouseEvent) | |
181 */ | |
182 public void mouseUp(MouseEvent e) { | |
183 } | |
184 | |
185 /* | |
186 * @see MouseListener#mouseDoubleClick(MouseEvent) | |
187 */ | |
188 public void mouseDoubleClick(MouseEvent e) { | |
189 hideInformationControl(); | |
190 } | |
191 | |
192 /* | |
193 * @see FocusListener#focusGained(FocusEvent) | |
194 */ | |
195 public void focusGained(FocusEvent e) { | |
196 } | |
197 | |
198 /* | |
199 * @see FocusListener#focusLost(FocusEvent) | |
200 */ | |
201 public void focusLost(FocusEvent e) { | |
202 Display d= fSubjectControl.getDisplay(); | |
203 d.asyncExec(new Runnable() { | |
204 // Without the asyncExec, mouse clicks to the workbench window are swallowed. | |
205 public void run() { | |
206 if (fInformationControlToClose is null || !fInformationControlToClose.isFocusControl()) | |
207 hideInformationControl(); | |
208 } | |
209 }); | |
210 } | |
211 | |
212 /* | |
213 * @see IViewportListenerListener#viewportChanged(int) | |
214 */ | |
215 public void viewportChanged(int topIndex) { | |
216 hideInformationControl(); | |
217 } | |
218 | |
219 /* | |
220 * @see KeyListener#keyPressed(KeyEvent) | |
221 */ | |
222 public void keyPressed(KeyEvent e) { | |
223 hideInformationControl(); | |
224 } | |
225 | |
226 /* | |
227 * @see KeyListener#keyReleased(KeyEvent) | |
228 */ | |
229 public void keyReleased(KeyEvent e) { | |
230 } | |
231 } | |
232 | |
233 | |
234 /** The text viewer this information presenter works on */ | |
235 private ITextViewer fTextViewer; | |
236 /** The map of <code>IInformationProvider</code> objects */ | |
237 private Map fProviders; | |
238 /** The offset to override selection. */ | |
239 private int fOffset= -1; | |
240 /** | |
241 * The document partitioning for this information presenter. | |
242 * @since 3.0 | |
243 */ | |
244 private String fPartitioning; | |
245 | |
246 /** | |
247 * Creates a new information presenter that uses the given information control creator. | |
248 * The presenter is not installed on any text viewer yet. By default, an information | |
249 * control closer is set that closes the information control in the event of key strokes, | |
250 * resizing, moves, focus changes, mouse clicks, and disposal - all of those applied to | |
251 * the information control's parent control. Also, the setup ensures that the information | |
252 * control when made visible will request the focus. By default, the default document | |
253 * partitioning {@link IDocumentExtension3#DEFAULT_PARTITIONING} is used. | |
254 * | |
255 * @param creator the information control creator to be used | |
256 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
257 public this(IInformationControlCreator creator) { |
129 | 258 super(creator); |
259 setCloser(new Closer()); | |
260 takesFocusWhenVisible(true); | |
261 fPartitioning= IDocumentExtension3.DEFAULT_PARTITIONING; | |
262 } | |
263 | |
264 /** | |
265 * Sets the document partitioning to be used by this information presenter. | |
266 * | |
267 * @param partitioning the document partitioning to be used by this information presenter | |
268 * @since 3.0 | |
269 */ | |
270 public void setDocumentPartitioning(String partitioning) { | |
271 Assert.isNotNull(partitioning); | |
272 fPartitioning= partitioning; | |
273 } | |
274 | |
275 /* | |
276 * @see dwtx.jface.text.information.IInformationPresenterExtension#getDocumentPartitioning() | |
277 * @since 3.0 | |
278 */ | |
279 public String getDocumentPartitioning() { | |
280 return fPartitioning; | |
281 } | |
282 | |
283 /** | |
284 * Registers a given information provider for a particular content type. | |
285 * If there is already a provider registered for this type, the new provider | |
286 * is registered instead of the old one. | |
287 * | |
288 * @param provider the information provider to register, or <code>null</code> to remove an existing one | |
289 * @param contentType the content type under which to register | |
290 */ | |
291 public void setInformationProvider(IInformationProvider provider, String contentType) { | |
292 | |
293 Assert.isNotNull(contentType); | |
294 | |
295 if (fProviders is null) | |
296 fProviders= new HashMap(); | |
297 | |
298 if (provider is null) | |
299 fProviders.remove(contentType); | |
300 else | |
301 fProviders.put(contentType, provider); | |
302 } | |
303 | |
304 /* | |
305 * @see IInformationPresenter#getInformationProvider(String) | |
306 */ | |
307 public IInformationProvider getInformationProvider(String contentType) { | |
308 if (fProviders is null) | |
309 return null; | |
310 | |
311 return (IInformationProvider) fProviders.get(contentType); | |
312 } | |
313 | |
314 /** | |
315 * Sets a offset to override the selection. Setting the value to <code>-1</code> will disable | |
316 * overriding. | |
317 * | |
318 * @param offset the offset to override selection or <code>-1</code> | |
319 */ | |
320 public void setOffset(int offset) { | |
321 fOffset= offset; | |
322 } | |
323 | |
324 /* | |
325 * @see AbstractInformationControlManager#computeInformation() | |
326 */ | |
327 protected void computeInformation() { | |
328 | |
329 int offset= fOffset < 0 ? fTextViewer.getSelectedRange().x : fOffset; | |
330 if (offset is -1) | |
331 return; | |
332 | |
333 fOffset= -1; | |
334 | |
335 IInformationProvider provider= null; | |
336 try { | |
337 String contentType= TextUtilities.getContentType(fTextViewer.getDocument(), getDocumentPartitioning(), offset, true); | |
338 provider= getInformationProvider(contentType); | |
339 } catch (BadLocationException x) { | |
340 } | |
341 if (provider is null) | |
342 return; | |
343 | |
344 IRegion subject= provider.getSubject(fTextViewer, offset); | |
345 if (subject is null) | |
346 return; | |
347 | |
348 Object info; | |
349 if (provider instanceof IInformationProviderExtension) { | |
350 IInformationProviderExtension extension= (IInformationProviderExtension) provider; | |
351 info= extension.getInformation2(fTextViewer, subject); | |
352 } else { | |
353 // backward compatibility code | |
354 info= provider.getInformation(fTextViewer, subject); | |
355 } | |
356 | |
357 if (provider instanceof IInformationProviderExtension2) | |
358 setCustomInformationControlCreator(((IInformationProviderExtension2) provider).getInformationPresenterControlCreator()); | |
359 else | |
360 setCustomInformationControlCreator(null); | |
361 | |
362 setInformation(info, computeArea(subject)); | |
363 } | |
364 | |
365 /** | |
366 * Determines the graphical area covered by the given text region. | |
367 * | |
368 * @param region the region whose graphical extend must be computed | |
369 * @return the graphical extend of the given region | |
370 */ | |
371 private Rectangle computeArea(IRegion region) { | |
372 | |
373 int start= 0; | |
374 int end= 0; | |
375 | |
376 IRegion widgetRegion= modelRange2WidgetRange(region); | |
377 if (widgetRegion !is null) { | |
378 start= widgetRegion.getOffset(); | |
379 end= widgetRegion.getOffset() + widgetRegion.getLength(); | |
380 } | |
381 | |
382 StyledText styledText= fTextViewer.getTextWidget(); | |
383 Rectangle bounds; | |
384 if (end > 0 && start < end) | |
385 bounds= styledText.getTextBounds(start, end - 1); | |
386 else { | |
387 Point loc= styledText.getLocationAtOffset(start); | |
388 bounds= new Rectangle(loc.x, loc.y, 0, styledText.getLineHeight(start)); | |
389 } | |
390 | |
391 return bounds; | |
392 } | |
393 | |
394 /** | |
395 * Translated the given range in the viewer's document into the corresponding | |
396 * range of the viewer's widget. | |
397 * | |
398 * @param region the range in the viewer's document | |
399 * @return the corresponding widget range | |
400 * @since 2.1 | |
401 */ | |
402 private IRegion modelRange2WidgetRange(IRegion region) { | |
403 if (fTextViewer instanceof ITextViewerExtension5) { | |
404 ITextViewerExtension5 extension= (ITextViewerExtension5) fTextViewer; | |
405 return extension.modelRange2WidgetRange(region); | |
406 } | |
407 | |
408 IRegion visibleRegion= fTextViewer.getVisibleRegion(); | |
409 int start= region.getOffset() - visibleRegion.getOffset(); | |
410 int end= start + region.getLength(); | |
411 if (end > visibleRegion.getLength()) | |
412 end= visibleRegion.getLength(); | |
413 | |
414 return new Region(start, end - start); | |
415 } | |
416 | |
417 /* | |
418 * @see IInformationPresenter#install(ITextViewer) | |
419 */ | |
420 public void install(ITextViewer textViewer) { | |
421 fTextViewer= textViewer; | |
422 install(fTextViewer.getTextWidget()); | |
423 } | |
424 | |
425 /* | |
426 * @see IInformationPresenter#uninstall() | |
427 */ | |
428 public void uninstall() { | |
429 dispose(); | |
430 } | |
431 | |
432 /* | |
433 * @see AbstractInformationControlManager#showInformationControl(Rectangle) | |
434 */ | |
435 protected void showInformationControl(Rectangle subjectArea) { | |
436 if (fTextViewer instanceof IWidgetTokenOwnerExtension && fTextViewer instanceof IWidgetTokenOwner) { | |
437 IWidgetTokenOwnerExtension extension= (IWidgetTokenOwnerExtension) fTextViewer; | |
438 if (extension.requestWidgetToken(this, WIDGET_PRIORITY)) | |
439 super.showInformationControl(subjectArea); | |
440 } else if (fTextViewer instanceof IWidgetTokenOwner) { | |
441 IWidgetTokenOwner owner= (IWidgetTokenOwner) fTextViewer; | |
442 if (owner.requestWidgetToken(this)) | |
443 super.showInformationControl(subjectArea); | |
444 | |
445 } else | |
446 super.showInformationControl(subjectArea); | |
447 } | |
448 | |
449 /* | |
450 * @see AbstractInformationControlManager#hideInformationControl() | |
451 */ | |
452 protected void hideInformationControl() { | |
453 try { | |
454 super.hideInformationControl(); | |
455 } finally { | |
456 if (fTextViewer instanceof IWidgetTokenOwner) { | |
457 IWidgetTokenOwner owner= (IWidgetTokenOwner) fTextViewer; | |
458 owner.releaseWidgetToken(this); | |
459 } | |
460 } | |
461 } | |
462 | |
463 /* | |
464 * @see AbstractInformationControlManager#handleInformationControlDisposed() | |
465 */ | |
466 protected void handleInformationControlDisposed() { | |
467 try { | |
468 super.handleInformationControlDisposed(); | |
469 } finally { | |
470 if (fTextViewer instanceof IWidgetTokenOwner) { | |
471 IWidgetTokenOwner owner= (IWidgetTokenOwner) fTextViewer; | |
472 owner.releaseWidgetToken(this); | |
473 } | |
474 } | |
475 } | |
476 | |
477 /* | |
478 * @see dwtx.jface.text.IWidgetTokenKeeper#requestWidgetToken(IWidgetTokenOwner) | |
479 */ | |
480 public bool requestWidgetToken(IWidgetTokenOwner owner) { | |
481 return false; | |
482 } | |
483 | |
484 /* | |
485 * @see dwtx.jface.text.IWidgetTokenKeeperExtension#requestWidgetToken(dwtx.jface.text.IWidgetTokenOwner, int) | |
486 * @since 3.0 | |
487 */ | |
488 public bool requestWidgetToken(IWidgetTokenOwner owner, int priority) { | |
489 return false; | |
490 } | |
491 | |
492 /* | |
493 * @see dwtx.jface.text.IWidgetTokenKeeperExtension#setFocus(dwtx.jface.text.IWidgetTokenOwner) | |
494 * @since 3.0 | |
495 */ | |
496 public bool setFocus(IWidgetTokenOwner owner) { | |
497 return false; | |
498 } | |
499 } | |
500 |