blob: d112c7ca493fe62c3d9927b158ea8c69795fe68d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 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.ui.internal.forms;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.forms.IMessage;
import org.eclipse.ui.forms.IMessageManager;
import org.eclipse.ui.forms.IMessagePrefixProvider;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.eclipse.ui.forms.widgets.ScrolledForm;
/**
* @see IMessageManager
*/
public class MessageManager implements IMessageManager {
private static final DefaultPrefixProvider DEFAULT_PREFIX_PROVIDER = new DefaultPrefixProvider();
private ArrayList messages = new ArrayList();
private Hashtable decorators = new Hashtable();
private boolean autoUpdate = true;
private ScrolledForm scrolledForm;
private IMessagePrefixProvider prefixProvider = DEFAULT_PREFIX_PROVIDER;
private int decorationPosition = SWT.LEFT | SWT.BOTTOM;
private static FieldDecoration standardError = FieldDecorationRegistry
.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR);
private static FieldDecoration standardWarning = FieldDecorationRegistry
.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_WARNING);
private static FieldDecoration standardInformation = FieldDecorationRegistry
.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_INFORMATION);
private static final String[] SINGLE_MESSAGE_SUMMARY_KEYS = {
Messages.MessageManager_sMessageSummary,
Messages.MessageManager_sMessageSummary,
Messages.MessageManager_sWarningSummary,
Messages.MessageManager_sErrorSummary };
private static final String[] MULTIPLE_MESSAGE_SUMMARY_KEYS = {
Messages.MessageManager_pMessageSummary,
Messages.MessageManager_pMessageSummary,
Messages.MessageManager_pWarningSummary,
Messages.MessageManager_pErrorSummary };
static class Message implements IMessage {
Control control;
Object data;
Object key;
String message;
int type;
String prefix;
Message(Object key, String message, int type, Object data) {
this.key = key;
this.message = message;
this.type = type;
this.data = data;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.IMessage#getKey()
*/
public Object getKey() {
return key;
}
/*
* (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;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.messages.IMessage#getControl()
*/
public Control getControl() {
return control;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.messages.IMessage#getData()
*/
public Object getData() {
return data;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.messages.IMessage#getPrefix()
*/
public String getPrefix() {
return prefix;
}
}
static class DefaultPrefixProvider implements IMessagePrefixProvider {
public String getPrefix(Control c) {
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-like widget
for (int j = i - 1; j >= 0; j--) {
Control label = siblings[j];
String ltext = null;
if (label instanceof Label) {
ltext = ((Label) label).getText();
} else if (label instanceof Hyperlink) {
ltext = ((Hyperlink) label).getText();
} else if (label instanceof CLabel) {
ltext = ((CLabel) label).getText();
}
if (ltext != null) {
if (!ltext.endsWith(":")) //$NON-NLS-1$
return ltext + ": "; //$NON-NLS-1$
return ltext + " "; //$NON-NLS-1$
}
}
break;
}
}
return null;
}
}
class ControlDecorator {
private ControlDecoration decoration;
private ArrayList controlMessages = new ArrayList();
private String prefix;
ControlDecorator(Control control) {
this.decoration = new ControlDecoration(control, decorationPosition, scrolledForm.getBody());
}
public boolean isDisposed() {
return decoration.getControl() == null;
}
void updatePrefix() {
prefix = null;
}
void updatePosition() {
Control control = decoration.getControl();
decoration.dispose();
this.decoration = new ControlDecoration(control, decorationPosition, scrolledForm.getBody());
update();
}
String getPrefix() {
if (prefix == null)
createPrefix();
return prefix;
}
private void createPrefix() {
if (prefixProvider == null) {
prefix = ""; //$NON-NLS-1$
return;
}
prefix = prefixProvider.getPrefix(decoration.getControl());
if (prefix == null)
// make a prefix anyway
prefix = ""; //$NON-NLS-1$
}
void addAll(ArrayList target) {
target.addAll(controlMessages);
}
void addMessage(Object key, String text, Object data, int type) {
Message message = MessageManager.this.addMessage(getPrefix(), key,
text, data, type, controlMessages);
message.control = decoration.getControl();
if (isAutoUpdate())
update();
}
boolean removeMessage(Object key) {
Message message = findMessage(key, controlMessages);
if (message != null) {
controlMessages.remove(message);
if (isAutoUpdate())
update();
}
return message != null;
}
boolean removeMessages() {
if (controlMessages.isEmpty())
return false;
controlMessages.clear();
if (isAutoUpdate())
update();
return true;
}
public void update() {
if (controlMessages.isEmpty()) {
decoration.setDescriptionText(null);
decoration.hide();
} else {
ArrayList peers = createPeers(controlMessages);
int type = ((IMessage) peers.get(0)).getMessageType();
String description = createDetails(createPeers(peers), true);
if (type == IMessageProvider.ERROR)
decoration.setImage(standardError.getImage());
else if (type == IMessageProvider.WARNING)
decoration.setImage(standardWarning.getImage());
else if (type == IMessageProvider.INFORMATION)
decoration.setImage(standardInformation.getImage());
decoration.setDescriptionText(description);
decoration.show();
}
}
}
/**
* Creates a new instance of the message manager that will work with the
* provided form.
*
* @param scrolledForm
* the form to control
*/
public MessageManager(ScrolledForm scrolledForm) {
this.scrolledForm = scrolledForm;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#addMessage(java.lang.Object,
* java.lang.String, int)
*/
public void addMessage(Object key, String messageText, Object data, int type) {
addMessage(null, key, messageText, data, type, messages);
if (isAutoUpdate())
updateForm();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#addMessage(java.lang.Object,
* java.lang.String, int, org.eclipse.swt.widgets.Control)
*/
public void addMessage(Object key, String messageText, Object data,
int type, Control control) {
ControlDecorator dec = (ControlDecorator) decorators.get(control);
if (dec == null) {
dec = new ControlDecorator(control);
decorators.put(control, dec);
}
dec.addMessage(key, messageText, data, type);
if (isAutoUpdate())
updateForm();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#removeMessage(java.lang.Object)
*/
public void removeMessage(Object key) {
Message message = findMessage(key, messages);
if (message != null) {
messages.remove(message);
if (isAutoUpdate())
updateForm();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#removeMessages()
*/
public void removeMessages() {
if (!messages.isEmpty()) {
messages.clear();
if (isAutoUpdate())
updateForm();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#removeMessage(java.lang.Object,
* org.eclipse.swt.widgets.Control)
*/
public void removeMessage(Object key, Control control) {
ControlDecorator dec = (ControlDecorator) decorators.get(control);
if (dec == null)
return;
if (dec.removeMessage(key))
if (isAutoUpdate())
updateForm();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#removeMessages(org.eclipse.swt.widgets.Control)
*/
public void removeMessages(Control control) {
ControlDecorator dec = (ControlDecorator) decorators.get(control);
if (dec != null) {
if (dec.removeMessages()) {
if (isAutoUpdate())
updateForm();
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#removeAllMessages()
*/
public void removeAllMessages() {
boolean needsUpdate = false;
for (Enumeration enm = decorators.elements(); enm.hasMoreElements();) {
ControlDecorator control = (ControlDecorator) enm.nextElement();
if (control.removeMessages())
needsUpdate = true;
}
if (!messages.isEmpty()) {
messages.clear();
needsUpdate = true;
}
if (needsUpdate && isAutoUpdate())
updateForm();
}
/*
* Adds the message if it does not already exist in the provided list.
*/
private Message addMessage(String prefix, Object key, String messageText,
Object data, int type, ArrayList list) {
Message message = findMessage(key, list);
if (message == null) {
message = new Message(key, messageText, type, data);
message.prefix = prefix;
list.add(message);
} else {
message.message = messageText;
message.type = type;
message.data = data;
}
return message;
}
/*
* Finds the message with the provided key in the provided list.
*/
private Message findMessage(Object key, ArrayList list) {
for (int i = 0; i < list.size(); i++) {
Message message = (Message) list.get(i);
if (message.getKey().equals(key))
return message;
}
return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#update()
*/
public void update() {
// Update decorations
for (Iterator iter = decorators.values().iterator(); iter.hasNext();) {
ControlDecorator dec = (ControlDecorator) iter.next();
dec.update();
}
// Update the form
updateForm();
}
/*
* Updates the container by rolling the messages up from the controls.
*/
private void updateForm() {
ArrayList mergedList = new ArrayList();
mergedList.addAll(messages);
for (Enumeration enm = decorators.elements(); enm.hasMoreElements();) {
ControlDecorator dec = (ControlDecorator) enm.nextElement();
dec.addAll(mergedList);
}
update(mergedList);
}
private void update(ArrayList mergedList) {
pruneControlDecorators();
if (scrolledForm.getForm().getHead().getBounds().height == 0 || mergedList.isEmpty() || mergedList == null) {
scrolledForm.setMessage(null, IMessageProvider.NONE);
return;
}
ArrayList peers = createPeers(mergedList);
int maxType = ((IMessage) peers.get(0)).getMessageType();
String messageText;
IMessage[] array = (IMessage[]) peers
.toArray(new IMessage[peers.size()]);
if (peers.size() == 1 && ((Message) peers.get(0)).prefix == null) {
// a single message
IMessage message = (IMessage) peers.get(0);
messageText = message.getMessage();
scrolledForm.setMessage(messageText, maxType, array);
} else {
// show a summary message for the message
// and list of errors for the details
if (peers.size() > 1)
messageText = Messages.bind(
MULTIPLE_MESSAGE_SUMMARY_KEYS[maxType],
new String[] { peers.size() + "" }); //$NON-NLS-1$
else
messageText = SINGLE_MESSAGE_SUMMARY_KEYS[maxType];
scrolledForm.setMessage(messageText, maxType, array);
}
}
private static String getFullMessage(IMessage message) {
if (message.getPrefix() == null)
return message.getMessage();
return message.getPrefix() + message.getMessage();
}
private ArrayList createPeers(ArrayList messages) {
ArrayList peers = new ArrayList();
int maxType = 0;
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);
}
return peers;
}
private String createDetails(ArrayList messages, boolean excludePrefix) {
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
for (int i = 0; i < messages.size(); i++) {
if (i > 0)
out.println();
IMessage m = (IMessage) messages.get(i);
out.print(excludePrefix ? m.getMessage() : getFullMessage(m));
}
out.flush();
return sw.toString();
}
public static String createDetails(IMessage[] messages) {
if (messages == null || messages.length == 0)
return null;
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
for (int i = 0; i < messages.length; i++) {
if (i > 0)
out.println();
out.print(getFullMessage(messages[i]));
}
out.flush();
return sw.toString();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#createSummary(org.eclipse.ui.forms.IMessage[])
*/
public String createSummary(IMessage[] messages) {
return createDetails(messages);
}
private void pruneControlDecorators() {
for (Iterator iter = decorators.values().iterator(); iter.hasNext();) {
ControlDecorator dec = (ControlDecorator) iter.next();
if (dec.isDisposed())
iter.remove();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#getMessagePrefixProvider()
*/
public IMessagePrefixProvider getMessagePrefixProvider() {
return prefixProvider;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#setMessagePrefixProvider(org.eclipse.ui.forms.IMessagePrefixProvider)
*/
public void setMessagePrefixProvider(IMessagePrefixProvider provider) {
this.prefixProvider = provider;
for (Iterator iter = decorators.values().iterator(); iter.hasNext();) {
ControlDecorator dec = (ControlDecorator) iter.next();
dec.updatePrefix();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#getDecorationPosition()
*/
public int getDecorationPosition() {
return decorationPosition;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#setDecorationPosition(int)
*/
public void setDecorationPosition(int position) {
this.decorationPosition = position;
for (Iterator iter = decorators.values().iterator(); iter.hasNext();) {
ControlDecorator dec = (ControlDecorator) iter.next();
dec.updatePosition();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#isAutoUpdate()
*/
public boolean isAutoUpdate() {
return autoUpdate;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.forms.IMessageManager#setAutoUpdate(boolean)
*/
public void setAutoUpdate(boolean autoUpdate) {
boolean needsUpdate = !this.autoUpdate && autoUpdate;
this.autoUpdate = autoUpdate;
if (needsUpdate)
update();
}
}