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 org.eclipse.epp.internal.logging.aeri.ide.dialogs.ConfigureServerDialog * */ public class RedmineCredentialsDialog extends TitleAreaDialog { private static final EAttribute REDMINE_SETTINGS__API_KEY = RedmineAERISettingsPackage.eINSTANCE.getRedmineAERISettings_ApiKey(); private static Map SYSTEM_SETTINGS_TO_SERVER = systemSettingsToServer(); private static Map systemSettingsToServer() { Map 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 {0} 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 {0} 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 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, "" + redmineEndpoint.getHref() + "", 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 > 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 > 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(); } } }