View Javadoc

1   /**
2    * Copyright (C) 2008 Atlassian
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.atlassian.theplugin.idea.ui;
17  
18  import com.atlassian.theplugin.idea.util.IdeaUiMultiTaskExecutor;
19  import com.atlassian.theplugin.util.PluginUtil;
20  import com.intellij.ide.BrowserUtil;
21  import com.intellij.openapi.project.Project;
22  import com.intellij.openapi.ui.DialogWrapper;
23  import com.intellij.openapi.ui.Messages;
24  import com.intellij.uiDesigner.core.GridConstraints;
25  import com.intellij.uiDesigner.core.GridLayoutManager;
26  import org.apache.commons.lang.mutable.MutableInt;
27  import org.jetbrains.annotations.Nullable;
28  
29  import javax.swing.*;
30  import java.awt.*;
31  import java.awt.event.ActionEvent;
32  import java.io.PrintWriter;
33  import java.io.StringWriter;
34  import java.util.List;
35  
36  public class DialogWithDetails extends DialogWrapper {
37      private final String description;
38      private final String exceptionStr;
39      private JLabel ctrlDescription;
40      private JTextArea ctrlDetailsText;
41      private JPanel rootPane;
42      private JScrollPane ctrlDetailsPane;
43      private static final int MAX_DESCRIPTION_LENGTH = 80;
44  
45      protected DialogWithDetails(Project project, String description, Throwable exception) {
46          super(project, false);
47          if (description.length() > MAX_DESCRIPTION_LENGTH) {
48              this.description = description.substring(0, MAX_DESCRIPTION_LENGTH) + "...";
49          } else {
50              this.description = description;
51          }
52          this.exceptionStr = getExceptionString(exception);
53  
54          setTitle(PluginUtil.PRODUCT_NAME);
55          init();
56  
57  
58      }
59  
60      protected DialogWithDetails(Project project, String description, String exceptionString) {
61          super(project, false);
62          this.description = description;
63          this.exceptionStr = exceptionString;
64  
65          setTitle(PluginUtil.PRODUCT_NAME);
66          init();
67      }
68  
69      protected DialogWithDetails(Component parent, String description, String exception) {
70          super(parent, false);
71          this.description = description;
72          this.exceptionStr = exception;
73  
74          setTitle(PluginUtil.PRODUCT_NAME);
75          init();
76          pack();
77      }
78  
79      protected DialogWithDetails(Component parent, String description, Throwable exception) {
80          super(parent, false);
81          this.description = description;
82          this.exceptionStr = getExceptionString(exception);
83  
84          setTitle(PluginUtil.PRODUCT_NAME);
85          init();
86          pack();
87      }
88  
89      public static int showExceptionDialog(Project project, String description, String details) {
90          final DialogWithDetails dialog = new DialogWithDetails(project, description, details);
91          dialog.show();
92          return dialog.getExitCode();
93      }
94  
95  
96      public static int showExceptionDialog(Component component, String description, String details) {
97          final DialogWithDetails dialog = new DialogWithDetails(component, description, details);
98          dialog.show();
99          return dialog.getExitCode();
100     }
101 
102 
103     public static int showExceptionDialog(Project project, String description, Throwable exception) {
104         final DialogWithDetails dialog = new DialogWithDetails(project, description, exception);
105         dialog.show();
106         return dialog.getExitCode();
107     }
108 
109     public static int showExceptionDialog(Component parent, String description, Throwable exception) {
110         final DialogWithDetails dialog = new DialogWithDetails(parent, description, exception);
111         dialog.show();
112         return dialog.getExitCode();
113     }
114 
115     public static int showExceptionDialog(final Project project, final String description, final Exception exception,
116                                           final String helpUrl) {
117         final DialogWithDetails dialog = new DialogWithDetails(project, description, exception) {
118             @Override
119             protected Action[] createActions() {
120                 return new Action[]{getOKAction(), getDetailsAction(), getWebHelpAction(helpUrl)};
121             }
122         };
123         dialog.show();
124 
125         return dialog.getExitCode();
126     }
127 
128     public static int showExceptionDialog(final Component component, final List<IdeaUiMultiTaskExecutor.ErrorObject> errors) {
129         if (errors == null || errors.size() == 0) {
130             return 0;
131         }
132         final DialogWithDetails dialog = new DialogWithDetails(component,
133                 "<html>(1/" + errors.size() + ") " + errors.get(0).getMessage(),
134                 errors.get(0).getException()) {
135 
136             @Override
137             protected Action[] createActions() {
138                 MutableInt currentErrorIndex = new MutableInt(0);
139                 PrevErrorAction prevAction = (PrevErrorAction) getPrevErrorAction(currentErrorIndex, errors);
140                 NextErrorAction nextAction = (NextErrorAction) getNextErrorAction(currentErrorIndex, errors);
141                 prevAction.setNextAction(nextAction);
142                 nextAction.setPrevAction(prevAction);
143                 return new Action[]{getOKAction(), getDetailsAction(), prevAction, nextAction};
144             }
145         };
146         dialog.show();
147 
148         return dialog.getExitCode();
149     }
150 
151     @Override
152     protected void init() {
153         super.init();
154 
155         ctrlDescription.setText(description);
156         ctrlDescription.setIcon(getIcon());
157 
158         ctrlDetailsText.setText(exceptionStr);
159         ctrlDetailsText.setCaretPosition(0);
160         ctrlDetailsText.setEditable(false);
161 
162         ctrlDetailsPane.setVisible(false);
163     }
164 
165     @Override
166     @Nullable
167     protected JComponent createCenterPanel() {
168         return rootPane;
169     }
170 
171     protected Icon getIcon() {
172         return Messages.getErrorIcon();
173     }
174 
175     @Override
176     protected Action[] createActions() {
177         return new Action[]{getOKAction(), getDetailsAction()};
178     }
179 
180     public static String getExceptionString(Throwable t) {
181         StringWriter sw = new StringWriter();
182         t.printStackTrace(new PrintWriter(sw));
183         return sw.getBuffer().toString();
184     }
185 
186     protected Action getDetailsAction() {
187         return new DetailsAction();
188     }
189 
190     public Action getWebHelpAction(final String helpUrl) {
191         return new WebHelpAction(helpUrl);
192     }
193 
194     public Action getNextErrorAction(final MutableInt currentErrorIndex,
195                                      final List<IdeaUiMultiTaskExecutor.ErrorObject> errors) {
196         return new NextErrorAction(currentErrorIndex, errors);
197     }
198 
199     public Action getPrevErrorAction(final MutableInt currentErrorIndex,
200                                      final List<IdeaUiMultiTaskExecutor.ErrorObject> errors) {
201         return new PrevErrorAction(currentErrorIndex, errors);
202     } // CHECKSTYLE:OFF
203 
204     private void createUIComponents() {
205         // TODO: place custom component creation code here
206     }
207 
208     {
209 // GUI initializer generated by IntelliJ IDEA GUI Designer
210 // >>> IMPORTANT!! <<<
211 // DO NOT EDIT OR ADD ANY CODE HERE!
212         $$$setupUI$$$();
213     }
214 
215     /**
216      * Method generated by IntelliJ IDEA GUI Designer
217      * >>> IMPORTANT!! <<<
218      * DO NOT edit this method OR call it in your code!
219      *
220      * @noinspection ALL
221      */
222     private void $$$setupUI$$$() {
223         rootPane = new JPanel();
224         rootPane.setLayout(new GridLayoutManager(2, 1, new Insets(10, 10, 10, 10), -1, -1));
225         ctrlDescription = new JLabel();
226         ctrlDescription.setText("Label");
227         rootPane.add(ctrlDescription, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_NORTH, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
228         ctrlDetailsPane = new JScrollPane();
229         rootPane.add(ctrlDetailsPane, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, new Dimension(600, 250), null, 0, false));
230         ctrlDetailsText = new JTextArea();
231         ctrlDetailsText.setBackground(new Color(-1));
232         ctrlDetailsText.setEditable(false);
233         ctrlDetailsText.setEnabled(true);
234         ctrlDetailsPane.setViewportView(ctrlDetailsText);
235     }
236 
237     /**
238      * @noinspection ALL
239      */
240     public JComponent $$$getRootComponent$$$() {
241         return rootPane;
242     }
243 
244     // CHECKSTYLE:ON
245 
246     private final class DetailsAction extends AbstractAction {
247         private static final String SHOW_TXT = "Show Details";
248         private static final String HIDE_TXT = "Hide Details";
249 
250         private DetailsAction() {
251             putValue(Action.NAME, SHOW_TXT);
252         }
253 
254         public void actionPerformed(ActionEvent e) {
255 
256             if (ctrlDetailsPane.isVisible()) {
257                 ctrlDetailsPane.setVisible(false);
258                 putValue(Action.NAME, SHOW_TXT);
259             } else {
260                 ctrlDetailsPane.setVisible(true);
261                 ctrlDetailsText.requestFocusInWindow();
262                 putValue(Action.NAME, HIDE_TXT);
263             }
264 
265             pack();
266         }
267     }
268 
269     private static final class WebHelpAction extends AbstractAction {
270         private String helpUrl;
271 
272         private WebHelpAction(final String helpUrl) {
273             this.helpUrl = helpUrl;
274             putValue(Action.NAME, "Help");
275         }
276 
277         public void actionPerformed(final ActionEvent e) {
278             BrowserUtil.launchBrowser(helpUrl);
279         }
280     }
281 
282     private final class NextErrorAction extends AbstractAction implements PrevNextAction {
283         private MutableInt currentErrorIndex;
284         private List<IdeaUiMultiTaskExecutor.ErrorObject> errors;
285         private PrevNextAction prevAction;
286 
287         public NextErrorAction(final MutableInt currentErrorIndex, final List<IdeaUiMultiTaskExecutor.ErrorObject> errors) {
288             this.currentErrorIndex = currentErrorIndex;
289             this.errors = errors;
290             putValue(Action.NAME, "Next");
291             enableDisable();
292         }
293 
294         public void actionPerformed(final ActionEvent e) {
295             currentErrorIndex.setValue((currentErrorIndex.intValue() + 1));
296 
297             int index = currentErrorIndex.intValue();
298             ctrlDescription.setText("<html>(" + (index + 1) + "/" + errors.size() + ") " + errors.get(index).getMessage());
299             ctrlDetailsText.setText(getExceptionString(errors.get(index).getException()));
300             ctrlDetailsText.setCaretPosition(0);
301 
302             enableDisable();
303 
304             if (prevAction != null) {
305                 prevAction.enableDisable();
306             }
307         }
308 
309         public void enableDisable() {
310             if (currentErrorIndex.intValue() == errors.size() - 1) {
311                 setEnabled(false);
312             } else {
313                 setEnabled(true);
314             }
315         }
316 
317         public void setPrevAction(final PrevNextAction prevAction) {
318             this.prevAction = prevAction;
319         }
320     }
321 
322     private class PrevErrorAction extends AbstractAction implements PrevNextAction {
323         private MutableInt currentErrorIndex;
324         private List<IdeaUiMultiTaskExecutor.ErrorObject> errors;
325         private PrevNextAction nextAction;
326 
327         public PrevErrorAction(final MutableInt currentErrorIndex, final List<IdeaUiMultiTaskExecutor.ErrorObject> errors) {
328             this.currentErrorIndex = currentErrorIndex;
329             this.errors = errors;
330             putValue(Action.NAME, "Prev");
331             enableDisable();
332         }
333 
334         public void actionPerformed(final ActionEvent e) {
335             currentErrorIndex.setValue((currentErrorIndex.intValue() + 1) % errors.size());
336 
337             int index = currentErrorIndex.intValue();
338             ctrlDescription.setText("<html>(" + (index + 1) + "/" + errors.size() + ") " + errors.get(index).getMessage());
339             ctrlDetailsText.setText(getExceptionString(errors.get(index).getException()));
340             ctrlDetailsText.setCaretPosition(0);
341 
342             enableDisable();
343             if (nextAction != null) {
344                 nextAction.enableDisable();
345             }
346         }
347 
348         public void enableDisable() {
349             if (currentErrorIndex.intValue() == 0) {
350                 setEnabled(false);
351             } else {
352                 setEnabled(true);
353             }
354         }
355 
356         public void setNextAction(final PrevNextAction nextAction) {
357             this.nextAction = nextAction;
358         }
359     }
360 
361     private interface PrevNextAction {
362         void enableDisable();
363     }
364 }