001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.swt.widgets;
011:
012: import org.eclipse.swt.internal.carbon.OS;
013:
014: import org.eclipse.swt.*;
015: import org.eclipse.swt.graphics.*;
016:
017: /**
018: * Instances of this class provide the appearance and
019: * behavior of <code>Shells</code>, but are not top
020: * level shells or dialogs. Class <code>Shell</code>
021: * shares a significant amount of code with this class,
022: * and is a subclass.
023: * <p>
024: * IMPORTANT: This class was intended to be abstract and
025: * should <em>never</em> be referenced or instantiated.
026: * Instead, the class <code>Shell</code> should be used.
027: * </p>
028: * <p>
029: * Instances are always displayed in one of the maximized,
030: * minimized or normal states:
031: * <ul>
032: * <li>
033: * When an instance is marked as <em>maximized</em>, the
034: * window manager will typically resize it to fill the
035: * entire visible area of the display, and the instance
036: * is usually put in a state where it can not be resized
037: * (even if it has style <code>RESIZE</code>) until it is
038: * no longer maximized.
039: * </li><li>
040: * When an instance is in the <em>normal</em> state (neither
041: * maximized or minimized), its appearance is controlled by
042: * the style constants which were specified when it was created
043: * and the restrictions of the window manager (see below).
044: * </li><li>
045: * When an instance has been marked as <em>minimized</em>,
046: * its contents (client area) will usually not be visible,
047: * and depending on the window manager, it may be
048: * "iconified" (that is, replaced on the desktop by a small
049: * simplified representation of itself), relocated to a
050: * distinguished area of the screen, or hidden. Combinations
051: * of these changes are also possible.
052: * </li>
053: * </ul>
054: * </p>
055: * Note: The styles supported by this class must be treated
056: * as <em>HINT</em>s, since the window manager for the
057: * desktop on which the instance is visible has ultimate
058: * control over the appearance and behavior of decorations.
059: * For example, some window managers only support resizable
060: * windows and will always assume the RESIZE style, even if
061: * it is not set.
062: * <dl>
063: * <dt><b>Styles:</b></dt>
064: * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE, ON_TOP, TOOL</dd>
065: * <dt><b>Events:</b></dt>
066: * <dd>(none)</dd>
067: * </dl>
068: * Class <code>SWT</code> provides two "convenience constants"
069: * for the most commonly required style combinations:
070: * <dl>
071: * <dt><code>SHELL_TRIM</code></dt>
072: * <dd>
073: * the result of combining the constants which are required
074: * to produce a typical application top level shell: (that
075: * is, <code>CLOSE | TITLE | MIN | MAX | RESIZE</code>)
076: * </dd>
077: * <dt><code>DIALOG_TRIM</code></dt>
078: * <dd>
079: * the result of combining the constants which are required
080: * to produce a typical application dialog shell: (that
081: * is, <code>TITLE | CLOSE | BORDER</code>)
082: * </dd>
083: * </dl>
084: * <p>
085: * IMPORTANT: This class is intended to be subclassed <em>only</em>
086: * within the SWT implementation.
087: * </p>
088: *
089: * @see #getMinimized
090: * @see #getMaximized
091: * @see Shell
092: * @see SWT
093: */
094: public class Decorations extends Canvas {
095: Image image;
096: Image[] images = new Image[0];
097: Menu menuBar;
098: String text = "";
099: boolean minimized, maximized;
100: Control savedFocus;
101: Button defaultButton;
102:
103: Decorations() {
104: /* Do nothing */
105: }
106:
107: /**
108: * Constructs a new instance of this class given its parent
109: * and a style value describing its behavior and appearance.
110: * <p>
111: * The style value is either one of the style constants defined in
112: * class <code>SWT</code> which is applicable to instances of this
113: * class, or must be built by <em>bitwise OR</em>'ing together
114: * (that is, using the <code>int</code> "|" operator) two or more
115: * of those <code>SWT</code> style constants. The class description
116: * lists the style constants that are applicable to the class.
117: * Style bits are also inherited from superclasses.
118: * </p>
119: *
120: * @param parent a composite control which will be the parent of the new instance (cannot be null)
121: * @param style the style of control to construct
122: *
123: * @exception IllegalArgumentException <ul>
124: * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
125: * </ul>
126: * @exception SWTException <ul>
127: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
128: * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
129: * </ul>
130: *
131: * @see SWT#BORDER
132: * @see SWT#CLOSE
133: * @see SWT#MIN
134: * @see SWT#MAX
135: * @see SWT#RESIZE
136: * @see SWT#TITLE
137: * @see SWT#NO_TRIM
138: * @see SWT#SHELL_TRIM
139: * @see SWT#DIALOG_TRIM
140: * @see SWT#ON_TOP
141: * @see SWT#TOOL
142: * @see Widget#checkSubclass
143: * @see Widget#getStyle
144: */
145: public Decorations(Composite parent, int style) {
146: super (parent, checkStyle(style));
147: }
148:
149: static int checkStyle(int style) {
150: if ((style & SWT.NO_TRIM) != 0) {
151: style &= ~(SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.MAX
152: | SWT.RESIZE | SWT.BORDER);
153: }
154: if ((style & (SWT.MENU | SWT.MIN | SWT.MAX | SWT.CLOSE)) != 0) {
155: style |= SWT.TITLE;
156: }
157: return style;
158: }
159:
160: void bringToTop(boolean force) {
161: moveAbove(null);
162: }
163:
164: protected void checkSubclass() {
165: if (!isValidSubclass())
166: error(SWT.ERROR_INVALID_SUBCLASS);
167: }
168:
169: int compare(ImageData data1, ImageData data2) {
170: if (data1.width == data2.width && data1.height == data2.height) {
171: int transparent1 = data1.getTransparencyType();
172: int transparent2 = data2.getTransparencyType();
173: if (transparent1 == SWT.TRANSPARENCY_ALPHA)
174: return -1;
175: if (transparent2 == SWT.TRANSPARENCY_ALPHA)
176: return 1;
177: if (transparent1 == SWT.TRANSPARENCY_MASK)
178: return -1;
179: if (transparent2 == SWT.TRANSPARENCY_MASK)
180: return 1;
181: if (transparent1 == SWT.TRANSPARENCY_PIXEL)
182: return -1;
183: if (transparent2 == SWT.TRANSPARENCY_PIXEL)
184: return 1;
185: return 0;
186: }
187: return data1.width > data2.width || data1.height > data2.height ? -1
188: : 1;
189: }
190:
191: Control computeTabGroup() {
192: return this ;
193: }
194:
195: Control computeTabRoot() {
196: return this ;
197: }
198:
199: void fixDecorations(Decorations newDecorations, Control control,
200: Menu[] menus) {
201: if (this == newDecorations)
202: return;
203: if (control == savedFocus)
204: savedFocus = null;
205: if (control == defaultButton)
206: defaultButton = null;
207: if (menus == null)
208: return;
209: Menu menu = control.menu;
210: if (menu != null) {
211: int index = 0;
212: while (index < menus.length) {
213: if (menus[index] == menu) {
214: control.setMenu(null);
215: return;
216: }
217: index++;
218: }
219: menu.fixMenus(newDecorations);
220: }
221: }
222:
223: /**
224: * Returns the receiver's default button if one had
225: * previously been set, otherwise returns null.
226: *
227: * @return the default button or null
228: *
229: * @exception SWTException <ul>
230: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
231: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
232: * </ul>
233: *
234: * @see #setDefaultButton(Button)
235: */
236: public Button getDefaultButton() {
237: checkWidget();
238: return defaultButton;
239: }
240:
241: /**
242: * Returns the receiver's image if it had previously been
243: * set using <code>setImage()</code>. The image is typically
244: * displayed by the window manager when the instance is
245: * marked as iconified, and may also be displayed somewhere
246: * in the trim when the instance is in normal or maximized
247: * states.
248: * <p>
249: * Note: This method will return null if called before
250: * <code>setImage()</code> is called. It does not provide
251: * access to a window manager provided, "default" image
252: * even if one exists.
253: * </p>
254: *
255: * @return the image
256: *
257: * @exception SWTException <ul>
258: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
259: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
260: * </ul>
261: */
262: public Image getImage() {
263: checkWidget();
264: return image;
265: }
266:
267: /**
268: * Returns the receiver's images if they had previously been
269: * set using <code>setImages()</code>. Images are typically
270: * displayed by the window manager when the instance is
271: * marked as iconified, and may also be displayed somewhere
272: * in the trim when the instance is in normal or maximized
273: * states. Depending where the icon is displayed, the platform
274: * chooses the icon with the "best" attributes. It is expected
275: * that the array will contain the same icon rendered at different
276: * sizes, with different depth and transparency attributes.
277: *
278: * <p>
279: * Note: This method will return an empty array if called before
280: * <code>setImages()</code> is called. It does not provide
281: * access to a window manager provided, "default" image
282: * even if one exists.
283: * </p>
284: *
285: * @return the images
286: *
287: * @exception SWTException <ul>
288: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
289: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
290: * </ul>
291: *
292: * @since 3.0
293: */
294: public Image[] getImages() {
295: checkWidget();
296: if (images == null)
297: return new Image[0];
298: Image[] result = new Image[images.length];
299: System.arraycopy(images, 0, result, 0, images.length);
300: return result;
301: }
302:
303: /**
304: * Returns <code>true</code> if the receiver is currently
305: * maximized, and false otherwise.
306: * <p>
307: *
308: * @return the maximized state
309: *
310: * @exception SWTException <ul>
311: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
312: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
313: * </ul>
314: *
315: * @see #setMaximized
316: */
317: public boolean getMaximized() {
318: checkWidget();
319: return maximized;
320: }
321:
322: /**
323: * Returns the receiver's menu bar if one had previously
324: * been set, otherwise returns null.
325: *
326: * @return the menu bar or null
327: *
328: * @exception SWTException <ul>
329: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
330: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
331: * </ul>
332: */
333: public Menu getMenuBar() {
334: checkWidget();
335: return menuBar;
336: }
337:
338: /**
339: * Returns <code>true</code> if the receiver is currently
340: * minimized, and false otherwise.
341: * <p>
342: *
343: * @return the minimized state
344: *
345: * @exception SWTException <ul>
346: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
347: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
348: * </ul>
349: *
350: * @see #setMinimized
351: */
352: public boolean getMinimized() {
353: checkWidget();
354: return minimized;
355: }
356:
357: String getNameText() {
358: return getText();
359: }
360:
361: /**
362: * Returns the receiver's text, which is the string that the
363: * window manager will typically display as the receiver's
364: * <em>title</em>. If the text has not previously been set,
365: * returns an empty string.
366: *
367: * @return the text
368: *
369: * @exception SWTException <ul>
370: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
371: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
372: * </ul>
373: */
374: public String getText() {
375: checkWidget();
376: return text;
377: }
378:
379: public boolean isReparentable() {
380: checkWidget();
381: return false;
382: }
383:
384: boolean isTabGroup() {
385: return true;
386: }
387:
388: boolean isTabItem() {
389: return false;
390: }
391:
392: Decorations menuShell() {
393: return this ;
394: }
395:
396: void releaseChildren(boolean destroy) {
397: if (menuBar != null) {
398: menuBar.dispose();
399: menuBar = null;
400: }
401: Display display = this .display;
402: super .releaseChildren(destroy);
403: Menu[] menus = display.getMenus(this );
404: if (menus != null) {
405: for (int i = 0; i < menus.length; i++) {
406: Menu menu = menus[i];
407: if (menu != null && !menu.isDisposed()) {
408: menu.dispose();
409: }
410: }
411: menus = null;
412: }
413: }
414:
415: void releaseWidget() {
416: super .releaseWidget();
417: image = null;
418: images = null;
419: savedFocus = null;
420: defaultButton = null;
421: }
422:
423: boolean restoreFocus() {
424: if (savedFocus != null && savedFocus.isDisposed())
425: savedFocus = null;
426: if (savedFocus == null)
427: return false;
428: return savedFocus.forceFocus();
429: }
430:
431: void saveFocus() {
432: int window = OS.GetControlOwner(handle);
433: Control control = display.getFocusControl(window, false);
434: if (control != null && control != this
435: && this == control.menuShell()) {
436: setSavedFocus(control);
437: }
438: }
439:
440: /**
441: * If the argument is not null, sets the receiver's default
442: * button to the argument, and if the argument is null, sets
443: * the receiver's default button to the first button which
444: * was set as the receiver's default button (called the
445: * <em>saved default button</em>). If no default button had
446: * previously been set, or the saved default button was
447: * disposed, the receiver's default button will be set to
448: * null.
449: * <p>
450: * The default button is the button that is selected when
451: * the receiver is active and the user presses ENTER.
452: * </p>
453: *
454: * @param button the new default button
455: *
456: * @exception IllegalArgumentException <ul>
457: * <li>ERROR_INVALID_ARGUMENT - if the button has been disposed</li>
458: * <li>ERROR_INVALID_PARENT - if the control is not in the same widget tree</li>
459: * </ul>
460: * @exception SWTException <ul>
461: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
462: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
463: * </ul>
464: */
465: public void setDefaultButton(Button button) {
466: checkWidget();
467: if (button != null) {
468: if (button.isDisposed())
469: error(SWT.ERROR_INVALID_ARGUMENT);
470: if (button.menuShell() != this )
471: error(SWT.ERROR_INVALID_PARENT);
472: if ((button.style & SWT.PUSH) == 0)
473: return;
474: }
475: if (button == defaultButton)
476: return;
477: if (defaultButton != null) {
478: if (!defaultButton.isDisposed())
479: defaultButton.setDefault(false);
480: }
481: defaultButton = button;
482: if (defaultButton != null) {
483: if (!defaultButton.isDisposed())
484: defaultButton.setDefault(true);
485: }
486: }
487:
488: /**
489: * Sets the receiver's image to the argument, which may
490: * be null. The image is typically displayed by the window
491: * manager when the instance is marked as iconified, and
492: * may also be displayed somewhere in the trim when the
493: * instance is in normal or maximized states.
494: *
495: * @param image the new image (or null)
496: *
497: * @exception IllegalArgumentException <ul>
498: * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
499: * </ul>
500: * @exception SWTException <ul>
501: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
502: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
503: * </ul>
504: */
505: public void setImage(Image image) {
506: checkWidget();
507: if (image != null && image.isDisposed())
508: error(SWT.ERROR_INVALID_ARGUMENT);
509: this .image = image;
510: if (parent != null)
511: return;
512: if (display.dockImage == 0) {
513: if (image != null) {
514: OS.SetApplicationDockTileImage(image.handle);
515: } else {
516: OS.RestoreApplicationDockTileImage();
517: }
518: }
519: }
520:
521: /**
522: * Sets the receiver's images to the argument, which may
523: * be an empty array. Images are typically displayed by the
524: * window manager when the instance is marked as iconified,
525: * and may also be displayed somewhere in the trim when the
526: * instance is in normal or maximized states. Depending where
527: * the icon is displayed, the platform chooses the icon with
528: * the "best" attributes. It is expected that the array will
529: * contain the same icon rendered at different sizes, with
530: * different depth and transparency attributes.
531: *
532: * @param images the new image array
533: *
534: * @exception IllegalArgumentException <ul>
535: * <li>ERROR_NULL_ARGUMENT - if the array of images is null</li>
536: * <li>ERROR_INVALID_ARGUMENT - if one of the images is null or has been disposed</li>
537: * </ul>
538: * @exception SWTException <ul>
539: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
540: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
541: * </ul>
542: *
543: * @since 3.0
544: */
545: public void setImages(Image[] images) {
546: checkWidget();
547: if (images == null)
548: error(SWT.ERROR_INVALID_ARGUMENT);
549: for (int i = 0; i < images.length; i++) {
550: if (images[i] == null || images[i].isDisposed())
551: error(SWT.ERROR_INVALID_ARGUMENT);
552: }
553: this .images = images;
554: if (parent != null)
555: return;
556: if (display.dockImage == 0) {
557: if (images != null && images.length > 1) {
558: Image[] bestImages = new Image[images.length];
559: System.arraycopy(images, 0, bestImages, 0,
560: images.length);
561: sort(bestImages);
562: images = bestImages;
563: }
564: OS.SetApplicationDockTileImage(images[0].handle);
565: }
566: }
567:
568: /**
569: * Sets the maximized state of the receiver.
570: * If the argument is <code>true</code> causes the receiver
571: * to switch to the maximized state, and if the argument is
572: * <code>false</code> and the receiver was previously maximized,
573: * causes the receiver to switch back to either the minimized
574: * or normal states.
575: * <p>
576: * Note: The result of intermixing calls to <code>setMaximized(true)</code>
577: * and <code>setMinimized(true)</code> will vary by platform. Typically,
578: * the behavior will match the platform user's expectations, but not
579: * always. This should be avoided if possible.
580: * </p>
581: *
582: * @param maximized the new maximized state
583: *
584: * @exception SWTException <ul>
585: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
586: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
587: * </ul>
588: *
589: * @see #setMinimized
590: */
591: public void setMaximized(boolean maximized) {
592: checkWidget();
593: this .maximized = maximized;
594: }
595:
596: /**
597: * Sets the receiver's menu bar to the argument, which
598: * may be null.
599: *
600: * @param menu the new menu bar
601: *
602: * @exception IllegalArgumentException <ul>
603: * <li>ERROR_INVALID_ARGUMENT - if the menu has been disposed</li>
604: * <li>ERROR_INVALID_PARENT - if the menu is not in the same widget tree</li>
605: * </ul>
606: * @exception SWTException <ul>
607: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
608: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
609: * </ul>
610: */
611: public void setMenuBar(Menu menu) {
612: checkWidget();
613: if (menuBar == menu)
614: return;
615: if (menu != null) {
616: if (menu.isDisposed())
617: error(SWT.ERROR_INVALID_ARGUMENT);
618: if ((menu.style & SWT.BAR) == 0)
619: error(SWT.ERROR_MENU_NOT_BAR);
620: if (menu.parent != this )
621: error(SWT.ERROR_INVALID_PARENT);
622: }
623: menuBar = menu;
624: }
625:
626: /**
627: * Sets the minimized stated of the receiver.
628: * If the argument is <code>true</code> causes the receiver
629: * to switch to the minimized state, and if the argument is
630: * <code>false</code> and the receiver was previously minimized,
631: * causes the receiver to switch back to either the maximized
632: * or normal states.
633: * <p>
634: * Note: The result of intermixing calls to <code>setMaximized(true)</code>
635: * and <code>setMinimized(true)</code> will vary by platform. Typically,
636: * the behavior will match the platform user's expectations, but not
637: * always. This should be avoided if possible.
638: * </p>
639: *
640: * @param minimized the new maximized state
641: *
642: * @exception SWTException <ul>
643: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
644: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
645: * </ul>
646: *
647: * @see #setMaximized
648: */
649: public void setMinimized(boolean minimized) {
650: checkWidget();
651: this .minimized = minimized;
652: }
653:
654: void setSavedFocus(Control control) {
655: savedFocus = control;
656: }
657:
658: /**
659: * Sets the receiver's text, which is the string that the
660: * window manager will typically display as the receiver's
661: * <em>title</em>, to the argument, which must not be null.
662: *
663: * @param string the new text
664: *
665: * @exception IllegalArgumentException <ul>
666: * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
667: * </ul>
668: * @exception SWTException <ul>
669: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
670: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
671: * </ul>
672: */
673: public void setText(String string) {
674: checkWidget();
675: if (string == null)
676: error(SWT.ERROR_NULL_ARGUMENT);
677: text = string;
678: }
679:
680: void sort(Image[] images) {
681: /* Shell Sort from K&R, pg 108 */
682: int length = images.length;
683: if (length <= 1)
684: return;
685: ImageData[] datas = new ImageData[length];
686: for (int i = 0; i < length; i++) {
687: datas[i] = images[i].getImageData();
688: }
689: for (int gap = length / 2; gap > 0; gap /= 2) {
690: for (int i = gap; i < length; i++) {
691: for (int j = i - gap; j >= 0; j -= gap) {
692: if (compare(datas[j], datas[j + gap]) >= 0) {
693: Image swap = images[j];
694: images[j] = images[j + gap];
695: images[j + gap] = swap;
696: ImageData swapData = datas[j];
697: datas[j] = datas[j + gap];
698: datas[j + gap] = swapData;
699: }
700: }
701: }
702: }
703: }
704:
705: boolean traverseItem(boolean next) {
706: return false;
707: }
708:
709: boolean traverseReturn() {
710: if (defaultButton == null || defaultButton.isDisposed())
711: return false;
712: if (!defaultButton.isVisible() || !defaultButton.isEnabled())
713: return false;
714: defaultButton.click();
715: return true;
716: }
717:
718: }
|