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: * Konstantin Scheglov <scheglov_ke@nlmk.ru > - Fix for bug 41172
011: * [Dialogs] Bug with Image in TitleAreaDialog
012: * Sebastian Davids <sdavids@gmx.de> - Fix for bug 82064
013: * [Dialogs] TitleAreaDialog#setTitleImage cannot be called before open()
014: *******************************************************************************/package org.eclipse.jface.dialogs;
015:
016: import org.eclipse.jface.resource.JFaceColors;
017: import org.eclipse.jface.resource.JFaceResources;
018: import org.eclipse.swt.SWT;
019: import org.eclipse.swt.events.DisposeEvent;
020: import org.eclipse.swt.events.DisposeListener;
021: import org.eclipse.swt.graphics.Color;
022: import org.eclipse.swt.graphics.Image;
023: import org.eclipse.swt.graphics.Point;
024: import org.eclipse.swt.graphics.RGB;
025: import org.eclipse.swt.layout.FormAttachment;
026: import org.eclipse.swt.layout.FormData;
027: import org.eclipse.swt.layout.FormLayout;
028: import org.eclipse.swt.layout.GridData;
029: import org.eclipse.swt.layout.GridLayout;
030: import org.eclipse.swt.widgets.Composite;
031: import org.eclipse.swt.widgets.Control;
032: import org.eclipse.swt.widgets.Display;
033: import org.eclipse.swt.widgets.Label;
034: import org.eclipse.swt.widgets.Shell;
035: import org.eclipse.swt.widgets.Text;
036:
037: /**
038: * A dialog that has a title area for displaying a title and an image as well as
039: * a common area for displaying a description, a message, or an error message.
040: * <p>
041: * This dialog class may be subclassed.
042: */
043: public class TitleAreaDialog extends TrayDialog {
044: /**
045: * Image registry key for error message image.
046: */
047: public static final String DLG_IMG_TITLE_ERROR = DLG_IMG_MESSAGE_ERROR;
048:
049: /**
050: * Image registry key for banner image (value
051: * <code>"dialog_title_banner_image"</code>).
052: */
053: public static final String DLG_IMG_TITLE_BANNER = "dialog_title_banner_image";//$NON-NLS-1$
054:
055: /**
056: * Message type constant used to display an info icon with the message.
057: *
058: * @since 2.0
059: * @deprecated
060: */
061: public final static String INFO_MESSAGE = "INFO_MESSAGE"; //$NON-NLS-1$
062:
063: /**
064: * Message type constant used to display a warning icon with the message.
065: *
066: * @since 2.0
067: * @deprecated
068: */
069: public final static String WARNING_MESSAGE = "WARNING_MESSAGE"; //$NON-NLS-1$
070:
071: // Space between an image and a label
072: private static final int H_GAP_IMAGE = 5;
073:
074: // Minimum dialog width (in dialog units)
075: private static final int MIN_DIALOG_WIDTH = 350;
076:
077: // Minimum dialog height (in dialog units)
078: private static final int MIN_DIALOG_HEIGHT = 150;
079:
080: private Label titleLabel;
081:
082: private Label titleImageLabel;
083:
084: private Label bottomFillerLabel;
085:
086: private Label leftFillerLabel;
087:
088: private RGB titleAreaRGB;
089:
090: Color titleAreaColor;
091:
092: private String message = ""; //$NON-NLS-1$
093:
094: private String errorMessage;
095:
096: private Text messageLabel;
097:
098: private Composite workArea;
099:
100: private Label messageImageLabel;
101:
102: private Image messageImage;
103:
104: private boolean showingError = false;
105:
106: private boolean titleImageLargest = true;
107:
108: private int messageLabelHeight;
109:
110: private Image titleAreaImage;
111:
112: /**
113: * Instantiate a new title area dialog.
114: *
115: * @param parentShell
116: * the parent SWT shell
117: */
118: public TitleAreaDialog(Shell parentShell) {
119: super (parentShell);
120: }
121:
122: /*
123: * @see Dialog.createContents(Composite)
124: */
125: protected Control createContents(Composite parent) {
126: // create the overall composite
127: Composite contents = new Composite(parent, SWT.NONE);
128: contents.setLayoutData(new GridData(GridData.FILL_BOTH));
129: // initialize the dialog units
130: initializeDialogUnits(contents);
131: FormLayout layout = new FormLayout();
132: contents.setLayout(layout);
133: // Now create a work area for the rest of the dialog
134: workArea = new Composite(contents, SWT.NONE);
135: GridLayout childLayout = new GridLayout();
136: childLayout.marginHeight = 0;
137: childLayout.marginWidth = 0;
138: childLayout.verticalSpacing = 0;
139: workArea.setLayout(childLayout);
140: Control top = createTitleArea(contents);
141: resetWorkAreaAttachments(top);
142: workArea.setFont(JFaceResources.getDialogFont());
143: // initialize the dialog units
144: initializeDialogUnits(workArea);
145: // create the dialog area and button bar
146: dialogArea = createDialogArea(workArea);
147: buttonBar = createButtonBar(workArea);
148: return contents;
149: }
150:
151: /**
152: * Creates and returns the contents of the upper part of this dialog (above
153: * the button bar).
154: * <p>
155: * The <code>Dialog</code> implementation of this framework method creates
156: * and returns a new <code>Composite</code> with no margins and spacing.
157: * Subclasses should override.
158: * </p>
159: *
160: * @param parent
161: * The parent composite to contain the dialog area
162: * @return the dialog area control
163: */
164: protected Control createDialogArea(Composite parent) {
165: // create the top level composite for the dialog area
166: Composite composite = new Composite(parent, SWT.NONE);
167: GridLayout layout = new GridLayout();
168: layout.marginHeight = 0;
169: layout.marginWidth = 0;
170: layout.verticalSpacing = 0;
171: layout.horizontalSpacing = 0;
172: composite.setLayout(layout);
173: composite.setLayoutData(new GridData(GridData.FILL_BOTH));
174: composite.setFont(parent.getFont());
175: // Build the separator line
176: Label titleBarSeparator = new Label(composite, SWT.HORIZONTAL
177: | SWT.SEPARATOR);
178: titleBarSeparator.setLayoutData(new GridData(
179: GridData.FILL_HORIZONTAL));
180: return composite;
181: }
182:
183: /**
184: * Creates the dialog's title area.
185: *
186: * @param parent
187: * the SWT parent for the title area widgets
188: * @return Control with the highest x axis value.
189: */
190: private Control createTitleArea(Composite parent) {
191:
192: // add a dispose listener
193: parent.addDisposeListener(new DisposeListener() {
194: public void widgetDisposed(DisposeEvent e) {
195: if (titleAreaColor != null) {
196: titleAreaColor.dispose();
197: }
198: }
199: });
200: // Determine the background color of the title bar
201: Display display = parent.getDisplay();
202: Color background;
203: Color foreground;
204: if (titleAreaRGB != null) {
205: titleAreaColor = new Color(display, titleAreaRGB);
206: background = titleAreaColor;
207: foreground = null;
208: } else {
209: background = JFaceColors.getBannerBackground(display);
210: foreground = JFaceColors.getBannerForeground(display);
211: }
212:
213: parent.setBackground(background);
214: int verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
215: int horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
216: // Dialog image @ right
217: titleImageLabel = new Label(parent, SWT.CENTER);
218: titleImageLabel.setBackground(background);
219: if (titleAreaImage == null)
220: titleImageLabel.setImage(JFaceResources
221: .getImage(DLG_IMG_TITLE_BANNER));
222: else
223: titleImageLabel.setImage(titleAreaImage);
224:
225: FormData imageData = new FormData();
226: imageData.top = new FormAttachment(0, 0);
227: // Note: do not use horizontalSpacing on the right as that would be a
228: // regression from
229: // the R2.x style where there was no margin on the right and images are
230: // flush to the right
231: // hand side. see reopened comments in 41172
232: imageData.right = new FormAttachment(100, 0); // horizontalSpacing
233: titleImageLabel.setLayoutData(imageData);
234: // Title label @ top, left
235: titleLabel = new Label(parent, SWT.LEFT);
236: JFaceColors.setColors(titleLabel, foreground, background);
237: titleLabel.setFont(JFaceResources.getBannerFont());
238: titleLabel.setText(" ");//$NON-NLS-1$
239: FormData titleData = new FormData();
240: titleData.top = new FormAttachment(0, verticalSpacing);
241: titleData.right = new FormAttachment(titleImageLabel);
242: titleData.left = new FormAttachment(0, horizontalSpacing);
243: titleLabel.setLayoutData(titleData);
244: // Message image @ bottom, left
245: messageImageLabel = new Label(parent, SWT.CENTER);
246: messageImageLabel.setBackground(background);
247: // Message label @ bottom, center
248: messageLabel = new Text(parent, SWT.WRAP | SWT.READ_ONLY);
249: JFaceColors.setColors(messageLabel, foreground, background);
250: messageLabel.setText(" \n "); // two lines//$NON-NLS-1$
251: messageLabel.setFont(JFaceResources.getDialogFont());
252: messageLabelHeight = messageLabel.computeSize(SWT.DEFAULT,
253: SWT.DEFAULT).y;
254: // Filler labels
255: leftFillerLabel = new Label(parent, SWT.CENTER);
256: leftFillerLabel.setBackground(background);
257: bottomFillerLabel = new Label(parent, SWT.CENTER);
258: bottomFillerLabel.setBackground(background);
259: setLayoutsForNormalMessage(verticalSpacing, horizontalSpacing);
260: determineTitleImageLargest();
261: if (titleImageLargest)
262: return titleImageLabel;
263: return messageLabel;
264: }
265:
266: /**
267: * Determine if the title image is larger than the title message and message
268: * area. This is used for layout decisions.
269: */
270: private void determineTitleImageLargest() {
271: int titleY = titleImageLabel.computeSize(SWT.DEFAULT,
272: SWT.DEFAULT).y;
273: int verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
274: int labelY = titleLabel.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
275: labelY += verticalSpacing;
276: labelY += messageLabelHeight;
277: labelY += verticalSpacing;
278: titleImageLargest = titleY > labelY;
279: }
280:
281: /**
282: * Set the layout values for the messageLabel, messageImageLabel and
283: * fillerLabel for the case where there is a normal message.
284: *
285: * @param verticalSpacing
286: * int The spacing between widgets on the vertical axis.
287: * @param horizontalSpacing
288: * int The spacing between widgets on the horizontal axis.
289: */
290: private void setLayoutsForNormalMessage(int verticalSpacing,
291: int horizontalSpacing) {
292: FormData messageImageData = new FormData();
293: messageImageData.top = new FormAttachment(titleLabel,
294: verticalSpacing);
295: messageImageData.left = new FormAttachment(0, H_GAP_IMAGE);
296: messageImageLabel.setLayoutData(messageImageData);
297: FormData messageLabelData = new FormData();
298: messageLabelData.top = new FormAttachment(titleLabel,
299: verticalSpacing);
300: messageLabelData.right = new FormAttachment(titleImageLabel);
301: messageLabelData.left = new FormAttachment(messageImageLabel,
302: horizontalSpacing);
303: messageLabelData.height = messageLabelHeight;
304: if (titleImageLargest)
305: messageLabelData.bottom = new FormAttachment(
306: titleImageLabel, 0, SWT.BOTTOM);
307: messageLabel.setLayoutData(messageLabelData);
308: FormData fillerData = new FormData();
309: fillerData.left = new FormAttachment(0, horizontalSpacing);
310: fillerData.top = new FormAttachment(messageImageLabel, 0);
311: fillerData.bottom = new FormAttachment(messageLabel, 0,
312: SWT.BOTTOM);
313: bottomFillerLabel.setLayoutData(fillerData);
314: FormData data = new FormData();
315: data.top = new FormAttachment(messageImageLabel, 0, SWT.TOP);
316: data.left = new FormAttachment(0, 0);
317: data.bottom = new FormAttachment(messageImageLabel, 0,
318: SWT.BOTTOM);
319: data.right = new FormAttachment(messageImageLabel, 0);
320: leftFillerLabel.setLayoutData(data);
321: }
322:
323: /**
324: * The <code>TitleAreaDialog</code> implementation of this
325: * <code>Window</code> methods returns an initial size which is at least
326: * some reasonable minimum.
327: *
328: * @return the initial size of the dialog
329: */
330: protected Point getInitialSize() {
331: Point shellSize = super .getInitialSize();
332: return new Point(Math.max(
333: convertHorizontalDLUsToPixels(MIN_DIALOG_WIDTH),
334: shellSize.x), Math.max(
335: convertVerticalDLUsToPixels(MIN_DIALOG_HEIGHT),
336: shellSize.y));
337: }
338:
339: /**
340: * Retained for backward compatibility.
341: *
342: * Returns the title area composite. There is no composite in this
343: * implementation so the shell is returned.
344: *
345: * @return Composite
346: * @deprecated
347: */
348: protected Composite getTitleArea() {
349: return getShell();
350: }
351:
352: /**
353: * Returns the title image label.
354: *
355: * @return the title image label
356: */
357: protected Label getTitleImageLabel() {
358: return titleImageLabel;
359: }
360:
361: /**
362: * Display the given error message. The currently displayed message is saved
363: * and will be redisplayed when the error message is set to
364: * <code>null</code>.
365: *
366: * @param newErrorMessage
367: * the newErrorMessage to display or <code>null</code>
368: */
369: public void setErrorMessage(String newErrorMessage) {
370: // Any change?
371: if (errorMessage == null ? newErrorMessage == null
372: : errorMessage.equals(newErrorMessage))
373: return;
374: errorMessage = newErrorMessage;
375:
376: // Clear or set error message.
377: if (errorMessage == null) {
378: if (showingError) {
379: // we were previously showing an error
380: showingError = false;
381: }
382: // show the message
383: // avoid calling setMessage in case it is overridden to call
384: // setErrorMessage,
385: // which would result in a recursive infinite loop
386: if (message == null) // this should probably never happen since
387: // setMessage does this conversion....
388: message = ""; //$NON-NLS-1$
389: updateMessage(message);
390: messageImageLabel.setImage(messageImage);
391: setImageLabelVisible(messageImage != null);
392: } else {
393: // Add in a space for layout purposes but do not
394: // change the instance variable
395: String displayedErrorMessage = " " + errorMessage; //$NON-NLS-1$
396: updateMessage(displayedErrorMessage);
397: if (!showingError) {
398: // we were not previously showing an error
399: showingError = true;
400: messageImageLabel.setImage(JFaceResources
401: .getImage(DLG_IMG_TITLE_ERROR));
402: setImageLabelVisible(true);
403: }
404: }
405: layoutForNewMessage();
406: }
407:
408: /**
409: * Re-layout the labels for the new message.
410: */
411: private void layoutForNewMessage() {
412: int verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
413: int horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
414: // If there are no images then layout as normal
415: if (errorMessage == null && messageImage == null) {
416: setImageLabelVisible(false);
417: setLayoutsForNormalMessage(verticalSpacing,
418: horizontalSpacing);
419: } else {
420: messageImageLabel.setVisible(true);
421: bottomFillerLabel.setVisible(true);
422: leftFillerLabel.setVisible(true);
423: /**
424: * Note that we do not use horizontalSpacing here as when the
425: * background of the messages changes there will be gaps between the
426: * icon label and the message that are the background color of the
427: * shell. We add a leading space elsewhere to compendate for this.
428: */
429: FormData data = new FormData();
430: data.left = new FormAttachment(0, H_GAP_IMAGE);
431: data.top = new FormAttachment(titleLabel, verticalSpacing);
432: messageImageLabel.setLayoutData(data);
433: data = new FormData();
434: data.top = new FormAttachment(messageImageLabel, 0);
435: data.left = new FormAttachment(0, 0);
436: data.bottom = new FormAttachment(messageLabel, 0,
437: SWT.BOTTOM);
438: data.right = new FormAttachment(messageImageLabel, 0,
439: SWT.RIGHT);
440: bottomFillerLabel.setLayoutData(data);
441: data = new FormData();
442: data.top = new FormAttachment(messageImageLabel, 0, SWT.TOP);
443: data.left = new FormAttachment(0, 0);
444: data.bottom = new FormAttachment(messageImageLabel, 0,
445: SWT.BOTTOM);
446: data.right = new FormAttachment(messageImageLabel, 0);
447: leftFillerLabel.setLayoutData(data);
448: FormData messageLabelData = new FormData();
449: messageLabelData.top = new FormAttachment(titleLabel,
450: verticalSpacing);
451: messageLabelData.right = new FormAttachment(titleImageLabel);
452: messageLabelData.left = new FormAttachment(
453: messageImageLabel, 0);
454: messageLabelData.height = messageLabelHeight;
455: if (titleImageLargest)
456: messageLabelData.bottom = new FormAttachment(
457: titleImageLabel, 0, SWT.BOTTOM);
458: messageLabel.setLayoutData(messageLabelData);
459: }
460: // Do not layout before the dialog area has been created
461: // to avoid incomplete calculations.
462: if (dialogArea != null)
463: workArea.getParent().layout(true);
464: }
465:
466: /**
467: * Set the message text. If the message line currently displays an error,
468: * the message is saved and will be redisplayed when the error message is
469: * set to <code>null</code>.
470: * <p>
471: * Shortcut for <code>setMessage(newMessage, IMessageProvider.NONE)</code>
472: * </p>
473: * This method should be called after the dialog has been opened as it
474: * updates the message label immediately.
475: *
476: * @param newMessage
477: * the message, or <code>null</code> to clear the message
478: */
479: public void setMessage(String newMessage) {
480: setMessage(newMessage, IMessageProvider.NONE);
481: }
482:
483: /**
484: * Sets the message for this dialog with an indication of what type of
485: * message it is.
486: * <p>
487: * The valid message types are one of <code>NONE</code>,
488: * <code>INFORMATION</code>,<code>WARNING</code>, or
489: * <code>ERROR</code>.
490: * </p>
491: * <p>
492: * Note that for backward compatibility, a message of type
493: * <code>ERROR</code> is different than an error message (set using
494: * <code>setErrorMessage</code>). An error message overrides the current
495: * message until the error message is cleared. This method replaces the
496: * current message and does not affect the error message.
497: * </p>
498: *
499: * @param newMessage
500: * the message, or <code>null</code> to clear the message
501: * @param newType
502: * the message type
503: * @since 2.0
504: */
505: public void setMessage(String newMessage, int newType) {
506: Image newImage = null;
507: if (newMessage != null) {
508: switch (newType) {
509: case IMessageProvider.NONE:
510: break;
511: case IMessageProvider.INFORMATION:
512: newImage = JFaceResources
513: .getImage(DLG_IMG_MESSAGE_INFO);
514: break;
515: case IMessageProvider.WARNING:
516: newImage = JFaceResources
517: .getImage(DLG_IMG_MESSAGE_WARNING);
518: break;
519: case IMessageProvider.ERROR:
520: newImage = JFaceResources
521: .getImage(DLG_IMG_MESSAGE_ERROR);
522: break;
523: }
524: }
525: showMessage(newMessage, newImage);
526: }
527:
528: /**
529: * Show the new message and image.
530: *
531: * @param newMessage
532: * @param newImage
533: */
534: private void showMessage(String newMessage, Image newImage) {
535: // Any change?
536: if (message.equals(newMessage) && messageImage == newImage) {
537: return;
538: }
539: message = newMessage;
540: if (message == null)
541: message = "";//$NON-NLS-1$
542: // Message string to be shown - if there is an image then add in
543: // a space to the message for layout purposes
544: String shownMessage = (newImage == null) ? message
545: : " " + message; //$NON-NLS-1$
546: messageImage = newImage;
547: if (!showingError) {
548: // we are not showing an error
549: updateMessage(shownMessage);
550: messageImageLabel.setImage(messageImage);
551: setImageLabelVisible(messageImage != null);
552: layoutForNewMessage();
553: }
554: }
555:
556: /**
557: * Update the contents of the messageLabel.
558: *
559: * @param newMessage
560: * the message to use
561: */
562: private void updateMessage(String newMessage) {
563: messageLabel.setText(newMessage);
564: }
565:
566: /**
567: * Sets the title to be shown in the title area of this dialog.
568: *
569: * @param newTitle
570: * the title show
571: */
572: public void setTitle(String newTitle) {
573: if (titleLabel == null)
574: return;
575: String title = newTitle;
576: if (title == null)
577: title = "";//$NON-NLS-1$
578: titleLabel.setText(title);
579: }
580:
581: /**
582: * Sets the title bar color for this dialog.
583: *
584: * @param color
585: * the title bar color
586: */
587: public void setTitleAreaColor(RGB color) {
588: titleAreaRGB = color;
589: }
590:
591: /**
592: * Sets the title image to be shown in the title area of this dialog.
593: *
594: * @param newTitleImage
595: * the title image to be shown
596: */
597: public void setTitleImage(Image newTitleImage) {
598:
599: titleAreaImage = newTitleImage;
600: if (titleImageLabel != null) {
601: titleImageLabel.setImage(newTitleImage);
602: titleImageLabel.setVisible(newTitleImage != null);
603: if (newTitleImage != null) {
604: determineTitleImageLargest();
605: Control top;
606: if (titleImageLargest)
607: top = titleImageLabel;
608: else
609: top = messageLabel;
610: resetWorkAreaAttachments(top);
611: }
612: }
613: }
614:
615: /**
616: * Make the label used for displaying error images visible depending on
617: * boolean.
618: *
619: * @param visible
620: * If <code>true</code> make the image visible, if not then
621: * make it not visible.
622: */
623: private void setImageLabelVisible(boolean visible) {
624: messageImageLabel.setVisible(visible);
625: bottomFillerLabel.setVisible(visible);
626: leftFillerLabel.setVisible(visible);
627: }
628:
629: /**
630: * Reset the attachment of the workArea to now attach to top as the top
631: * control.
632: *
633: * @param top
634: */
635: private void resetWorkAreaAttachments(Control top) {
636: FormData childData = new FormData();
637: childData.top = new FormAttachment(top);
638: childData.right = new FormAttachment(100, 0);
639: childData.left = new FormAttachment(0, 0);
640: childData.bottom = new FormAttachment(100, 0);
641: workArea.setLayoutData(childData);
642: }
643: }
|