From fa518bf81aa6e8121946d7afdd842c3c401c316f Mon Sep 17 00:00:00 2001 From: Cherian Mathew Date: Tue, 16 Sep 2014 08:37:06 +0000 Subject: [PATCH] Added copy button to popup and context info to the error trace --- .../taxeditor/model/CdmErrorDialog.java | 99 ++++++++++++- .../taxeditor/model/MessagingUtils.java | 131 ++++++++++++++---- 2 files changed, 193 insertions(+), 37 deletions(-) diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/CdmErrorDialog.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/CdmErrorDialog.java index 792386b58..9d33e2a12 100644 --- a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/CdmErrorDialog.java +++ b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/CdmErrorDialog.java @@ -5,7 +5,13 @@ import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.List; import org.eclipse.swt.widgets.Shell; @@ -22,14 +28,49 @@ public class CdmErrorDialog extends ErrorDialog { private static final int DIALOG_MAX_HEIGHT = 500; - public CdmErrorDialog(Shell parentShell, String dialogTitle, - String message, IStatus status) { - super(parentShell, - dialogTitle, - message, status, - IStatus.OK| IStatus.INFO | IStatus.WARNING | IStatus.ERROR); - } + private Button copyButton; + private final String stackTrace; + + /** + * The current clipboard. To be disposed when closing the dialog. + */ + private Clipboard clipboard; + + /** + * @param parentShell + * @param dialogTitle + * @param message + * @param status + * @param stackTrace + */ + public CdmErrorDialog(Shell parentShell, + String dialogTitle, + String message, + IStatus status, + String stackTrace) { + super(parentShell, + dialogTitle, + message, status, + IStatus.OK| IStatus.INFO | IStatus.WARNING | IStatus.ERROR); + this.stackTrace = stackTrace; + } + /** + * @param parentShell + * @param dialogTitle + * @param message + * @param status + */ + public CdmErrorDialog(Shell parentShell, + String dialogTitle, + String message, + IStatus status) { + this(parentShell, dialogTitle, message, status, ""); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.ErrorDialog#buttonPressed(int) + */ @Override protected void buttonPressed(int id) { super.buttonPressed(id); @@ -45,10 +86,54 @@ public class CdmErrorDialog extends ErrorDialog { } + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.ErrorDialog#createDropDownList(org.eclipse.swt.widgets.Composite) + */ @Override protected List createDropDownList(Composite parent) { List list = super.createDropDownList(parent); list.getMenu().getItem(0).setText(JFaceResources.getString("copy all")); return list; } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.ErrorDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) + */ + @Override + protected void createButtonsForButtonBar(Composite parent) { + copyButton = createButton(parent, 2000,"Copy Error", false); + copyButton.addSelectionListener(new SelectionListener() { + /* + * @see SelectionListener.widgetSelected (SelectionEvent) + */ + @Override + public void widgetSelected(SelectionEvent e) { + copyStackTraceToClipboard(); + } + /* + * @see SelectionListener.widgetDefaultSelected(SelectionEvent) + */ + @Override + public void widgetDefaultSelected(SelectionEvent e) { + copyStackTraceToClipboard(); + } + }); + super.createButtonsForButtonBar(parent); + } + + + /** + * Copies the stack trace to the clipboard + * + */ + private void copyStackTraceToClipboard() { + if(stackTrace != null && !stackTrace.isEmpty()) { + if (clipboard != null) { + clipboard.dispose(); + } + clipboard = new Clipboard(copyButton.getDisplay()); + clipboard.setContents(new Object[] { stackTrace }, + new Transfer[] { TextTransfer.getInstance() }); + } + } } diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/MessagingUtils.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/MessagingUtils.java index 3fbc51236..959e49d92 100644 --- a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/MessagingUtils.java +++ b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/MessagingUtils.java @@ -8,11 +8,13 @@ import java.util.List; import org.apache.log4j.Logger; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.widgets.Display; import eu.etaxonomy.cdm.persistence.hibernate.permission.SecurityExceptionUtils; +import eu.etaxonomy.taxeditor.store.CdmStore; import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin; /** @@ -154,36 +156,74 @@ public class MessagingUtils { error(source.getClass(), t.getMessage(), t); } + + /** - * Displays a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog}. + * Returns a list of strings, providing info on, + * - login + * - editor version + * - server (address + source name) + * - db schema version * - * @param title - * a {@link java.lang.String} object. - * @param source - * a {@link java.lang.Object} object. - * @param status - * a {@link org.eclipse.core.runtime.IStatus} object. + * @return */ - private static void errorDialog(final String title, - final Object source, - final String message, - final IStatus status) { + public static List getContextInfo() { + List contextInfo = new ArrayList(); + String name = ""; + String schemaVersion = ""; + String server = ""; + String version = ""; + String login = ""; + try { + version = Platform.getBundle("eu.etaxonomy.taxeditor.application").getHeaders().get(org.osgi.framework.Constants.BUNDLE_VERSION); + + if(CdmStore.getActiveCdmSource() != null ) { + login = CdmStore.getLoginManager().getAuthenticatedUser().getUsername(); + name = CdmStore.getActiveCdmSource().getName(); + schemaVersion = CdmStore.getActiveCdmSource().getDbSchemaVersion(); + server = CdmStore.getActiveCdmSource().getServer(); + } - Display.getDefault().asyncExec(new Runnable() { + } catch (Exception e) { + // Nothing to do + } + contextInfo.add("login : " + login); + contextInfo.add("editor version : " + version); + contextInfo.add("server : " + server + " / " + name); + contextInfo.add("schema version : " + schemaVersion); - @Override - public void run() { - CdmErrorDialog ced = new CdmErrorDialog(AbstractUtility.getShell(), title, message, status); - ced.open(); - Class clazz = source != null ? source.getClass() : this.getClass(); - error(clazz, status); - } - }); + return contextInfo; + } + + public static String getStackTraceAndContextInfo(Throwable t, List contextInfo) { + StringBuffer stackTraceAndContextInfo = new StringBuffer(); + + for(String infoItem : contextInfo) { + stackTraceAndContextInfo.append(infoItem + System.getProperty("line.separator")); + } + + StringWriter sw = new StringWriter(); + t.printStackTrace(new PrintWriter(sw)); + + stackTraceAndContextInfo.append(sw.toString()); + + return stackTraceAndContextInfo.toString(); } + /** + * Displays a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog}. + * + * @param title + * @param source + * @param t + * @param contextInfo + * @param message + * @param status + */ private static void errorDialog(final String title, final Object source, final Throwable t, + final List contextInfo, final String message, final MultiStatus status) { @@ -191,19 +231,16 @@ public class MessagingUtils { @Override public void run() { - CdmErrorDialog ced = new CdmErrorDialog(AbstractUtility.getShell(), title, message, status); + String stackTraceWithContext = getStackTraceAndContextInfo(t, contextInfo); + CdmErrorDialog ced = new CdmErrorDialog(AbstractUtility.getShell(), title, message, status, stackTraceWithContext); ced.open(); Class clazz = source != null ? source.getClass() : this.getClass(); - // Usually the status contains only the first line of the stack trace. - // For the unexpected messages we need the entire stack trace so we - // create a new status with the entire stacktrace - StringWriter sw = new StringWriter(); - t.printStackTrace(new PrintWriter(sw)); + IStatus singleStatus = new Status(IStatus.ERROR, status.getPlugin(), message, - new Exception(sw.toString())); + new Exception(stackTraceWithContext)); error(clazz, singleStatus); } @@ -233,11 +270,19 @@ public class MessagingUtils { // idea of writing out the stack trace as a single string // leads to a single line on windows List childStatuses = new ArrayList(); + + // add context info + List contextInfo = getContextInfo(); + for(String infoItem : contextInfo) { + childStatuses.add(new Status(IStatus.ERROR, pluginId, infoItem)); + } + + // add main execption for (StackTraceElement ste : t.getStackTrace()) { - // build & add status childStatuses.add(new Status(IStatus.ERROR, pluginId, "at " + ste.toString())); } + // add cause if(t.getCause() != null) { childStatuses.add(new Status(IStatus.ERROR, pluginId, "")); childStatuses.add(new Status(IStatus.ERROR, pluginId, "Caused by : " + t.getCause().toString())); @@ -247,7 +292,6 @@ public class MessagingUtils { } } - // build message with contact info String finalMessage = message; if(finalMessage == null || finalMessage.isEmpty()) { @@ -255,6 +299,7 @@ public class MessagingUtils { } if(addContactMesg) { + // add edit support contact info to message finalMessage += MessagingUtils.CONTACT_MESSAGE; } @@ -264,9 +309,35 @@ public class MessagingUtils { t.toString(), t); - errorDialog(title, source, t, finalMessage, ms); + errorDialog(title, source, t, contextInfo, finalMessage, ms); } + /** + * Displays a {@link eu.etaxonomy.taxeditor.model.CdmErrorDialog}. + * + * @param title + * a {@link java.lang.String} object. + * @param source + * a {@link java.lang.Object} object. + * @param status + * a {@link org.eclipse.core.runtime.IStatus} object. + */ + private static void errorDialog(final String title, + final Object source, + final String message, + final IStatus status) { + + Display.getDefault().asyncExec(new Runnable() { + + @Override + public void run() { + CdmErrorDialog ced = new CdmErrorDialog(AbstractUtility.getShell(), title, message, status); + ced.open(); + Class clazz = source != null ? source.getClass() : this.getClass(); + error(clazz, status); + } + }); + } /** * Displays a dialog for an exception occurring in an operation. -- 2.34.1