Added copy button to popup and context info to the error trace
authorCherian Mathew <c.mathew@bgbm.org>
Tue, 16 Sep 2014 08:37:06 +0000 (08:37 +0000)
committerCherian Mathew <c.mathew@bgbm.org>
Tue, 16 Sep 2014 08:37:06 +0000 (08:37 +0000)
eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/CdmErrorDialog.java
eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/MessagingUtils.java

index 792386b585b7ef11ad73b42bc7cdf0651b3dcbb3..9d33e2a124d598eae1deb25ccde3a9571b38e96b 100644 (file)
@@ -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() });
+           }
+       }
 }
index 3fbc5123655c9dd0be5314ae360fd72b5b887c4b..959e49d92df4715109cbf5ca0e329b6139c91b6e 100644 (file)
@@ -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<String> getContextInfo() {
+        List<String> contextInfo = new ArrayList<String>();
+        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<? extends Object> clazz = source != null ? source.getClass() : this.getClass();
-                error(clazz, status);
-            }
-        });
+        return contextInfo;
+    }
+
+    public static String getStackTraceAndContextInfo(Throwable t, List<String> 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<String> 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<? extends Object> 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<Status> childStatuses = new ArrayList<Status>();
+
+        // add context info
+        List<String> 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<? extends Object> clazz = source != null ? source.getClass() : this.getClass();
+                error(clazz, status);
+            }
+        });
+    }
 
     /**
      * Displays a dialog for an exception occurring in an operation.