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