connectivity/com.nokia.carbide.remoteConnections/src/com/nokia/carbide/remoteconnections/internal/ui/mylyn/AbstractNotificationPopup.java
changeset 1104 e84724c7f393
equal deleted inserted replaced
1103:a5d7a2345c4a 1104:e84724c7f393
       
     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 }