initial commit of error reporting plugin
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/.checkstyle b/org.eclipse.emf.emfstore.ui.errorreporting/.checkstyle
new file mode 100644
index 0000000..2f2667a
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/.checkstyle
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false">
+ <fileset name="all" enabled="true" check-config-name="emfstoreStyle" local="false">
+ <file-match-pattern match-pattern="." include-pattern="true"/>
+ </fileset>
+</fileset-config>
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/.classpath b/org.eclipse.emf.emfstore.ui.errorreporting/.classpath
new file mode 100644
index 0000000..2d1a430
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/.project b/org.eclipse.emf.emfstore.ui.errorreporting/.project
new file mode 100644
index 0000000..dd4bfef
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.emf.emfstore.ui.errorreporting</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.emf.emfstore.ui.errorreporting/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ef029ba
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+#Thu Aug 23 11:06:00 CEST 2012
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/META-INF/MANIFEST.MF b/org.eclipse.emf.emfstore.ui.errorreporting/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..df7b415
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/META-INF/MANIFEST.MF
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Error Diagnosis Plugin
+Bundle-SymbolicName: org.eclipse.emf.emfstore.ui.errorreporting;singleton:=true
+Bundle-Version: 0.9.3.qualifier
+Bundle-Activator: org.eclipse.emf.emfstore.ui.errorreporting.Activator
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.emf.emfstore.client;bundle-version="0.9.3",
+ com.ibm.icu;bundle-version="4.4.2"
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-Vendor: Eclipse Modeling Project
+Export-Package: org.eclipse.emf.emfstore.ui.errorreporting
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/build.properties b/org.eclipse.emf.emfstore.ui.errorreporting/build.properties
new file mode 100644
index 0000000..73a5119
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/build.properties
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.properties,\
+ plugin.xml
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/plugin.properties b/org.eclipse.emf.emfstore.ui.errorreporting/plugin.properties
new file mode 100644
index 0000000..09f0eaf
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/plugin.properties
@@ -0,0 +1,2 @@
+supportMailURL = mailto:emueller@eclipsesource.com?subject=EMFStore%20Bug%20Report&body=Thank%20you%20for%20reporting%20this%20bug.%20Please%20help%20us%20to%20fix%20the%20problem%20by%20following%20these%20steps%3A%0A%0A1.%20Give%20a%20summary%0A%3CDescription%3E%0A%0A2.%20Describe%20steps%20to%20reproduce%20the%20error%0A%20%201.%20%3CStep%201%3E%0A%20%202.%20%3CStep%202%3E%0A%0A3.%20Paste%20%28Ctrl%2Bv%29%20the%20content%20of%20the%20clipboard%20below%20%28parts%20of%20the%20log%20file%20have%20been%20copied%20to%20it%29%0A%3CContent%20from%20Log%20File%3E
+supportMailURL_errorDiagnosisCaptured = mailto:emueller@eclipsesource.com?subject=EMFStore%20Bug%20Report&body=Thank%20you%20for%20reporting%20this%20bug%3A%0A%0AThe%20error%20diagnosis%20has%20been%20captured%20by%20you.%20Please%20help%20us%20to%20fix%20the%20problem%20by%20following%20these%20steps%3A%0A%0A1.%20Give%20a%20summary%0A%3CDescription%3E%0A%0A2.%20Describe%20steps%20to%20reproduce%20the%20error%0A%20%201.%20%3CStep%201%3E%0A%20%202.%20%3CStep%202%3E
\ No newline at end of file
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/plugin.xml b/org.eclipse.emf.emfstore.ui.errorreporting/plugin.xml
new file mode 100644
index 0000000..1775e63
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/plugin.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+ <extension-point id="org.eclipse.emf.emfstore.ui.errorreporting" name="customLog" schema="schema/org.eclipse.emf.emfstore.ui.errorreporting.exsd"/>
+ <extension
+ point="org.eclipse.ui.commands">
+ <command
+ id="org.eclipse.emf.emfstore.ui.createErrorLog"
+ name="Create Error Log">
+ </command>
+ </extension>
+ <extension
+ id="org.eclipse.emf.emfstore.ui.createErrorLog"
+ point="org.eclipse.ui.handlers">
+ <handler
+ class="org.eclipse.emf.emfstore.ui.errorreporting.MailBugHandler"
+ commandId="org.eclipse.emf.emfstore.ui.createErrorLog">
+ </handler>
+ </extension>
+ <extension
+ point="org.eclipse.emf.emfstore.client.exceptionObserver">
+ <observer
+ exceptionObserver="org.eclipse.emf.emfstore.ui.errorreporting.EmfStoreExceptionObserver">
+ </observer>
+ </extension>
+ <extension
+ point="org.eclipse.ui.statusHandlers">
+ <statusHandler
+ class="org.eclipse.emf.emfstore.ui.errorreporting.EmfStoreStatusHandler"
+ id="org.eclipse.emf.emfstore.ui.statusHandler">
+ </statusHandler>
+ </extension>
+</plugin>
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/schema/org.eclipse.emf.emfstore.ui.errorreporting.exsd b/org.eclipse.emf.emfstore.ui.errorreporting/schema/org.eclipse.emf.emfstore.ui.errorreporting.exsd
new file mode 100644
index 0000000..9926e13
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/schema/org.eclipse.emf.emfstore.ui.errorreporting.exsd
@@ -0,0 +1,102 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.emf.emfstore.ui.errorreporting" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appInfo>
+ <meta.schema plugin="org.eclipse.emf.emfstore.ui.errorreporting" id="org.eclipse.emf.emfstore.ui.errorreporting.customLog" name="org.eclipse.emf.emfstore.ui.errorreporting.customLog"/>
+ </appInfo>
+ <documentation>
+ [Enter description of this extension point.]
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appInfo>
+ <meta.element />
+ </appInfo>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="loggable"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="loggable">
+ <complexType>
+ <attribute name="class" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appInfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.emf.emfstore.ui.errorreporting.ILoggable"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="since"/>
+ </appInfo>
+ <documentation>
+ [Enter the first release in which this extension point appears.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="examples"/>
+ </appInfo>
+ <documentation>
+ [Enter extension point usage example here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="apiinfo"/>
+ </appInfo>
+ <documentation>
+ [Enter API information here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="implementation"/>
+ </appInfo>
+ <documentation>
+ [Enter information about supplied implementation of this extension point.]
+ </documentation>
+ </annotation>
+
+
+</schema>
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/Activator.java b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/Activator.java
new file mode 100644
index 0000000..6cbdf0d
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/Activator.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2012 EclipseSource Muenchen GmbH.
+ *
+ * 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:
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.ui.errorreporting;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Activator class for the error reporting plugin.
+ */
+public class Activator extends AbstractUIPlugin {
+
+ /**
+ * Error reporting plugin ID.
+ */
+ public static final String PLUGIN_ID = "org.eclipse.emf.emfstore.ui.errorreporting"; //$NON-NLS-1$
+
+ private static Activator plugin;
+
+ /**
+ * Constructor.
+ */
+ public Activator() {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ // BEGIN SUPRESS CATCH EXCEPTION
+ public void start(BundleContext context) throws Exception {
+ // END SUPRESS CATCH EXCEPTION
+ super.start(context);
+ plugin = this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ // BEGIN SUPRESS CATCH EXCEPTION
+ public void stop(BundleContext context) throws Exception {
+ // END SUPRESS CATCH EXCEPTION
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance.
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+}
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/EmfStoreExceptionObserver.java b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/EmfStoreExceptionObserver.java
new file mode 100644
index 0000000..b48b444
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/EmfStoreExceptionObserver.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2012 EclipseSource Muenchen GmbH.
+ *
+ * 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:
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.ui.errorreporting;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.emfstore.client.model.Configuration;
+import org.eclipse.emf.emfstore.client.model.exceptions.MissingCommandException;
+import org.eclipse.emf.emfstore.client.model.observers.ExceptionObserver;
+import org.eclipse.emf.emfstore.client.model.util.WorkspaceUtil;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.ui.PlatformUI;
+
+import com.ibm.icu.text.MessageFormat;
+
+/**
+ * An exception observer that collects logs.
+ *
+ * @author Maximilian Koegel
+ */
+public class EmfStoreExceptionObserver implements ExceptionObserver {
+
+ private static EmfStoreExceptionObserver instance;
+ private Set<ExceptionLog> exceptionLogs;
+
+ /**
+ * Constructor.
+ */
+ public EmfStoreExceptionObserver() {
+ instance = this;
+ exceptionLogs = new HashSet<ExceptionLog>();
+ }
+
+ /**
+ * Returns the instance.
+ *
+ * @return the instance
+ */
+ public static EmfStoreExceptionObserver getInstance() {
+ if (instance == null) {
+ instance = new EmfStoreExceptionObserver();
+ }
+ return instance;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean handleError(RuntimeException e) {
+ if (Configuration.isDebugMode()) {
+
+ MailBugHandler bugHandler = new MailBugHandler();
+
+ try {
+ bugHandler.execute(new ExecutionEvent());
+ } catch (ExecutionException exception) {
+ WorkspaceUtil.handleException(exception);
+ }
+
+ ErrorDialog
+ .openError(
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+ "DEBUG MODE ACTIVE: An Error Occured",
+ MessageFormat.format(
+ "This error message only appears if debug mode is active. \n"
+ + "Although this error message might be an error itself, it might help to find bugs faster. \n"
+ + "The most recent log has been copied to the clipboard, please add it to the bug report. Thanks! \n"
+ + "To disable, launch without {0}={1} switch.",
+ Configuration.DEBUG_SWITCH, Configuration.DEBUG_SWITCH_ENABLED_VALUE),
+ new Status(Status.ERROR, "org.eclipse.emf.emfstore.client", "An error occured.", e));
+
+ throw e;
+ }
+
+ // MissingCommandException should only be logged if the debug switch is not set
+ if (e.getCause() instanceof MissingCommandException) {
+ return true;
+ }
+
+ for (ExceptionLog exceptionLog : exceptionLogs) {
+ exceptionLog.addException(e);
+ }
+
+ return true;
+ }
+
+ /**
+ * Adds a log.
+ *
+ * @param log
+ * the log being added
+ */
+ public void addLog(ExceptionLog log) {
+ exceptionLogs.add(log);
+ }
+
+ /**
+ * Removes a log.
+ *
+ * @param log
+ * the log to be removed
+ */
+ public void removeLog(ExceptionLog log) {
+ exceptionLogs.remove(log);
+ }
+
+ /**
+ * Returns the log.
+ * @return the log
+ */
+ public ExceptionLog getLog() {
+ return new ExceptionLog(this);
+ }
+
+}
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/EmfStoreStatusHandler.java b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/EmfStoreStatusHandler.java
new file mode 100644
index 0000000..86a6b28
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/EmfStoreStatusHandler.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2012 EclipseSource Muenchen GmbH.
+ *
+ * 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:
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.ui.errorreporting;
+
+import org.eclipse.ui.statushandlers.WorkbenchErrorHandler;
+import org.eclipse.ui.statushandlers.WorkbenchStatusDialogManager;
+
+/**
+ * Status handler for enabling the submission of a bug via mail.
+ *
+ * @author Maximilian Koegel
+ */
+public class EmfStoreStatusHandler extends WorkbenchErrorHandler {
+
+ @Override
+ protected void configureStatusDialog(WorkbenchStatusDialogManager statusDialog) {
+ super.configureStatusDialog(statusDialog);
+ statusDialog.enableDefaultSupportArea(true);
+ statusDialog.setSupportAreaProvider(new MailBugStatusAreaProvider());
+ }
+}
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ErrorReportingUtil.java b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ErrorReportingUtil.java
new file mode 100644
index 0000000..9edc451
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ErrorReportingUtil.java
@@ -0,0 +1,357 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2012 EclipseSource Muenchen GmbH.
+ *
+ * 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:
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.ui.errorreporting;
+
+import java.awt.AWTException;
+import java.awt.HeadlessException;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.Toolkit;
+import java.awt.image.BufferedImage;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.commons.lang.StringUtils;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.emf.emfstore.client.model.Configuration;
+import org.eclipse.emf.emfstore.client.model.util.WorkspaceUtil;
+import org.eclipse.emf.emfstore.common.extensionpoint.ExtensionElement;
+import org.eclipse.emf.emfstore.common.extensionpoint.ExtensionPoint;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+
+import com.ibm.icu.text.MessageFormat;
+import com.ibm.icu.text.SimpleDateFormat;
+
+/**
+ * Utility class for capturing system specific information for debugging purposes.
+ *
+ * @author emueller
+ */
+public final class ErrorReportingUtil {
+
+ private static final String CUSTOMLOG_EXTENSION_POINT_ID = "org.eclipse.emf.emfstore.ui.errorreporting";
+ private static final String SCREENSHOT_FOLDER_NAME = "screenshots";
+ private static final String DEFAULT_SCREENSHOT_PREFIX = "emfstore-screenshot-";
+ private static final String DEFAULT_SYSINFO_PREFIX = "emfstore-sysinfo-";
+ private static final String SYSINFO_SUFFIX = "txt";
+
+ private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
+
+ /**
+ * Private constructor.
+ */
+ private ErrorReportingUtil() {
+
+ }
+
+ private static String getLogText() {
+
+ String filename = Platform.getLogFileLocation().toOSString();
+ File log = new File(filename);
+
+ try {
+ String version = Configuration.getClientVersion().getVersion();
+ String logFileContent = FileUtils.readFileToString(log);
+
+ StringBuffer result = new StringBuffer(16384);
+ result.append(
+ MessageFormat.format("EMFStore client {0}. Log copied at {1}\n\n",
+ version, SimpleDateFormat.getDateTimeInstance().format(new Date())));
+ result.append(logFileContent);
+
+ return result.toString();
+ } catch (IOException ex) {
+ WorkspaceUtil.logException("Exception while copying log to clipboard", ex);
+ }
+
+ return null;
+ }
+
+ /**
+ * Copies the content of the current log file to the clipboard.
+ *
+ * @param window
+ * the window that is used to determine which Display to copy to
+ */
+ public static void copyLogToClipboard(IWorkbenchWindow window) {
+ String text = getLogText();
+ Clipboard clipboard = null;
+
+ if (text == null) {
+ return;
+ }
+
+ try {
+ clipboard = new Clipboard(window.getShell().getDisplay());
+ clipboard.setContents(new Object[] { text }, new Transfer[] { TextTransfer.getInstance() });
+ } finally {
+ if (clipboard != null) {
+ clipboard.dispose();
+ }
+ }
+ }
+
+ /**
+ * Creates the error diagnosis file.
+ *
+ * @param date
+ * the date that will be written to the error diagnosis file in order to indicate when the
+ * file was created
+ * @param path
+ * the parent path under which the error diagnosis file will be put
+ * @param statusAdapter
+ * a status adapter that may contain the most recent stack trace, that will be copied
+ * into the error diagnosis file
+ * @return the absolute path to the created error diagnosis file
+ */
+ public static String captureSysInfo(Date date, String path, StatusAdapter statusAdapter) {
+
+ File temp = new File(path);
+ FileWriter fileWriter = null;
+ BufferedWriter bufferedWriter = null;
+
+ temp.deleteOnExit();
+
+ try {
+ Runtime runtime = Runtime.getRuntime();
+ RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
+ fileWriter = new FileWriter(temp);
+
+ bufferedWriter = new BufferedWriter(fileWriter);
+ bufferedWriter.write(MessageFormat.format("Log file created on {0}\n", new Date()));
+ bufferedWriter.write(MessageFormat.format("Client version: {0} {1}\n",
+ Configuration.getClientVersion().getName(), Configuration.getClientVersion().getVersion()));
+ bufferedWriter.write("List of open editors:\n");
+
+ if (getOpenEditorIDs().size() == 0) {
+ bufferedWriter.write("\t<None>\n");
+ } else {
+ for (String viewId : getOpenEditorIDs()) {
+ bufferedWriter.write(MessageFormat.format("\t{0}\n", viewId));
+ }
+ }
+
+ bufferedWriter.write(MessageFormat.format("Working directory: {0}",
+ System.getProperty("user.dir")));
+ bufferedWriter.write(MessageFormat.format("System user: {0}",
+ System.getProperty("user.name")));
+ bufferedWriter.write(MessageFormat.format("Memory usage: {0}/{1} MB",
+ toMb(runtime.totalMemory() - runtime.freeMemory()), toMb(runtime.maxMemory())));
+ bufferedWriter.write(MessageFormat.format("Available processors (cores): {0}\n",
+ runtime.availableProcessors()));
+ bufferedWriter.write(MessageFormat.format("Java version: {0}",
+ System.getProperty("java.version")));
+ bufferedWriter.write(MessageFormat.format("OS version: {0}",
+ System.getProperty("os.version")));
+ bufferedWriter.write("VM Startup parameters:\n");
+
+ for (String vmArg : runtimeMXBean.getInputArguments()) {
+ bufferedWriter.write(MessageFormat.format("\t{0}\n", vmArg));
+ }
+
+ ExtensionPoint extPoint = new ExtensionPoint(CUSTOMLOG_EXTENSION_POINT_ID);
+ for (ExtensionElement el : extPoint.getExtensionElements()) {
+ ILoggable loggable = el.getClass("class", ILoggable.class);
+ bufferedWriter.write(loggable.getLoggable());
+ }
+
+ if (statusAdapter != null) {
+ bufferedWriter.write(MessageFormat.format("Stacktrace: {0}\n", getStatus(statusAdapter)));
+ }
+
+ return temp.getAbsolutePath();
+ } catch (IOException e) {
+ WorkspaceUtil.logException("Error while writing error diagnosis file: ", e);
+ } finally {
+ if (bufferedWriter != null) {
+ try {
+ bufferedWriter.close();
+ } catch (IOException e) {
+ WorkspaceUtil.logException("Error while closing buffered error diagnosis stream.", e);
+ }
+ }
+
+ if (fileWriter != null) {
+ try {
+ fileWriter.close();
+ } catch (IOException e) {
+ WorkspaceUtil.logException("Error while closing error diagnosis stream.", e);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Creates the error diagnosis file.
+ *
+ * @param date
+ * the date that will be written to the error diagnosis file in order to indicate when the
+ * file was created
+ * @param path
+ * the parent path under which the error diagnosis file will be put
+ * @return the absolute path to the created error diagnosis file
+ */
+ public static String captureSysInfo(Date date, String path) {
+ return captureSysInfo(date, path, null);
+ }
+
+ /**
+ * Returns a list of strings containing the IDs of all opened editors.
+ *
+ * @return a list of strings containing the IDs of all opened editors
+ */
+ private static List<String> getOpenEditorIDs() {
+
+ List<String> openedEditors = new ArrayList<String>();
+ IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+
+ for (IEditorReference editorRef : activePage.getEditorReferences()) {
+ openedEditors.add(editorRef.getId());
+ }
+
+ return openedEditors;
+ }
+
+ private static String getStatus(StatusAdapter statusAdapter) {
+ StringBuilder sb = new StringBuilder();
+ addException(sb, statusAdapter.getStatus());
+ String logText = sb.toString();
+ if (logText == null || logText.length() == 0) {
+ logText = "Could not find exception";
+ }
+ return logText;
+ }
+
+
+ private static void addException(StringBuilder collector, IStatus iStatus) {
+ if (iStatus instanceof MultiStatus) {
+ MultiStatus ms = (MultiStatus) iStatus;
+ IStatus[] children = ms.getChildren();
+ for (IStatus childStatus : children) {
+ addException(collector, childStatus);
+ }
+ } else {
+ Throwable ex = iStatus.getException();
+ if (ex != null) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintWriter pw = new PrintWriter(baos);
+ ex.printStackTrace(pw);
+ pw.flush();
+ collector.append(new String(baos.toByteArray()));
+ }
+ }
+ }
+
+ private static int toMb(long value) {
+ return (int) (value / 1024 / 1024);
+ }
+
+ /**
+ * Returns the path to the file that contains error diagnosis and system specific information.
+ *
+ * @param date
+ * the date to be used as a part of the constructed path
+ * @return the constructed path
+ */
+ public static String getSysInfoPath(Date date) {
+ String errorDiagnosisFilename = DEFAULT_SYSINFO_PREFIX + formatDate(date) + "." + SYSINFO_SUFFIX;
+ return StringUtils.join(Arrays.asList(Configuration.getErrorLogDirectory(), errorDiagnosisFilename),
+ File.separatorChar);
+ }
+
+ /**
+ * Formats the given date.
+ * @param date
+ * the date to be formatted
+ * @return the formatted date
+ */
+ public static String formatDate(Date date) {
+ return format.format(date);
+ }
+
+ /**
+ * Takes a screenshot.
+ * @param screenshotPath
+ * the path under which the screenshot will be put
+ * @param format
+ * the format of the screenshot being created
+ * @return the path to the taken screenshot
+ */
+ public static String makeScreenshot(String screenshotPath, ScreenshotFormat format) {
+
+ try {
+ BufferedImage bufferedImage = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit()
+ .getScreenSize()));
+ File temp = new File(screenshotPath);
+ temp.deleteOnExit();
+ ImageIO.write(bufferedImage, format.getType(), temp);
+ return temp.getAbsolutePath();
+ } catch (HeadlessException e) {
+ WorkspaceUtil.logException("Could not create screenshot.", e);
+ } catch (AWTException e) {
+ WorkspaceUtil.logException("Could not create screenshot.", e);
+ } catch (IOException e) {
+ WorkspaceUtil.logException("Could not create screenshot.", e);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the screenshot path.
+ * @param date
+ * the date that will be part of the screenshot name
+ * @param format
+ * the format of the screenshot
+ * @return the constructed path to the screenshot
+ */
+ public static String getScreenshotPath(Date date, ScreenshotFormat format) {
+ String screenShotFilename = DEFAULT_SCREENSHOT_PREFIX + formatDate(date) + "." + format.getType();
+ return StringUtils.join(Arrays.asList(getScreenshotFolder(), screenShotFilename),
+ File.separatorChar);
+ }
+
+
+ private static String getScreenshotFolder() {
+ File screenshotDir = new File(StringUtils.join(Arrays.asList(Configuration.getErrorLogDirectory(),
+ SCREENSHOT_FOLDER_NAME), File.separatorChar));
+
+ if (!screenshotDir.exists()) {
+ screenshotDir.mkdir();
+ }
+
+ return screenshotDir.getAbsolutePath();
+ }
+}
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ExceptionLog.java b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ExceptionLog.java
new file mode 100644
index 0000000..0aa0bb3
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ExceptionLog.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2012 EclipseSource Muenchen GmbH.
+ *
+ * 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:
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.ui.errorreporting;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class for logging exceptions.
+ *
+ * @author Maximilian Koegel
+ */
+public class ExceptionLog {
+
+ private List<Exception> exceptions;
+ private EmfStoreExceptionObserver exceptionObserver;
+
+ /**
+ * Constructor.
+ *
+ * @param exceptionObserver
+ * the exception that is used to notify this class when to add exceptions
+ */
+ public ExceptionLog(EmfStoreExceptionObserver exceptionObserver) {
+ this.exceptions = new ArrayList<Exception>();
+ this.exceptionObserver = exceptionObserver;
+ exceptionObserver.addLog(this);
+ }
+
+ /**
+ * Adds and exception to the log.
+ *
+ * @param exception
+ * the exception to be added
+ */
+ public void addException(Exception exception) {
+ exceptions.add(exception);
+ }
+
+ /**
+ * Destroys the exception log.
+ *
+ * @return the list of collected exceptions
+ */
+ public List<Exception> destroy() {
+ exceptionObserver.removeLog(this);
+ return exceptions;
+ }
+}
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ILoggable.java b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ILoggable.java
new file mode 100644
index 0000000..b7d8415
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ILoggable.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2012 EclipseSource Muenchen GmbH.
+ *
+ * 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:
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.ui.errorreporting;
+
+/**
+ * Interface for adding information to the error diagnosis and system information file that
+ * is created via {@link ErrorReportingUtil#captureSysInfo(java.util.Date, String)}.
+ *
+ * @author emueller
+ */
+public interface ILoggable {
+
+ /**
+ * Returns the string to be logged.
+ *
+ * @return the string to be logged
+ */
+ String getLoggable();
+}
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/LogFilenameFilter.java b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/LogFilenameFilter.java
new file mode 100644
index 0000000..fb447c7
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/LogFilenameFilter.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2012 EclipseSource Muenchen GmbH.
+ *
+ * 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:
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.ui.errorreporting;
+
+import java.io.File;
+import java.io.FilenameFilter;
+
+/**
+ * Filter for log files.
+ */
+public class LogFilenameFilter implements FilenameFilter {
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean accept(File file, String name) {
+ return name.toLowerCase().endsWith(".log");
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/MailBugHandler.java b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/MailBugHandler.java
new file mode 100644
index 0000000..5bdeff4
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/MailBugHandler.java
@@ -0,0 +1,240 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2012 EclipseSource Muenchen GmbH.
+ *
+ * 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:
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.ui.errorreporting;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Date;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.StringUtils;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.emf.emfstore.client.model.Configuration;
+import org.eclipse.emf.emfstore.client.model.util.WorkspaceUtil;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.browser.IWebBrowser;
+import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
+import org.eclipse.ui.progress.IProgressService;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+
+import com.ibm.icu.text.MessageFormat;
+
+/**
+ * Handler for submitting a bug via mail.
+ *
+ * @author emueller
+ */
+public class MailBugHandler extends AbstractHandler implements IWorkbenchWindowActionDelegate {
+
+ private IWorkbenchWindow window;
+ private StatusAdapter statusAdapter;
+
+ /**
+ * Constructor.
+ */
+ public MailBugHandler() {
+ this.window = null;
+ this.statusAdapter = null;
+ }
+
+ /**
+ * Constructor.
+ * @param window
+ * a window that is used to determine the shell
+ * @param statusAdapter
+ * a status adapter that may contain the most recent stack trace
+ */
+ public MailBugHandler(IWorkbenchWindow window, StatusAdapter statusAdapter) {
+ this.window = window;
+ this.statusAdapter = statusAdapter;
+ }
+
+ private void archive(final Date currentDate, IProgressMonitor monitor, String[] paths)
+ throws FileNotFoundException {
+ monitor.beginTask("Creating error report...", paths.length);
+ try {
+ ZipHandle zipHandle = ZipHandle.openZipHandle(getZipPathname(currentDate));
+
+ for (String path : paths) {
+ File file = new File(path);
+
+ if (!file.exists()) {
+ continue;
+ }
+
+ if (file.isDirectory()) {
+ zipHandle.addFile(StringUtils.EMPTY, path + "/");
+ } else {
+ zipHandle.addFile(StringUtils.EMPTY, path);
+ }
+
+ monitor.worked(1);
+ }
+
+ zipHandle.close();
+ } catch (IOException e) {
+ MessageDialog.openError(window.getShell(), "Error while creating zip",
+ MessageFormat.format("An error occurred while trying to archive the workspace folder {0}: {1}",
+ Configuration.getErrorLogDirectory(), e.getMessage()));
+ }
+
+ monitor.done();
+ }
+
+ private String getZipPathname(Date currentDate) {
+ String userHome = System.getProperty("user.home");
+ // TODO: where to put zip
+ return StringUtils.join(Arrays.asList(userHome, "Desktop",
+ ZipHandle.ZIP_PREFIX + ErrorReportingUtil.formatDate(currentDate) + ".zip"), File.separatorChar);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void dispose() {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void init(IWorkbenchWindow window) {
+ this.window = window;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void selectionChanged(IAction action, ISelection selection) {
+
+ }
+
+ /**
+ * Display an error message.
+ */
+ private void openWebBrowserError(final String href, final Throwable t) {
+ String title = "Send Bug Report";
+ String msg = "Unable to open URL " + href + " exception: " + t.getLocalizedMessage();
+ MessageDialog.openError(window.getShell(), title, msg);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+
+ final Date date = new Date();
+ boolean shouldCaptureErrorDiagnosis = openShouldCreateErrorReportDialog(date);
+
+ if (shouldCaptureErrorDiagnosis) {
+ IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
+ try {
+ progressService.run(false, false, new IRunnableWithProgress() {
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ try {
+ String screenshotPath = ErrorReportingUtil.makeScreenshot(
+ ErrorReportingUtil.getScreenshotPath(date, ScreenshotFormat.JPG), ScreenshotFormat.JPG);
+ String sysInfoPath = ErrorReportingUtil.captureSysInfo(date, ErrorReportingUtil.getSysInfoPath(date), statusAdapter);
+ IPath logFolder = Platform.getLogFileLocation().removeLastSegments(1);
+ String[] logFiles = getLogFilePaths(logFolder);
+
+ archive(date, monitor, (String[]) ArrayUtils.addAll(new String[] { screenshotPath, sysInfoPath, Configuration.getWorkspaceDirectory() },
+ logFiles));
+ } catch (FileNotFoundException exception) {
+ WorkspaceUtil.logException("Could not capture error diagnosis information.", exception);
+ }
+ }
+
+ });
+ } catch (InvocationTargetException exception) {
+ WorkspaceUtil.logException("Could not capture error diagnosis information.", exception);
+ } catch (InterruptedException exception) {
+ WorkspaceUtil.logException("Could not capture error diagnosis information.", exception);
+ }
+ }
+
+ ErrorReportingUtil.copyLogToClipboard(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
+
+ String url;
+
+ if (shouldCaptureErrorDiagnosis) {
+ url = Platform.getResourceBundle((Activator.getDefault().getBundle())).getString("supportMailURL_errorDiagnosisCaptured");
+ } else {
+ url = Platform.getResourceBundle((Activator.getDefault().getBundle())).getString("supportMailURL");
+ }
+
+ IWorkbenchBrowserSupport support = PlatformUI.getWorkbench().getBrowserSupport();
+
+ try {
+ IWebBrowser browser = support.getExternalBrowser();
+ browser.openURL(new URL(url));
+ } catch (MalformedURLException exception) {
+ openWebBrowserError(url, exception);
+ } catch (PartInitException exception) {
+ openWebBrowserError(url, exception);
+ }
+
+ return null;
+ }
+
+ private String[] getLogFilePaths(IPath logFolder) {
+ String[] logFiles = new File(logFolder.toOSString()).list(new LogFilenameFilter());
+
+ for (int i = 0; i < logFiles.length; i++) {
+ logFiles[i] = logFolder.toOSString() + File.separatorChar + logFiles[i];
+ }
+
+ return logFiles;
+ }
+
+ private boolean openShouldCreateErrorReportDialog(final Date date) {
+ return MessageDialog.openQuestion(window == null ? Display.getDefault().getActiveShell() : window.getShell(),
+ "Error diagnosis information capture", MessageFormat.format("Would you like to capture error diagnosis information?\n"
+ + "The data will be stored in a zip file on your desktop with the name \"{0}\".",
+ ZipHandle.ZIP_PREFIX + ErrorReportingUtil.formatDate(date) + ".zip"));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run(IAction action) {
+ execute();
+ }
+
+ /**
+ * Executes the handler.
+ */
+ public void execute() {
+ try {
+ execute(new ExecutionEvent());
+ } catch (ExecutionException e) {
+ WorkspaceUtil.logException(e.getMessage(), e);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/MailBugStatusAreaProvider.java b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/MailBugStatusAreaProvider.java
new file mode 100644
index 0000000..4f91cbf
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/MailBugStatusAreaProvider.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2012 EclipseSource Muenchen GmbH.
+ *
+ * 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:
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.ui.errorreporting;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.statushandlers.AbstractStatusAreaProvider;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+
+/**
+ * Status area provider for sending a bug report via mail.
+ *
+ * @author Maximilian Koegel
+ *
+ */
+public class MailBugStatusAreaProvider extends AbstractStatusAreaProvider {
+
+ /**
+ * {@inheritDoc}
+ */
+ public Control createSupportArea(final Composite parent, final StatusAdapter statusAdapter) {
+ Link link = new Link(parent, SWT.NONE);
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ final MailBugHandler bugHandler = new MailBugHandler(window, statusAdapter);
+ link.setText("Please <a>send us a bug report</a>. Clicking\nthe link will create a new mail with\nyour default mail program. Before\nsending the mail please follow the\ninstructions in the mail body.");
+ // TODo
+// link.setToolTipText(bugHandler.getToolTipText());
+ link.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ bugHandler.execute();
+ }
+ });
+ Dialog.applyDialogFont(link);
+ return parent;
+ }
+
+}
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ScreenshotFormat.java b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ScreenshotFormat.java
new file mode 100644
index 0000000..6128c2f
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ScreenshotFormat.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2012 EclipseSource Muenchen GmbH.
+ *
+ * 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:
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.ui.errorreporting;
+
+/**
+ * Represents the format of a screenshot.
+ *
+ * @author emueller
+ *
+ */
+public enum ScreenshotFormat {
+
+ /**
+ * JPG format.
+ */
+ JPG("jpg");
+
+ private final String type;
+
+ /**
+ * Constructor.
+ *
+ * @param type
+ * the format type
+ */
+ ScreenshotFormat(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Returns the format type as a string.
+ * @return the format type as a string
+ */
+ public String getType() {
+ return type;
+ }
+
+}
diff --git a/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ZipHandle.java b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ZipHandle.java
new file mode 100644
index 0000000..ace1901
--- /dev/null
+++ b/org.eclipse.emf.emfstore.ui.errorreporting/src/org/eclipse/emf/emfstore/ui/errorreporting/ZipHandle.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2012 EclipseSource Muenchen GmbH.
+ *
+ * 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:
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.ui.errorreporting;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.commons.io.IOUtils;
+
+/**
+ * A zip handle for creating zip files.
+ *
+ * @author emueller
+ */
+public final class ZipHandle {
+
+ /**
+ * The prefix that will be used as part of the zip file.
+ */
+ public static final String ZIP_PREFIX = "EMFStoreErrorLog_";
+
+ private final ZipOutputStream zipOutputStream;
+ private final FileOutputStream fileOutputStream;
+ private final BufferedOutputStream bufferedOutputStream;
+
+ private ZipHandle(FileOutputStream fileOutputStream, BufferedOutputStream bufferedOutputStream,
+ ZipOutputStream zipOutputStream) {
+ this.fileOutputStream = fileOutputStream;
+ this.bufferedOutputStream = bufferedOutputStream;
+ this.zipOutputStream = zipOutputStream;
+ }
+
+ /**
+ * Adds a file to the zip.
+ *
+ * @param base
+ * the base name of the file being added
+ * @param path
+ * the actual path of file to be added to the zip
+ * @throws IOException in case the file could not be added
+ */
+ public void addFile(String base, String path) throws IOException {
+
+ if (path == null) {
+ return;
+ }
+
+ addFileToZip(zipOutputStream, path, base);
+ }
+
+ /**
+ * Closes the handle.
+ *
+ * @throws IOException in case anything goes wrong during the closing of the handle
+ */
+ public void close() throws IOException {
+ if (zipOutputStream != null) {
+ zipOutputStream.finish();
+ zipOutputStream.close();
+ }
+
+ if (bufferedOutputStream != null) {
+ bufferedOutputStream.close();
+ }
+
+ if (fileOutputStream != null) {
+ fileOutputStream.close();
+ }
+ }
+
+ /**
+ * Creates a zip entry for the path specified with a name built from the base passed in and the file/directory
+ * name. If the path is a directory, a recursive call is made such that the full directory is added to the zip.
+ *
+ * @param zipOutputStream
+ * the zip file's output stream
+ * @param path
+ * the filesystem path of the file/directory being added
+ * @param base
+ * the base prefix to for the name of the zip file entry
+ *
+ * @throws IOException in case of an error during addition of the file to the zip
+ */
+ private void addFileToZip(ZipOutputStream zipOutputStream, String path, String base) throws IOException {
+ File file = new File(path);
+ String entryName = base + file.getName();
+ ZipEntry zipEntry = new ZipEntry(entryName);
+
+
+ if (file.isFile()) {
+ zipOutputStream.putNextEntry(zipEntry);
+ FileInputStream fileInputStream = null;
+ try {
+ fileInputStream = new FileInputStream(file);
+ IOUtils.copy(fileInputStream, zipOutputStream);
+ } finally {
+ }
+ } else {
+ File[] children = file.listFiles();
+
+ if (children != null) {
+ for (File child : children) {
+ addFileToZip(zipOutputStream, child.getAbsolutePath(), entryName + "/");
+ }
+ }
+ }
+ }
+
+ /**
+ * Opens up a zip handle.
+ * @param zipPath
+ * the path of the zip file being created
+ * @return the created zip handle
+ * @throws FileNotFoundException in case intial zip file creation fails
+ */
+ public static ZipHandle openZipHandle(String zipPath) throws FileNotFoundException {
+ FileOutputStream fileOutputStream = null;
+ BufferedOutputStream bufferedOutputStream = null;
+ ZipOutputStream zipOutputStream = null;
+
+ fileOutputStream = new FileOutputStream(new File(zipPath));
+ bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
+ zipOutputStream = new ZipOutputStream(bufferedOutputStream);
+ ZipHandle zipHandle = new ZipHandle(fileOutputStream, bufferedOutputStream, zipOutputStream);
+ return zipHandle;
+ }
+}