### Eclipse Workspace Patch 1.0 #P org.eclipse.jface Index: src/org/eclipse/jface/dialogs/TitleAreaDialog.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jface/src/org/eclipse/jface/dialogs/TitleAreaDialog.java,v retrieving revision 1.41 diff -u -r1.41 TitleAreaDialog.java --- src/org/eclipse/jface/dialogs/TitleAreaDialog.java 6 Oct 2006 13:43:03 -0000 1.41 +++ src/org/eclipse/jface/dialogs/TitleAreaDialog.java 20 Dec 2006 20:32:09 -0000 @@ -44,7 +44,7 @@ *
* This dialog class may be subclassed. */ -public class TitleAreaDialog extends TrayDialog { +public class TitleAreaDialog extends TrayDialog implements IMessageContainer { /** * Image registry key for error message image. */ @@ -99,6 +99,8 @@ Color titleAreaColor; private String message = ""; //$NON-NLS-1$ + + private int messageType; private String errorMessage; @@ -475,6 +477,20 @@ public void setMessage(String newMessage) { setMessage(newMessage, IMessageProvider.NONE); } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.IMessageProvider#getMessage() + */ + public String getMessage() { + return message; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.IMessageProvider#getMessageType() + */ + public int getMessageType() { + return messageType; + } /** * Sets the message for this dialog with an indication of what type of @@ -515,21 +531,23 @@ break; } } - showMessage(newMessage, newImage); + showMessage(newMessage, newType, newImage); } /** * Show the new message and image. * * @param newMessage + * @param newType * @param newImage */ - private void showMessage(String newMessage, Image newImage) { + private void showMessage(String newMessage, int newType, Image newImage) { // Any change? if (message.equals(newMessage) && messageImage == newImage) { return; } message = newMessage; + messageType = newType; if (message == null) message = "";//$NON-NLS-1$ // Message string to be shown - if there is an image then add in Index: src/org/eclipse/jface/dialogs/DialogPage.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jface/src/org/eclipse/jface/dialogs/DialogPage.java,v retrieving revision 1.13 diff -u -r1.13 DialogPage.java --- src/org/eclipse/jface/dialogs/DialogPage.java 8 May 2006 20:57:00 -0000 1.13 +++ src/org/eclipse/jface/dialogs/DialogPage.java 20 Dec 2006 20:32:09 -0000 @@ -27,7 +27,7 @@ * Abstract base implementation of a dialog page. All dialog pages are * subclasses of this one. */ -public abstract class DialogPage implements IDialogPage, IMessageProvider { +public abstract class DialogPage implements IDialogPage, IMessageContainer { /** * The control for this dialog page. */ @@ -270,6 +270,7 @@ /* * (non-Javadoc) Method declared on IDialogPage. + * @since 3.3 */ public String getMessage() { return message; @@ -277,6 +278,7 @@ /* * (non-Javadoc) Method declared on IMessageProvider. + * @since 3.3 */ public int getMessageType() { return messageType; Index: src/org/eclipse/jface/messages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jface/src/org/eclipse/jface/messages.properties,v retrieving revision 1.21 diff -u -r1.21 messages.properties --- src/org/eclipse/jface/messages.properties 7 Jul 2006 01:18:01 -0000 1.21 +++ src/org/eclipse/jface/messages.properties 20 Dec 2006 20:32:09 -0000 @@ -193,3 +193,11 @@ FieldDecorationRegistry.contentAssistMessage=Content Assist Available FieldDecorationRegistry.requiredFieldMessage=Required Field +MessageManager.sMessageSummary = 1 message detected +MessageManager.sWarningSummary = 1 warning detected +MessageManager.sErrorSummary = 1 error detected +MessageManager.pMessageSummary = {0} messages detected +MessageManager.pWarningSummary = {0} warnings detected +MessageManager.pErrorSummary = {0} errors detected + + Index: src/org/eclipse/jface/fieldassist/ControlDecoration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jface/src/org/eclipse/jface/fieldassist/ControlDecoration.java,v retrieving revision 1.12 diff -u -r1.12 ControlDecoration.java --- src/org/eclipse/jface/fieldassist/ControlDecoration.java 10 Nov 2006 22:43:35 -0000 1.12 +++ src/org/eclipse/jface/fieldassist/ControlDecoration.java 20 Dec 2006 20:32:09 -0000 @@ -241,7 +241,7 @@ .getSystemColor(SWT.COLOR_INFO_FOREGROUND)); hoverShell.addPaintListener(new PaintListener() { public void paintControl(PaintEvent pe) { - pe.gc.drawString(text, hm, hm); + pe.gc.drawText(text, hm, hm); if (!CARBON) { pe.gc.drawPolygon(getPolygon(true)); } Index: src/org/eclipse/jface/dialogs/IMessageContainerWithDetails.java =================================================================== RCS file: src/org/eclipse/jface/dialogs/IMessageContainerWithDetails.java diff -N src/org/eclipse/jface/dialogs/IMessageContainerWithDetails.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/jface/dialogs/IMessageContainerWithDetails.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2006 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.jface.dialogs; + +/** + *
+ * This interface should be implemented by message containers that are capable + * of showing messages that have a summary and details. + *
+ *+ * EXPERIMENTAL This class or interface has been added as part + * of a work in progress. This API may change at any given time. Please do not + * use this API without consulting with the Platform/UI team. + *
+ * + * @since 3.3 + */ +public interface IMessageContainerWithDetails extends IMessageContainer { + + /** + * Sets the message for this container with an indication of what type of + * message it is. + *
+ * The valid message types are one of NONE
,
+ * INFORMATION
,WARNING
, or
+ * ERROR
.
+ *
null
to clear the message
+ * @param detailedMessage
+ * the detailed message that provides more information. If used,
+ * newMessage
should be used as a summary.
+ * @param newType
+ * the message type
+ */
+ public void setMessage(String newMessage, String detailedMessage,
+ int newType);
+}
Index: src/org/eclipse/jface/fieldassist/MessageManager.java
===================================================================
RCS file: src/org/eclipse/jface/fieldassist/MessageManager.java
diff -N src/org/eclipse/jface/fieldassist/MessageManager.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/jface/fieldassist/MessageManager.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,489 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.jface.fieldassist;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.eclipse.jface.dialogs.IMessageContainer;
+import org.eclipse.jface.dialogs.IMessageContainerWithDetails;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+/**
+ * Use this class to work with message containers that contain decorated fields.
+ * The class provides for:
+ * EXPERIMENTAL This class or interface has been added as part + * of a work in progress. This API may change at any given time. Please do not + * use this API without consulting with the Platform/UI team.
+ * + * @see IMessageContainer + * @see IMessageContainerWithDetails + * @since 3.3 + */ + +public class MessageManager { + private ArrayList messages = new ArrayList(); + private Hashtable decorators = new Hashtable(); + private boolean showOnlyOnFocus; + private IMessageContainer messageContainer; + private static FieldDecoration standardError = FieldDecorationRegistry + .getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR); + private static FieldDecoration standardWarning = FieldDecorationRegistry + .getDefault().getFieldDecoration( + FieldDecorationRegistry.DEC_WARNING); + + private static final String[] SINGLE_MESSAGE_SUMMARY_KEYS = { + "MessageManager.sMessageSummary", //$NON-NLS-1$ + "MessageManager.sMessageSummary", //$NON-NLS-1$ + "MessageManager.sWarningSummary", //$NON-NLS-1$ + "MessageManager.sErrorSummary" //$NON-NLS-1$ + }; + + private static final String[] MULTIPLE_MESSAGE_SUMMARY_KEYS = { + "MessageManager.pMessageSummary", //$NON-NLS-1$ + "MessageManager.pMessageSummary", //$NON-NLS-1$ + "MessageManager.pWarningSummary", //$NON-NLS-1$ + "MessageManager.pErrorSummary" //$NON-NLS-1$ + }; + + class Message { + String prefix; + String id; + int type; + String message; + + Message(String prefix, String id, String message, int type) { + this.id = id; + this.message = message; + this.type = type; + this.prefix = prefix; + } + + String getFullMessage() { + if (prefix == null) + return message; + return prefix + message; + } + } + + class ControlDecorator implements IMessageContainerWithDetails { + private ControlDecoration decoration; + private ArrayList controlMessages = new ArrayList(); + private String message; + private int type; + private String prefix; + + ControlDecorator(Control control) { + this.decoration = new ControlDecoration(control, SWT.LEFT + | SWT.BOTTOM); + updateFocusSetting(); + } + + String getPrefix() { + if (prefix == null) + createPrefix(); + return prefix; + } + + void updateFocusSetting() { + if (getShowOnlyOnFocus() != decoration.getShowOnlyOnFocus()) + decoration.setShowOnlyOnFocus(getShowOnlyOnFocus()); + } + + private void createPrefix() { + Control c = decoration.getControl(); + Composite parent = c.getParent(); + Control[] siblings = parent.getChildren(); + for (int i = 0; i < siblings.length; i++) { + if (siblings[i] == c) { + // this is us - go backward until you hit + // a label + for (int j = i - 1; j >= 0; j--) { + Control label = siblings[j]; + if (label instanceof Label) { + prefix = ((Label) label).getText() + ": "; //$NON-NLS-1$ + return; + } + } + break; + } + } + // make a prefix anyway + prefix = ""; //$NON-NLS-1$ + } + + void addAll(ArrayList target) { + target.addAll(controlMessages); + } + + void addMessage(String id, String text, int type) { + MessageManager.this.addMessage(getPrefix(), id, text, type, + controlMessages); + updateMessageContainer(this, controlMessages, true); + } + + void removeMessage(String id) { + Message message = findMessage(id, controlMessages); + if (message != null) { + controlMessages.remove(message); + updateMessageContainer(this, controlMessages, true); + } + } + + void removeMessages() { + controlMessages.clear(); + updateMessageContainer(this, controlMessages, true); + } + + boolean isEmpty() { + return controlMessages.isEmpty(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.dialogs.IMessageContainer#setMessage(java.lang.String, + * int) + */ + public void setMessage(String newMessage, int newType) { + if (this.message != null && newMessage != null + && newMessage.equals(this.message) && newType == this.type) + return; + this.message = newMessage; + this.type = newType; + update(); + } + + public void setMessage(String newMessage, String details, int type) { + setMessage(newMessage, type); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.dialogs.IMessageProvider#getMessage() + */ + public String getMessage() { + return message; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.dialogs.IMessageProvider#getMessageType() + */ + public int getMessageType() { + return type; + } + + private void update() { + if (message == null) + decoration.hide(); + else { + if (type == IMessageProvider.ERROR) + decoration.setImage(standardError.getImage()); + else if (type == IMessageProvider.WARNING) + decoration.setImage(standardWarning.getImage()); + decoration.setDescriptionText(message); + decoration.show(); + } + } + } + + /** + * Creates a new instance of the message manager that will work with the + * provided message container. + * + * @param messageContainer + * the container to control + */ + public MessageManager(IMessageContainer messageContainer) { + this.messageContainer = messageContainer; + } + + /** + * Adds a general message that is not associated with any decorated field. + * + * @param id + * a unique message identifier that will be used to look the + * message up later + * + * @param messageText + * the message to add + * @param type + * the message type as defined inIMessageProvider
.
+ */
+
+ public void addMessage(String id, String messageText, int type) {
+ addMessage(null, id, messageText, type, messages);
+ updateMessageContainer();
+ }
+
+ /**
+ * Adds a message that should be associated with the provided control.
+ *
+ * @param id
+ * the unique message identifier
+ * @param messageText
+ * the message to add
+ * @param type
+ * the message type
+ * @param control
+ * the control to associate the message with
+ */
+
+ public void addMessage(String id, String messageText, int type,
+ Control control) {
+ ControlDecorator dec = (ControlDecorator) decorators.get(control);
+ if (dec == null) {
+ dec = new ControlDecorator(control);
+ decorators.put(control, dec);
+ control.addDisposeListener(new DisposeListener() {
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
+ */
+ public void widgetDisposed(DisposeEvent e) {
+ decorators.remove(e.widget);
+ updateMessageContainer();
+ }
+ });
+ }
+ dec.addMessage(id, messageText, type);
+ updateMessageContainer();
+ }
+
+ /**
+ * Set the boolean that controls whether the control decorations are shown
+ * only when the controls have focus. The default value of this setting is
+ * false
.
+ *
+ * @param showOnlyOnFocus
+ * true
if the decoration should only be shown
+ * when the control has focus, and false
if it
+ * should always be shown.
+ */
+ public void setShowOnlyOnFocus(boolean showOnlyOnFocus) {
+ this.showOnlyOnFocus = showOnlyOnFocus;
+ updateMessageContainer();
+ }
+
+ /**
+ * Get the boolean that controls whether the control decorations are shown
+ * only when the controls have focus. The default value of this setting is
+ * false
.
+ *
+ * @return true
if the control decoration should only be
+ * shown when the control has focus, and false
if it
+ * should always be shown.
+ */
+ public boolean getShowOnlyOnFocus() {
+ return showOnlyOnFocus;
+ }
+
+ /**
+ * Removes the provided general message.
+ *
+ * @param id
+ * the id of the message to remove
+ */
+
+ public void removeMessage(String id) {
+ Message message = findMessage(id, messages);
+ if (message != null) {
+ messages.remove(message);
+ updateMessageContainer();
+ }
+ }
+
+ /**
+ * Removes all the general messages. If there are local messages associated
+ * with controls, the replacement message may show up drawing user's
+ * attention to these local messages. Otherwise, the container will clear
+ * the message area.
+ */
+ public void removeMessages() {
+ messages.clear();
+ updateMessageContainer();
+ }
+
+ /**
+ * Removes the message associated with the provided control.
+ *
+ * @param id
+ * the id of the message to remove
+ * @param control
+ * the control the message is associated with
+ */
+
+ public void removeMessage(String id, Control control) {
+ ControlDecorator dec = (ControlDecorator) decorators.get(control);
+ if (dec == null)
+ return;
+ dec.removeMessage(id);
+ updateMessageContainer();
+ }
+
+ /**
+ * Removes all the messages associated with the provided control.
+ *
+ * @param control
+ * the control the messages are associated with
+ */
+
+ public void removeMessages(Control control) {
+ ControlDecorator dec = (ControlDecorator) decorators.get(control);
+ dec.removeMessages();
+ updateMessageContainer();
+ }
+
+ /**
+ * Removes all the local field messages and all the general container
+ * messages.
+ */
+
+ public void removeAllMessages() {
+ for (Enumeration enm = decorators.elements(); enm.hasMoreElements();) {
+ ControlDecorator control = (ControlDecorator) enm.nextElement();
+ control.removeMessages();
+ }
+ messages.clear();
+ updateMessageContainer();
+ }
+
+ /*
+ * Adds the message if it does not already exist in the provided list.
+ */
+
+ private void addMessage(String prefix, String id, String messageText,
+ int type, ArrayList list) {
+ Message message = findMessage(id, list);
+ if (message == null) {
+ message = new Message(prefix, id, messageText, type);
+ list.add(message);
+ } else {
+ message.message = messageText;
+ message.type = type;
+ }
+ }
+
+ /*
+ * Finds the message with the provided id in the provided list.
+ */
+
+ private Message findMessage(String id, ArrayList list) {
+ for (int i = 0; i < list.size(); i++) {
+ Message message = (Message) list.get(i);
+ if (message.id.equals(id))
+ return message;
+ }
+ return null;
+ }
+
+ /*
+ * Updates the entire container by building up a merged list that contains
+ * messages from each decorated field plus messages from the container
+ * itself.
+ */
+
+ private void updateMessageContainer() {
+ ArrayList mergedList = new ArrayList();
+ mergedList.addAll(messages);
+ for (Enumeration enm = decorators.elements(); enm.hasMoreElements();) {
+ ControlDecorator dec = (ControlDecorator) enm.nextElement();
+ dec.addAll(mergedList);
+ dec.updateFocusSetting();
+ }
+ updateMessageContainer(messageContainer, mergedList, false);
+ }
+
+ /*
+ * This method works with a generic message container when a list of
+ * messages of various types need to be shown. The messages with the highest
+ * type are picked first. If there are more than one with this type, a
+ * multiple message is constructed; otherwise, the message is used as-is.
+ */
+
+ private void updateMessageContainer(IMessageContainer container,
+ ArrayList messages, boolean showAll) {
+ if (messages.isEmpty() || messages == null) {
+ container.setMessage(null, IMessageProvider.NONE);
+ return;
+ }
+ int maxType = 0;
+ // create a subset of messages with the highest type
+ ArrayList peers = new ArrayList();
+ for (int i = 0; i < messages.size(); i++) {
+ Message message = (Message) messages.get(i);
+ if (message.type > maxType) {
+ peers.clear();
+ maxType = message.type;
+ }
+ if (message.type == maxType)
+ peers.add(message);
+ }
+ String messageText;
+ String details = null;
+ if (peers.size() == 1 && ((Message) peers.get(0)).prefix == null) {
+ // a single message
+ messageText = ((Message) peers.get(0)).message;
+ } else {
+ StringWriter sw = new StringWriter();
+ PrintWriter out = new PrintWriter(sw);
+ // StringBuffer sw = new StringBuffer();
+ for (int i = 0; i < peers.size(); i++) {
+ if (i > 0)
+ out.println();
+ Message m = (Message) peers.get(i);
+ out.print(showAll ? m.message : m.getFullMessage());
+ }
+ out.flush();
+ if (showAll)
+ messageText = sw.toString();
+ else {
+ // show a summary message for the message
+ // and list of errors for the details
+ if (peers.size() > 1)
+ messageText = JFaceResources.format(
+ MULTIPLE_MESSAGE_SUMMARY_KEYS[maxType],
+ new String[] { peers.size() + "" }); //$NON-NLS-1$
+ else
+ messageText = JFaceResources
+ .getString(SINGLE_MESSAGE_SUMMARY_KEYS[maxType]);
+ details = sw.toString();
+ }
+ }
+ if (container instanceof IMessageContainerWithDetails)
+ ((IMessageContainerWithDetails) container).setMessage(messageText,
+ details, maxType);
+ else
+ container.setMessage(messageText, maxType);
+ }
+}
Index: src/org/eclipse/jface/dialogs/IMessageContainer.java
===================================================================
RCS file: src/org/eclipse/jface/dialogs/IMessageContainer.java
diff -N src/org/eclipse/jface/dialogs/IMessageContainer.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/jface/dialogs/IMessageContainer.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.jface.dialogs;
+
+/**
+ * A generic interface for containers capable of displaying messages of a set
+ * type (as defined in IMessageProvider
). Although there is no
+ * firm contract on how these messages are displayed, a typical implementation
+ * will have some kind of a header area for this purpose.
+ *
+ * EXPERIMENTAL This class or interface has been added as part + * of a work in progress. This API may change at any given time. Please do not + * use this API without consulting with the Platform/UI team.
+ * + * @since 3.3 + */ +public interface IMessageContainer extends IMessageProvider { + /** + * Sets the message for this container with an indication of what type of + * message it is. + *
+ * The valid message types are one of NONE
,
+ * INFORMATION
,WARNING
, or
+ * ERROR
.
+ *
null
to clear the message
+ * @param newType
+ * the message type
+ */
+ public void setMessage(String newMessage, int newType);
+}