1 package org.simantics.aeri.ui.redmine;
3 import static org.eclipse.epp.logging.aeri.core.IModelPackage.Literals.USER_SETTINGS__ANONYMIZE_MESSAGES;
4 import static org.eclipse.epp.logging.aeri.core.IModelPackage.Literals.USER_SETTINGS__ANONYMIZE_STACK_TRACES;
5 import static org.eclipse.epp.logging.aeri.core.util.Links.REL_PRIVACY_POLICY;
6 import static org.eclipse.epp.logging.aeri.core.util.Links.REL_TERMS_OF_USE;
9 import java.util.HashMap;
11 import java.util.Map.Entry;
13 import javax.inject.Inject;
14 import javax.inject.Named;
16 import org.eclipse.core.databinding.DataBindingContext;
17 import org.eclipse.core.databinding.observable.value.IObservableValue;
18 import org.eclipse.e4.core.di.annotations.Optional;
19 import org.eclipse.e4.ui.services.IServiceConstants;
20 import org.eclipse.emf.databinding.EMFProperties;
21 import org.eclipse.emf.ecore.EAttribute;
22 import org.eclipse.epp.internal.logging.aeri.ide.IServerDescriptor;
23 import org.eclipse.epp.logging.aeri.core.ILink;
24 import org.eclipse.epp.logging.aeri.core.ISystemSettings;
25 import org.eclipse.epp.logging.aeri.core.util.Formats;
26 import org.eclipse.epp.logging.aeri.core.util.Links;
27 import org.eclipse.jface.databinding.swt.ISWTObservableValue;
28 import org.eclipse.jface.databinding.swt.WidgetProperties;
29 import org.eclipse.jface.dialogs.Dialog;
30 import org.eclipse.jface.dialogs.IDialogConstants;
31 import org.eclipse.jface.dialogs.TitleAreaDialog;
32 import org.eclipse.jface.layout.GridDataFactory;
33 import org.eclipse.jface.layout.GridLayoutFactory;
34 import org.eclipse.jface.resource.ImageRegistry;
35 import org.eclipse.jface.resource.JFaceResources;
36 import org.eclipse.jface.window.DefaultToolTip;
37 import org.eclipse.swt.SWT;
38 import org.eclipse.swt.events.SelectionAdapter;
39 import org.eclipse.swt.events.SelectionEvent;
40 import org.eclipse.swt.graphics.Point;
41 import org.eclipse.swt.layout.RowLayout;
42 import org.eclipse.swt.program.Program;
43 import org.eclipse.swt.widgets.Button;
44 import org.eclipse.swt.widgets.Composite;
45 import org.eclipse.swt.widgets.Control;
46 import org.eclipse.swt.widgets.Group;
47 import org.eclipse.swt.widgets.Label;
48 import org.eclipse.swt.widgets.Link;
49 import org.eclipse.swt.widgets.Shell;
50 import org.eclipse.swt.widgets.Text;
51 import org.eclipse.ui.PlatformUI;
52 import org.eclipse.ui.browser.IWebBrowser;
53 import org.simantics.aeri.redmine.core.settings.RedmineAERISettings;
54 import org.simantics.aeri.redmine.core.settings.RedmineAERISettingsPackage;
59 * Very much mimicked from <a>org.eclipse.epp.internal.logging.aeri.ide.dialogs.ConfigureServerDialog</a>
62 public class RedmineCredentialsDialog extends TitleAreaDialog {
64 private static final EAttribute REDMINE_SETTINGS__API_KEY = RedmineAERISettingsPackage.eINSTANCE.getRedmineAERISettings_ApiKey();
66 private static Map<EAttribute, EAttribute> SYSTEM_SETTINGS_TO_SERVER = systemSettingsToServer();
68 private static Map<EAttribute, EAttribute> systemSettingsToServer() {
69 Map<EAttribute, EAttribute> result = new HashMap<>();
70 result.put(USER_SETTINGS__ANONYMIZE_MESSAGES, USER_SETTINGS__ANONYMIZE_MESSAGES);
71 result.put(USER_SETTINGS__ANONYMIZE_STACK_TRACES, USER_SETTINGS__ANONYMIZE_STACK_TRACES);
75 private static final String DIALOG_TITLE_CONFIGURE_SERVER = "Configure Error Reporting for {0}";
76 private static final String BUTTON_TEXT_ENABLE = "Enable";
77 private static final String BUTTON_TEXT_DISABLE = "Disable";
80 * Return code to indicate a cancel using the esc-button.
82 public static final int ESC_CANCEL = 42 + 42;
84 private static final Point TOOLTIP_DISPLACEMENT = new Point(5, 20);
85 private static final String DIALOG_MESSAGE_CONFIGURE_SERVER = "Configure the default sending and anonymization options for {0}.";
86 private static final String LINK_TEXT_ENABLE_ADMONITION_WITH_TERMS_OF_USE_AND_PRIVACY_POLICY = "";
87 private static final String LINK_TEXT_TERMS_OF_USE = "Terms of Use";
88 private static final String LINK_TEXT_PRIVACY_POLICY = "Privacy Policy";
89 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.";
90 private static final String GROUP_TEXT_REDMINE_INFORMATION = "Redmine Information";
91 private static final String FIELD_LABEL_API_KEY = "API key:";
92 private static final String FIELD_MESSAGE_API_KEY = "Required. Redmine API key is used to authenticate and identify the reporter.";
93 private static final String FIELD_MESSAGE_REDMINE_URL = "Location of Redmine server.";
94 private static final String TOOLTIP_SETTINGS_EMAIL = "";
95 private static final String FIELD_LABEL_REDMINE_URL = "URL:";
96 private static final String TOOLTIP_SETTINGS_MAKE_STACKTRACE_ANONYMOUS = "";
97 private static final String FIELD_LABEL_ANONYMIZE_STACKTRACES = "Anonymize package, class, and method names";
98 private static final String FIELD_LABEL_ANONYMIZE_MESSAGES = "Anonymize error log messages";
99 private static final String TOOLTIP_SETTINGS_MAKE_MESSAGES_ANONYMOUS = "";
100 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.";
101 private static final String GROUP_TEXT_ANONYMIZATION = "Send Options";
102 private static final String REL_REDMINE_LINK = "org.simantics.aeri.ui.redmine.redmine.link";
103 private static int TOOLTIP_MS_HIDE_DELAY = 20000;
105 private IServerDescriptor server;
106 private DataBindingContext context;
108 private RedmineAERISettings redmineSettings;
111 public RedmineCredentialsDialog(IServerDescriptor server, RedmineAERISettings redmineSettings, ISystemSettings settings,
112 @Named(IServiceConstants.ACTIVE_SHELL) @Optional Shell parentShell, ImageRegistry registry) {
114 this.server = server;
115 this.redmineSettings = redmineSettings;
116 setHelpAvailable(false);
117 setShellStyle(SWT.SHELL_TRIM | SWT.RESIZE | SWT.SHEET);
118 context = new DataBindingContext();
119 copySystemDefaultsIfUnset(settings, server);
122 private static void copySystemDefaultsIfUnset(ISystemSettings source, IServerDescriptor target) {
123 for (Entry<EAttribute, EAttribute> entry : SYSTEM_SETTINGS_TO_SERVER.entrySet()) {
124 EAttribute toAttr = entry.getValue();
125 if (!target.eIsSet(toAttr)) {
126 EAttribute fromAttr = entry.getKey();
127 Object value = source.eGet(fromAttr);
128 target.eSet(toAttr, value);
134 protected void createButtonsForButtonBar(Composite parent) {
135 createButton(parent, IDialogConstants.OK_ID, BUTTON_TEXT_ENABLE, true);
136 createButton(parent, IDialogConstants.CANCEL_ID, BUTTON_TEXT_DISABLE, false);
140 public void create() {
142 setTitle(Formats.format(DIALOG_TITLE_CONFIGURE_SERVER, server.getName()));
143 ILink redmineEndpoint = Links.Link(server, REL_REDMINE_LINK);
144 setMessage(Formats.format(DIALOG_MESSAGE_CONFIGURE_SERVER, redmineEndpoint.getTitle()));
148 protected Control createDialogArea(Composite parent) {
149 Composite container = new Composite(parent, SWT.NONE);
150 GridLayoutFactory.fillDefaults().extendedMargins(5, 5, 5, 0).applyTo(container);
151 GridDataFactory.fillDefaults().grab(true, true).applyTo(container);
153 Composite personalGroup = createPersonalGroup(container);
154 GridDataFactory.fillDefaults().indent(0, 10).grab(true, false).applyTo(personalGroup);
156 Group makeAnonymousGroup = createAnonymizeGroup(container);
157 GridDataFactory.fillDefaults().indent(0, 5).applyTo(makeAnonymousGroup);
159 ILink termsOfUse = Links.Link(server, REL_TERMS_OF_USE);
160 ILink privacyPolicy = Links.Link(server, REL_PRIVACY_POLICY);
162 String legalText = null;
163 if (termsOfUse != null && privacyPolicy != null) {
164 legalText = Formats.format(LINK_TEXT_ENABLE_ADMONITION_WITH_TERMS_OF_USE_AND_PRIVACY_POLICY,
165 LINK_TEXT_TERMS_OF_USE, termsOfUse.getHref(),
166 LINK_TEXT_PRIVACY_POLICY, privacyPolicy.getHref());
167 } else if (termsOfUse != null && privacyPolicy == null) {
168 legalText = Formats.format(LINK_TEXT_ENABLE_ADMONITION_WITH_TERMS_OF_USE,
169 LINK_TEXT_TERMS_OF_USE, termsOfUse.getHref());
170 } else if (termsOfUse == null && privacyPolicy != null) {
171 legalText = Formats.format(LINK_TEXT_ENABLE_ADMONITION_WITH_PRIVACY_POLICY,
172 LINK_TEXT_PRIVACY_POLICY, privacyPolicy.getHref());
174 if (legalText != null) {
175 Link termsAndConditions = new Link(container, SWT.NONE);
176 termsAndConditions.setText(legalText);
177 termsAndConditions.addSelectionListener(new SelectionAdapter() {
179 public void widgetSelected(SelectionEvent e) {
180 openInExternalBrowser(e.text);
183 GridDataFactory.fillDefaults().indent(10, 10).hint(300, SWT.DEFAULT).align(SWT.FILL, SWT.CENTER).applyTo(termsAndConditions);
186 Dialog.applyDialogFont(container);
190 // TODO Move to UI class. Similar methods in PreferencePage and SystemSettingsPage
191 private Composite createPersonalGroup(Composite parent) {
192 Group personalGroup = new Group(parent, SWT.NONE);
193 personalGroup.setText(GROUP_TEXT_REDMINE_INFORMATION);
194 GridLayoutFactory.fillDefaults().margins(5, 5).numColumns(2).applyTo(personalGroup);
196 ILink redmineEndpoint = Links.Link(server, REL_REDMINE_LINK);
198 String tooltip = FIELD_MESSAGE_REDMINE_URL + '\n' + TOOLTIP_SETTINGS_EMAIL;
199 Link link = createLabelWithLink(personalGroup, FIELD_LABEL_REDMINE_URL, "<A>" + redmineEndpoint.getHref() + "</A>", tooltip);
200 link.addSelectionListener(new SelectionAdapter() {
202 public void widgetSelected(SelectionEvent e) {
203 openInExternalBrowser(e.text);
209 Text name = createLabelWithText(personalGroup, FIELD_LABEL_API_KEY, FIELD_MESSAGE_API_KEY,
210 FIELD_MESSAGE_API_KEY);
211 ISWTObservableValue swt = WidgetProperties.text(SWT.Modify).observe(name);
212 IObservableValue emf = EMFProperties.value(REDMINE_SETTINGS__API_KEY).observe(redmineSettings);
213 context.bindValue(swt, emf);
215 return personalGroup;
218 private Group createAnonymizeGroup(Composite container) {
219 Group makeAnonymousGroup = new Group(container, SWT.SHADOW_ETCHED_IN | SWT.SHADOW_ETCHED_OUT | SWT.SHADOW_IN | SWT.SHADOW_OUT);
220 makeAnonymousGroup.setLayout(new RowLayout(SWT.VERTICAL));
221 makeAnonymousGroup.setText(GROUP_TEXT_ANONYMIZATION);
223 Button anonStackTraces = createGroupCheckButton(makeAnonymousGroup, FIELD_LABEL_ANONYMIZE_STACKTRACES,
224 TOOLTIP_SETTINGS_MAKE_STACKTRACE_ANONYMOUS);
225 anonStackTraces.setFocus();
226 IObservableValue swt = WidgetProperties.selection().observe(anonStackTraces);
227 IObservableValue emf = EMFProperties.value(USER_SETTINGS__ANONYMIZE_STACK_TRACES).observe(server);
228 context.bindValue(swt, emf);
231 Button anonMessages = createGroupCheckButton(makeAnonymousGroup, FIELD_LABEL_ANONYMIZE_MESSAGES,
232 TOOLTIP_SETTINGS_MAKE_MESSAGES_ANONYMOUS);
233 IObservableValue swt = WidgetProperties.selection().observe(anonMessages);
234 IObservableValue emf = EMFProperties.value(USER_SETTINGS__ANONYMIZE_MESSAGES).observe(server);
235 context.bindValue(swt, emf);
237 return makeAnonymousGroup;
240 private static Link createLabelWithLink(Composite parent, String labelText, String linkText, String toolTip) {
241 createLabel(parent, labelText, toolTip);
243 Link link = new Link(parent, SWT.NONE);
244 link.setText(linkText);
248 private static Text createLabelWithText(Composite parent, String labelText, String textMessage, String toolTip) {
249 createLabel(parent, labelText, toolTip);
251 Text text = new Text(parent, SWT.BORDER);
252 text.setMessage(textMessage);
253 calibrateTooltip(new DefaultToolTip(text), toolTip);
254 GridDataFactory.fillDefaults().grab(true, false).applyTo(text);
258 private static void createLabel(Composite parent, String labelText, String toolTip) {
259 Label label = new Label(parent, SWT.NONE);
260 label.setText(labelText);
261 calibrateTooltip(new DefaultToolTip(label), toolTip);
264 private static Button createGroupCheckButton(Group group, String buttonText, String toolTipText) {
265 Button button = new Button(group, SWT.CHECK);
266 button.setText(buttonText);
267 calibrateTooltip(new DefaultToolTip(button), toolTipText);
271 private static void calibrateTooltip(DefaultToolTip toolTip, String toolTipText) {
272 toolTip.setText(toolTipText);
273 toolTip.setFont(JFaceResources.getDialogFont());
274 toolTip.setShift(TOOLTIP_DISPLACEMENT);
275 toolTip.setHideDelay(TOOLTIP_MS_HIDE_DELAY);
279 protected void okPressed() {
280 server.setEnabled(true);
285 protected void cancelPressed() {
286 server.setEnabled(false);
287 super.cancelPressed();
291 * Tries to open an URL with an external web browser. If one is configure in the Eclipse preferences (General > Web Browser) it will
292 * prefer that over the operating system's default browser. If either way to open an external browser does not succeed, this method will
293 * this will open a new editor to display the URL within the Eclipse IDE.
295 private static void openInExternalBrowser(String url) {
297 IWebBrowser externalBrowser = PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser();
298 externalBrowser.openURL(new URL(url));
299 } catch (Throwable e) {
301 if (!Program.launch(url)) {
302 openInDefaultBrowser(url);
304 } catch (Throwable t) {
311 * Tries to open an URL wit the web browser configured in the Eclipse preferences (General > Web Browser). By default, this will open
312 * a new editor to display the URL within the Eclipse IDE.
314 private static void openInDefaultBrowser(String url) {
316 IWebBrowser defaultBrowser = PlatformUI.getWorkbench().getBrowserSupport().createBrowser(null);
317 defaultBrowser.openURL(new URL(url));
318 } catch (Throwable t) {
319 // Ignore failure; this method is best effort.