Mercurial > projects > dwt-addons
comparison dwtx/jface/text/AbstractInformationControlManager.d @ 129:eb30df5ca28b
Added JFace Text sources
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 23 Aug 2008 19:10:48 +0200 |
parents | |
children | c4fb132a086c |
comparison
equal
deleted
inserted
replaced
128:8df1d4193877 | 129:eb30df5ca28b |
---|---|
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 * Sean Montgomery, sean_montgomery@comcast.net - https://bugs.eclipse.org/bugs/show_bug.cgi?id=45095 | |
11 * Port to the D programming language: | |
12 * Frank Benoit <benoit@tionex.de> | |
13 *******************************************************************************/ | |
14 | |
15 module dwtx.jface.text.AbstractInformationControlManager; | |
16 | |
17 import dwt.dwthelper.utils; | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 import dwt.DWT; | |
24 import dwt.events.DisposeEvent; | |
25 import dwt.events.DisposeListener; | |
26 import dwt.graphics.GC; | |
27 import dwt.graphics.Point; | |
28 import dwt.graphics.Rectangle; | |
29 import dwt.widgets.Control; | |
30 import dwt.widgets.Display; | |
31 import dwt.widgets.Monitor; | |
32 import dwtx.core.runtime.Assert; | |
33 import dwtx.core.runtime.Platform; | |
34 import dwtx.jface.dialogs.IDialogSettings; | |
35 import dwtx.jface.internal.text.InformationControlReplacer; | |
36 import dwtx.jface.internal.text.InternalAccessor; | |
37 import dwtx.jface.text.ITextViewerExtension8.EnrichMode; | |
38 import dwtx.jface.util.Geometry; | |
39 | |
40 | |
41 /** | |
42 * Manages the life cycle, visibility, layout, and contents of an | |
43 * {@link dwtx.jface.text.IInformationControl}. This manager can be | |
44 * installed on and removed from a control, referred to as the subject control, | |
45 * i.e. the one from which the subject of the information to be shown is | |
46 * retrieved. Also a manager can be enabled or disabled. An installed and | |
47 * enabled manager can be forced to show information in its information control | |
48 * using <code>showInformation</code>. An information control manager uses an | |
49 * <code>IInformationControlCloser</code> to define the behavior when a | |
50 * presented information control must be closed. The disposal of the subject and | |
51 * the information control are internally handled by the information control | |
52 * manager and are not the responsibility of the information control closer. | |
53 * | |
54 * @see dwtx.jface.text.IInformationControl | |
55 * @since 2.0 | |
56 */ | |
57 abstract public class AbstractInformationControlManager { | |
58 | |
59 /** | |
60 * An internal class that gives access to internal methods. | |
61 * | |
62 * @since 3.4 | |
63 */ | |
64 class MyInternalAccessor : InternalAccessor { | |
65 public IInformationControl getCurrentInformationControl() { | |
66 return AbstractInformationControlManager.this.getCurrentInformationControl(); | |
67 } | |
68 | |
69 public void setInformationControlReplacer(InformationControlReplacer replacer) { | |
70 AbstractInformationControlManager.this.setInformationControlReplacer(replacer); | |
71 } | |
72 | |
73 public InformationControlReplacer getInformationControlReplacer() { | |
74 return AbstractInformationControlManager.this.getInformationControlReplacer(); | |
75 } | |
76 | |
77 public bool canReplace(IInformationControl control) { | |
78 return AbstractInformationControlManager.this.canReplace(control); | |
79 } | |
80 | |
81 public bool isReplaceInProgress() { | |
82 return AbstractInformationControlManager.this.isReplaceInProgress(); | |
83 } | |
84 | |
85 public void replaceInformationControl(bool takeFocus) { | |
86 AbstractInformationControlManager.this.replaceInformationControl(takeFocus); | |
87 } | |
88 | |
89 public void cropToClosestMonitor(Rectangle bounds) { | |
90 AbstractInformationControlManager.this.cropToClosestMonitor(bounds); | |
91 } | |
92 | |
93 public void setHoverEnrichMode(EnrichMode mode) { | |
94 throw new UnsupportedOperationException("only implemented in AbstractHoverInformationControlManager"); //$NON-NLS-1$ | |
95 } | |
96 | |
97 public bool getAllowMouseExit() { | |
98 throw new UnsupportedOperationException("only implemented in AnnotationBarHoverManager"); //$NON-NLS-1$ | |
99 } | |
100 } | |
101 | |
102 /** | |
103 * Interface of an information control closer. An information control closer | |
104 * monitors its information control and its subject control and closes the | |
105 * information control if necessary. | |
106 * <p> | |
107 * Clients must implement this interface in order to equip an information | |
108 * control manager accordingly. | |
109 */ | |
110 public interface IInformationControlCloser { | |
111 | |
112 /** | |
113 * Sets the closer's subject control. This is the control that parents | |
114 * the information control and from which the subject of the information | |
115 * to be shown is retrieved. <p> | |
116 * Must be called before <code>start</code>. May again be called | |
117 * between <code>start</code> and <code>stop</code>. | |
118 * | |
119 * @param subject the subject control | |
120 */ | |
121 public void setSubjectControl(Control subject); | |
122 | |
123 /** | |
124 * Sets the closer's information control, the one to close if necessary. <p> | |
125 * Must be called before <code>start</code>. May again be called | |
126 * between <code>start</code> and <code>stop</code>. | |
127 * | |
128 * @param control the information control | |
129 */ | |
130 public void setInformationControl(IInformationControl control); | |
131 | |
132 /** | |
133 * Tells this closer to start monitoring the subject and the information | |
134 * control. The presented information is considered valid for the given | |
135 * area of the subject control's display. | |
136 * | |
137 * @param subjectArea the area for which the presented information is valid | |
138 */ | |
139 public void start(Rectangle subjectArea); | |
140 | |
141 /** | |
142 * Tells this closer to stop monitoring the subject and the information control. | |
143 */ | |
144 public void stop(); | |
145 } | |
146 | |
147 | |
148 | |
149 /** | |
150 * Constitutes entities to enumerate anchors for the layout of the information control. | |
151 */ | |
152 public static final class Anchor { | |
153 private final int fFlag; | |
154 private Anchor(int flag) { | |
155 fFlag= flag; | |
156 } | |
157 /** | |
158 * Returns the DWT direction flag. One of {@link DWT#BOTTOM}, {@link DWT#TOP}, | |
159 * {@link DWT#LEFT}, {@link DWT#RIGHT}, {@link DWT#CENTER}, | |
160 * | |
161 * @return the DWT direction flag | |
162 * @since 3.3 | |
163 */ | |
164 int getSWTFlag() { | |
165 return fFlag; | |
166 } | |
167 | |
168 public String toString() { | |
169 switch (fFlag) { | |
170 case DWT.BOTTOM: return "BOTTOM"; //$NON-NLS-1$ | |
171 case DWT.TOP: return "TOP"; //$NON-NLS-1$ | |
172 case DWT.LEFT: return "LEFT"; //$NON-NLS-1$ | |
173 case DWT.RIGHT: return "RIGHT"; //$NON-NLS-1$ | |
174 case DWT.CENTER: return "CENTER"; //$NON-NLS-1$ | |
175 default: return Integer.toHexString(fFlag); | |
176 } | |
177 } | |
178 } | |
179 | |
180 /** Internal anchor list. */ | |
181 private final static Anchor[] ANCHORS= { new Anchor(DWT.TOP), new Anchor(DWT.BOTTOM), new Anchor(DWT.LEFT), new Anchor(DWT.RIGHT) }; | |
182 | |
183 /** Anchor representing the top of the information area */ | |
184 public final static Anchor ANCHOR_TOP= ANCHORS[0]; | |
185 /** Anchor representing the bottom of the information area */ | |
186 public final static Anchor ANCHOR_BOTTOM= ANCHORS[1]; | |
187 /** Anchor representing the left side of the information area */ | |
188 public final static Anchor ANCHOR_LEFT= ANCHORS[2]; | |
189 /** Anchor representing the right side of the information area */ | |
190 public final static Anchor ANCHOR_RIGHT= ANCHORS[3]; | |
191 /** | |
192 * Anchor representing the middle of the subject control | |
193 * @since 2.1 | |
194 */ | |
195 public final static Anchor ANCHOR_GLOBAL= new Anchor(DWT.CENTER); | |
196 | |
197 /** | |
198 * Dialog store constant for the location's x-coordinate. | |
199 * @since 3.0 | |
200 */ | |
201 public static final String STORE_LOCATION_X= "location.x"; //$NON-NLS-1$ | |
202 /** | |
203 * Dialog store constant for the location's y-coordinate. | |
204 * @since 3.0 | |
205 */ | |
206 public static final String STORE_LOCATION_Y= "location.y"; //$NON-NLS-1$ | |
207 /** | |
208 * Dialog store constant for the size's width. | |
209 * @since 3.0 | |
210 */ | |
211 public static final String STORE_SIZE_WIDTH= "size.width"; //$NON-NLS-1$ | |
212 /** | |
213 * Dialog store constant for the size's height. | |
214 * @since 3.0 | |
215 */ | |
216 public static final String STORE_SIZE_HEIGHT= "size.height"; //$NON-NLS-1$ | |
217 | |
218 /** | |
219 * Tells whether this class and its subclasses are in debug mode. | |
220 * <p> | |
221 * Subclasses may use this. | |
222 * </p> | |
223 * @since 3.4 | |
224 */ | |
225 protected static final bool DEBUG= "true".equalsIgnoreCase(Platform.getDebugOption("dwtx.jface.text/debug/AbstractInformationControlManager")); //$NON-NLS-1$//$NON-NLS-2$ | |
226 | |
227 | |
228 /** The subject control of the information control */ | |
229 private Control fSubjectControl; | |
230 | |
231 /** The display area for which the information to be presented is valid */ | |
232 private Rectangle fSubjectArea; | |
233 | |
234 /** The information to be presented */ | |
235 private Object fInformation; | |
236 | |
237 /** Indicates whether the information control takes focus when visible */ | |
238 private bool fTakesFocusWhenVisible= false; | |
239 | |
240 /** | |
241 * The information control. | |
242 * | |
243 * <p>This field should not be referenced by subclasses. It is <code>protected</code> for API | |
244 * compatibility reasons. | |
245 */ | |
246 protected IInformationControl fInformationControl; | |
247 | |
248 /** | |
249 * The information control creator. | |
250 * | |
251 * <p>This field should not be referenced by subclasses. It is <code>protected</code> for API | |
252 * compatibility reasons. | |
253 */ | |
254 protected IInformationControlCreator fInformationControlCreator; | |
255 | |
256 /** | |
257 * The information control closer. | |
258 * | |
259 * <p>This field should not be referenced by subclasses. It is <code>protected</code> for API | |
260 * compatibility reasons. | |
261 */ | |
262 protected IInformationControlCloser fInformationControlCloser; | |
263 | |
264 /** | |
265 * Indicates that the information control has been disposed. | |
266 * | |
267 * <p>This field should not be referenced by subclasses. It is <code>protected</code> for API | |
268 * compatibility reasons. | |
269 */ | |
270 protected bool fDisposed= false; | |
271 | |
272 /** | |
273 * The information control replacer to be used when this information control | |
274 * needs to be replaced with another information control. | |
275 * | |
276 * @since 3.4 | |
277 */ | |
278 private InformationControlReplacer fInformationControlReplacer; | |
279 | |
280 /** Indicates the enable state of this manager */ | |
281 private bool fEnabled= false; | |
282 | |
283 /** Cached, computed size constraints of the information control in points */ | |
284 private Point fSizeConstraints; | |
285 | |
286 /** The vertical margin when laying out the information control */ | |
287 private int fMarginY= 5; | |
288 | |
289 /** The horizontal margin when laying out the information control */ | |
290 private int fMarginX= 5; | |
291 | |
292 /** The width constraint of the information control in characters */ | |
293 private int fWidthConstraint= 60; | |
294 | |
295 /** The height constraint of the information control in characters */ | |
296 private int fHeightConstraint= 6; | |
297 | |
298 /** Indicates whether the size constraints should be enforced as minimal control size */ | |
299 private bool fEnforceAsMinimalSize= false; | |
300 | |
301 /** Indicates whether the size constraints should be enforced as maximal control size */ | |
302 private bool fEnforceAsMaximalSize= false; | |
303 | |
304 /** The anchor for laying out the information control in relation to the subject control */ | |
305 private Anchor fAnchor= ANCHOR_BOTTOM; | |
306 | |
307 /** | |
308 * The anchor sequence used to layout the information control if the original anchor | |
309 * can not be used because the information control would not fit in the display client area. | |
310 * <p> | |
311 * The fallback anchor for a given anchor is the one that comes directly after the given anchor or | |
312 * is the first one in the sequence if the given anchor is the last one in the sequence. | |
313 * <p> | |
314 * </p> | |
315 * Note: This sequence is ignored if the original anchor is not contained in this sequence. | |
316 * </p> | |
317 * | |
318 * @see #fAnchor | |
319 */ | |
320 private Anchor[] fFallbackAnchors= ANCHORS; | |
321 | |
322 /** | |
323 * The custom information control creator. | |
324 * @since 3.0 | |
325 */ | |
326 private volatile IInformationControlCreator fCustomInformationControlCreator; | |
327 | |
328 /** | |
329 * Tells whether a custom information control is in use. | |
330 * @since 3.0 | |
331 */ | |
332 private bool fIsCustomInformationControl= false; | |
333 | |
334 /** | |
335 * The dialog settings for the control's bounds. | |
336 * @since 3.0 | |
337 */ | |
338 private IDialogSettings fDialogSettings; | |
339 | |
340 /** | |
341 * Tells whether the control's location should be read | |
342 * from the dialog settings and whether the last | |
343 * valid control's size is stored back into the settings. | |
344 * | |
345 * @since 3.0 | |
346 */ | |
347 private bool fIsRestoringLocation; | |
348 | |
349 /** | |
350 * Tells whether the control's size should be read | |
351 * from the dialog settings and whether the last | |
352 * valid control's size is stored back into the settings. | |
353 * | |
354 * @since 3.0 | |
355 */ | |
356 private bool fIsRestoringSize; | |
357 | |
358 /** | |
359 * The dispose listener on the subject control. | |
360 * | |
361 * @since 3.1 | |
362 */ | |
363 private DisposeListener fSubjectControlDisposeListener; | |
364 | |
365 | |
366 /** | |
367 * Creates a new information control manager using the given information control creator. | |
368 * By default the following configuration is given: | |
369 * <ul> | |
370 * <li> enabled is false | |
371 * <li> horizontal margin is 5 points | |
372 * <li> vertical margin is 5 points | |
373 * <li> width constraint is 60 characters | |
374 * <li> height constraint is 6 characters | |
375 * <li> enforce constraints as minimal size is false | |
376 * <li> enforce constraints as maximal size is false | |
377 * <li> layout anchor is ANCHOR_BOTTOM | |
378 * <li> fall back anchors is { ANCHOR_TOP, ANCHOR_BOTTOM, ANCHOR_LEFT, ANCHOR_RIGHT, ANCHOR_GLOBAL } | |
379 * <li> takes focus when visible is false | |
380 * </ul> | |
381 * | |
382 * @param creator the information control creator | |
383 */ | |
384 protected AbstractInformationControlManager(IInformationControlCreator creator) { | |
385 Assert.isNotNull(creator); | |
386 fInformationControlCreator= creator; | |
387 } | |
388 | |
389 /** | |
390 * Computes the information to be displayed and the area in which the computed | |
391 * information is valid. Implementation of this method must finish their computation | |
392 * by setting the computation results using <code>setInformation</code>. | |
393 */ | |
394 abstract protected void computeInformation(); | |
395 | |
396 /** | |
397 * Sets the parameters of the information to be displayed. These are the information itself and | |
398 * the area for which the given information is valid. This so called subject area is a graphical | |
399 * region of the information control's subject control. This method calls <code>presentInformation()</code> | |
400 * to trigger the presentation of the computed information. | |
401 * | |
402 * @param information the information, or <code>null</code> if none is available | |
403 * @param subjectArea the subject area, or <code>null</code> if none is available | |
404 */ | |
405 protected final void setInformation(String information, Rectangle subjectArea) { | |
406 setInformation((Object)information, subjectArea); | |
407 } | |
408 | |
409 /** | |
410 * Sets the parameters of the information to be displayed. These are the information itself and | |
411 * the area for which the given information is valid. This so called subject area is a graphical | |
412 * region of the information control's subject control. This method calls <code>presentInformation()</code> | |
413 * to trigger the presentation of the computed information. | |
414 * | |
415 * @param information the information, or <code>null</code> if none is available | |
416 * @param subjectArea the subject area, or <code>null</code> if none is available | |
417 * @since 2.1 | |
418 */ | |
419 protected final void setInformation(Object information, Rectangle subjectArea) { | |
420 fInformation= information; | |
421 fSubjectArea= subjectArea; | |
422 presentInformation(); | |
423 } | |
424 | |
425 /** | |
426 * Sets the information control closer for this manager. | |
427 * | |
428 * @param closer the information control closer for this manager | |
429 */ | |
430 protected void setCloser(IInformationControlCloser closer) { | |
431 fInformationControlCloser= closer; | |
432 } | |
433 | |
434 /** | |
435 * Sets the information control replacer for this manager and disposes the | |
436 * old one if set. | |
437 * | |
438 * @param replacer the information control replacer for this manager, or | |
439 * <code>null</code> if no information control replacing should | |
440 * take place | |
441 * @since 3.4 | |
442 */ | |
443 void setInformationControlReplacer(InformationControlReplacer replacer) { | |
444 if (fInformationControlReplacer !is null) | |
445 fInformationControlReplacer.dispose(); | |
446 fInformationControlReplacer= replacer; | |
447 } | |
448 | |
449 /** | |
450 * Returns the current information control replacer or <code>null</code> if none has been installed. | |
451 * | |
452 * @return the current information control replacer or <code>null</code> if none has been installed | |
453 * @since 3.4 | |
454 */ | |
455 InformationControlReplacer getInformationControlReplacer() { | |
456 return fInformationControlReplacer; | |
457 } | |
458 | |
459 /** | |
460 * Returns whether an information control replacer has been installed. | |
461 * | |
462 * @return whether an information control replacer has been installed | |
463 * @since 3.4 | |
464 */ | |
465 bool hasInformationControlReplacer() { | |
466 return fInformationControlReplacer !is null; | |
467 } | |
468 | |
469 /** | |
470 * Tests whether the given information control is replaceable. | |
471 * | |
472 * @param iControl information control or <code>null</code> if none | |
473 * @return <code>true</code> if information control is replaceable, <code>false</code> otherwise | |
474 * @since 3.4 | |
475 */ | |
476 bool canReplace(IInformationControl iControl) { | |
477 return iControl instanceof IInformationControlExtension3 | |
478 && iControl instanceof IInformationControlExtension5 | |
479 && ((IInformationControlExtension5) iControl).getInformationPresenterControlCreator() !is null; | |
480 } | |
481 | |
482 /** | |
483 * Returns the current information control, or <code>null</code> if none. | |
484 * | |
485 * @return the current information control, or <code>null</code> if none | |
486 * @since 3.4 | |
487 */ | |
488 IInformationControl getCurrentInformationControl() { | |
489 return fInformationControl; | |
490 } | |
491 | |
492 /** | |
493 * Tells whether this manager's information control is currently being replaced. | |
494 * | |
495 * @return <code>true</code> if a replace is in progress | |
496 * @since 3.4 | |
497 */ | |
498 bool isReplaceInProgress() { | |
499 return fInformationControlReplacer !is null && fInformationControlReplacer.isReplacing(); | |
500 } | |
501 | |
502 /** | |
503 * Sets the horizontal and vertical margin to be used when laying out the | |
504 * information control relative to the subject control. | |
505 * | |
506 * @param xMargin the x-margin | |
507 * @param yMargin the y-Margin | |
508 */ | |
509 public void setMargins(int xMargin, int yMargin) { | |
510 fMarginX= xMargin; | |
511 fMarginY= yMargin; | |
512 } | |
513 | |
514 /** | |
515 * Sets the width- and height constraints of the information control. | |
516 * | |
517 * @param widthInChar the width constraint in number of characters | |
518 * @param heightInChar the height constrain in number of characters | |
519 * @param enforceAsMinimalSize indicates whether the constraints describe the minimal allowed size of the control | |
520 * @param enforceAsMaximalSize indicates whether the constraints describe the maximal allowed size of the control | |
521 */ | |
522 public void setSizeConstraints(int widthInChar, int heightInChar, bool enforceAsMinimalSize, bool enforceAsMaximalSize) { | |
523 fSizeConstraints= null; | |
524 fWidthConstraint= widthInChar; | |
525 fHeightConstraint= heightInChar; | |
526 fEnforceAsMinimalSize= enforceAsMinimalSize; | |
527 fEnforceAsMaximalSize= enforceAsMaximalSize; | |
528 | |
529 } | |
530 | |
531 /** | |
532 * Tells this information control manager to open the information | |
533 * control with the values contained in the given dialog settings | |
534 * and to store the control's last valid size in the given dialog | |
535 * settings. | |
536 * <p> | |
537 * Note: This API is only valid if the information control implements | |
538 * {@link IInformationControlExtension3}. Not following this restriction | |
539 * will later result in an {@link UnsupportedOperationException}. | |
540 * </p> | |
541 * <p> | |
542 * The constants used to store the values are: | |
543 * <ul> | |
544 * <li>{@link AbstractInformationControlManager#STORE_LOCATION_X}</li> | |
545 * <li>{@link AbstractInformationControlManager#STORE_LOCATION_Y}</li> | |
546 * <li>{@link AbstractInformationControlManager#STORE_SIZE_WIDTH}</li> | |
547 * <li>{@link AbstractInformationControlManager#STORE_SIZE_HEIGHT}</li> | |
548 * </ul> | |
549 * </p> | |
550 * | |
551 * @param dialogSettings | |
552 * @param restoreLocation <code>true</code> iff the location is must be (re-)stored | |
553 * @param restoreSize <code>true</code>iff the size is (re-)stored | |
554 * @since 3.0 | |
555 */ | |
556 public void setRestoreInformationControlBounds(IDialogSettings dialogSettings, bool restoreLocation, bool restoreSize) { | |
557 Assert.isTrue(dialogSettings !is null && (restoreLocation || restoreSize)); | |
558 fDialogSettings= dialogSettings; | |
559 fIsRestoringLocation= restoreLocation; | |
560 fIsRestoringSize= restoreSize; | |
561 } | |
562 | |
563 /** | |
564 * Sets the anchor used for laying out the information control relative to the | |
565 * subject control. E.g, using <code>ANCHOR_TOP</code> indicates that the | |
566 * information control is position above the area for which the information to | |
567 * be displayed is valid. | |
568 * | |
569 * @param anchor the layout anchor | |
570 */ | |
571 public void setAnchor(Anchor anchor) { | |
572 fAnchor= anchor; | |
573 } | |
574 | |
575 /** | |
576 * Sets the anchors fallback sequence used to layout the information control if the original | |
577 * anchor can not be used because the information control would not fit in the display client | |
578 * area. | |
579 * <p> | |
580 * The fallback anchor for a given anchor is the one that comes directly after the given anchor or | |
581 * is the first one in the sequence if the given anchor is the last one in the sequence. | |
582 * <p> | |
583 * </p> | |
584 * Note: This sequence is ignored if the original anchor is not contained in this list. | |
585 * </p> | |
586 * | |
587 * @param fallbackAnchors the array with the anchor fallback sequence | |
588 * @see #setAnchor(AbstractInformationControlManager.Anchor) | |
589 */ | |
590 public void setFallbackAnchors(Anchor[] fallbackAnchors) { | |
591 if (fallbackAnchors !is null) { | |
592 fFallbackAnchors= new Anchor[fallbackAnchors.length]; | |
593 System.arraycopy(fallbackAnchors, 0, fFallbackAnchors, 0, fallbackAnchors.length); | |
594 } else | |
595 fFallbackAnchors= null; | |
596 } | |
597 | |
598 /** | |
599 * Sets the temporary custom control creator, overriding this manager's default information control creator. | |
600 * | |
601 * @param informationControlCreator the creator, possibly <code>null</code> | |
602 * @since 3.0 | |
603 */ | |
604 protected void setCustomInformationControlCreator(IInformationControlCreator informationControlCreator) { | |
605 if (informationControlCreator !is null && fCustomInformationControlCreator instanceof IInformationControlCreatorExtension) { | |
606 IInformationControlCreatorExtension extension= (IInformationControlCreatorExtension) fCustomInformationControlCreator; | |
607 if (extension.canReplace(informationControlCreator)) | |
608 return; | |
609 } | |
610 fCustomInformationControlCreator= informationControlCreator; | |
611 } | |
612 | |
613 /** | |
614 * Tells the manager whether it should set the focus to the information control when made visible. | |
615 * | |
616 * @param takesFocus <code>true</code> if information control should take focus when made visible | |
617 */ | |
618 public void takesFocusWhenVisible(bool takesFocus) { | |
619 fTakesFocusWhenVisible= takesFocus; | |
620 } | |
621 | |
622 /** | |
623 * Handles the disposal of the subject control. By default, the information control | |
624 * is disposed by calling <code>disposeInformationControl</code>. Subclasses may extend | |
625 * this method. | |
626 */ | |
627 protected void handleSubjectControlDisposed() { | |
628 disposeInformationControl(); | |
629 } | |
630 | |
631 /** | |
632 * Installs this manager on the given control. The control is now taking the role of | |
633 * the subject control. This implementation sets the control also as the information | |
634 * control closer's subject control and automatically enables this manager. | |
635 * | |
636 * @param subjectControl the subject control | |
637 */ | |
638 public void install(Control subjectControl) { | |
639 if (fSubjectControl !is null && !fSubjectControl.isDisposed() && fSubjectControlDisposeListener !is null) | |
640 fSubjectControl.removeDisposeListener(fSubjectControlDisposeListener); | |
641 | |
642 fSubjectControl= subjectControl; | |
643 | |
644 if (fSubjectControl !is null) | |
645 fSubjectControl.addDisposeListener(getSubjectControlDisposeListener()); | |
646 | |
647 if (fInformationControlCloser !is null) | |
648 fInformationControlCloser.setSubjectControl(subjectControl); | |
649 | |
650 setEnabled(true); | |
651 fDisposed= false; | |
652 } | |
653 | |
654 /** | |
655 * Returns the dispose listener which gets added | |
656 * to the subject control. | |
657 * | |
658 * @return the dispose listener | |
659 * @since 3.1 | |
660 */ | |
661 private DisposeListener getSubjectControlDisposeListener() { | |
662 if (fSubjectControlDisposeListener is null) { | |
663 fSubjectControlDisposeListener= new DisposeListener() { | |
664 public void widgetDisposed(DisposeEvent e) { | |
665 handleSubjectControlDisposed(); | |
666 } | |
667 }; | |
668 } | |
669 return fSubjectControlDisposeListener; | |
670 } | |
671 | |
672 /** | |
673 * Returns the subject control of this manager/information control. | |
674 * | |
675 * @return the subject control | |
676 */ | |
677 protected Control getSubjectControl() { | |
678 return fSubjectControl; | |
679 } | |
680 | |
681 /** | |
682 * Returns the actual subject area. | |
683 * | |
684 * @return the actual subject area | |
685 */ | |
686 protected Rectangle getSubjectArea() { | |
687 return fSubjectArea; | |
688 } | |
689 | |
690 /** | |
691 * Sets the enable state of this manager. | |
692 * | |
693 * @param enabled the enable state | |
694 * @deprecated visibility will be changed to protected | |
695 */ | |
696 public void setEnabled(bool enabled) { | |
697 fEnabled= enabled; | |
698 } | |
699 | |
700 /** | |
701 * Returns whether this manager is enabled or not. | |
702 * | |
703 * @return <code>true</code> if this manager is enabled otherwise <code>false</code> | |
704 */ | |
705 protected bool isEnabled() { | |
706 return fEnabled; | |
707 } | |
708 | |
709 /** | |
710 * Computes the size constraints of the information control in points based on the | |
711 * default font of the given subject control as well as the size constraints in character | |
712 * width. | |
713 * | |
714 * @param subjectControl the subject control | |
715 * @param informationControl the information control whose size constraints are computed | |
716 * @return the computed size constraints in points | |
717 */ | |
718 protected Point computeSizeConstraints(Control subjectControl, IInformationControl informationControl) { | |
719 | |
720 if (fSizeConstraints is null) { | |
721 if (informationControl instanceof IInformationControlExtension5) { | |
722 IInformationControlExtension5 iControl5= (IInformationControlExtension5) informationControl; | |
723 fSizeConstraints= iControl5.computeSizeConstraints(fWidthConstraint, fHeightConstraint); | |
724 if (fSizeConstraints !is null) | |
725 return Geometry.copy(fSizeConstraints); | |
726 } | |
727 if (subjectControl is null) | |
728 return null; | |
729 | |
730 GC gc= new GC(subjectControl); | |
731 gc.setFont(subjectControl.getFont()); | |
732 int width= gc.getFontMetrics().getAverageCharWidth(); | |
733 int height = gc.getFontMetrics().getHeight(); | |
734 gc.dispose(); | |
735 | |
736 fSizeConstraints= new Point (fWidthConstraint * width, fHeightConstraint * height); | |
737 } | |
738 | |
739 return new Point(fSizeConstraints.x, fSizeConstraints.y); | |
740 } | |
741 | |
742 /** | |
743 * Computes the size constraints of the information control in points. | |
744 * | |
745 * @param subjectControl the subject control | |
746 * @param subjectArea the subject area | |
747 * @param informationControl the information control whose size constraints are computed | |
748 * @return the computed size constraints in points | |
749 * @since 3.0 | |
750 */ | |
751 protected Point computeSizeConstraints(Control subjectControl, Rectangle subjectArea, IInformationControl informationControl) { | |
752 return computeSizeConstraints(subjectControl, informationControl); | |
753 } | |
754 | |
755 /** | |
756 * Handles the disposal of the information control. By default, the information | |
757 * control closer is stopped. | |
758 */ | |
759 protected void handleInformationControlDisposed() { | |
760 | |
761 storeInformationControlBounds(); | |
762 | |
763 if (fInformationControl instanceof IInformationControlExtension5) | |
764 fSizeConstraints= null; | |
765 fInformationControl= null; | |
766 if (fInformationControlCloser !is null) { | |
767 fInformationControlCloser.setInformationControl(null); //XXX: null is against the spec | |
768 fInformationControlCloser.stop(); | |
769 } | |
770 } | |
771 | |
772 /** | |
773 * Returns the information control. If the information control has not been created yet, | |
774 * it is automatically created. | |
775 * | |
776 * @return the information control | |
777 */ | |
778 protected IInformationControl getInformationControl() { | |
779 | |
780 if (fDisposed) | |
781 return fInformationControl; | |
782 | |
783 IInformationControlCreator creator= null; | |
784 | |
785 if (fCustomInformationControlCreator is null) { | |
786 creator= fInformationControlCreator; | |
787 if (fIsCustomInformationControl && fInformationControl !is null) { | |
788 if (fInformationControl instanceof IInformationControlExtension5) | |
789 fSizeConstraints= null; | |
790 fInformationControl.dispose(); | |
791 fInformationControl= null; | |
792 } | |
793 fIsCustomInformationControl= false; | |
794 | |
795 } else { | |
796 | |
797 creator= fCustomInformationControlCreator; | |
798 if (creator instanceof IInformationControlCreatorExtension) { | |
799 IInformationControlCreatorExtension extension= (IInformationControlCreatorExtension) creator; | |
800 if (fInformationControl !is null && extension.canReuse(fInformationControl)) | |
801 return fInformationControl; | |
802 } | |
803 if (fInformationControl !is null) { | |
804 if (fInformationControl instanceof IInformationControlExtension5) | |
805 fSizeConstraints= null; | |
806 fInformationControl.dispose(); | |
807 fInformationControl= null; | |
808 } | |
809 fIsCustomInformationControl= true; | |
810 } | |
811 | |
812 if (fInformationControl is null) { | |
813 fInformationControl= creator.createInformationControl(fSubjectControl.getShell()); | |
814 fInformationControl.addDisposeListener(new DisposeListener() { | |
815 public void widgetDisposed(DisposeEvent e) { | |
816 handleInformationControlDisposed(); | |
817 } | |
818 }); | |
819 | |
820 if (fInformationControlCloser !is null) | |
821 fInformationControlCloser.setInformationControl(fInformationControl); | |
822 } | |
823 | |
824 return fInformationControl; | |
825 } | |
826 | |
827 /** | |
828 * Computes the display location of the information control. The location is computed | |
829 * considering the given subject area, the anchor at the subject area, and the | |
830 * size of the information control. This method does not care about whether the information | |
831 * control would be completely visible when placed at the result location. | |
832 * | |
833 * @param subjectArea the subject area | |
834 * @param controlSize the size of the information control | |
835 * @param anchor the anchor at the subject area | |
836 * @return the display location of the information control | |
837 */ | |
838 protected Point computeLocation(Rectangle subjectArea, Point controlSize, Anchor anchor) { | |
839 int xShift= 0; | |
840 int yShift= 0; | |
841 | |
842 switch (anchor.getSWTFlag()) { | |
843 case DWT.CENTER: | |
844 Point subjectControlSize= fSubjectControl.getSize(); | |
845 Point location= new Point(subjectControlSize.x / 2, subjectControlSize.y / 2); | |
846 location.x -= (controlSize.x / 2); | |
847 location.y -= (controlSize.y / 2); | |
848 return fSubjectControl.toDisplay(location); | |
849 case DWT.BOTTOM: | |
850 yShift= subjectArea.height + fMarginY; | |
851 break; | |
852 case DWT.RIGHT: | |
853 xShift= fMarginX + subjectArea.width; | |
854 break; | |
855 case DWT.TOP: | |
856 yShift= -controlSize.y - fMarginY; | |
857 break; | |
858 case DWT.LEFT: | |
859 xShift= -controlSize.x - fMarginX; | |
860 break; | |
861 } | |
862 | |
863 bool isRTL= fSubjectControl !is null && (fSubjectControl.getStyle() & DWT.RIGHT_TO_LEFT) !is 0; | |
864 if (isRTL) | |
865 xShift += controlSize.x; | |
866 | |
867 return fSubjectControl.toDisplay(new Point(subjectArea.x + xShift, subjectArea.y + yShift)); | |
868 } | |
869 | |
870 /** | |
871 * Computes the area available for an information control given an anchor and the subject area | |
872 * within <code>bounds</code>. | |
873 * | |
874 * @param subjectArea the subject area | |
875 * @param bounds the bounds | |
876 * @param anchor the anchor at the subject area | |
877 * @return the area available at the given anchor relative to the subject area, confined to the | |
878 * monitor's client area | |
879 * @since 3.3 | |
880 */ | |
881 protected Rectangle computeAvailableArea(Rectangle subjectArea, Rectangle bounds, Anchor anchor) { | |
882 Rectangle area; | |
883 switch (anchor.getSWTFlag()) { | |
884 case DWT.CENTER: | |
885 area= bounds; | |
886 break; | |
887 case DWT.BOTTOM: | |
888 int y= subjectArea.y + subjectArea.height + fMarginY; | |
889 area= new Rectangle(bounds.x, y, bounds.width, bounds.y + bounds.height - y); | |
890 break; | |
891 case DWT.RIGHT: | |
892 int x= subjectArea.x + subjectArea.width + fMarginX; | |
893 area= new Rectangle(x, bounds.y, bounds.x + bounds.width - x, bounds.height); | |
894 break; | |
895 case DWT.TOP: | |
896 area= new Rectangle(bounds.x, bounds.y, bounds.width, subjectArea.y - bounds.y - fMarginY); | |
897 break; | |
898 case DWT.LEFT: | |
899 area= new Rectangle(bounds.x, bounds.y, subjectArea.x - bounds.x - fMarginX, bounds.height); | |
900 break; | |
901 default: | |
902 Assert.isLegal(false); | |
903 return null; | |
904 } | |
905 | |
906 // Don't return negative areas if the subjectArea overlaps with the monitor bounds. | |
907 area.intersect(bounds); | |
908 return area; | |
909 } | |
910 | |
911 /** | |
912 * Checks whether a control of the given size at the given location would be completely visible | |
913 * in the given display area when laid out by using the given anchor. If not, this method tries | |
914 * to shift the control orthogonal to the direction given by the anchor to make it visible. If possible | |
915 * it updates the location.<p> | |
916 * This method returns <code>true</code> if the potentially updated position results in a | |
917 * completely visible control, or <code>false</code> otherwise. | |
918 * | |
919 * | |
920 * @param location the location of the control | |
921 * @param size the size of the control | |
922 * @param displayArea the display area in which the control should be visible | |
923 * @param anchor anchor for lying out the control | |
924 * @return <code>true</code>if the updated location is useful | |
925 */ | |
926 protected bool updateLocation(Point location, Point size, Rectangle displayArea, Anchor anchor) { | |
927 | |
928 int displayLowerRightX= displayArea.x + displayArea.width; | |
929 int displayLowerRightY= displayArea.y + displayArea.height; | |
930 int lowerRightX= location.x + size.x; | |
931 int lowerRightY= location.y + size.y; | |
932 | |
933 if (ANCHOR_BOTTOM is anchor || ANCHOR_TOP is anchor) { | |
934 | |
935 if (ANCHOR_BOTTOM is anchor) { | |
936 if (lowerRightY > displayLowerRightY) | |
937 return false; | |
938 } else { | |
939 if (location.y < displayArea.y) | |
940 return false; | |
941 } | |
942 | |
943 if (lowerRightX > displayLowerRightX) | |
944 location.x= location.x - (lowerRightX - displayLowerRightX); | |
945 | |
946 return (location.x >= displayArea.x && location.y >= displayArea.y); | |
947 | |
948 } else if (ANCHOR_RIGHT is anchor || ANCHOR_LEFT is anchor) { | |
949 | |
950 if (ANCHOR_RIGHT is anchor) { | |
951 if (lowerRightX > displayLowerRightX) | |
952 return false; | |
953 } else { | |
954 if (location.x < displayArea.x) | |
955 return false; | |
956 } | |
957 | |
958 if (lowerRightY > displayLowerRightY) | |
959 location.y= location.y - (lowerRightY - displayLowerRightY); | |
960 | |
961 return (location.x >= displayArea.x && location.y >= displayArea.y); | |
962 | |
963 } else if (ANCHOR_GLOBAL is anchor) { | |
964 | |
965 if (lowerRightX > displayLowerRightX) | |
966 location.x= location.x - (lowerRightX - displayLowerRightX); | |
967 | |
968 if (lowerRightY > displayLowerRightY) | |
969 location.y= location.y - (lowerRightY - displayLowerRightY); | |
970 | |
971 return (location.x >= displayArea.x && location.y >= displayArea.y); | |
972 } | |
973 | |
974 return false; | |
975 } | |
976 | |
977 /** | |
978 * Returns the next fallback anchor as specified by this manager's | |
979 * fallback anchor sequence. | |
980 * <p> | |
981 * The fallback anchor for the given anchor is the one that comes directly after | |
982 * the given anchor or is the first one in the sequence if the given anchor is the | |
983 * last one in the sequence. | |
984 * </p> | |
985 * <p> | |
986 * Note: It is the callers responsibility to prevent an endless loop i.e. to test | |
987 * whether a given anchor has already been used once. | |
988 * then | |
989 * </p> | |
990 * | |
991 * @param anchor the current anchor | |
992 * @return the next fallback anchor or <code>null</code> if no fallback anchor is available | |
993 */ | |
994 protected Anchor getNextFallbackAnchor(Anchor anchor) { | |
995 | |
996 if (anchor is null || fFallbackAnchors is null) | |
997 return null; | |
998 | |
999 for (int i= 0; i < fFallbackAnchors.length; i++) { | |
1000 if (fFallbackAnchors[i] is anchor) | |
1001 return fFallbackAnchors[i + 1 is fFallbackAnchors.length ? 0 : i + 1]; | |
1002 } | |
1003 | |
1004 return null; | |
1005 } | |
1006 | |
1007 /** | |
1008 * Computes the location of the information control depending on the | |
1009 * subject area and the size of the information control. This method attempts | |
1010 * to find a location at which the information control lies completely in the display's | |
1011 * client area while honoring the manager's default anchor. If this isn't possible using the | |
1012 * default anchor, the fallback anchors are tried out. | |
1013 * | |
1014 * @param subjectArea the information area | |
1015 * @param controlSize the size of the information control | |
1016 * @return the computed location of the information control | |
1017 */ | |
1018 protected Point computeInformationControlLocation(Rectangle subjectArea, Point controlSize) { | |
1019 Rectangle subjectAreaDisplayRelative= Geometry.toDisplay(fSubjectControl, subjectArea); | |
1020 | |
1021 Point upperLeft; | |
1022 Anchor testAnchor= fAnchor; | |
1023 Rectangle bestBounds= null; | |
1024 int bestArea= Integer.MIN_VALUE; | |
1025 Anchor bestAnchor= null; | |
1026 do { | |
1027 | |
1028 upperLeft= computeLocation(subjectArea, controlSize, testAnchor); | |
1029 Monitor monitor= getClosestMonitor(subjectAreaDisplayRelative, testAnchor); | |
1030 if (updateLocation(upperLeft, controlSize, monitor.getClientArea(), testAnchor)) | |
1031 return upperLeft; | |
1032 | |
1033 // compute available area for this anchor and update if better than best | |
1034 Rectangle available= computeAvailableArea(subjectAreaDisplayRelative, monitor.getClientArea(), testAnchor); | |
1035 Rectangle proposed= new Rectangle(upperLeft.x, upperLeft.y, controlSize.x, controlSize.y); | |
1036 available.intersect(proposed); | |
1037 int area= available.width * available.height; | |
1038 if (area > bestArea) { | |
1039 bestArea= area; | |
1040 bestBounds= available; | |
1041 bestAnchor= testAnchor; | |
1042 } | |
1043 | |
1044 testAnchor= getNextFallbackAnchor(testAnchor); | |
1045 | |
1046 } while (testAnchor !is fAnchor && testAnchor !is null); | |
1047 | |
1048 // no anchor is perfect - select the one with larges area and set the size to not overlap with the subjectArea | |
1049 if (bestAnchor !is ANCHOR_GLOBAL) | |
1050 Geometry.set(controlSize, Geometry.getSize(bestBounds)); | |
1051 return Geometry.getLocation(bestBounds); | |
1052 } | |
1053 | |
1054 /** | |
1055 * Gets the closest monitor given an anchor and the subject area. | |
1056 * | |
1057 * @param area the subject area | |
1058 * @param anchor the anchor | |
1059 * @return the monitor closest to the edge of <code>area</code> defined by | |
1060 * <code>anchor</code> | |
1061 * @since 3.3 | |
1062 */ | |
1063 private Monitor getClosestMonitor(Rectangle area, Anchor anchor) { | |
1064 Point center; | |
1065 if (ANCHOR_GLOBAL is anchor) | |
1066 center= Geometry.centerPoint(area); | |
1067 else | |
1068 center= Geometry.centerPoint(Geometry.getExtrudedEdge(area, 0, anchor.getSWTFlag())); | |
1069 return getClosestMonitor(fSubjectControl.getDisplay(), Geometry.createRectangle(center, new Point(0, 0))); | |
1070 } | |
1071 | |
1072 /** | |
1073 * Copied from dwtx.jface.window.Window. Returns the monitor whose client area contains | |
1074 * the given point. If no monitor contains the point, returns the monitor that is closest to the | |
1075 * point. If this is ever made public, it should be moved into a separate utility class. | |
1076 * | |
1077 * @param display the display to search for monitors | |
1078 * @param rectangle the rectangle to find the closest monitor for (display coordinates) | |
1079 * @return the monitor closest to the given point | |
1080 * @since 3.3 | |
1081 */ | |
1082 private Monitor getClosestMonitor(Display display, Rectangle rectangle) { | |
1083 int closest = Integer.MAX_VALUE; | |
1084 | |
1085 Point toFind= Geometry.centerPoint(rectangle); | |
1086 Monitor[] monitors = display.getMonitors(); | |
1087 Monitor result = monitors[0]; | |
1088 | |
1089 for (int idx = 0; idx < monitors.length; idx++) { | |
1090 Monitor current = monitors[idx]; | |
1091 | |
1092 Rectangle clientArea = current.getClientArea(); | |
1093 | |
1094 if (clientArea.contains(toFind)) { | |
1095 return current; | |
1096 } | |
1097 | |
1098 int distance = Geometry.distanceSquared(Geometry.centerPoint(clientArea), toFind); | |
1099 if (distance < closest) { | |
1100 closest = distance; | |
1101 result = current; | |
1102 } | |
1103 } | |
1104 | |
1105 return result; | |
1106 } | |
1107 | |
1108 /** | |
1109 * Computes information to be displayed as well as the subject area | |
1110 * and initiates that this information is presented in the information control. | |
1111 * This happens only if this controller is enabled. | |
1112 */ | |
1113 public void showInformation() { | |
1114 if (fEnabled) | |
1115 doShowInformation(); | |
1116 } | |
1117 | |
1118 /** | |
1119 * Computes information to be displayed as well as the subject area | |
1120 * and initiates that this information is presented in the information control. | |
1121 */ | |
1122 protected void doShowInformation() { | |
1123 fSubjectArea= null; | |
1124 fInformation= null; | |
1125 computeInformation(); | |
1126 } | |
1127 | |
1128 /** | |
1129 * Presents the information in the information control or hides the information | |
1130 * control if no information should be presented. The information has previously | |
1131 * been set using <code>setInformation</code>. | |
1132 */ | |
1133 protected void presentInformation() { | |
1134 bool hasContents= false; | |
1135 if (fInformation instanceof String) | |
1136 hasContents= ((String)fInformation).trim().length() > 0; | |
1137 else | |
1138 hasContents= (fInformation !is null); | |
1139 | |
1140 if (fSubjectArea !is null && hasContents) | |
1141 internalShowInformationControl(fSubjectArea, fInformation); | |
1142 else | |
1143 hideInformationControl(); | |
1144 } | |
1145 | |
1146 /** | |
1147 * Opens the information control with the given information and the specified | |
1148 * subject area. It also activates the information control closer. | |
1149 * | |
1150 * @param subjectArea the information area | |
1151 * @param information the information | |
1152 */ | |
1153 private void internalShowInformationControl(Rectangle subjectArea, Object information) { | |
1154 if (this instanceof InformationControlReplacer) { | |
1155 ((InformationControlReplacer) this).showInformationControl(subjectArea, information); | |
1156 return; | |
1157 } | |
1158 | |
1159 IInformationControl informationControl= getInformationControl(); | |
1160 if (informationControl !is null) { | |
1161 | |
1162 Point sizeConstraints= computeSizeConstraints(fSubjectControl, fSubjectArea, informationControl); | |
1163 if (informationControl instanceof IInformationControlExtension3) { | |
1164 IInformationControlExtension3 iControl3= (IInformationControlExtension3) informationControl; | |
1165 Rectangle trim= iControl3.computeTrim(); | |
1166 sizeConstraints.x += trim.width; | |
1167 sizeConstraints.y += trim.height; | |
1168 } | |
1169 informationControl.setSizeConstraints(sizeConstraints.x, sizeConstraints.y); | |
1170 | |
1171 if (informationControl instanceof IInformationControlExtension2) | |
1172 ((IInformationControlExtension2)informationControl).setInput(information); | |
1173 else | |
1174 informationControl.setInformation(information.toString()); | |
1175 | |
1176 if (informationControl instanceof IInformationControlExtension) { | |
1177 IInformationControlExtension extension= (IInformationControlExtension)informationControl; | |
1178 if (!extension.hasContents()) | |
1179 return; | |
1180 } | |
1181 | |
1182 Point size= null; | |
1183 Point location= null; | |
1184 Rectangle bounds= restoreInformationControlBounds(); | |
1185 | |
1186 if (bounds !is null) { | |
1187 if (bounds.x > -1 && bounds.y > -1) | |
1188 location= Geometry.getLocation(bounds); | |
1189 | |
1190 if (bounds.width > -1 && bounds.height > -1) | |
1191 size= Geometry.getSize(bounds); | |
1192 } | |
1193 | |
1194 if (size is null) | |
1195 size= informationControl.computeSizeHint(); | |
1196 | |
1197 if (fEnforceAsMinimalSize) | |
1198 size= Geometry.max(size, sizeConstraints); | |
1199 if (fEnforceAsMaximalSize) | |
1200 size= Geometry.min(size, sizeConstraints); | |
1201 | |
1202 if (location is null) | |
1203 location= computeInformationControlLocation(subjectArea, size); | |
1204 | |
1205 Rectangle controlBounds= Geometry.createRectangle(location, size); | |
1206 cropToClosestMonitor(controlBounds); | |
1207 location= Geometry.getLocation(controlBounds); | |
1208 size= Geometry.getSize(controlBounds); | |
1209 informationControl.setLocation(location); | |
1210 informationControl.setSize(size.x, size.y); | |
1211 | |
1212 showInformationControl(subjectArea); | |
1213 } | |
1214 } | |
1215 | |
1216 /** | |
1217 * Crops the given bounds such that they lie completely on the closest monitor. | |
1218 * | |
1219 * @param bounds shell bounds to crop | |
1220 * @since 3.4 | |
1221 */ | |
1222 void cropToClosestMonitor(Rectangle bounds) { | |
1223 Rectangle monitorBounds= getClosestMonitor(fSubjectControl.getDisplay(), bounds).getClientArea(); | |
1224 bounds.intersect(monitorBounds); | |
1225 } | |
1226 | |
1227 /** | |
1228 * Hides the information control and stops the information control closer. | |
1229 */ | |
1230 protected void hideInformationControl() { | |
1231 if (fInformationControl !is null) { | |
1232 storeInformationControlBounds(); | |
1233 fInformationControl.setVisible(false); | |
1234 if (fInformationControlCloser !is null) | |
1235 fInformationControlCloser.stop(); | |
1236 } | |
1237 } | |
1238 | |
1239 /** | |
1240 * Shows the information control and starts the information control closer. | |
1241 * This method may not be called by clients. | |
1242 * | |
1243 * @param subjectArea the information area | |
1244 */ | |
1245 protected void showInformationControl(Rectangle subjectArea) { | |
1246 fInformationControl.setVisible(true); | |
1247 | |
1248 if (fTakesFocusWhenVisible) | |
1249 fInformationControl.setFocus(); | |
1250 | |
1251 if (fInformationControlCloser !is null) | |
1252 fInformationControlCloser.start(subjectArea); | |
1253 } | |
1254 | |
1255 /** | |
1256 * Replaces this manager's information control as defined by | |
1257 * the information control replacer. | |
1258 * <strong>Must only be called when {@link #fInformationControl} instanceof {@link IInformationControlExtension3}!</strong> | |
1259 * | |
1260 * @param takeFocus <code>true</code> iff the replacing information control should take focus | |
1261 * | |
1262 * @since 3.4 | |
1263 */ | |
1264 void replaceInformationControl(bool takeFocus) { | |
1265 if (fInformationControlReplacer !is null && canReplace(fInformationControl)) { | |
1266 IInformationControlExtension3 iControl3= (IInformationControlExtension3) fInformationControl; | |
1267 Rectangle b= iControl3.getBounds(); | |
1268 Rectangle t= iControl3.computeTrim(); | |
1269 Rectangle contentBounds= new Rectangle(b.x - t.x, b.y - t.y, b.width - t.width, b.height - t.height); | |
1270 IInformationControlCreator informationPresenterControlCreator= ((IInformationControlExtension5) fInformationControl).getInformationPresenterControlCreator(); | |
1271 fInformationControlReplacer.replaceInformationControl(informationPresenterControlCreator, contentBounds, fInformation, fSubjectArea, takeFocus); | |
1272 } | |
1273 hideInformationControl(); | |
1274 } | |
1275 | |
1276 /** | |
1277 * Disposes this manager's information control. | |
1278 */ | |
1279 public void disposeInformationControl() { | |
1280 if (fInformationControl !is null) { | |
1281 fInformationControl.dispose(); | |
1282 handleInformationControlDisposed(); | |
1283 } | |
1284 } | |
1285 | |
1286 /** | |
1287 * Disposes this manager and if necessary all dependent parts such as | |
1288 * the information control. For symmetry it first disables this manager. | |
1289 */ | |
1290 public void dispose() { | |
1291 if (!fDisposed) { | |
1292 | |
1293 fDisposed= true; | |
1294 | |
1295 setEnabled(false); | |
1296 disposeInformationControl(); | |
1297 | |
1298 if (fInformationControlReplacer !is null) { | |
1299 fInformationControlReplacer.dispose(); | |
1300 fInformationControlReplacer= null; | |
1301 } | |
1302 | |
1303 if (fSubjectControl !is null && !fSubjectControl.isDisposed() && fSubjectControlDisposeListener !is null) | |
1304 fSubjectControl.removeDisposeListener(fSubjectControlDisposeListener); | |
1305 fSubjectControl= null; | |
1306 fSubjectControlDisposeListener= null; | |
1307 | |
1308 fIsCustomInformationControl= false; | |
1309 fCustomInformationControlCreator= null; | |
1310 fInformationControlCreator= null; | |
1311 fInformationControlCloser= null; | |
1312 } | |
1313 } | |
1314 | |
1315 // ------ control's size handling dialog settings ------ | |
1316 | |
1317 /** | |
1318 * Stores the information control's bounds. | |
1319 * | |
1320 * @since 3.0 | |
1321 */ | |
1322 protected void storeInformationControlBounds() { | |
1323 if (fDialogSettings is null || fInformationControl is null || !(fIsRestoringLocation || fIsRestoringSize)) | |
1324 return; | |
1325 | |
1326 if (!(fInformationControl instanceof IInformationControlExtension3)) | |
1327 throw new UnsupportedOperationException(); | |
1328 | |
1329 bool controlRestoresSize= ((IInformationControlExtension3)fInformationControl).restoresSize(); | |
1330 bool controlRestoresLocation= ((IInformationControlExtension3)fInformationControl).restoresLocation(); | |
1331 | |
1332 Rectangle bounds= ((IInformationControlExtension3)fInformationControl).getBounds(); | |
1333 if (bounds is null) | |
1334 return; | |
1335 | |
1336 if (fIsRestoringSize && controlRestoresSize) { | |
1337 fDialogSettings.put(STORE_SIZE_WIDTH, bounds.width); | |
1338 fDialogSettings.put(STORE_SIZE_HEIGHT, bounds.height); | |
1339 } | |
1340 if (fIsRestoringLocation && controlRestoresLocation) { | |
1341 fDialogSettings.put(STORE_LOCATION_X, bounds.x); | |
1342 fDialogSettings.put(STORE_LOCATION_Y, bounds.y); | |
1343 } | |
1344 } | |
1345 /** | |
1346 * Restores the information control's bounds. | |
1347 * | |
1348 * @return the stored bounds | |
1349 * @since 3.0 | |
1350 */ | |
1351 protected Rectangle restoreInformationControlBounds() { | |
1352 if (fDialogSettings is null || !(fIsRestoringLocation || fIsRestoringSize)) | |
1353 return null; | |
1354 | |
1355 if (!(fInformationControl instanceof IInformationControlExtension3)) | |
1356 throw new UnsupportedOperationException(); | |
1357 | |
1358 bool controlRestoresSize= ((IInformationControlExtension3)fInformationControl).restoresSize(); | |
1359 bool controlRestoresLocation= ((IInformationControlExtension3)fInformationControl).restoresLocation(); | |
1360 | |
1361 Rectangle bounds= new Rectangle(-1, -1, -1, -1); | |
1362 | |
1363 if (fIsRestoringSize && controlRestoresSize) { | |
1364 try { | |
1365 bounds.width= fDialogSettings.getInt(STORE_SIZE_WIDTH); | |
1366 bounds.height= fDialogSettings.getInt(STORE_SIZE_HEIGHT); | |
1367 } catch (NumberFormatException ex) { | |
1368 bounds.width= -1; | |
1369 bounds.height= -1; | |
1370 } | |
1371 } | |
1372 | |
1373 if (fIsRestoringLocation && controlRestoresLocation) { | |
1374 try { | |
1375 bounds.x= fDialogSettings.getInt(STORE_LOCATION_X); | |
1376 bounds.y= fDialogSettings.getInt(STORE_LOCATION_Y); | |
1377 } catch (NumberFormatException ex) { | |
1378 bounds.x= -1; | |
1379 bounds.y= -1; | |
1380 } | |
1381 } | |
1382 | |
1383 // sanity check | |
1384 if (bounds.x is -1 && bounds.y is -1 && bounds.width is -1 && bounds.height is -1) | |
1385 return null; | |
1386 | |
1387 Rectangle maxBounds= null; | |
1388 if (fSubjectControl !is null && !fSubjectControl.isDisposed()) | |
1389 maxBounds= fSubjectControl.getDisplay().getBounds(); | |
1390 else { | |
1391 // fallback | |
1392 Display display= Display.getCurrent(); | |
1393 if (display is null) | |
1394 display= Display.getDefault(); | |
1395 if (display !is null && !display.isDisposed()) | |
1396 maxBounds= display.getBounds(); | |
1397 } | |
1398 | |
1399 | |
1400 if (bounds.width > -1 && bounds.height > -1) { | |
1401 if (maxBounds !is null) { | |
1402 bounds.width= Math.min(bounds.width, maxBounds.width); | |
1403 bounds.height= Math.min(bounds.height, maxBounds.height); | |
1404 } | |
1405 | |
1406 // Enforce an absolute minimal size | |
1407 bounds.width= Math.max(bounds.width, 30); | |
1408 bounds.height= Math.max(bounds.height, 30); | |
1409 } | |
1410 | |
1411 if (bounds.x > -1 && bounds.y > -1 && maxBounds !is null) { | |
1412 bounds.x= Math.max(bounds.x, maxBounds.x); | |
1413 bounds.y= Math.max(bounds.y, maxBounds.y); | |
1414 | |
1415 if (bounds .width > -1 && bounds.height > -1) { | |
1416 bounds.x= Math.min(bounds.x, maxBounds.width - bounds.width); | |
1417 bounds.y= Math.min(bounds.y, maxBounds.height - bounds.height); | |
1418 } | |
1419 } | |
1420 | |
1421 return bounds; | |
1422 } | |
1423 | |
1424 /** | |
1425 * Returns an adapter that gives access to internal methods. | |
1426 * <p> | |
1427 * <strong>Note:</strong> This method is not intended to be referenced or overridden by clients.</p> | |
1428 * | |
1429 * @return the replaceable information control accessor | |
1430 * @since 3.4 | |
1431 * @noreference This method is not intended to be referenced by clients. | |
1432 * @nooverride This method is not intended to be re-implemented or extended by clients. | |
1433 */ | |
1434 public InternalAccessor getInternalAccessor() { | |
1435 return new MyInternalAccessor(); | |
1436 } | |
1437 } |