]> gerrit.simantics Code Review - simantics/platform.git/blob - 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
1 package org.simantics.aeri.ui.redmine;
2
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;
7
8 import java.net.URL;
9 import java.util.HashMap;
10 import java.util.Map;
11 import java.util.Map.Entry;
12
13 import javax.inject.Inject;
14 import javax.inject.Named;
15
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;
55
56 /**
57  * @author jsjani
58  *
59  *  Very much mimicked from <a>org.eclipse.epp.internal.logging.aeri.ide.dialogs.ConfigureServerDialog</a>
60  *
61  */
62 public class RedmineCredentialsDialog extends TitleAreaDialog {
63
64     private static final EAttribute REDMINE_SETTINGS__API_KEY = RedmineAERISettingsPackage.eINSTANCE.getRedmineAERISettings_ApiKey();
65
66     private static Map<EAttribute, EAttribute> SYSTEM_SETTINGS_TO_SERVER = systemSettingsToServer();
67         
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);
72         return result;
73     }
74     
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";
78     
79     /**
80      * Return code to indicate a cancel using the esc-button.
81      */
82     public static final int ESC_CANCEL = 42 + 42;
83
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;
104
105     private IServerDescriptor server;
106     private DataBindingContext context;
107
108     private RedmineAERISettings redmineSettings;
109
110     @Inject
111     public RedmineCredentialsDialog(IServerDescriptor server, RedmineAERISettings redmineSettings, ISystemSettings settings,
112             @Named(IServiceConstants.ACTIVE_SHELL) @Optional Shell parentShell, ImageRegistry registry) {
113         super(parentShell);
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);
120     }
121     
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);
129             }
130         }
131     }
132
133     @Override
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);
137     }
138
139     @Override
140     public void create() {
141         super.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()));
145     }
146     
147     @Override
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);
152
153         Composite personalGroup = createPersonalGroup(container);
154         GridDataFactory.fillDefaults().indent(0, 10).grab(true, false).applyTo(personalGroup);
155
156         Group makeAnonymousGroup = createAnonymizeGroup(container);
157         GridDataFactory.fillDefaults().indent(0, 5).applyTo(makeAnonymousGroup);
158
159         ILink termsOfUse = Links.Link(server, REL_TERMS_OF_USE);
160         ILink privacyPolicy = Links.Link(server, REL_PRIVACY_POLICY);
161         
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());
173         }
174         if (legalText != null) {
175             Link termsAndConditions = new Link(container, SWT.NONE);
176             termsAndConditions.setText(legalText);
177             termsAndConditions.addSelectionListener(new SelectionAdapter() {
178                 @Override
179                 public void widgetSelected(SelectionEvent e) {
180                     openInExternalBrowser(e.text);
181                 }
182             });
183             GridDataFactory.fillDefaults().indent(10, 10).hint(300, SWT.DEFAULT).align(SWT.FILL, SWT.CENTER).applyTo(termsAndConditions);
184         }
185
186         Dialog.applyDialogFont(container);
187         return container;
188     }
189
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);
195         {
196             ILink redmineEndpoint = Links.Link(server, REL_REDMINE_LINK);
197             
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() {
201                 @Override
202                 public void widgetSelected(SelectionEvent e) {
203                     openInExternalBrowser(e.text);
204                 }
205             });
206         }
207
208         {
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);
214         }
215         return personalGroup;
216     }
217
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);
222         {
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);
229         }
230         {
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);
236         }
237         return makeAnonymousGroup;
238     }
239
240     private static Link createLabelWithLink(Composite parent, String labelText, String linkText, String toolTip) {
241         createLabel(parent, labelText, toolTip);
242         
243         Link link = new Link(parent, SWT.NONE);
244         link.setText(linkText);
245         return link;
246     }
247     
248     private static Text createLabelWithText(Composite parent, String labelText, String textMessage, String toolTip) {
249         createLabel(parent, labelText, toolTip);
250         
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);
255         return text;
256     }
257     
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);
262     }
263     
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);
268         return button;
269     }
270
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);
276     }
277     
278     @Override
279     protected void okPressed() {
280         server.setEnabled(true);
281         super.okPressed();
282     }
283
284     @Override
285     protected void cancelPressed() {
286         server.setEnabled(false);
287         super.cancelPressed();
288     }
289     
290     /**
291      * Tries to open an URL with an external web browser. If one is configure in the Eclipse preferences (General &gt; 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.
294      */
295     private static void openInExternalBrowser(String url) {
296         try {
297             IWebBrowser externalBrowser = PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser();
298             externalBrowser.openURL(new URL(url));
299         } catch (Throwable e) {
300             try {
301                 if (!Program.launch(url)) {
302                     openInDefaultBrowser(url);
303                 }
304             } catch (Throwable t) {
305                 t.printStackTrace();
306             }
307         }
308     }
309
310     /**
311      * Tries to open an URL wit the web browser configured in the Eclipse preferences (General &gt; Web Browser). By default, this will open
312      * a new editor to display the URL within the Eclipse IDE.
313      */
314     private static void openInDefaultBrowser(String url) {
315         try {
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.
320             t.printStackTrace();
321         }
322     }
323
324 }