|
1 /******************************************************************************* |
|
2 * Copyright (c) 2004, 2009 Tasktop Technologies 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 * Benjamin Pasero - intial API and implementation |
|
10 * Tasktop Technologies - initial API and implementation |
|
11 *******************************************************************************/ |
|
12 |
|
13 package com.nokia.carbide.remoteconnections.internal.ui.mylyn; |
|
14 |
|
15 import org.eclipse.core.runtime.IProgressMonitor; |
|
16 import org.eclipse.core.runtime.IStatus; |
|
17 import org.eclipse.core.runtime.Status; |
|
18 import org.eclipse.core.runtime.jobs.Job; |
|
19 import org.eclipse.jface.resource.JFaceResources; |
|
20 import org.eclipse.jface.resource.LocalResourceManager; |
|
21 import org.eclipse.jface.window.Window; |
|
22 import org.eclipse.swt.SWT; |
|
23 import org.eclipse.swt.events.ControlAdapter; |
|
24 import org.eclipse.swt.events.ControlEvent; |
|
25 import org.eclipse.swt.events.MouseAdapter; |
|
26 import org.eclipse.swt.events.MouseEvent; |
|
27 import org.eclipse.swt.events.MouseTrackAdapter; |
|
28 import org.eclipse.swt.graphics.Color; |
|
29 import org.eclipse.swt.graphics.GC; |
|
30 import org.eclipse.swt.graphics.Image; |
|
31 import org.eclipse.swt.graphics.Point; |
|
32 import org.eclipse.swt.graphics.Rectangle; |
|
33 import org.eclipse.swt.graphics.Region; |
|
34 import org.eclipse.swt.layout.GridData; |
|
35 import org.eclipse.swt.layout.GridLayout; |
|
36 import org.eclipse.swt.widgets.Composite; |
|
37 import org.eclipse.swt.widgets.Control; |
|
38 import org.eclipse.swt.widgets.Display; |
|
39 import org.eclipse.swt.widgets.Label; |
|
40 import org.eclipse.swt.widgets.Monitor; |
|
41 import org.eclipse.swt.widgets.Shell; |
|
42 import org.eclipse.ui.IWorkbenchWindow; |
|
43 import org.eclipse.ui.PlatformUI; |
|
44 |
|
45 import com.nokia.carbide.remoteconnections.internal.ui.mylyn.SwtUtil.FadeJob; |
|
46 import com.nokia.carbide.remoteconnections.internal.ui.mylyn.SwtUtil.IFadeListener; |
|
47 |
|
48 /** |
|
49 * @author Benjamin Pasero |
|
50 * @author Mik Kersten |
|
51 * @author Steffen Pingel |
|
52 */ |
|
53 public abstract class AbstractNotificationPopup extends Window { |
|
54 |
|
55 private static final int TITLE_HEIGHT = 24; |
|
56 |
|
57 private static final String LABEL_NOTIFICATION = "Notification"; |
|
58 |
|
59 private static final String LABEL_JOB_CLOSE = "Close Notification Job"; |
|
60 |
|
61 private static final int MAX_WIDTH = 400; |
|
62 |
|
63 private static final int MIN_HEIGHT = 100; |
|
64 |
|
65 private static final long DEFAULT_DELAY_CLOSE = 8 * 1000; |
|
66 |
|
67 private static final int PADDING_EDGE = 5; |
|
68 |
|
69 private long delayClose = DEFAULT_DELAY_CLOSE; |
|
70 |
|
71 protected LocalResourceManager resources; |
|
72 |
|
73 private NotificationPopupColors color; |
|
74 |
|
75 private final Display display; |
|
76 |
|
77 private Shell shell; |
|
78 |
|
79 private Region lastUsedRegion; |
|
80 |
|
81 private Image lastUsedBgImage; |
|
82 |
|
83 private final Job closeJob = new Job(LABEL_JOB_CLOSE) { |
|
84 |
|
85 @Override |
|
86 protected IStatus run(IProgressMonitor monitor) { |
|
87 if (!display.isDisposed()) { |
|
88 display.asyncExec(new Runnable() { |
|
89 public void run() { |
|
90 Shell shell = AbstractNotificationPopup.this.getShell(); |
|
91 if (shell == null || shell.isDisposed()) { |
|
92 return; |
|
93 } |
|
94 |
|
95 if (isMouseOver(shell)) { |
|
96 scheduleAutoClose(); |
|
97 return; |
|
98 } |
|
99 |
|
100 AbstractNotificationPopup.this.closeFade(); |
|
101 } |
|
102 |
|
103 }); |
|
104 } |
|
105 if (monitor.isCanceled()) { |
|
106 return Status.CANCEL_STATUS; |
|
107 } |
|
108 |
|
109 return Status.OK_STATUS; |
|
110 } |
|
111 }; |
|
112 |
|
113 private final boolean respectDisplayBounds = true; |
|
114 |
|
115 private final boolean respectMonitorBounds = true; |
|
116 |
|
117 private FadeJob fadeJob; |
|
118 |
|
119 private boolean fadingEnabled; |
|
120 |
|
121 public AbstractNotificationPopup(Display display) { |
|
122 this(display, SWT.NO_TRIM | SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL); |
|
123 } |
|
124 |
|
125 public AbstractNotificationPopup(Display display, int style) { |
|
126 super(new Shell(display)); |
|
127 setShellStyle(style); |
|
128 |
|
129 this.display = display; |
|
130 resources = new LocalResourceManager(JFaceResources.getResources()); |
|
131 initResources(); |
|
132 |
|
133 closeJob.setSystem(true); |
|
134 } |
|
135 |
|
136 public boolean isFadingEnabled() { |
|
137 return fadingEnabled; |
|
138 } |
|
139 |
|
140 public void setFadingEnabled(boolean fadingEnabled) { |
|
141 this.fadingEnabled = fadingEnabled; |
|
142 } |
|
143 |
|
144 /** |
|
145 * Override to return a customized name. Default is to return the name of the product, specified by the -name (e.g. |
|
146 * "Eclipse SDK") command line parameter that's associated with the product ID (e.g. "org.eclipse.sdk.ide"). Strips |
|
147 * the trailing "SDK" for any name, since this part of the label is considered visual noise. |
|
148 * |
|
149 * @return the name to be used in the title of the popup. |
|
150 */ |
|
151 protected String getPopupShellTitle() { |
|
152 // String productName = CommonUiUtil.getProductName(); |
|
153 // if (productName != null) { |
|
154 // return productName + " " + LABEL_NOTIFICATION; //$NON-NLS-1$ |
|
155 // } else { |
|
156 return LABEL_NOTIFICATION; |
|
157 // } |
|
158 } |
|
159 |
|
160 protected Image getPopupShellImage(int maximumHeight) { |
|
161 // always use the launching workbench window |
|
162 IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows(); |
|
163 if (windows != null && windows.length > 0) { |
|
164 IWorkbenchWindow workbenchWindow = windows[0]; |
|
165 if (workbenchWindow != null && !workbenchWindow.getShell().isDisposed()) { |
|
166 Image image = getShell().getImage(); |
|
167 int diff = Integer.MAX_VALUE; |
|
168 if (image != null && image.getBounds().height <= maximumHeight) { |
|
169 diff = maximumHeight - image.getBounds().height; |
|
170 } else { |
|
171 image = null; |
|
172 } |
|
173 |
|
174 Image[] images = getShell().getImages(); |
|
175 if (images != null && images.length > 0) { |
|
176 // find the icon that is closest in size, but not larger than maximumHeight |
|
177 for (Image image2 : images) { |
|
178 int newDiff = maximumHeight - image2.getBounds().height; |
|
179 if (newDiff >= 0 && newDiff <= diff) { |
|
180 diff = newDiff; |
|
181 image = image2; |
|
182 } |
|
183 } |
|
184 } |
|
185 |
|
186 return image; |
|
187 } |
|
188 } |
|
189 return null; |
|
190 } |
|
191 |
|
192 /** |
|
193 * Override to populate with notifications. |
|
194 * |
|
195 * @param parent |
|
196 */ |
|
197 protected void createContentArea(Composite parent) { |
|
198 // empty by default |
|
199 } |
|
200 |
|
201 /** |
|
202 * Override to customize the title bar |
|
203 */ |
|
204 protected void createTitleArea(Composite parent) { |
|
205 ((GridData) parent.getLayoutData()).heightHint = TITLE_HEIGHT; |
|
206 |
|
207 Label titleImageLabel = new Label(parent, SWT.NONE); |
|
208 titleImageLabel.setImage(getPopupShellImage(TITLE_HEIGHT)); |
|
209 |
|
210 Label titleTextLabel = new Label(parent, SWT.NONE); |
|
211 titleTextLabel.setText(getPopupShellTitle()); |
|
212 titleTextLabel.setFont(CommonFonts.BOLD); |
|
213 titleTextLabel.setForeground(getTitleForeground()); |
|
214 // titleTextLabel.setForeground(color.getTitleText()); |
|
215 titleTextLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true)); |
|
216 titleTextLabel.setCursor(parent.getDisplay().getSystemCursor(SWT.CURSOR_HAND)); |
|
217 |
|
218 final Label button = new Label(parent, SWT.NONE); |
|
219 button.setImage(CommonImages.getImage(CommonImages.NOTIFICATION_CLOSE)); |
|
220 button.addMouseTrackListener(new MouseTrackAdapter() { |
|
221 @Override |
|
222 public void mouseEnter(MouseEvent e) { |
|
223 button.setImage(CommonImages.getImage(CommonImages.NOTIFICATION_CLOSE_HOVER)); |
|
224 } |
|
225 |
|
226 @Override |
|
227 public void mouseExit(MouseEvent e) { |
|
228 button.setImage(CommonImages.getImage(CommonImages.NOTIFICATION_CLOSE)); |
|
229 } |
|
230 }); |
|
231 button.addMouseListener(new MouseAdapter() { |
|
232 |
|
233 @Override |
|
234 public void mouseUp(MouseEvent e) { |
|
235 close(); |
|
236 setReturnCode(CANCEL); |
|
237 } |
|
238 |
|
239 }); |
|
240 } |
|
241 |
|
242 protected Color getTitleForeground() { |
|
243 return color.getTitleText(); |
|
244 } |
|
245 |
|
246 private void initResources() { |
|
247 color = new NotificationPopupColors(display, resources); |
|
248 } |
|
249 |
|
250 @Override |
|
251 protected void configureShell(Shell newShell) { |
|
252 super.configureShell(newShell); |
|
253 |
|
254 shell = newShell; |
|
255 newShell.setBackground(color.getBorder()); |
|
256 } |
|
257 |
|
258 @Override |
|
259 public void create() { |
|
260 super.create(); |
|
261 addRegion(shell); |
|
262 } |
|
263 |
|
264 private void addRegion(Shell shell) { |
|
265 Region region = new Region(); |
|
266 Point s = shell.getSize(); |
|
267 |
|
268 /* Add entire Shell */ |
|
269 region.add(0, 0, s.x, s.y); |
|
270 |
|
271 /* Subtract Top-Left Corner */ |
|
272 region.subtract(0, 0, 5, 1); |
|
273 region.subtract(0, 1, 3, 1); |
|
274 region.subtract(0, 2, 2, 1); |
|
275 region.subtract(0, 3, 1, 1); |
|
276 region.subtract(0, 4, 1, 1); |
|
277 |
|
278 /* Subtract Top-Right Corner */ |
|
279 region.subtract(s.x - 5, 0, 5, 1); |
|
280 region.subtract(s.x - 3, 1, 3, 1); |
|
281 region.subtract(s.x - 2, 2, 2, 1); |
|
282 region.subtract(s.x - 1, 3, 1, 1); |
|
283 region.subtract(s.x - 1, 4, 1, 1); |
|
284 |
|
285 /* Subtract Bottom-Left Corner */ |
|
286 region.subtract(0, s.y, 5, 1); |
|
287 region.subtract(0, s.y - 1, 3, 1); |
|
288 region.subtract(0, s.y - 2, 2, 1); |
|
289 region.subtract(0, s.y - 3, 1, 1); |
|
290 region.subtract(0, s.y - 4, 1, 1); |
|
291 |
|
292 /* Subtract Bottom-Right Corner */ |
|
293 region.subtract(s.x - 5, s.y - 0, 5, 1); |
|
294 region.subtract(s.x - 3, s.y - 1, 3, 1); |
|
295 region.subtract(s.x - 2, s.y - 2, 2, 1); |
|
296 region.subtract(s.x - 1, s.y - 3, 1, 1); |
|
297 region.subtract(s.x - 1, s.y - 4, 1, 1); |
|
298 |
|
299 /* Dispose old first */ |
|
300 if (shell.getRegion() != null) { |
|
301 shell.getRegion().dispose(); |
|
302 } |
|
303 |
|
304 /* Apply Region */ |
|
305 shell.setRegion(region); |
|
306 |
|
307 /* Remember to dispose later */ |
|
308 lastUsedRegion = region; |
|
309 } |
|
310 |
|
311 private boolean isMouseOver(Shell shell) { |
|
312 if (display.isDisposed()) { |
|
313 return false; |
|
314 } |
|
315 return shell.getBounds().contains(display.getCursorLocation()); |
|
316 } |
|
317 |
|
318 @Override |
|
319 public int open() { |
|
320 if (shell == null || shell.isDisposed()) { |
|
321 shell = null; |
|
322 create(); |
|
323 } |
|
324 |
|
325 constrainShellSize(); |
|
326 shell.setLocation(fixupDisplayBounds(shell.getSize(), shell.getLocation())); |
|
327 |
|
328 if (isFadingEnabled()) { |
|
329 shell.setAlpha(0); |
|
330 } |
|
331 shell.setVisible(true); |
|
332 fadeJob = SwtUtil.fadeIn(shell, new IFadeListener() { |
|
333 public void faded(Shell shell, int alpha) { |
|
334 if (shell.isDisposed()) { |
|
335 return; |
|
336 } |
|
337 |
|
338 if (alpha == 255) { |
|
339 scheduleAutoClose(); |
|
340 } |
|
341 } |
|
342 }); |
|
343 |
|
344 return Window.OK; |
|
345 } |
|
346 |
|
347 protected void scheduleAutoClose() { |
|
348 if (delayClose > 0) { |
|
349 closeJob.schedule(delayClose); |
|
350 } |
|
351 } |
|
352 |
|
353 @Override |
|
354 protected Control createContents(Composite parent) { |
|
355 ((GridLayout) parent.getLayout()).marginWidth = 1; |
|
356 ((GridLayout) parent.getLayout()).marginHeight = 1; |
|
357 |
|
358 /* Outer Composite holding the controls */ |
|
359 final Composite outerCircle = new Composite(parent, SWT.NO_FOCUS); |
|
360 outerCircle.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); |
|
361 outerCircle.setBackgroundMode(SWT.INHERIT_FORCE); |
|
362 |
|
363 outerCircle.addControlListener(new ControlAdapter() { |
|
364 |
|
365 @Override |
|
366 public void controlResized(ControlEvent e) { |
|
367 Rectangle clArea = outerCircle.getClientArea(); |
|
368 lastUsedBgImage = new Image(outerCircle.getDisplay(), clArea.width, clArea.height); |
|
369 GC gc = new GC(lastUsedBgImage); |
|
370 |
|
371 /* Gradient */ |
|
372 drawGradient(gc, clArea); |
|
373 |
|
374 /* Fix Region Shape */ |
|
375 fixRegion(gc, clArea); |
|
376 |
|
377 gc.dispose(); |
|
378 |
|
379 Image oldBGImage = outerCircle.getBackgroundImage(); |
|
380 outerCircle.setBackgroundImage(lastUsedBgImage); |
|
381 |
|
382 if (oldBGImage != null) { |
|
383 oldBGImage.dispose(); |
|
384 } |
|
385 } |
|
386 |
|
387 private void drawGradient(GC gc, Rectangle clArea) { |
|
388 gc.setForeground(color.getGradientBegin()); |
|
389 gc.setBackground(color.getGradientEnd()); |
|
390 gc.fillGradientRectangle(clArea.x, clArea.y, clArea.width, clArea.height, true); |
|
391 } |
|
392 |
|
393 private void fixRegion(GC gc, Rectangle clArea) { |
|
394 gc.setForeground(color.getBorder()); |
|
395 |
|
396 /* Fill Top Left */ |
|
397 gc.drawPoint(2, 0); |
|
398 gc.drawPoint(3, 0); |
|
399 gc.drawPoint(1, 1); |
|
400 gc.drawPoint(0, 2); |
|
401 gc.drawPoint(0, 3); |
|
402 |
|
403 /* Fill Top Right */ |
|
404 gc.drawPoint(clArea.width - 4, 0); |
|
405 gc.drawPoint(clArea.width - 3, 0); |
|
406 gc.drawPoint(clArea.width - 2, 1); |
|
407 gc.drawPoint(clArea.width - 1, 2); |
|
408 gc.drawPoint(clArea.width - 1, 3); |
|
409 |
|
410 /* Fill Bottom Left */ |
|
411 gc.drawPoint(2, clArea.height - 0); |
|
412 gc.drawPoint(3, clArea.height - 0); |
|
413 gc.drawPoint(1, clArea.height - 1); |
|
414 gc.drawPoint(0, clArea.height - 2); |
|
415 gc.drawPoint(0, clArea.height - 3); |
|
416 |
|
417 /* Fill Bottom Right */ |
|
418 gc.drawPoint(clArea.width - 4, clArea.height - 0); |
|
419 gc.drawPoint(clArea.width - 3, clArea.height - 0); |
|
420 gc.drawPoint(clArea.width - 2, clArea.height - 1); |
|
421 gc.drawPoint(clArea.width - 1, clArea.height - 2); |
|
422 gc.drawPoint(clArea.width - 1, clArea.height - 3); |
|
423 } |
|
424 }); |
|
425 |
|
426 GridLayout layout = new GridLayout(1, false); |
|
427 layout.marginWidth = 0; |
|
428 layout.marginHeight = 0; |
|
429 layout.verticalSpacing = 0; |
|
430 |
|
431 outerCircle.setLayout(layout); |
|
432 |
|
433 /* Title area containing label and close button */ |
|
434 final Composite titleCircle = new Composite(outerCircle, SWT.NO_FOCUS); |
|
435 titleCircle.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); |
|
436 titleCircle.setBackgroundMode(SWT.INHERIT_FORCE); |
|
437 |
|
438 layout = new GridLayout(4, false); |
|
439 layout.marginWidth = 3; |
|
440 layout.marginHeight = 0; |
|
441 layout.verticalSpacing = 5; |
|
442 layout.horizontalSpacing = 3; |
|
443 |
|
444 titleCircle.setLayout(layout); |
|
445 |
|
446 /* Create Title Area */ |
|
447 createTitleArea(titleCircle); |
|
448 |
|
449 /* Outer composite to hold content controlls */ |
|
450 Composite outerContentCircle = new Composite(outerCircle, SWT.NONE); |
|
451 outerContentCircle.setBackgroundMode(SWT.INHERIT_FORCE); |
|
452 |
|
453 layout = new GridLayout(1, false); |
|
454 layout.marginWidth = 0; |
|
455 layout.marginHeight = 0; |
|
456 |
|
457 outerContentCircle.setLayout(layout); |
|
458 outerContentCircle.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); |
|
459 outerContentCircle.setBackground(outerCircle.getBackground()); |
|
460 |
|
461 /* Middle composite to show a 1px black line around the content controls */ |
|
462 Composite middleContentCircle = new Composite(outerContentCircle, SWT.NO_FOCUS); |
|
463 middleContentCircle.setBackgroundMode(SWT.INHERIT_FORCE); |
|
464 |
|
465 layout = new GridLayout(1, false); |
|
466 layout.marginWidth = 0; |
|
467 layout.marginHeight = 0; |
|
468 layout.marginTop = 1; |
|
469 |
|
470 middleContentCircle.setLayout(layout); |
|
471 middleContentCircle.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); |
|
472 middleContentCircle.setBackground(color.getBorder()); |
|
473 |
|
474 /* Inner composite containing the content controls */ |
|
475 Composite innerContent = new Composite(middleContentCircle, SWT.NO_FOCUS); |
|
476 innerContent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); |
|
477 innerContent.setBackgroundMode(SWT.INHERIT_FORCE); |
|
478 |
|
479 layout = new GridLayout(1, false); |
|
480 layout.marginWidth = 0; |
|
481 layout.marginHeight = 5; |
|
482 layout.marginLeft = 5; |
|
483 layout.marginRight = 5; |
|
484 innerContent.setLayout(layout); |
|
485 |
|
486 innerContent.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_WHITE)); |
|
487 |
|
488 /* Content Area */ |
|
489 createContentArea(innerContent); |
|
490 |
|
491 setNullBackground(outerCircle); |
|
492 |
|
493 return outerCircle; |
|
494 } |
|
495 |
|
496 private void setNullBackground(final Composite outerCircle) { |
|
497 for (Control c : outerCircle.getChildren()) { |
|
498 c.setBackground(null); |
|
499 if (c instanceof Composite) { |
|
500 setNullBackground((Composite) c); |
|
501 } |
|
502 } |
|
503 } |
|
504 |
|
505 @Override |
|
506 protected void initializeBounds() { |
|
507 Rectangle clArea = getPrimaryClientArea(); |
|
508 Point initialSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT); |
|
509 int height = Math.max(initialSize.y, MIN_HEIGHT); |
|
510 int width = Math.min(initialSize.x, MAX_WIDTH); |
|
511 |
|
512 Point size = new Point(width, height); |
|
513 shell.setLocation(clArea.width + clArea.x - size.x - PADDING_EDGE, clArea.height + clArea.y - size.y |
|
514 - PADDING_EDGE); |
|
515 shell.setSize(size); |
|
516 } |
|
517 |
|
518 private Rectangle getPrimaryClientArea() { |
|
519 Monitor primaryMonitor = shell.getDisplay().getPrimaryMonitor(); |
|
520 return (primaryMonitor != null) ? primaryMonitor.getClientArea() : shell.getDisplay().getClientArea(); |
|
521 } |
|
522 |
|
523 public void closeFade() { |
|
524 if (fadeJob != null) { |
|
525 fadeJob.cancelAndWait(false); |
|
526 } |
|
527 fadeJob = SwtUtil.fadeOut(getShell(), new IFadeListener() { |
|
528 public void faded(Shell shell, int alpha) { |
|
529 if (!shell.isDisposed()) { |
|
530 if (alpha == 0) { |
|
531 shell.close(); |
|
532 } else if (isMouseOver(shell)) { |
|
533 if (fadeJob != null) { |
|
534 fadeJob.cancelAndWait(false); |
|
535 } |
|
536 fadeJob = SwtUtil.fastFadeIn(shell, new IFadeListener() { |
|
537 public void faded(Shell shell, int alpha) { |
|
538 if (shell.isDisposed()) { |
|
539 return; |
|
540 } |
|
541 |
|
542 if (alpha == 255) { |
|
543 scheduleAutoClose(); |
|
544 } |
|
545 } |
|
546 }); |
|
547 } |
|
548 } |
|
549 } |
|
550 }); |
|
551 } |
|
552 |
|
553 @Override |
|
554 public boolean close() { |
|
555 resources.dispose(); |
|
556 if (lastUsedRegion != null) { |
|
557 lastUsedRegion.dispose(); |
|
558 } |
|
559 if (lastUsedBgImage != null && !lastUsedBgImage.isDisposed()) { |
|
560 lastUsedBgImage.dispose(); |
|
561 } |
|
562 return super.close(); |
|
563 } |
|
564 |
|
565 public long getDelayClose() { |
|
566 return delayClose; |
|
567 } |
|
568 |
|
569 public void setDelayClose(long delayClose) { |
|
570 this.delayClose = delayClose; |
|
571 } |
|
572 |
|
573 private Point fixupDisplayBounds(Point tipSize, Point location) { |
|
574 if (respectDisplayBounds) { |
|
575 Rectangle bounds; |
|
576 Point rightBounds = new Point(tipSize.x + location.x, tipSize.y + location.y); |
|
577 |
|
578 if (respectMonitorBounds) { |
|
579 bounds = shell.getDisplay().getPrimaryMonitor().getBounds(); |
|
580 } else { |
|
581 bounds = getPrimaryClientArea(); |
|
582 } |
|
583 |
|
584 if (!(bounds.contains(location) && bounds.contains(rightBounds))) { |
|
585 if (rightBounds.x > bounds.x + bounds.width) { |
|
586 location.x -= rightBounds.x - (bounds.x + bounds.width); |
|
587 } |
|
588 |
|
589 if (rightBounds.y > bounds.y + bounds.height) { |
|
590 location.y -= rightBounds.y - (bounds.y + bounds.height); |
|
591 } |
|
592 |
|
593 if (location.x < bounds.x) { |
|
594 location.x = bounds.x; |
|
595 } |
|
596 |
|
597 if (location.y < bounds.y) { |
|
598 location.y = bounds.y; |
|
599 } |
|
600 } |
|
601 } |
|
602 |
|
603 return location; |
|
604 } |
|
605 |
|
606 } |