]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.aeri.ui.redmine/src/org/simantics/aeri/ui/redmine/RedmineCredentialsDialog.java
Experiment around with AERI in Simantics Products
[simantics/platform.git] / bundles / org.simantics.aeri.ui.redmine / src / org / simantics / aeri / ui / redmine / RedmineCredentialsDialog.java
diff --git a/bundles/org.simantics.aeri.ui.redmine/src/org/simantics/aeri/ui/redmine/RedmineCredentialsDialog.java b/bundles/org.simantics.aeri.ui.redmine/src/org/simantics/aeri/ui/redmine/RedmineCredentialsDialog.java
new file mode 100644 (file)
index 0000000..7e84bc9
--- /dev/null
@@ -0,0 +1,324 @@
+package org.simantics.aeri.ui.redmine;
+
+import static org.eclipse.epp.logging.aeri.core.IModelPackage.Literals.USER_SETTINGS__ANONYMIZE_MESSAGES;
+import static org.eclipse.epp.logging.aeri.core.IModelPackage.Literals.USER_SETTINGS__ANONYMIZE_STACK_TRACES;
+import static org.eclipse.epp.logging.aeri.core.util.Links.REL_PRIVACY_POLICY;
+import static org.eclipse.epp.logging.aeri.core.util.Links.REL_TERMS_OF_USE;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.emf.databinding.EMFProperties;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.epp.internal.logging.aeri.ide.IServerDescriptor;
+import org.eclipse.epp.logging.aeri.core.ILink;
+import org.eclipse.epp.logging.aeri.core.ISystemSettings;
+import org.eclipse.epp.logging.aeri.core.util.Formats;
+import org.eclipse.epp.logging.aeri.core.util.Links;
+import org.eclipse.jface.databinding.swt.ISWTObservableValue;
+import org.eclipse.jface.databinding.swt.WidgetProperties;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.window.DefaultToolTip;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.program.Program;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.browser.IWebBrowser;
+import org.simantics.aeri.redmine.core.settings.RedmineAERISettings;
+import org.simantics.aeri.redmine.core.settings.RedmineAERISettingsPackage;
+
+/**
+ * @author jsjani
+ *
+ *  Very much mimicked from <a>org.eclipse.epp.internal.logging.aeri.ide.dialogs.ConfigureServerDialog</a>
+ *
+ */
+public class RedmineCredentialsDialog extends TitleAreaDialog {
+
+    private static final EAttribute REDMINE_SETTINGS__API_KEY = RedmineAERISettingsPackage.eINSTANCE.getRedmineAERISettings_ApiKey();
+
+    private static Map<EAttribute, EAttribute> SYSTEM_SETTINGS_TO_SERVER = systemSettingsToServer();
+        
+    private static Map<EAttribute, EAttribute> systemSettingsToServer() {
+        Map<EAttribute, EAttribute> result = new HashMap<>();
+        result.put(USER_SETTINGS__ANONYMIZE_MESSAGES, USER_SETTINGS__ANONYMIZE_MESSAGES);
+        result.put(USER_SETTINGS__ANONYMIZE_STACK_TRACES, USER_SETTINGS__ANONYMIZE_STACK_TRACES);
+        return result;
+    }
+    
+    private static final String DIALOG_TITLE_CONFIGURE_SERVER = "Configure Error Reporting for {0}";
+    private static final String BUTTON_TEXT_ENABLE = "Enable";
+    private static final String BUTTON_TEXT_DISABLE = "Disable";
+    
+    /**
+     * Return code to indicate a cancel using the esc-button.
+     */
+    public static final int ESC_CANCEL = 42 + 42;
+
+    private static final Point TOOLTIP_DISPLACEMENT = new Point(5, 20);
+    private static final String DIALOG_MESSAGE_CONFIGURE_SERVER = "Configure the default sending and anonymization options for {0}.";
+    private static final String LINK_TEXT_ENABLE_ADMONITION_WITH_TERMS_OF_USE_AND_PRIVACY_POLICY = "";
+    private static final String LINK_TEXT_TERMS_OF_USE = "Terms of Use";
+    private static final String LINK_TEXT_PRIVACY_POLICY = "Privacy Policy";
+    private static final String LINK_TEXT_ENABLE_ADMONITION_WITH_TERMS_OF_USE = "By clicking \u2018Enable\u2019 you agree to the <a href=\"{1}\">{0}</a> of this server.";
+    private static final String GROUP_TEXT_REDMINE_INFORMATION = "Redmine Information";
+    private static final String FIELD_LABEL_API_KEY = "API key:";
+    private static final String FIELD_MESSAGE_API_KEY = "Required. Redmine API key is used to authenticate and identify the reporter.";
+    private static final String FIELD_MESSAGE_REDMINE_URL = "Location of Redmine server.";
+    private static final String TOOLTIP_SETTINGS_EMAIL = "";
+    private static final String FIELD_LABEL_REDMINE_URL = "URL:";
+    private static final String TOOLTIP_SETTINGS_MAKE_STACKTRACE_ANONYMOUS = "";
+    private static final String FIELD_LABEL_ANONYMIZE_STACKTRACES = "Anonymize package, class, and method names";
+    private static final String FIELD_LABEL_ANONYMIZE_MESSAGES = "Anonymize error log messages";
+    private static final String TOOLTIP_SETTINGS_MAKE_MESSAGES_ANONYMOUS = "";
+    private static final String LINK_TEXT_ENABLE_ADMONITION_WITH_PRIVACY_POLICY = "By clicking \u2018Enable\u2019 you agree to the <a href=\"{1}\">{0}</a> of this server.";
+    private static final String GROUP_TEXT_ANONYMIZATION = "Send Options";
+    private static final String REL_REDMINE_LINK = "org.simantics.aeri.ui.redmine.redmine.link";
+    private static int TOOLTIP_MS_HIDE_DELAY = 20000;
+
+    private IServerDescriptor server;
+    private DataBindingContext context;
+
+    private RedmineAERISettings redmineSettings;
+
+    @Inject
+    public RedmineCredentialsDialog(IServerDescriptor server, RedmineAERISettings redmineSettings, ISystemSettings settings,
+            @Named(IServiceConstants.ACTIVE_SHELL) @Optional Shell parentShell, ImageRegistry registry) {
+        super(parentShell);
+        this.server = server;
+        this.redmineSettings = redmineSettings;
+        setHelpAvailable(false);
+        setShellStyle(SWT.SHELL_TRIM | SWT.RESIZE | SWT.SHEET);
+        context = new DataBindingContext();
+        copySystemDefaultsIfUnset(settings, server);
+    }
+    
+    private static void copySystemDefaultsIfUnset(ISystemSettings source, IServerDescriptor target) {
+        for (Entry<EAttribute, EAttribute> entry : SYSTEM_SETTINGS_TO_SERVER.entrySet()) {
+            EAttribute toAttr = entry.getValue();
+            if (!target.eIsSet(toAttr)) {
+                EAttribute fromAttr = entry.getKey();
+                Object value = source.eGet(fromAttr);
+                target.eSet(toAttr, value);
+            }
+        }
+    }
+
+    @Override
+    protected void createButtonsForButtonBar(Composite parent) {
+        createButton(parent, IDialogConstants.OK_ID, BUTTON_TEXT_ENABLE, true);
+        createButton(parent, IDialogConstants.CANCEL_ID, BUTTON_TEXT_DISABLE, false);
+    }
+
+    @Override
+    public void create() {
+        super.create();
+        setTitle(Formats.format(DIALOG_TITLE_CONFIGURE_SERVER, server.getName()));
+        ILink redmineEndpoint = Links.Link(server, REL_REDMINE_LINK);
+        setMessage(Formats.format(DIALOG_MESSAGE_CONFIGURE_SERVER, redmineEndpoint.getTitle()));
+    }
+    
+    @Override
+    protected Control createDialogArea(Composite parent) {
+        Composite container = new Composite(parent, SWT.NONE);
+        GridLayoutFactory.fillDefaults().extendedMargins(5, 5, 5, 0).applyTo(container);
+        GridDataFactory.fillDefaults().grab(true, true).applyTo(container);
+
+        Composite personalGroup = createPersonalGroup(container);
+        GridDataFactory.fillDefaults().indent(0, 10).grab(true, false).applyTo(personalGroup);
+
+        Group makeAnonymousGroup = createAnonymizeGroup(container);
+        GridDataFactory.fillDefaults().indent(0, 5).applyTo(makeAnonymousGroup);
+
+        ILink termsOfUse = Links.Link(server, REL_TERMS_OF_USE);
+        ILink privacyPolicy = Links.Link(server, REL_PRIVACY_POLICY);
+        
+        String legalText = null;
+        if (termsOfUse != null && privacyPolicy != null) {
+            legalText = Formats.format(LINK_TEXT_ENABLE_ADMONITION_WITH_TERMS_OF_USE_AND_PRIVACY_POLICY,
+                    LINK_TEXT_TERMS_OF_USE, termsOfUse.getHref(),
+                    LINK_TEXT_PRIVACY_POLICY, privacyPolicy.getHref());
+        } else if (termsOfUse != null && privacyPolicy == null) {
+            legalText = Formats.format(LINK_TEXT_ENABLE_ADMONITION_WITH_TERMS_OF_USE,
+                    LINK_TEXT_TERMS_OF_USE, termsOfUse.getHref());
+        } else if (termsOfUse == null && privacyPolicy != null) {
+            legalText = Formats.format(LINK_TEXT_ENABLE_ADMONITION_WITH_PRIVACY_POLICY,
+                    LINK_TEXT_PRIVACY_POLICY, privacyPolicy.getHref());
+        }
+        if (legalText != null) {
+            Link termsAndConditions = new Link(container, SWT.NONE);
+            termsAndConditions.setText(legalText);
+            termsAndConditions.addSelectionListener(new SelectionAdapter() {
+                @Override
+                public void widgetSelected(SelectionEvent e) {
+                    openInExternalBrowser(e.text);
+                }
+            });
+            GridDataFactory.fillDefaults().indent(10, 10).hint(300, SWT.DEFAULT).align(SWT.FILL, SWT.CENTER).applyTo(termsAndConditions);
+        }
+
+        Dialog.applyDialogFont(container);
+        return container;
+    }
+
+    // TODO Move to UI class. Similar methods in PreferencePage and SystemSettingsPage
+    private Composite createPersonalGroup(Composite parent) {
+        Group personalGroup = new Group(parent, SWT.NONE);
+        personalGroup.setText(GROUP_TEXT_REDMINE_INFORMATION);
+        GridLayoutFactory.fillDefaults().margins(5, 5).numColumns(2).applyTo(personalGroup);
+        {
+            ILink redmineEndpoint = Links.Link(server, REL_REDMINE_LINK);
+            
+            String tooltip = FIELD_MESSAGE_REDMINE_URL + '\n' + TOOLTIP_SETTINGS_EMAIL;
+            Link link = createLabelWithLink(personalGroup, FIELD_LABEL_REDMINE_URL, "<A>" + redmineEndpoint.getHref() + "</A>", tooltip);
+            link.addSelectionListener(new SelectionAdapter() {
+                @Override
+                public void widgetSelected(SelectionEvent e) {
+                    openInExternalBrowser(e.text);
+                }
+            });
+        }
+
+        {
+            Text name = createLabelWithText(personalGroup, FIELD_LABEL_API_KEY, FIELD_MESSAGE_API_KEY,
+                    FIELD_MESSAGE_API_KEY);
+            ISWTObservableValue swt = WidgetProperties.text(SWT.Modify).observe(name);
+            IObservableValue emf = EMFProperties.value(REDMINE_SETTINGS__API_KEY).observe(redmineSettings);
+            context.bindValue(swt, emf);
+        }
+        return personalGroup;
+    }
+
+    private Group createAnonymizeGroup(Composite container) {
+        Group makeAnonymousGroup = new Group(container, SWT.SHADOW_ETCHED_IN | SWT.SHADOW_ETCHED_OUT | SWT.SHADOW_IN | SWT.SHADOW_OUT);
+        makeAnonymousGroup.setLayout(new RowLayout(SWT.VERTICAL));
+        makeAnonymousGroup.setText(GROUP_TEXT_ANONYMIZATION);
+        {
+            Button anonStackTraces = createGroupCheckButton(makeAnonymousGroup, FIELD_LABEL_ANONYMIZE_STACKTRACES,
+                    TOOLTIP_SETTINGS_MAKE_STACKTRACE_ANONYMOUS);
+            anonStackTraces.setFocus();
+            IObservableValue swt = WidgetProperties.selection().observe(anonStackTraces);
+            IObservableValue emf = EMFProperties.value(USER_SETTINGS__ANONYMIZE_STACK_TRACES).observe(server);
+            context.bindValue(swt, emf);
+        }
+        {
+            Button anonMessages = createGroupCheckButton(makeAnonymousGroup, FIELD_LABEL_ANONYMIZE_MESSAGES,
+                    TOOLTIP_SETTINGS_MAKE_MESSAGES_ANONYMOUS);
+            IObservableValue swt = WidgetProperties.selection().observe(anonMessages);
+            IObservableValue emf = EMFProperties.value(USER_SETTINGS__ANONYMIZE_MESSAGES).observe(server);
+            context.bindValue(swt, emf);
+        }
+        return makeAnonymousGroup;
+    }
+
+    private static Link createLabelWithLink(Composite parent, String labelText, String linkText, String toolTip) {
+        createLabel(parent, labelText, toolTip);
+        
+        Link link = new Link(parent, SWT.NONE);
+        link.setText(linkText);
+        return link;
+    }
+    
+    private static Text createLabelWithText(Composite parent, String labelText, String textMessage, String toolTip) {
+        createLabel(parent, labelText, toolTip);
+        
+        Text text = new Text(parent, SWT.BORDER);
+        text.setMessage(textMessage);
+        calibrateTooltip(new DefaultToolTip(text), toolTip);
+        GridDataFactory.fillDefaults().grab(true, false).applyTo(text);
+        return text;
+    }
+    
+    private static void createLabel(Composite parent, String labelText, String toolTip) {
+        Label label = new Label(parent, SWT.NONE);
+        label.setText(labelText);
+        calibrateTooltip(new DefaultToolTip(label), toolTip);
+    }
+    
+    private static Button createGroupCheckButton(Group group, String buttonText, String toolTipText) {
+        Button button = new Button(group, SWT.CHECK);
+        button.setText(buttonText);
+        calibrateTooltip(new DefaultToolTip(button), toolTipText);
+        return button;
+    }
+
+    private static void calibrateTooltip(DefaultToolTip toolTip, String toolTipText) {
+        toolTip.setText(toolTipText);
+        toolTip.setFont(JFaceResources.getDialogFont());
+        toolTip.setShift(TOOLTIP_DISPLACEMENT);
+        toolTip.setHideDelay(TOOLTIP_MS_HIDE_DELAY);
+    }
+    
+    @Override
+    protected void okPressed() {
+        server.setEnabled(true);
+        super.okPressed();
+    }
+
+    @Override
+    protected void cancelPressed() {
+        server.setEnabled(false);
+        super.cancelPressed();
+    }
+    
+    /**
+     * Tries to open an URL with an external web browser. If one is configure in the Eclipse preferences (General &gt; Web Browser) it will
+     * prefer that over the operating system's default browser. If either way to open an external browser does not succeed, this method will
+     * this will open a new editor to display the URL within the Eclipse IDE.
+     */
+    private static void openInExternalBrowser(String url) {
+        try {
+            IWebBrowser externalBrowser = PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser();
+            externalBrowser.openURL(new URL(url));
+        } catch (Throwable e) {
+            try {
+                if (!Program.launch(url)) {
+                    openInDefaultBrowser(url);
+                }
+            } catch (Throwable t) {
+                t.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * Tries to open an URL wit the web browser configured in the Eclipse preferences (General &gt; Web Browser). By default, this will open
+     * a new editor to display the URL within the Eclipse IDE.
+     */
+    private static void openInDefaultBrowser(String url) {
+        try {
+            IWebBrowser defaultBrowser = PlatformUI.getWorkbench().getBrowserSupport().createBrowser(null);
+            defaultBrowser.openURL(new URL(url));
+        } catch (Throwable t) {
+            // Ignore failure; this method is best effort.
+            t.printStackTrace();
+        }
+    }
+
+}