| /******************************************************************************* |
| * Copyright (c) 2000, 2009 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.swt.widgets; |
| |
| |
| import org.eclipse.swt.*; |
| import org.eclipse.swt.graphics.*; |
| import org.eclipse.swt.internal.cocoa.*; |
| |
| /** |
| * Instances of this class represent a task item. |
| * |
| * <dl> |
| * <dt><b>Styles:</b></dt> |
| * <dd>(none)</dd> |
| * <dt><b>Events:</b></dt> |
| * <dd>(none)</dd> |
| * </dl> |
| * |
| * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> |
| * |
| * @since 3.6 |
| * |
| * @noextend This class is not intended to be subclassed by clients. |
| */ |
| public class TaskItem extends Item { |
| TaskBar parent; |
| Shell shell; |
| NSImage defaultImage; |
| int progress, iProgress, progressState = SWT.DEFAULT; |
| Image overlayImage; |
| String overlayText = ""; |
| Menu menu; |
| |
| static final int PROGRESS_MAX = 100; |
| static final int PROGRESS_TIMER = 350; |
| static final int PROGRESS_BARS = 7; |
| |
| /** |
| * Constructs a new instance of this class given its parent |
| * (which must be a <code>Tray</code>) and a style value |
| * describing its behavior and appearance. The item is added |
| * to the end of the items maintained by its parent. |
| * <p> |
| * The style value is either one of the style constants defined in |
| * class <code>SWT</code> which is applicable to instances of this |
| * class, or must be built by <em>bitwise OR</em>'ing together |
| * (that is, using the <code>int</code> "|" operator) two or more |
| * of those <code>SWT</code> style constants. The class description |
| * lists the style constants that are applicable to the class. |
| * Style bits are also inherited from superclasses. |
| * </p> |
| * |
| * @param parent a composite control which will be the parent of the new instance (cannot be null) |
| * @param style the style of control to construct |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> |
| * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> |
| * </ul> |
| * |
| * @see SWT |
| * @see Widget#checkSubclass |
| * @see Widget#getStyle |
| */ |
| TaskItem (TaskBar parent, int style) { |
| super (parent, style); |
| this.parent = parent; |
| parent.createItem (this, -1); |
| createWidget (); |
| } |
| |
| protected void checkSubclass () { |
| if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); |
| } |
| |
| void createWidget () { |
| NSApplication app = NSApplication.sharedApplication (); |
| NSImage image = app.applicationIconImage (); |
| defaultImage = new NSImage (image.copy ()); |
| } |
| |
| void destroyWidget () { |
| parent.destroyItem (this); |
| releaseHandle (); |
| } |
| |
| /** |
| * Returns the receiver's pop up menu if it has one, or null |
| * if it does not. |
| * |
| * @return the receiver's menu |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public Menu getMenu () { |
| checkWidget (); |
| return menu; |
| } |
| |
| /** |
| * Returns the receiver's overlay image if it has one, or null |
| * if it does not. |
| * |
| * @return the receiver's overlay image |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public Image getOverlayImage () { |
| checkWidget (); |
| return overlayImage; |
| } |
| |
| /** |
| * Returns the receiver's overlay text, which will be an empty |
| * string if it has never been set. |
| * |
| * @return the receiver's overlay text |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public String getOverlayText () { |
| checkWidget (); |
| return overlayText; |
| } |
| |
| /** |
| * Returns the receiver's parent, which must be a <code>TaskBar</code>. |
| * |
| * @return the receiver's parent |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| * |
| */ |
| public TaskBar getParent () { |
| checkWidget (); |
| return parent; |
| } |
| |
| /** |
| * Returns the receiver's progress. |
| * |
| * @return the receiver's progress |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public int getProgress () { |
| checkWidget (); |
| return progress; |
| } |
| |
| /** |
| * Returns the receiver's progress state. |
| * |
| * @return the receiver's progress state |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public int getProgressState () { |
| checkWidget (); |
| return progressState; |
| } |
| |
| void releaseHandle () { |
| super.releaseHandle (); |
| parent = null; |
| if (defaultImage != null) defaultImage.release (); |
| defaultImage = null; |
| } |
| |
| void releaseWidget () { |
| super.releaseWidget (); |
| overlayImage = null; |
| overlayText = null; |
| shell = null; |
| } |
| |
| /** |
| * Sets the receiver's pop up menu to the argument. The way the menu is |
| * shown is platform specific. |
| * |
| * <p> |
| * This feature might not be available for the receiver on all |
| * platforms. The application code can check if it is supported |
| * by calling the respective get method. When the feature is not |
| * available, the get method will always return the NULL.</p> |
| * |
| * <p> |
| * For better cross platform support, the application code should |
| * set this feature on the <code>TaskItem</code> for application.<br> |
| * On Windows, this feature will only work on RCP applications.</p> |
| * |
| * <p> |
| * The menu should be fully created before this method is called. |
| * Dynamic changes to the menu after the method is called will not be reflected |
| * in the native menu.</p> |
| * |
| * @param menu the new pop up menu |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_MENU_NOT_POP_UP - the menu is not a pop up menu</li> |
| * <li>ERROR_INVALID_ARGUMENT - if the menu has been disposed</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public void setMenu (Menu menu) { |
| checkWidget (); |
| if (menu != null) { |
| if (menu.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| if ((menu.style & SWT.POP_UP) == 0) { |
| error (SWT.ERROR_MENU_NOT_POP_UP); |
| } |
| } |
| this.menu = menu; |
| } |
| |
| /** |
| * Sets the receiver's overlay image, which may be null |
| * indicating that no image should be displayed. The bounds |
| * for the overlay image is determined by the platform and in |
| * general it should be a small image. |
| * |
| * <p> |
| * This feature might not be available for the receiver on all |
| * platforms. The application code can check if it is supported |
| * by calling the respective get method. When the feature is not |
| * available, the get method will always return the NULL.</p> |
| * |
| * <p> |
| * For better cross platform support, the application code should |
| * first try to set this feature on the <code>TaskItem</code> for the |
| * main shell then on the <code>TaskItem</code> for the application.</p> |
| * |
| * @param overlayImage the new overlay image (may be null) |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_INVALID_ARGUMENT - if the overlayImage has been disposed</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public void setOverlayImage (Image image) { |
| checkWidget (); |
| if (image != null && image.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); |
| overlayImage = image; |
| updateOverlayText (image != null ? null : overlayText); |
| updateImage (); |
| } |
| |
| /** |
| * Sets the receiver's overlay text. The space available to display the |
| * overlay text is platform dependent and in general it should be no longer |
| * than a few characters. |
| * |
| * <p> |
| * This feature might not be available for the receiver on all |
| * platforms. The application code can check if it is supported |
| * by calling the respective get method. When the feature is not |
| * available, the get method will always return an empty string.</p> |
| * |
| * <p> |
| * For better cross platform support, the application code should |
| * first try to set this feature on the <code>TaskItem</code> for the |
| * main shell then on the <code>TaskItem</code> for the application.</p> |
| * |
| * @param overlayText the new overlay text |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT - if the overlayText is null</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public void setOverlayText (String string) { |
| checkWidget (); |
| if (string == null) error (SWT.ERROR_NULL_ARGUMENT); |
| overlayText = string; |
| updateOverlayText (string); |
| updateImage (); |
| } |
| |
| /** |
| * Sets the receiver's progress, the progress represents a percentage and |
| * should be in range from 0 to 100. The progress is only shown when the progress |
| * state is different than <code>SWT#DEFAULT</code>. |
| * |
| * <p> |
| * This feature might not be available for the receiver on all |
| * platforms. The application code can check if it is supported |
| * by calling the respective get method. When the feature is not |
| * available, the get method will always return zero.</p> |
| * |
| * <p> |
| * For better cross platform support, the application code should |
| * first try to set this feature on the <code>TaskItem</code> for the |
| * main shell then on the <code>TaskItem</code> for the application.</p> |
| * |
| * @param progress the new progress |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| * |
| * #see {@link #setProgressState(int)} |
| */ |
| public void setProgress (int progress) { |
| checkWidget (); |
| progress = Math.max (0, Math.min (progress, PROGRESS_MAX)); |
| if (this.progress == progress) return; |
| this.progress = progress; |
| updateImage (); |
| } |
| |
| /** |
| * Sets the receiver's progress state, the state can be one of |
| * the following: |
| * <p><ul> |
| * <li>{@link SWT#DEFAULT}</li> |
| * <li>{@link SWT#NORMAL}</li> |
| * <li>{@link SWT#PAUSED}</li> |
| * <li>{@link SWT#ERROR}</li> |
| * <li>{@link SWT#INDETERMINATE}</li> |
| * </ul></p> |
| * |
| * The percentage of progress shown by the states <code>SWT#NORMAL</code>, <code>SWT#PAUSED</code>, |
| * <code>SWT#ERROR</code> is set with <code>setProgress()</code>. <br> |
| * The state <code>SWT#DEFAULT</code> indicates that no progress should be shown. |
| * |
| * <p> |
| * This feature might not be available for the receiver on all |
| * platforms. The application code can check if it is supported |
| * by calling the respective get method. When the feature is not |
| * available, the get method will always return <code>SWT#DEFAULT</code>.</p> |
| * |
| * <p> |
| * For better cross platform support, the application code should |
| * first try to set this feature on the <code>TaskItem</code> for the |
| * main shell then on the <code>TaskItem</code> for the application.</p> |
| * |
| * @param progressState the new progress state |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| * |
| * #see {@link #setProgress(int)} |
| */ |
| public void setProgressState (int progressState) { |
| checkWidget (); |
| if (this.progressState == progressState) return; |
| this.progressState = progressState; |
| updateImage (); |
| } |
| |
| void setShell (Shell shell) { |
| this.shell = shell; |
| shell.addListener (SWT.Dispose, new Listener () { |
| public void handleEvent (Event event) { |
| if (isDisposed ()) return; |
| dispose (); |
| } |
| }); |
| } |
| |
| void updateImage () { |
| boolean drawProgress = progress != 0 && progressState != SWT.DEFAULT; |
| boolean drawIntermidiate = progressState == SWT.INDETERMINATE; |
| NSApplication app = NSApplication.sharedApplication (); |
| NSDockTile dock = app.dockTile (); |
| boolean drawImage = overlayImage != null && dock.badgeLabel () == null; |
| if (!drawImage && !drawProgress && !drawIntermidiate) { |
| app.setApplicationIconImage (defaultImage); |
| return; |
| } |
| |
| NSSize size = defaultImage.size (); |
| NSImage newImage = (NSImage)new NSImage().alloc (); |
| newImage = newImage.initWithSize (size); |
| NSBitmapImageRep rep = (NSBitmapImageRep)new NSBitmapImageRep ().alloc (); |
| rep = rep.initWithBitmapDataPlanes (0, (int)size.width, (int)size.height, 8, 4, true, false, OS.NSDeviceRGBColorSpace, OS.NSAlphaFirstBitmapFormat | OS.NSAlphaNonpremultipliedBitmapFormat, (int)size.width * 4, 32); |
| newImage.addRepresentation (rep); |
| rep.release (); |
| |
| NSRect rect = new NSRect (); |
| rect.height = size.height; |
| rect.width = size.width; |
| newImage.lockFocus (); |
| defaultImage.drawInRect (rect, rect, OS.NSCompositeSourceOver, 1); |
| if (drawImage) { |
| NSImage badgetImage = overlayImage.handle; |
| NSSize badgeSize = badgetImage.size (); |
| NSRect srcRect = new NSRect (); |
| srcRect.height = badgeSize.height; |
| srcRect.width = badgeSize.width; |
| NSRect dstRect = new NSRect (); |
| dstRect.x = size.width / 2; |
| dstRect.height = size.height / 2; |
| dstRect.width = size.width / 2; |
| badgetImage.drawInRect(dstRect, srcRect, OS.NSCompositeSourceOver, 1); |
| } |
| if (drawIntermidiate || drawProgress) { |
| switch (progressState) { |
| case SWT.ERROR: |
| NSColor.colorWithDeviceRed (1, 0, 0, 0.6f).setFill (); |
| break; |
| case SWT.PAUSED: |
| NSColor.colorWithDeviceRed (1, 1, 0, 0.6f).setFill (); |
| break; |
| default: |
| NSColor.colorWithDeviceRed (1, 1, 1, 0.6f).setFill (); |
| } |
| rect.width = size.width / (PROGRESS_BARS * 2 - 1); |
| rect.height = size.height / 3; |
| int count; |
| if (drawIntermidiate) { |
| count = iProgress; |
| iProgress = (iProgress + 1) % (PROGRESS_BARS + 1); |
| getDisplay ().timerExec (PROGRESS_TIMER, new Runnable () { |
| public void run () { |
| updateImage (); |
| } |
| }); |
| } else { |
| count = progress * PROGRESS_BARS / PROGRESS_MAX; |
| } |
| for (int i = 0; i <= count; i++) { |
| rect.x = i * 2 * rect.width; |
| NSBezierPath.fillRect (rect); |
| } |
| } |
| newImage.unlockFocus (); |
| app.setApplicationIconImage (newImage); |
| newImage.release (); |
| } |
| |
| void updateOverlayText (String string) { |
| NSApplication app = NSApplication.sharedApplication (); |
| NSDockTile dock = app.dockTile (); |
| if (string != null && string.length () > 0) { |
| dock.setBadgeLabel (NSString.stringWith (string)); |
| } else { |
| dock.setBadgeLabel (null); |
| } |
| } |
| |
| } |