ec906b1fb5480914d7263023d23f3edc0b4b08b9
[idea/community.git] / platform / platform-api / src / com / intellij / openapi / ui / Messages.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
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.intellij.openapi.ui;
17
18 import com.intellij.CommonBundle;
19 import com.intellij.openapi.application.Application;
20 import com.intellij.openapi.application.ApplicationManager;
21 import com.intellij.openapi.application.ModalityState;
22 import com.intellij.openapi.diagnostic.Logger;
23 import com.intellij.openapi.project.Project;
24 import com.intellij.openapi.util.Pair;
25 import com.intellij.openapi.util.SystemInfo;
26 import com.intellij.openapi.util.TextRange;
27 import com.intellij.openapi.util.registry.Registry;
28 import com.intellij.openapi.util.text.StringUtil;
29 import com.intellij.openapi.wm.IdeFrame;
30 import com.intellij.openapi.wm.WindowManager;
31 import com.intellij.ui.*;
32 import com.intellij.ui.components.JBScrollPane;
33 import com.intellij.ui.mac.MacMessages;
34 import com.intellij.ui.mac.foundation.MacUtil;
35 import com.intellij.util.Alarm;
36 import com.intellij.util.Function;
37 import com.intellij.util.PairFunction;
38 import com.intellij.util.execution.ParametersListUtil;
39 import com.intellij.util.ui.UIUtil;
40 import org.intellij.lang.annotations.MagicConstant;
41 import org.jetbrains.annotations.*;
42
43 import javax.swing.*;
44 import javax.swing.event.DocumentEvent;
45 import javax.swing.plaf.basic.BasicHTML;
46 import javax.swing.text.JTextComponent;
47 import java.awt.*;
48 import java.awt.event.ActionEvent;
49 import java.awt.event.ItemEvent;
50 import java.awt.event.ItemListener;
51 import java.lang.reflect.Method;
52 import java.util.Arrays;
53 import java.util.List;
54 import java.util.concurrent.atomic.AtomicInteger;
55
56 public class Messages {
57   public static final int OK = 0;
58   public static final int YES = 0;
59   public static final int NO = 1;
60   public static final int CANCEL = 2;
61
62   public static final String OK_BUTTON = CommonBundle.getOkButtonText();
63   public static final String YES_BUTTON = CommonBundle.getYesButtonText();
64   public static final String NO_BUTTON = CommonBundle.getNoButtonText();
65   public static final String CANCEL_BUTTON = CommonBundle.getCancelButtonText();
66
67   private static TestDialog ourTestImplementation = TestDialog.DEFAULT;
68   private static TestInputDialog ourTestInputImplementation = TestInputDialog.DEFAULT;
69
70   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.ui.Messages");
71
72   @TestOnly
73   public static TestDialog setTestDialog(TestDialog newValue) {
74     Application application = ApplicationManager.getApplication();
75     if (application != null) {
76       LOG.assertTrue(application.isUnitTestMode(), "This method is available for tests only");
77     }
78     TestDialog oldValue = ourTestImplementation;
79     ourTestImplementation = newValue;
80     return oldValue;
81   }
82
83   @TestOnly
84   public static TestInputDialog setTestInputDialog(TestInputDialog newValue) {
85     Application application = ApplicationManager.getApplication();
86     if (application != null) {
87       LOG.assertTrue(application.isUnitTestMode(), "This method is available for tests only");
88     }
89     TestInputDialog oldValue = ourTestInputImplementation;
90     ourTestInputImplementation = newValue;
91     return oldValue;
92   }
93
94   @NotNull
95   public static Icon getErrorIcon() {
96     return UIUtil.getErrorIcon();
97   }
98
99   @NotNull
100   public static Icon getInformationIcon() {
101     return UIUtil.getInformationIcon();
102   }
103
104   @NotNull
105   public static Icon getWarningIcon() {
106     return UIUtil.getWarningIcon();
107   }
108
109   @NotNull
110   public static Icon getQuestionIcon() {
111     return UIUtil.getQuestionIcon();
112   }
113
114   @NotNull
115   public static Runnable createMessageDialogRemover(@Nullable Project project) {
116     Window projectWindow = project == null ? null : WindowManager.getInstance().suggestParentWindow(project);
117     return () -> UIUtil.invokeLaterIfNeeded(() -> makeCurrentMessageDialogGoAway(
118       projectWindow != null ? projectWindow.getOwnedWindows() : Window.getWindows()));
119   }
120
121   private static void makeCurrentMessageDialogGoAway(@NotNull Window[] checkWindows) {
122     for (Window w : checkWindows) {
123       JDialog dialog = w instanceof JDialog ? (JDialog)w : null;
124       if (dialog == null || !dialog.isModal()) continue;
125       JButton cancelButton = UIUtil.uiTraverser(dialog.getRootPane()).filter(JButton.class)
126         .filter(b -> CommonBundle.getCancelButtonText().equals(b.getText()))
127         .first();
128       if (cancelButton != null) cancelButton.doClick();
129     }
130   }
131
132   /**
133    * Please, use {@link #showOkCancelDialog} or {@link #showYesNoCancelDialog} if possible (these dialogs implements native OS behavior)!
134    * @return number of button pressed: from 0 up to options.length-1 inclusive, or -1 for Cancel
135    */
136   public static int showDialog(@Nullable Project project,
137                                String message,
138                                @Nls(capitalization = Nls.Capitalization.Title) String title,
139                                @NotNull String[] options,
140                                int defaultOptionIndex,
141                                @Nullable Icon icon) {
142     return showDialog(project, message, title, options, defaultOptionIndex, icon, null);
143   }
144
145   /**
146    * Please, use {@link #showOkCancelDialog} or {@link #showYesNoCancelDialog} if possible (these dialogs implements native OS behavior)!
147    * @return number of button pressed: from 0 up to options.length-1 inclusive, or -1 for Cancel
148    */
149   public static int showDialog(@Nullable Project project,
150                                String message,
151                                @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title,
152                                @NotNull String[] options,
153                                int defaultOptionIndex,
154                                @Nullable Icon icon,
155                                @Nullable DialogWrapper.DoNotAskOption doNotAskOption) {
156     if (isApplicationInUnitTestOrHeadless()) {
157       return ourTestImplementation.show(message);
158     }
159
160     try {
161       if (canShowMacSheetPanel()) {
162         WindowManager windowManager = WindowManager.getInstance();
163         if (windowManager != null) {
164           Window parentWindow = windowManager.suggestParentWindow(project);
165           return MacMessages.getInstance()
166             .showMessageDialog(title, message, options, false, parentWindow, defaultOptionIndex, defaultOptionIndex, doNotAskOption);
167         }
168       }
169     }
170     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
171     catch (Exception reportThis) {LOG.error(reportThis);}
172
173     return showIdeaMessageDialog(project, message, title, options, defaultOptionIndex, icon, doNotAskOption);
174   }
175
176   /**
177    * @return number of button pressed: from 0 up to options.length-1 inclusive, or -1 for Cancel
178    */
179   public static int showIdeaMessageDialog(@Nullable Project project,
180                                           String message,
181                                           @Nls(capitalization = Nls.Capitalization.Title) String title,
182                                           @NotNull String[] options,
183                                           int defaultOptionIndex,
184                                           @Nullable Icon icon,
185                                           @Nullable DialogWrapper.DoNotAskOption doNotAskOption) {
186     MessageDialog dialog = new MessageDialog(project, message, title, options, defaultOptionIndex, -1, icon, doNotAskOption, false);
187     dialog.show();
188     return dialog.getExitCode();
189   }
190
191   public static boolean canShowMacSheetPanel() {
192     return SystemInfo.isMac
193            && !isApplicationInUnitTestOrHeadless()
194            && Registry.is("ide.mac.message.dialogs.as.sheets");
195            //&& !DialogWrapper.isMultipleModalDialogs();
196   }
197
198   public static boolean isMacSheetEmulation() {
199     return SystemInfo.isMac && Registry.is("ide.mac.message.dialogs.as.sheets") && Registry.is("ide.mac.message.sheets.java.emulation");
200   }
201
202   /**
203    * @return number of button pressed: from 0 up to options.length-1 inclusive, or -1 for Cancel
204    */
205   public static int showDialog(Project project,
206                                String message,
207                                @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title,
208                                @Nullable String moreInfo,
209                                @NotNull String[] options,
210                                int defaultOptionIndex,
211                                int focusedOptionIndex,
212                                Icon icon) {
213     if (isApplicationInUnitTestOrHeadless()) {
214       return ourTestImplementation.show(message);
215     }
216
217     try {
218       if (canShowMacSheetPanel() && moreInfo == null) {
219         return MacMessages.getInstance()
220           .showMessageDialog(title, message, options, false, WindowManager.getInstance().suggestParentWindow(project), defaultOptionIndex,
221                              focusedOptionIndex, null);
222       }
223     }
224     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
225     catch (Exception reportThis) {LOG.error(reportThis);}
226
227     MessageDialog dialog = new MoreInfoMessageDialog(project, message, title, moreInfo, options, defaultOptionIndex, focusedOptionIndex, icon);
228     dialog.show();
229     return dialog.getExitCode();
230   }
231
232   static boolean isApplicationInUnitTestOrHeadless(){
233     final Application application = ApplicationManager.getApplication();
234     return application != null && (application.isUnitTestMode() || application.isHeadlessEnvironment());
235   }
236
237   /**
238    * @return number of button pressed: from 0 up to options.length-1 inclusive, or -1 for Cancel
239    */
240   public static int showDialog(@NotNull Component parent, String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String[] options, int defaultOptionIndex, @Nullable Icon icon) {
241     if (isApplicationInUnitTestOrHeadless()) {
242       return ourTestImplementation.show(message);
243     }
244     else {
245       try {
246         if (canShowMacSheetPanel()) {
247           return MacMessages.getInstance().showMessageDialog(title, message, options, false, SwingUtilities.getWindowAncestor(parent),
248                                                              defaultOptionIndex, defaultOptionIndex, null);
249         }
250       }
251       catch (MessageException ignored) {/*rollback the message and show a dialog*/}
252       catch (Exception reportThis) {LOG.error(reportThis);}
253
254       MessageDialog dialog = new MessageDialog(parent, message, title, options, defaultOptionIndex, defaultOptionIndex, icon, false);
255       dialog.show();
256       return dialog.getExitCode();
257     }
258   }
259
260   /**
261    * Use this method only if you do not know project or component
262    *
263    * @see #showDialog(Project, String, String, String[], int, Icon, DialogWrapper.DoNotAskOption)
264    * @see #showDialog(Component, String, String, String[], int, Icon)
265    * @return number of button pressed: from 0 up to options.length-1 inclusive, or -1 for Cancel
266    */
267   public static int showDialog(String message,
268                                @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title,
269                                @NotNull String[] options,
270                                int defaultOptionIndex,
271                                int focusedOptionIndex,
272                                @Nullable Icon icon,
273                                @Nullable DialogWrapper.DoNotAskOption doNotAskOption) {
274     if (isApplicationInUnitTestOrHeadless()) {
275       return ourTestImplementation.show(message);
276     }
277     try {
278       if (canShowMacSheetPanel()) {
279         return MacMessages.getInstance().showMessageDialog(title, message, options, false, null, defaultOptionIndex, focusedOptionIndex,
280                                                            doNotAskOption);
281       }
282     }
283     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
284     catch (Exception reportThis) {LOG.error(reportThis);}
285
286     //what's it? if (application.isUnitTestMode()) throw new RuntimeException(message);
287     MessageDialog dialog = new MessageDialog(message, title, options, defaultOptionIndex, focusedOptionIndex, icon, doNotAskOption);
288     dialog.show();
289     return dialog.getExitCode();
290   }
291
292   /**
293    * Use this method only if you do not know project or component
294    *
295    * @see #showDialog(Project, String, String, String[], int, Icon)
296    * @see #showDialog(Component, String, String, String[], int, Icon)
297    * @return number of button pressed: from 0 up to options.length-1 inclusive, or -1 for Cancel
298    */
299   public static int showDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String[] options, int defaultOptionIndex, @Nullable Icon icon, @Nullable DialogWrapper.DoNotAskOption doNotAskOption) {
300     return showDialog(message, title, options, defaultOptionIndex, defaultOptionIndex, icon, doNotAskOption);
301   }
302
303   /**
304    * Use this method only if you do not know project or component
305    *
306    * @see #showDialog(Project, String, String, String[], int, Icon)
307    * @see #showDialog(Component, String, String, String[], int, Icon)
308    * @return number of button pressed: from 0 up to options.length-1 inclusive, or -1 for Cancel
309    */
310   public static int showDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String[] options, int defaultOptionIndex, @Nullable Icon icon) {
311     return showDialog(message, title, options, defaultOptionIndex, icon, null);
312   }
313
314   /**
315    * @see DialogWrapper#DialogWrapper(Project,boolean)
316    */
317   public static void showMessageDialog(@Nullable Project project, String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title, @Nullable Icon icon) {
318     try {
319       if (canShowMacSheetPanel()) {
320         MacMessages.getInstance().showOkMessageDialog(title, message, OK_BUTTON, WindowManager.getInstance().suggestParentWindow(project));
321         return;
322       }
323     }
324     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
325     catch (Exception reportThis) {LOG.error(reportThis);}
326
327     showDialog(project, message, title, new String[]{OK_BUTTON}, 0, icon);
328   }
329
330   public static void showMessageDialog(@NotNull Component parent, String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title, @Nullable Icon icon) {
331     try {
332       if (canShowMacSheetPanel()) {
333         MacMessages.getInstance().showOkMessageDialog(title, message, OK_BUTTON, SwingUtilities.getWindowAncestor(parent));
334         return;
335       }
336     }
337     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
338     catch (Exception reportThis) {LOG.error(reportThis);}
339
340     showDialog(parent, message, title, new String[]{OK_BUTTON}, 0, icon);
341   }
342
343   /**
344    * Use this method only if you do not know project or component
345    *
346    * @see #showMessageDialog(Project, String, String, Icon)
347    * @see #showMessageDialog(Component, String, String, Icon)
348    */
349   public static void showMessageDialog(String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title, @Nullable Icon icon) {
350     try {
351       if (canShowMacSheetPanel()) {
352         MacMessages.getInstance().showOkMessageDialog(title, message, OK_BUTTON);
353         return;
354       }
355     }
356     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
357     catch (Exception reportThis) {LOG.error(reportThis);}
358
359     showDialog(message, title, new String[]{OK_BUTTON}, 0, icon);
360   }
361
362   @MagicConstant(intValues = {YES, NO})
363   public @interface YesNoResult {
364   }
365
366   /**
367    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No" button.
368    */
369   @YesNoResult
370   public static int showYesNoDialog(@Nullable Project project, String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String yesText, @NotNull String noText, @Nullable Icon icon) {
371     try {
372       if (canShowMacSheetPanel()) {
373         return MacMessages.getInstance()
374           .showYesNoDialog(title, message, yesText, noText, WindowManager.getInstance().suggestParentWindow(project));
375       }
376     }
377     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
378     catch (Exception reportThis) {LOG.error(reportThis);}
379
380     int result = showDialog(project, message, title, new String[]{yesText, noText}, 0, icon) == 0 ? YES : NO;
381     //noinspection ConstantConditions
382     LOG.assertTrue(result == YES || result == NO, result);
383     return result;
384   }
385
386   /**
387    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No" button.
388    */
389   @YesNoResult
390   public static int showYesNoDialog(@Nullable Project project,
391                                     String message,
392                                     @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title,
393                                     @NotNull String yesText,
394                                     @NotNull String noText,
395                                     @Nullable Icon icon,
396                                     @Nullable DialogWrapper.DoNotAskOption doNotAskOption) {
397     try {
398       if (canShowMacSheetPanel()) {
399         return MacMessages.getInstance()
400           .showYesNoDialog(title, message, yesText, noText, WindowManager.getInstance().suggestParentWindow(project), doNotAskOption);
401       }
402     }
403     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
404     catch (Exception reportThis) {LOG.error(reportThis);}
405
406     int result = showDialog(project, message, title, new String[]{yesText, noText}, 0, icon, doNotAskOption) == 0 ? YES : NO;
407     //noinspection ConstantConditions
408     LOG.assertTrue(result == YES || result == NO, result);
409     return result;
410   }
411
412   /**
413    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No" button.
414    */
415   @YesNoResult
416   public static int showYesNoDialog(@Nullable Project project, String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title, @Nullable Icon icon) {
417     try {
418       if (canShowMacSheetPanel()) {
419         return MacMessages.getInstance().showYesNoDialog(title, message, YES_BUTTON, NO_BUTTON,
420                                                          WindowManager.getInstance().suggestParentWindow(project));
421       }
422     }
423     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
424     catch (Exception reportThis) {LOG.error(reportThis);}
425
426     int result = showYesNoDialog(project, message, title, YES_BUTTON, NO_BUTTON, icon);
427
428     LOG.assertTrue(result == YES || result == NO, result);
429     return result;
430   }
431
432   /**
433    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No" button.
434    */
435   @YesNoResult
436   public static int showYesNoDialog(@Nullable Project project,
437                                     String message,
438                                     @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title,
439                                     @Nullable Icon icon,
440                                     @Nullable DialogWrapper.DoNotAskOption doNotAskOption) {
441     try {
442       if (canShowMacSheetPanel()) {
443         return MacMessages.getInstance().showYesNoDialog(title, message, YES_BUTTON, NO_BUTTON,
444                                                          WindowManager.getInstance().suggestParentWindow(project), doNotAskOption);
445       }
446     }
447     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
448     catch (Exception reportThis) {LOG.error(reportThis);}
449
450     int result = showYesNoDialog(project, message, title, YES_BUTTON, NO_BUTTON, icon, doNotAskOption);
451
452     LOG.assertTrue(result == YES || result == NO, result);
453     return result;
454   }
455
456
457   /**
458    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No" button.
459    */
460   @YesNoResult
461   public static int showYesNoDialog(@NotNull Component parent, String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title, @Nullable Icon icon) {
462     try {
463       if (canShowMacSheetPanel()) {
464         return MacMessages.getInstance().showYesNoDialog(title, message, YES_BUTTON, NO_BUTTON, SwingUtilities.getWindowAncestor(parent));
465       }
466     }
467     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
468     catch (Exception reportThis) {LOG.error(reportThis);}
469
470     int result = showDialog(parent, message, title, new String[]{YES_BUTTON, NO_BUTTON}, 0, icon) == 0 ? YES : NO;
471     //noinspection ConstantConditions
472     LOG.assertTrue(result == YES || result == NO, result);
473     return result;
474   }
475
476   /**
477    * Use this method only if you do not know project or component
478    *
479    * @see #showYesNoDialog(Project, String, String, Icon)
480    * @see #showYesNoCancelDialog(Component, String, String, Icon)
481    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No" button.
482    */
483   @YesNoResult
484   public static int showYesNoDialog(String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String yesText, @NotNull String noText, @Nullable Icon icon,
485                                     @Nullable DialogWrapper.DoNotAskOption doNotAskOption) {
486     try {
487       if (canShowMacSheetPanel()) {
488         return MacMessages.getInstance().showYesNoDialog(title, message, yesText, noText, null, doNotAskOption);
489       }
490     }
491     catch (MessageException messageException) {
492       // just show a dialog instead
493     }
494     catch (Exception exception) {
495       LOG.error(exception);
496     }
497
498     int result = showDialog(message, title, new String[]{yesText, noText}, 0, icon, doNotAskOption) == 0 ? YES : NO;
499     //noinspection ConstantConditions
500     LOG.assertTrue(result == YES || result == NO, result);
501     return result;
502   }
503
504   /**
505    * Use this method only if you do not know project or component
506    *
507    * @see #showYesNoDialog(Project, String, String, String, String, Icon)
508    * @see #showYesNoDialog(Component, String, String, Icon)
509    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No" button.
510    */
511   @YesNoResult
512   public static int showYesNoDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, String yesText, String noText, @Nullable Icon icon) {
513     return showYesNoDialog(message, title, yesText, noText, icon, null);
514   }
515
516   /**
517    * Use this method only if you do not know project or component
518    *
519    * @see #showYesNoDialog(Project, String, String, Icon)
520    * @see #showYesNoDialog(Component, String, String, Icon)
521    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No" button.
522    */
523   @YesNoResult
524   public static int showYesNoDialog(String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title, @Nullable Icon icon) {
525     try {
526       if (canShowMacSheetPanel()) {
527         return MacMessages.getInstance().showYesNoDialog(title, message, YES_BUTTON, NO_BUTTON, null);
528       }
529     }
530     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
531     catch (Exception reportThis) {LOG.error(reportThis);}
532
533     int result = showYesNoDialog(message, title, YES_BUTTON, NO_BUTTON, icon);
534     LOG.assertTrue(result == YES || result == NO, result);
535     return result;
536   }
537
538   @MagicConstant(intValues = {OK, CANCEL})
539   public @interface OkCancelResult {
540   }
541
542   /**
543    * @return {@link #OK} if user pressed "Ok" or {@link #CANCEL} if user pressed "Cancel" button.
544    */
545   @OkCancelResult
546   public static int showOkCancelDialog(Project project,
547                                        String message,
548                                        @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title,
549                                        @NotNull String okText,
550                                        @NotNull String cancelText,
551                                        Icon icon,
552                                        DialogWrapper.DoNotAskOption doNotAskOption) {
553     try {
554       if (canShowMacSheetPanel()) {
555         int result = MacMessages.getInstance()
556           .showYesNoDialog(title, message, okText, cancelText, WindowManager.getInstance().suggestParentWindow(project),
557                            doNotAskOption);
558         return result == YES ? OK : CANCEL;
559       }
560     }
561     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
562     catch (Exception reportThis) {LOG.error(reportThis);}
563
564     return showDialog(project, message, title, new String[]{okText, cancelText}, 0, icon, doNotAskOption) == 0 ? OK : CANCEL;
565   }
566
567   /**
568    * @return {@link #OK} if user pressed "Ok" or {@link #CANCEL} if user pressed "Cancel" button.
569    */
570   @OkCancelResult
571   public static int showOkCancelDialog(Project project, String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String okText, @NotNull String cancelText, Icon icon) {
572     return showOkCancelDialog(project, message, title, okText, cancelText, icon, null);
573   }
574
575   /**
576    * @return {@link #OK} if user pressed "Ok" or {@link #CANCEL} if user pressed "Cancel" button.
577    */
578   @OkCancelResult
579   public static int showOkCancelDialog(Project project, String message, @Nls(capitalization = Nls.Capitalization.Title) String title, Icon icon) {
580     return showOkCancelDialog(project, message, title, OK_BUTTON, CANCEL_BUTTON, icon);
581   }
582
583   /**
584    * @return {@link #OK} if user pressed "Ok" or {@link #CANCEL} if user pressed "Cancel" button.
585    */
586   @OkCancelResult
587   public static int showOkCancelDialog(@NotNull Component parent, String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String okText, @NotNull String cancelText, Icon icon) {
588     try {
589       if (canShowMacSheetPanel()) {
590         int result =
591           MacMessages.getInstance().showYesNoDialog(title, message, okText, cancelText, SwingUtilities.getWindowAncestor(parent));
592         return result == YES ? OK : CANCEL;
593       }
594     }
595     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
596     catch (Exception reportThis) {LOG.error(reportThis);}
597
598     return showDialog(parent, message, title, new String[]{okText, cancelText}, 0, icon) == 0 ? OK : CANCEL;
599   }
600
601   /**
602    * @return {@link #OK} if user pressed "Ok" or {@link #CANCEL} if user pressed "Cancel" button.
603    */
604   @OkCancelResult
605   public static int showOkCancelDialog(@NotNull Component parent, String message, @Nls(capitalization = Nls.Capitalization.Title) String title, Icon icon) {
606     return showOkCancelDialog(parent, message, title, OK_BUTTON, CANCEL_BUTTON, icon);
607   }
608
609   /**
610    * Use this method only if you do not know project or component
611    *
612    * @see #showOkCancelDialog(Project, String, String, Icon)
613    * @see #showOkCancelDialog(Component, String, String, Icon)
614    * @return {@link #OK} if user pressed "Ok" or {@link #CANCEL} if user pressed "Cancel" button.
615    */
616   @OkCancelResult
617   public static int showOkCancelDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, Icon icon) {
618     return showOkCancelDialog(message, title, OK_BUTTON, CANCEL_BUTTON, icon, null);
619   }
620
621   /**
622    * Use this method only if you do not know project or component
623    *
624    * @see #showOkCancelDialog(Project, String, String, String, String, Icon)
625    * @see #showOkCancelDialog(Component, String, String, String, String, Icon)
626    * @return {@link #OK} if user pressed "Ok" or {@link #CANCEL} if user pressed "Cancel" button.
627    */
628   @OkCancelResult
629   public static int showOkCancelDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, String okText, String cancelText, Icon icon) {
630     return showOkCancelDialog(message, title, okText, cancelText, icon, null);
631   }
632
633   /**
634    * Use this method only if you do not know project or component
635    *
636    * @see #showOkCancelDialog(Project, String, String, String, String, Icon, DialogWrapper.DoNotAskOption)
637    * @see #showOkCancelDialog(Component, String, String, String, String, Icon)
638    * @return {@link #OK} if user pressed "Ok" or {@link #CANCEL} if user pressed "Cancel" button.
639    */
640   @OkCancelResult
641   public static int showOkCancelDialog(String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String okText, @NotNull String cancelText, Icon icon, @Nullable DialogWrapper.DoNotAskOption doNotAskOption) {
642     try {
643       if (canShowMacSheetPanel()) {
644         int result = MacMessages.getInstance().showYesNoDialog(title, message, okText, cancelText, null, doNotAskOption);
645         return result == YES ? OK : CANCEL;
646       }
647     }
648     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
649     catch (Exception reportThis) {LOG.error(reportThis);}
650
651     return showDialog(message, title, new String[]{okText, cancelText}, 0, icon, doNotAskOption) == 0 ? OK : CANCEL;
652   }
653
654   public static int showCheckboxOkCancelDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, String checkboxText, final boolean checked,
655                                                final int defaultOptionIndex, final int focusedOptionIndex, Icon icon) {
656     return showCheckboxMessageDialog(message, title, new String[]{OK_BUTTON, CANCEL_BUTTON}, checkboxText, checked, defaultOptionIndex,
657                                      focusedOptionIndex, icon,
658                                      (exitCode, cb) -> exitCode == -1 ? CANCEL : exitCode + (cb.isSelected() ? 1 : 0));
659   }
660
661   public static int showCheckboxMessageDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String[] options, String checkboxText, final boolean checked,
662                                               final int defaultOptionIndex, final int focusedOptionIndex, Icon icon,
663                                               @Nullable final PairFunction<Integer, JCheckBox, Integer> exitFunc) {
664     if (isApplicationInUnitTestOrHeadless()) {
665       return ourTestImplementation.show(message);
666     }
667     else {
668       TwoStepConfirmationDialog dialog = new TwoStepConfirmationDialog(message, title, options, checkboxText, checked, defaultOptionIndex,
669                                                                        focusedOptionIndex, icon, exitFunc);
670       dialog.show();
671       return dialog.getExitCode();
672     }
673   }
674
675
676   public static int showTwoStepConfirmationDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, String checkboxText, Icon icon) {
677     return showCheckboxMessageDialog(message, title, new String[]{OK_BUTTON}, checkboxText, true, -1, -1, icon, null);
678   }
679
680   public static void showErrorDialog(@Nullable Project project, @Nls String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title) {
681     try {
682       if (canShowMacSheetPanel()) {
683         MacMessages.getInstance().showErrorDialog(title, message, OK_BUTTON, WindowManager.getInstance().suggestParentWindow(project));
684         return;
685       }
686     }
687     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
688     catch (Exception reportThis) {LOG.error(reportThis);}
689
690     showDialog(project, message, title, new String[]{OK_BUTTON}, 0, getErrorIcon());
691   }
692
693   public static void showErrorDialog(@NotNull Component component, String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title) {
694     try {
695       if (canShowMacSheetPanel()) {
696         MacMessages.getInstance().showErrorDialog(title, message, OK_BUTTON, UIUtil.getWindow(component));
697         return;
698       }
699     }
700     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
701     catch (Exception reportThis) {LOG.error(reportThis);}
702
703     showDialog(component, message, title, new String[]{OK_BUTTON}, 0, getErrorIcon());
704   }
705
706   public static void showErrorDialog(@NotNull Component component, String message) {
707     try {
708       if (canShowMacSheetPanel()) {
709         MacMessages.getInstance().showErrorDialog(CommonBundle.getErrorTitle(), message, OK_BUTTON, SwingUtilities.getWindowAncestor(
710           component));
711         return;
712       }
713     }
714     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
715     catch (Exception reportThis) {LOG.error(reportThis);}
716
717     showDialog(component, message, CommonBundle.getErrorTitle(), new String[]{OK_BUTTON}, 0, getErrorIcon());
718   }
719
720   /**
721    * Use this method only if you do not know project or component
722    *
723    * @see #showErrorDialog(Project, String, String)
724    * @see #showErrorDialog(Component, String, String)
725    */
726   public static void showErrorDialog(String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title) {
727     try {
728       if (canShowMacSheetPanel()) {
729         MacMessages.getInstance().showErrorDialog(title, message, OK_BUTTON, null);
730         return;
731       }
732     }
733     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
734     catch (Exception reportThis) {LOG.error(reportThis);}
735
736     showDialog(message, title, new String[]{OK_BUTTON}, 0, getErrorIcon());
737   }
738
739   public static void showWarningDialog(@Nullable Project project, String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title) {
740     try {
741       if (canShowMacSheetPanel()) {
742         MacMessages.getInstance().showErrorDialog(title, message, OK_BUTTON, WindowManager.getInstance().suggestParentWindow(project));
743         return;
744       }
745     }
746     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
747     catch (Exception reportThis) {LOG.error(reportThis);}
748
749     showDialog(project, message, title, new String[]{OK_BUTTON}, 0, getWarningIcon());
750   }
751
752   public static void showWarningDialog(@NotNull Component component, String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title) {
753     try {
754       if (canShowMacSheetPanel()) {
755         MacMessages.getInstance().showErrorDialog(title, message, OK_BUTTON, SwingUtilities.getWindowAncestor(component));
756         return;
757       }
758     }
759     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
760     catch (Exception reportThis) {LOG.error(reportThis);}
761
762     showDialog(component, message, title, new String[]{OK_BUTTON}, 0, getWarningIcon());
763   }
764
765   /**
766    * Use this method only if you do not know project or component
767    *
768    * @see #showWarningDialog(Project, String, String)
769    * @see #showWarningDialog(Component, String, String)
770    */
771   public static void showWarningDialog(String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title) {
772     try {
773       if (canShowMacSheetPanel()) {
774         MacMessages.getInstance().showErrorDialog(title, message, OK_BUTTON, null);
775         return;
776       }
777     }
778     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
779     catch (Exception reportThis) {LOG.error(reportThis);}
780
781     showDialog(message, title, new String[]{OK_BUTTON}, 0, getWarningIcon());
782   }
783
784   @MagicConstant(intValues = {YES, NO, CANCEL})
785   public @interface YesNoCancelResult {
786   }
787
788
789   /**
790    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No", or {@link #CANCEL} if user pressed "Cancel" button.
791    */
792   @YesNoCancelResult
793   public static int showYesNoCancelDialog(Project project,
794                                           String message,
795                                           @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title,
796                                           @NotNull String yes,
797                                           @NotNull String no,
798                                           @NotNull String cancel,
799                                           @Nullable Icon icon) {
800     try {
801       if (canShowMacSheetPanel()) {
802         return MacMessages.getInstance().showYesNoCancelDialog(title, message, yes, no, cancel,
803                                                                WindowManager.getInstance().suggestParentWindow(project), null);
804       }
805     }
806     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
807     catch (Exception reportThis) {LOG.error(reportThis);}
808
809     int buttonNumber = showDialog(project, message, title, new String[]{yes, no, cancel}, 0, icon);
810     return buttonNumber == 0 ? YES : buttonNumber == 1 ? NO : CANCEL;
811   }
812
813   /**
814    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No", or {@link #CANCEL} if user pressed "Cancel" button.
815    */
816   @YesNoCancelResult
817   public static int showYesNoCancelDialog(Project project, String message, @Nls(capitalization = Nls.Capitalization.Title) String title, Icon icon) {
818     return showYesNoCancelDialog(project, message, title, YES_BUTTON, NO_BUTTON, CANCEL_BUTTON, icon);
819   }
820
821   /**
822    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No", or {@link #CANCEL} if user pressed "Cancel" button.
823    */
824   @YesNoCancelResult
825   public static int showYesNoCancelDialog(@NotNull Component parent,
826                                           String message,
827                                           @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title,
828                                           @NotNull String yes,
829                                           @NotNull String no,
830                                           @NotNull String cancel,
831                                           Icon icon) {
832     try {
833       if (canShowMacSheetPanel()) {
834         return MacMessages.getInstance().showYesNoCancelDialog(title, message, yes, no, cancel,
835                                                                SwingUtilities.getWindowAncestor(parent), null);
836       }
837     }
838     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
839     catch (Exception reportThis) {LOG.error(reportThis);}
840
841     int buttonNumber = showDialog(parent, message, title, new String[]{yes, no, cancel}, 0, icon);
842     return buttonNumber == 0 ? YES : buttonNumber == 1 ? NO : CANCEL;
843   }
844
845   /**
846    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No", or {@link #CANCEL} if user pressed "Cancel" button.
847    */
848   @YesNoCancelResult
849   public static int showYesNoCancelDialog(@NotNull Component parent, String message, @Nls(capitalization = Nls.Capitalization.Title) String title, Icon icon) {
850     return showYesNoCancelDialog(parent, message, title, YES_BUTTON, NO_BUTTON, CANCEL_BUTTON, icon);
851   }
852
853
854   /**
855    * Use this method only if you do not know project or component
856    *
857    * @see #showYesNoCancelDialog(Project, String, String, String, String, String, Icon)
858    * @see #showYesNoCancelDialog(Component, String, String, String, String, String, Icon)
859    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No", or {@link #CANCEL} if user pressed "Cancel" button.
860    */
861   @YesNoCancelResult
862   public static int showYesNoCancelDialog(String message,
863                                           @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title,
864                                           @NotNull String yes,
865                                           @NotNull String no,
866                                           @NotNull String cancel,
867                                           Icon icon,
868                                           @Nullable DialogWrapper.DoNotAskOption doNotAskOption) {
869     try {
870       if (canShowMacSheetPanel()) {
871         return MacMessages.getInstance().showYesNoCancelDialog(title, message, yes, no, cancel, null, doNotAskOption);
872       }
873     }
874     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
875     catch (Exception reportThis) {LOG.error(reportThis);}
876
877     int buttonNumber = showDialog(message, title, new String[]{yes, no, cancel}, 0, icon, doNotAskOption);
878     return buttonNumber == 0 ? YES : buttonNumber == 1 ? NO : CANCEL;
879   }
880
881   /**
882    * Use this method only if you do not know project or component
883    *
884    * @see #showYesNoCancelDialog(Project, String, String, String, String, String, Icon)
885    * @see #showYesNoCancelDialog(Component, String, String, String, String, String, Icon)
886    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No", or {@link #CANCEL} if user pressed "Cancel" button.
887    */
888   @YesNoCancelResult
889   public static int showYesNoCancelDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, String yes, String no, String cancel, Icon icon) {
890     return showYesNoCancelDialog(message, title, yes, no, cancel, icon, null);
891   }
892
893   /**
894    * Use this method only if you do not know project or component
895    *
896    * @see #showYesNoCancelDialog(Project, String, String, Icon)
897    * @see #showYesNoCancelDialog(Component, String, String, Icon)
898    * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No", or {@link #CANCEL} if user pressed "Cancel" button.
899    */
900   @YesNoCancelResult
901   public static int showYesNoCancelDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, Icon icon) {
902     return showYesNoCancelDialog(message, title, YES_BUTTON, NO_BUTTON, CANCEL_BUTTON, icon);
903   }
904
905   /**
906    * @return trimmed input string or <code>null</code> if user cancelled dialog.
907    */
908   @Nullable
909   public static String showPasswordDialog(@Nls String message, @Nls(capitalization = Nls.Capitalization.Title) String title) {
910     return showPasswordDialog(null, message, title, null, null);
911   }
912
913   /**
914    * @return trimmed input string or <code>null</code> if user cancelled dialog.
915    */
916   @Nullable
917   public static String showPasswordDialog(Project project, @Nls String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @Nullable Icon icon) {
918     return showPasswordDialog(project, message, title, icon, null);
919   }
920
921   /**
922    * @return trimmed input string or <code>null</code> if user cancelled dialog.
923    */
924   @Nullable
925   public static String showPasswordDialog(@Nullable Project project,
926                                           @Nls String message,
927                                           @Nls(capitalization = Nls.Capitalization.Title) String title,
928                                           @Nullable Icon icon,
929                                           @Nullable InputValidator validator) {
930     if (isApplicationInUnitTestOrHeadless()) {
931       return ourTestInputImplementation.show(message, validator);
932     }
933
934     final InputDialog dialog = project != null ? new PasswordInputDialog(project, message, title, icon, validator)
935                                                : new PasswordInputDialog(message, title, icon, validator);
936     dialog.show();
937     return dialog.getInputString();
938   }
939
940   /**
941    * @return trimmed input string or <code>null</code> if user cancelled dialog.
942    */
943   @Nullable
944   public static String showInputDialog(@Nullable Project project, String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @Nullable Icon icon) {
945     return showInputDialog(project, message, title, icon, null, null);
946   }
947
948   /**
949    * @return trimmed input string or <code>null</code> if user cancelled dialog.
950    */
951   @Nullable
952   public static String showInputDialog(@NotNull Component parent, String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @Nullable Icon icon) {
953     return showInputDialog(parent, message, title, icon, null, null);
954   }
955
956   /**
957    * Use this method only if you do not know project or component
958    *
959    * @see #showInputDialog(Project, String, String, Icon)
960    * @see #showInputDialog(Component, String, String, Icon)
961    */
962   @Nullable
963   public static String showInputDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @Nullable Icon icon) {
964     return showInputDialog(message, title, icon, null, null);
965   }
966
967   @Nullable
968   public static String showInputDialog(@Nullable Project project,
969                                        @Nls String message,
970                                        @Nls(capitalization = Nls.Capitalization.Title) String title,
971                                        @Nullable Icon icon,
972                                        @Nullable String initialValue,
973                                        @Nullable InputValidator validator) {
974     if (isApplicationInUnitTestOrHeadless()) {
975       return ourTestInputImplementation.show(message, validator);
976     }
977     else {
978       InputDialog dialog = new InputDialog(project, message, title, icon, initialValue, validator);
979       dialog.show();
980       return dialog.getInputString();
981     }
982   }
983
984   @Nullable
985   public static String showInputDialog(Project project,
986                                        @Nls String message,
987                                        @Nls(capitalization = Nls.Capitalization.Title) String title,
988                                        @Nullable Icon icon,
989                                        @Nullable String initialValue,
990                                        @Nullable InputValidator validator,
991                                        @Nullable TextRange selection) {
992     if (isApplicationInUnitTestOrHeadless()) {
993       return ourTestInputImplementation.show(message, validator);
994     }
995     else {
996       InputDialog dialog = new InputDialog(project, message, title, icon, initialValue, validator);
997
998       final JTextComponent field = dialog.getTextField();
999       if (selection != null) {
1000         // set custom selection
1001         field.select(selection.getStartOffset(),
1002                      selection.getEndOffset());
1003       } else {
1004         // reset selection
1005         final int length = field.getDocument().getLength();
1006         field.select(length, length);
1007       }
1008       field.putClientProperty(DialogWrapperPeer.HAVE_INITIAL_SELECTION, true);
1009
1010       dialog.show();
1011       return dialog.getInputString();
1012     }
1013   }
1014
1015   @Nullable
1016   public static String showInputDialog(@NotNull Component parent,
1017                                        String message,
1018                                        @Nls(capitalization = Nls.Capitalization.Title) String title,
1019                                        @Nullable Icon icon,
1020                                        @Nullable String initialValue,
1021                                        @Nullable InputValidator validator) {
1022     if (isApplicationInUnitTestOrHeadless()) {
1023       return ourTestInputImplementation.show(message, validator);
1024     }
1025     else {
1026
1027       InputDialog dialog = new InputDialog(parent, message, title, icon, initialValue, validator);
1028       dialog.show();
1029       return dialog.getInputString();
1030     }
1031   }
1032
1033   /**
1034    * Use this method only if you do not know project or component
1035    *
1036    * @see #showInputDialog(Project, String, String, Icon, String, InputValidator)
1037    * @see #showInputDialog(Component, String, String, Icon, String, InputValidator)
1038    */
1039   @Nullable
1040   public static String showInputDialog(String message,
1041                                        @Nls(capitalization = Nls.Capitalization.Title) String title,
1042                                        @Nullable Icon icon,
1043                                        @Nullable String initialValue,
1044                                        @Nullable InputValidator validator) {
1045     if (isApplicationInUnitTestOrHeadless()) {
1046       return ourTestInputImplementation.show(message, validator);
1047     }
1048     else {
1049       InputDialog dialog = new InputDialog(message, title, icon, initialValue, validator);
1050       dialog.show();
1051       return dialog.getInputString();
1052     }
1053   }
1054
1055   @Nullable
1056   public static String showMultilineInputDialog(Project project,
1057                                                 String message,
1058                                                 @Nls(capitalization = Nls.Capitalization.Title) String title,
1059                                                 @Nullable String initialValue,
1060                                                 @Nullable Icon icon,
1061                                                 @Nullable InputValidator validator) {
1062     if (isApplicationInUnitTestOrHeadless()) {
1063       return ourTestInputImplementation.show(message, validator);
1064     }
1065     InputDialog dialog = new MultilineInputDialog(project, message, title, icon, initialValue, validator, new String[]{OK_BUTTON, CANCEL_BUTTON}, 0);
1066     dialog.show();
1067     return dialog.getInputString();
1068   }
1069
1070   @NotNull
1071   public static Pair<String, Boolean> showInputDialogWithCheckBox(String message,
1072                                                                   @Nls(capitalization = Nls.Capitalization.Title) String title,
1073                                                                   String checkboxText,
1074                                                                   boolean checked,
1075                                                                   boolean checkboxEnabled,
1076                                                                   @Nullable Icon icon,
1077                                                                   @NonNls String initialValue,
1078                                                                   @Nullable InputValidator validator) {
1079     if (isApplicationInUnitTestOrHeadless()) {
1080       return new Pair<>(ourTestInputImplementation.show(message, validator), checked);
1081     }
1082     else {
1083       InputDialogWithCheckbox dialog = new InputDialogWithCheckbox(message, title, checkboxText, checked, checkboxEnabled, icon, initialValue, validator);
1084       dialog.show();
1085       return Pair.create(dialog.getInputString(), dialog.isChecked());
1086     }
1087   }
1088
1089   @Nullable
1090   public static String showEditableChooseDialog(String message,
1091                                                 @Nls(capitalization = Nls.Capitalization.Title) String title,
1092                                                 @Nullable Icon icon,
1093                                                 String[] values,
1094                                                 String initialValue,
1095                                                 @Nullable InputValidator validator) {
1096     if (isApplicationInUnitTestOrHeadless()) {
1097       return ourTestInputImplementation.show(message, validator);
1098     }
1099     else {
1100       ChooseDialog dialog = new ChooseDialog(message, title, icon, values, initialValue);
1101       dialog.setValidator(validator);
1102       dialog.getComboBox().setEditable(true);
1103       dialog.getComboBox().getEditor().setItem(initialValue);
1104       dialog.getComboBox().setSelectedItem(initialValue);
1105       dialog.show();
1106       return dialog.getInputString();
1107     }
1108   }
1109
1110   /** @deprecated It looks awful! */
1111   @Deprecated
1112   public static int showChooseDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, String[] values, String initialValue, @Nullable Icon icon) {
1113     if (isApplicationInUnitTestOrHeadless()) {
1114       return ourTestImplementation.show(message);
1115     }
1116     else {
1117       ChooseDialog dialog = new ChooseDialog(message, title, icon, values, initialValue);
1118       dialog.show();
1119       return dialog.getSelectedIndex();
1120     }
1121   }
1122
1123   /** @deprecated It looks awful! */
1124   @Deprecated
1125   public static int showChooseDialog(@NotNull Component parent, String message, @Nls(capitalization = Nls.Capitalization.Title) String title, String[] values, String initialValue, Icon icon) {
1126     if (isApplicationInUnitTestOrHeadless()) {
1127       return ourTestImplementation.show(message);
1128     }
1129     else {
1130       ChooseDialog dialog = new ChooseDialog(parent, message, title, icon, values, initialValue);
1131       dialog.show();
1132       return dialog.getSelectedIndex();
1133     }
1134   }
1135
1136   /**
1137    * @deprecated It looks awful!
1138    * @see DialogWrapper#DialogWrapper(Project,boolean)
1139    */
1140   @Deprecated
1141   public static int showChooseDialog(Project project, String message, @Nls(capitalization = Nls.Capitalization.Title) String title, Icon icon, String[] values, String initialValue) {
1142     if (isApplicationInUnitTestOrHeadless()) {
1143       return ourTestImplementation.show(message);
1144     }
1145     else {
1146       ChooseDialog dialog = new ChooseDialog(project, message, title, icon, values, initialValue);
1147       dialog.show();
1148       return dialog.getSelectedIndex();
1149     }
1150   }
1151
1152   /**
1153    * Shows dialog with given message and title, information icon {@link #getInformationIcon()} and OK button
1154    */
1155   public static void showInfoMessage(Component component, String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title) {
1156     try {
1157       if (canShowMacSheetPanel()) {
1158         MacMessages.getInstance().showOkMessageDialog(title, message, OK_BUTTON, SwingUtilities.getWindowAncestor(component));
1159         return;
1160       }
1161     }
1162     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
1163     catch (Exception reportThis) {LOG.error(reportThis);}
1164
1165     showMessageDialog(component, message, title, getInformationIcon());
1166   }
1167
1168   /**
1169    * Shows dialog with given message and title, information icon {@link #getInformationIcon()} and OK button
1170    */
1171   public static void showInfoMessage(@Nullable Project project, @Nls String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title) {
1172     try {
1173       if (canShowMacSheetPanel()) {
1174         MacMessages.getInstance().showOkMessageDialog(title, message, OK_BUTTON, WindowManager.getInstance().suggestParentWindow(project));
1175         return;
1176       }
1177     }
1178     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
1179     catch (Exception reportThis) {LOG.error(reportThis);}
1180
1181     showMessageDialog(project, message, title, getInformationIcon());
1182   }
1183
1184   /**
1185    * Shows dialog with given message and title, information icon {@link #getInformationIcon()} and OK button
1186    *
1187    * Use this method only if you do not know project or component
1188    *
1189    * @see #showInputDialog(Project, String, String, Icon, String, InputValidator)
1190    * @see #showInputDialog(Component, String, String, Icon, String, InputValidator)
1191    */
1192   public static void showInfoMessage(String message, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String title) {
1193     try {
1194       if (canShowMacSheetPanel()) {
1195         MacMessages.getInstance().showOkMessageDialog(title, message, OK_BUTTON, null);
1196         return;
1197       }
1198     }
1199     catch (MessageException ignored) {/*rollback the message and show a dialog*/}
1200     catch (Exception reportThis) {LOG.error(reportThis);}
1201
1202     showMessageDialog(message, title, getInformationIcon());
1203   }
1204
1205   /**
1206    * Shows dialog with text area to edit long strings that don't fit in text field.
1207    */
1208   public static void showTextAreaDialog(final JTextField textField,
1209                                         final @Nls(capitalization = Nls.Capitalization.Title) String title,
1210                                         @NonNls final String dimensionServiceKey,
1211                                         final Function<String, List<String>> parser,
1212                                         final Function<List<String>, String> lineJoiner) {
1213     if (isApplicationInUnitTestOrHeadless()) {
1214       ourTestImplementation.show(title);
1215     }
1216     else {
1217       final JTextArea textArea = new JTextArea(10, 50);
1218       UIUtil.addUndoRedoActions(textArea);
1219       textArea.setWrapStyleWord(true);
1220       textArea.setLineWrap(true);
1221       List<String> lines = parser.fun(textField.getText());
1222       textArea.setText(StringUtil.join(lines, "\n"));
1223       InsertPathAction.copyFromTo(textField, textArea);
1224       final DialogBuilder builder = new DialogBuilder(textField);
1225       builder.setDimensionServiceKey(dimensionServiceKey);
1226       builder.setCenterPanel(ScrollPaneFactory.createScrollPane(textArea));
1227       builder.setPreferredFocusComponent(textArea);
1228       String rawText = title;
1229       if (StringUtil.endsWithChar(rawText, ':')) {
1230         rawText = rawText.substring(0, rawText.length() - 1);
1231       }
1232       builder.setTitle(rawText);
1233       builder.addOkAction();
1234       builder.addCancelAction();
1235       builder.setOkOperation(() -> {
1236         textField.setText(lineJoiner.fun(Arrays.asList(StringUtil.splitByLines(textArea.getText()))));
1237         builder.getDialogWrapper().close(DialogWrapper.OK_EXIT_CODE);
1238       });
1239       builder.show();
1240     }
1241   }
1242
1243   public static void showTextAreaDialog(final JTextField textField, final @Nls(capitalization = Nls.Capitalization.Title) String title, @NonNls final String dimensionServiceKey) {
1244     showTextAreaDialog(textField, title, dimensionServiceKey, ParametersListUtil.DEFAULT_LINE_PARSER, ParametersListUtil.DEFAULT_LINE_JOINER);
1245   }
1246
1247   private static class MoreInfoMessageDialog extends MessageDialog {
1248     @Nullable private final String myInfoText;
1249
1250     public MoreInfoMessageDialog(Project project,
1251                                  String message,
1252                                  @Nls(capitalization = Nls.Capitalization.Title) String title,
1253                                  @Nullable String moreInfo,
1254                                  @NotNull String[] options,
1255                                  int defaultOptionIndex, int focusedOptionIndex, Icon icon) {
1256       super(project);
1257       myInfoText = moreInfo;
1258       _init(title, message, options, defaultOptionIndex, focusedOptionIndex, icon, null);
1259     }
1260
1261     @Override
1262     protected JComponent createNorthPanel() {
1263       return doCreateCenterPanel();
1264     }
1265
1266     @Override
1267     protected JComponent createCenterPanel() {
1268       if (myInfoText == null) {
1269         return null;
1270       }
1271       final JPanel panel = new JPanel(new BorderLayout());
1272       final JTextArea area = new JTextArea(myInfoText);
1273       area.setEditable(false);
1274       final JBScrollPane scrollPane = new JBScrollPane(area) {
1275         @Override
1276         public Dimension getPreferredSize() {
1277           final Dimension preferredSize = super.getPreferredSize();
1278           final Container parent = getParent();
1279           if (parent != null) {
1280             return new Dimension(preferredSize.width, Math.min(150, preferredSize.height));
1281           }
1282           return preferredSize;
1283         }
1284       };
1285       panel.add(scrollPane);
1286       return panel;
1287     }
1288   }
1289
1290   private static class MessageDialog extends DialogWrapper {
1291     protected String myMessage;
1292     protected String[] myOptions;
1293     protected int myDefaultOptionIndex;
1294     protected int myFocusedOptionIndex;
1295     protected Icon myIcon;
1296     private MyBorderLayout myLayout;
1297
1298     public MessageDialog(@Nullable Project project, String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String[] options, int defaultOptionIndex, @Nullable Icon icon, boolean canBeParent) {
1299       this(project, message, title, options, defaultOptionIndex, -1, icon, canBeParent);
1300     }
1301
1302     public MessageDialog(@Nullable Project project,
1303                          String message,
1304                          @Nls(capitalization = Nls.Capitalization.Title) String title,
1305                          @NotNull String[] options,
1306                          int defaultOptionIndex,
1307                          int focusedOptionIndex,
1308                          @Nullable Icon icon,
1309                          @Nullable DoNotAskOption doNotAskOption,
1310                          boolean canBeParent) {
1311       super(project, canBeParent);
1312       _init(title, message, options, defaultOptionIndex, focusedOptionIndex, icon, doNotAskOption);
1313     }
1314
1315     public MessageDialog(@Nullable Project project, String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String[] options, int defaultOptionIndex, int focusedOptionIndex, @Nullable Icon icon,
1316                          boolean canBeParent) {
1317       super(project, canBeParent);
1318       _init(title, message, options, defaultOptionIndex, focusedOptionIndex, icon, null);
1319     }
1320
1321     public MessageDialog(@NotNull Component parent, String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String[] options, int defaultOptionIndex, @Nullable Icon icon) {
1322       this(parent, message, title, options, defaultOptionIndex, icon, false);
1323     }
1324
1325     public MessageDialog(@NotNull Component parent, String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String[] options, int defaultOptionIndex, @Nullable Icon icon, boolean canBeParent) {
1326       this(parent, message, title, options, defaultOptionIndex, -1, icon, canBeParent);
1327     }
1328
1329     public MessageDialog(@NotNull Component parent,
1330                          String message,
1331                          @Nls(capitalization = Nls.Capitalization.Title) String title,
1332                          @NotNull String[] options,
1333                          int defaultOptionIndex,
1334                          int focusedOptionIndex,
1335                          @Nullable Icon icon,
1336                          boolean canBeParent) {
1337       super(parent, canBeParent);
1338       _init(title, message, options, defaultOptionIndex, focusedOptionIndex, icon, null);
1339     }
1340
1341     public MessageDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String[] options, int defaultOptionIndex, @Nullable Icon icon) {
1342       this(message, title, options, defaultOptionIndex, icon, false);
1343     }
1344
1345     public MessageDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String[] options, int defaultOptionIndex, @Nullable Icon icon, boolean canBeParent) {
1346       super(canBeParent);
1347       _init(title, message, options, defaultOptionIndex, -1, icon, null);
1348     }
1349
1350     public MessageDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String[] options, int defaultOptionIndex, int focusedOptionIndex, @Nullable Icon icon, @Nullable DoNotAskOption doNotAskOption) {
1351       super(false);
1352       _init(title, message, options, defaultOptionIndex, focusedOptionIndex, icon, doNotAskOption);
1353     }
1354
1355     public MessageDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String[] options, int defaultOptionIndex, Icon icon, DoNotAskOption doNotAskOption) {
1356       this(message, title, options, defaultOptionIndex, -1, icon, doNotAskOption);
1357     }
1358
1359     protected MessageDialog() {
1360       super(false);
1361     }
1362
1363     protected MessageDialog(Project project) {
1364       super(project, false);
1365     }
1366
1367     protected void _init(@Nls(capitalization = Nls.Capitalization.Title) String title,
1368                          String message,
1369                          @NotNull String[] options,
1370                          int defaultOptionIndex,
1371                          int focusedOptionIndex,
1372                          @Nullable Icon icon,
1373                          @Nullable DoNotAskOption doNotAskOption) {
1374       setTitle(title);
1375       if (isMacSheetEmulation()) {
1376         setUndecorated(true);
1377       }
1378       myMessage = message;
1379       myOptions = options;
1380       myDefaultOptionIndex = defaultOptionIndex;
1381       myFocusedOptionIndex = focusedOptionIndex;
1382       myIcon = icon;
1383       if (!SystemInfo.isMac) {
1384         setButtonsAlignment(SwingConstants.CENTER);
1385       }
1386       setDoNotAskOption(doNotAskOption);
1387       init();
1388       if (isMacSheetEmulation()) {
1389         MacUtil.adjustFocusTraversal(myDisposable);
1390       }
1391     }
1392
1393     @NotNull
1394     @Override
1395     protected Action[] createActions() {
1396       Action[] actions = new Action[myOptions.length];
1397       for (int i = 0; i < myOptions.length; i++) {
1398         String option = myOptions[i];
1399         final int exitCode = i;
1400         actions[i] = new AbstractAction(UIUtil.replaceMnemonicAmpersand(option)) {
1401           @Override
1402           public void actionPerformed(ActionEvent e) {
1403             close(exitCode, true);
1404           }
1405         };
1406
1407         if (i == myDefaultOptionIndex) {
1408           actions[i].putValue(DEFAULT_ACTION, Boolean.TRUE);
1409         }
1410
1411         if (i == myFocusedOptionIndex) {
1412           actions[i].putValue(FOCUSED_ACTION, Boolean.TRUE);
1413         }
1414
1415         UIUtil.assignMnemonic(option, actions[i]);
1416
1417       }
1418       return actions;
1419     }
1420
1421     @Override
1422     public void doCancelAction() {
1423       close(-1);
1424     }
1425
1426     @Override
1427     protected JComponent createCenterPanel() {
1428       return doCreateCenterPanel();
1429     }
1430
1431     @NotNull
1432     @Override
1433     LayoutManager createRootLayout() {
1434       return isMacSheetEmulation() ? myLayout = new MyBorderLayout() : super.createRootLayout();
1435     }
1436
1437     @Override
1438     protected void dispose() {
1439       if (isMacSheetEmulation()) {
1440         animate();
1441       } else {
1442         super.dispose();
1443       }
1444     }
1445
1446     @Override
1447     public void show() {
1448       if (isMacSheetEmulation()) {
1449         setInitialLocationCallback(() -> {
1450           JRootPane rootPane = SwingUtilities.getRootPane(getWindow().getParent());
1451           if (rootPane == null) {
1452             rootPane = SwingUtilities.getRootPane(getWindow().getOwner());
1453           }
1454
1455           Point p = rootPane.getLocationOnScreen();
1456           p.x += (rootPane.getWidth() - getWindow().getWidth()) / 2;
1457           return p;
1458         });
1459         animate();
1460         if (SystemInfo.isJavaVersionAtLeast("1.7")) {
1461           try {
1462             Method method = Class.forName("java.awt.Window").getDeclaredMethod("setOpacity", float.class);
1463             if (method != null) method.invoke(getPeer().getWindow(), .8f);
1464           }
1465           catch (Exception exception) {
1466           }
1467         }
1468         setAutoAdjustable(false);
1469         setSize(getPreferredSize().width, 0);//initial state before animation, zero height
1470       }
1471       super.show();
1472     }
1473
1474     private void animate() {
1475       final int height = getPreferredSize().height;
1476       final int frameCount = 10;
1477       final boolean toClose = isShowing();
1478
1479
1480       final AtomicInteger i = new AtomicInteger(-1);
1481       final Alarm animator = new Alarm(myDisposable);
1482       final Runnable runnable = new Runnable() {
1483         @Override
1484         public void run() {
1485           int state = i.addAndGet(1);
1486
1487           double linearProgress = (double)state / frameCount;
1488           if (toClose) {
1489             linearProgress = 1 - linearProgress;
1490           }
1491           myLayout.myPhase = (1 - Math.cos(Math.PI * linearProgress)) / 2;
1492           Window window = getPeer().getWindow();
1493           Rectangle bounds = window.getBounds();
1494           bounds.height = (int)(height * myLayout.myPhase);
1495
1496           window.setBounds(bounds);
1497
1498           if (state == 0 && !toClose && window.getOwner() instanceof IdeFrame) {
1499             WindowManager.getInstance().requestUserAttention((IdeFrame)window.getOwner(), true);
1500           }
1501
1502           if (state < frameCount) {
1503             animator.addRequest(this, 10);
1504           }
1505           else if (toClose) {
1506             MessageDialog.super.dispose();
1507           }
1508         }
1509       };
1510       animator.addRequest(runnable, 10, ModalityState.stateForComponent(getRootPane()));
1511     }
1512
1513     protected JComponent doCreateCenterPanel() {
1514       JPanel panel = createIconPanel();
1515       if (myMessage != null) {
1516         JTextPane messageComponent = createMessageComponent(myMessage);
1517         panel.add(wrapToScrollPaneIfNeeded(messageComponent, 100, 10), BorderLayout.CENTER);
1518       }
1519       return panel;
1520     }
1521
1522     @NotNull
1523     protected JPanel createIconPanel() {
1524       JPanel panel = new JPanel(new BorderLayout(15, 0));
1525       if (myIcon != null) {
1526         JLabel iconLabel = new JLabel(myIcon);
1527         Container container = new Container();
1528         container.setLayout(new BorderLayout());
1529         container.add(iconLabel, BorderLayout.NORTH);
1530         panel.add(container, BorderLayout.WEST);
1531       }
1532       return panel;
1533     }
1534
1535     @NotNull
1536     protected JPanel createMessagePanel() {
1537       JPanel messagePanel = new JPanel(new BorderLayout());
1538       if (myMessage != null) {
1539         JLabel textLabel = new JLabel(myMessage);
1540         textLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
1541         textLabel.setUI(new MultiLineLabelUI());
1542         messagePanel.add(textLabel, BorderLayout.NORTH);
1543       }
1544       return messagePanel;
1545     }
1546
1547     protected static JTextPane createMessageComponent(final String message) {
1548       final JTextPane messageComponent = new JTextPane();
1549       return configureMessagePaneUi(messageComponent, message);
1550     }
1551
1552     @Override
1553     protected void doHelpAction() {
1554       // do nothing
1555     }
1556   }
1557
1558   private static class MyBorderLayout extends BorderLayout {
1559     private double myPhase = 0;//it varies from 0 (hidden state) to 1 (fully visible)
1560
1561     private MyBorderLayout() {
1562     }
1563
1564     @Override
1565     public void layoutContainer(Container target) {
1566       final Dimension realSize = target.getSize();
1567       target.setSize(target.getPreferredSize());
1568
1569       super.layoutContainer(target);
1570
1571       target.setSize(realSize);
1572
1573       synchronized (target.getTreeLock()) {
1574         int yShift = (int)((1 - myPhase) * target.getPreferredSize().height);
1575         Component[] components = target.getComponents();
1576         for (Component component : components) {
1577           Point point = component.getLocation();
1578           point.y -= yShift;
1579           component.setLocation(point);
1580         }
1581       }
1582     }
1583   }
1584
1585   public static void installHyperlinkSupport(JTextPane messageComponent) {
1586     configureMessagePaneUi(messageComponent, "<html></html>");
1587   }
1588
1589   @NotNull
1590   public static JTextPane configureMessagePaneUi(JTextPane messageComponent, String message) {
1591     JTextPane pane = configureMessagePaneUi(messageComponent, message, null);
1592     if (UIUtil.HTML_MIME.equals(pane.getContentType())) {
1593       pane.addHyperlinkListener(BrowserHyperlinkListener.INSTANCE);
1594     }
1595     return pane;
1596   }
1597
1598   @NotNull
1599   public static JTextPane configureMessagePaneUi(@NotNull JTextPane messageComponent,
1600                                                  @Nullable String message,
1601                                                  @Nullable UIUtil.FontSize fontSize) {
1602     UIUtil.FontSize fixedFontSize = fontSize == null ? UIUtil.FontSize.NORMAL : fontSize;
1603     messageComponent.setFont(UIUtil.getLabelFont(fixedFontSize));
1604     if (BasicHTML.isHTMLString(message)) {
1605       messageComponent.setEditorKit(UIUtil.getHTMLEditorKit());
1606     }
1607     messageComponent.setText(message);
1608     messageComponent.setEditable(false);
1609     if (messageComponent.getCaret() != null) {
1610       messageComponent.setCaretPosition(0);
1611     }
1612
1613     if (UIUtil.isUnderNimbusLookAndFeel()) {
1614       messageComponent.setOpaque(false);
1615       messageComponent.setBackground(UIUtil.TRANSPARENT_COLOR);
1616     }
1617     else {
1618       messageComponent.setBackground(UIUtil.getOptionPaneBackground());
1619     }
1620
1621     messageComponent.setForeground(UIUtil.getLabelForeground());
1622     return messageComponent;
1623   }
1624
1625   @NotNull
1626   public static JComponent wrapToScrollPaneIfNeeded(@NotNull JComponent comp, int columns, int lines) {
1627     float fontSize = comp.getFont().getSize2D();
1628     Dimension maxDim = new Dimension((int)(fontSize * columns), (int)(fontSize * lines));
1629     Dimension prefDim = comp.getPreferredSize();
1630     if (prefDim.width <= maxDim.width && prefDim.height <= maxDim.height) return comp;
1631
1632     JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(comp);
1633     scrollPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
1634     scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
1635     scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
1636     int barWidth = UIUtil.getScrollBarWidth();
1637     Dimension preferredSize = new Dimension(
1638       Math.min(prefDim.width, maxDim.width) + barWidth,
1639       Math.min(prefDim.height, maxDim.height) + barWidth);
1640     if (prefDim.width > maxDim.width) { //Too wide single-line message should be wrapped
1641       preferredSize.height = Math.max(preferredSize.height, (int)(4 * fontSize) + barWidth);
1642     }
1643     scrollPane.setPreferredSize(preferredSize);
1644     return scrollPane;
1645   }
1646
1647   protected static class TwoStepConfirmationDialog extends MessageDialog {
1648     private JCheckBox myCheckBox;
1649     private final String myCheckboxText;
1650     private final boolean myChecked;
1651     private final PairFunction<Integer, JCheckBox, Integer> myExitFunc;
1652
1653     public TwoStepConfirmationDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @NotNull String[] options, String checkboxText, boolean checked, final int defaultOptionIndexed,
1654                                      final int focusedOptionIndex, Icon icon, @Nullable final PairFunction<Integer, JCheckBox, Integer> exitFunc) {
1655       myCheckboxText = checkboxText;
1656       myChecked = checked;
1657       myExitFunc = exitFunc;
1658
1659       _init(title, message, options, defaultOptionIndexed, focusedOptionIndex, icon, null);
1660     }
1661
1662     @Override
1663     protected JComponent createNorthPanel() {
1664       JPanel panel = createIconPanel();
1665       JPanel messagePanel = createMessagePanel();
1666
1667       messagePanel.add(createCheckComponent(), BorderLayout.SOUTH);
1668       panel.add(messagePanel, BorderLayout.CENTER);
1669
1670       return panel;
1671     }
1672
1673     @NotNull
1674     protected JComponent createCheckComponent() {
1675       myCheckBox = new JCheckBox(myCheckboxText);
1676       myCheckBox.setSelected(myChecked);
1677       return myCheckBox;
1678     }
1679
1680     @Override
1681     public int getExitCode() {
1682       final int exitCode = super.getExitCode();
1683       if (myExitFunc != null) {
1684         return myExitFunc.fun(exitCode, myCheckBox);
1685       }
1686
1687       boolean checkBoxSelected = (myCheckBox != null && myCheckBox.isSelected());
1688
1689       boolean okExitCode = (exitCode == OK_EXIT_CODE);
1690
1691       return checkBoxSelected && okExitCode ? OK_EXIT_CODE : CANCEL_EXIT_CODE;
1692     }
1693
1694     @Override
1695     public JComponent getPreferredFocusedComponent() {
1696       return myDefaultOptionIndex == -1 ? myCheckBox : super.getPreferredFocusedComponent();
1697     }
1698
1699     @Override
1700     protected JComponent createCenterPanel() {
1701       return null;
1702     }
1703   }
1704
1705   public static class InputDialog extends MessageDialog {
1706     protected JTextComponent myField;
1707     private final InputValidator myValidator;
1708
1709     public InputDialog(@Nullable Project project,
1710                        String message,
1711                        @Nls(capitalization = Nls.Capitalization.Title) String title,
1712                        @Nullable Icon icon,
1713                        @Nullable String initialValue,
1714                        @Nullable InputValidator validator,
1715                        @NotNull String[] options,
1716                        int defaultOption) {
1717       super(project, message, title, options, defaultOption, icon, true);
1718       myValidator = validator;
1719       myField.setText(initialValue);
1720       enableOkAction();
1721     }
1722
1723     public InputDialog(@Nullable Project project,
1724                        String message,
1725                        @Nls(capitalization = Nls.Capitalization.Title) String title,
1726                        @Nullable Icon icon,
1727                        @Nullable String initialValue,
1728                        @Nullable InputValidator validator) {
1729       this(project, message, title, icon, initialValue, validator, new String[]{OK_BUTTON, CANCEL_BUTTON}, 0);
1730     }
1731
1732     public InputDialog(@NotNull Component parent,
1733                        String message,
1734                        @Nls(capitalization = Nls.Capitalization.Title) String title,
1735                        @Nullable Icon icon,
1736                        @Nullable String initialValue,
1737                        @Nullable InputValidator validator) {
1738       super(parent, message, title, new String[]{OK_BUTTON, CANCEL_BUTTON}, 0, icon, true);
1739       myValidator = validator;
1740       myField.setText(initialValue);
1741       enableOkAction();
1742     }
1743
1744     public InputDialog(String message,
1745                        @Nls(capitalization = Nls.Capitalization.Title) String title,
1746                        @Nullable Icon icon,
1747                        @Nullable String initialValue,
1748                        @Nullable InputValidator validator) {
1749       super(message, title, new String[]{OK_BUTTON, CANCEL_BUTTON}, 0, icon, true);
1750       myValidator = validator;
1751       myField.setText(initialValue);
1752       enableOkAction();
1753     }
1754
1755     private void enableOkAction() {
1756       getOKAction().setEnabled(myValidator == null || myValidator.checkInput(myField.getText().trim()));
1757     }
1758
1759     @NotNull
1760     @Override
1761     protected Action[] createActions() {
1762       final Action[] actions = new Action[myOptions.length];
1763       for (int i = 0; i < myOptions.length; i++) {
1764         String option = myOptions[i];
1765         final int exitCode = i;
1766         if (i == 0) { // "OK" is default button. It has index 0.
1767           actions[i] = getOKAction();
1768           actions[i].putValue(DEFAULT_ACTION, Boolean.TRUE);
1769           myField.getDocument().addDocumentListener(new DocumentAdapter() {
1770             @Override
1771             public void textChanged(DocumentEvent event) {
1772               final String text = myField.getText().trim();
1773               actions[exitCode].setEnabled(myValidator == null || myValidator.checkInput(text));
1774               if (myValidator instanceof InputValidatorEx) {
1775                 setErrorText(((InputValidatorEx) myValidator).getErrorText(text), myField);
1776               }
1777             }
1778           });
1779         }
1780         else {
1781           actions[i] = new AbstractAction(option) {
1782             @Override
1783             public void actionPerformed(ActionEvent e) {
1784               close(exitCode);
1785             }
1786           };
1787         }
1788       }
1789       return actions;
1790     }
1791
1792     @Override
1793     protected void doOKAction() {
1794       String inputString = myField.getText().trim();
1795       if (myValidator == null ||
1796           myValidator.checkInput(inputString) &&
1797           myValidator.canClose(inputString)) {
1798         close(0);
1799       }
1800     }
1801
1802     @Override
1803     protected JComponent createCenterPanel() {
1804       return null;
1805     }
1806
1807     @Override
1808     protected JComponent createNorthPanel() {
1809       JPanel panel = createIconPanel();
1810
1811       JPanel messagePanel = createMessagePanel();
1812       panel.add(messagePanel, BorderLayout.CENTER);
1813
1814       return panel;
1815     }
1816
1817     protected JPanel createMessagePanel() {
1818       JPanel messagePanel = new JPanel(new BorderLayout());
1819       if (myMessage != null) {
1820         JComponent textComponent = createTextComponent();
1821         messagePanel.add(textComponent, BorderLayout.NORTH);
1822       }
1823
1824       myField = createTextFieldComponent();
1825       messagePanel.add(createScrollableTextComponent(), BorderLayout.SOUTH);
1826
1827       return messagePanel;
1828     }
1829
1830     protected JComponent createScrollableTextComponent() {
1831       return myField;
1832     }
1833
1834     protected JComponent createTextComponent() {
1835       JComponent textComponent;
1836       if (BasicHTML.isHTMLString(myMessage)) {
1837         textComponent = createMessageComponent(myMessage);
1838       }
1839       else {
1840         JLabel textLabel = new JLabel(myMessage);
1841         textLabel.setUI(new MultiLineLabelUI());
1842         textComponent = textLabel;
1843       }
1844       textComponent.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 20));
1845       return textComponent;
1846     }
1847
1848     public JTextComponent getTextField() {
1849       return myField;
1850     }
1851
1852     protected JTextComponent createTextFieldComponent() {
1853       return new JTextField(30);
1854     }
1855
1856     @Override
1857     public JComponent getPreferredFocusedComponent() {
1858       return myField;
1859     }
1860
1861     @Nullable
1862     public String getInputString() {
1863       if (getExitCode() == 0) {
1864         return myField.getText().trim();
1865       }
1866       return null;
1867     }
1868   }
1869
1870   protected static class MultilineInputDialog extends InputDialog {
1871     public MultilineInputDialog(Project project,
1872                                 String message,
1873                                 @Nls(capitalization = Nls.Capitalization.Title) String title,
1874                                 @Nullable Icon icon,
1875                                 @Nullable String initialValue,
1876                                 @Nullable InputValidator validator,
1877                                 @NotNull String[] options,
1878                                 int defaultOption) {
1879       super(project, message, title, icon, initialValue, validator, options, defaultOption);
1880     }
1881
1882     @Override
1883     protected JTextComponent createTextFieldComponent() {
1884       return new JTextArea(7, 50);
1885     }
1886
1887     @Override
1888     protected JComponent createScrollableTextComponent() {
1889       return new JBScrollPane(myField);
1890     }
1891   }
1892
1893   protected static class PasswordInputDialog extends InputDialog {
1894     public PasswordInputDialog(String message,
1895                                @Nls(capitalization = Nls.Capitalization.Title) String title,
1896                                @Nullable Icon icon,
1897                                @Nullable InputValidator validator) {
1898       super(message, title, icon, null, validator);
1899     }
1900
1901     public PasswordInputDialog(Project project,
1902                                String message,
1903                                @Nls(capitalization = Nls.Capitalization.Title) String title,
1904                                @Nullable Icon icon,
1905                                @Nullable InputValidator validator) {
1906       super(project, message, title, icon, null, validator);
1907     }
1908
1909     @Override
1910     protected JTextComponent createTextFieldComponent() {
1911       return new JPasswordField(30);
1912     }
1913   }
1914
1915   protected static class InputDialogWithCheckbox extends InputDialog {
1916     private JCheckBox myCheckBox;
1917
1918     public InputDialogWithCheckbox(String message,
1919                                    @Nls(capitalization = Nls.Capitalization.Title) String title,
1920                                    String checkboxText,
1921                                    boolean checked,
1922                                    boolean checkboxEnabled,
1923                                    @Nullable Icon icon,
1924                                    @Nullable String initialValue,
1925                                    @Nullable InputValidator validator) {
1926       super(message, title, icon, initialValue, validator);
1927       myCheckBox.setText(checkboxText);
1928       myCheckBox.setSelected(checked);
1929       myCheckBox.setEnabled(checkboxEnabled);
1930     }
1931
1932     @Override
1933     protected JPanel createMessagePanel() {
1934       JPanel messagePanel = new JPanel(new BorderLayout());
1935       if (myMessage != null) {
1936         JComponent textComponent = createTextComponent();
1937         messagePanel.add(textComponent, BorderLayout.NORTH);
1938       }
1939
1940       myField = createTextFieldComponent();
1941       messagePanel.add(createScrollableTextComponent(), BorderLayout.CENTER);
1942
1943       myCheckBox = new JCheckBox();
1944       messagePanel.add(myCheckBox, BorderLayout.SOUTH);
1945
1946       return messagePanel;
1947     }
1948
1949     public Boolean isChecked() {
1950       return myCheckBox.isSelected();
1951     }
1952   }
1953
1954   /** It looks awful! */
1955   @Deprecated
1956   protected static class ChooseDialog extends MessageDialog {
1957     private ComboBox myComboBox;
1958     private InputValidator myValidator;
1959
1960     public ChooseDialog(Project project,
1961                         String message,
1962                         @Nls(capitalization = Nls.Capitalization.Title) String title,
1963                         @Nullable Icon icon,
1964                         String[] values,
1965                         String initialValue,
1966                         @NotNull String[] options,
1967                         int defaultOption) {
1968       super(project, message, title, options, defaultOption, icon, true);
1969       myComboBox.setModel(new DefaultComboBoxModel(values));
1970       myComboBox.setSelectedItem(initialValue);
1971     }
1972
1973     public ChooseDialog(Project project, String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @Nullable Icon icon, String[] values, String initialValue) {
1974       this(project, message, title, icon, values, initialValue, new String[]{OK_BUTTON, CANCEL_BUTTON}, 0);
1975     }
1976
1977     public ChooseDialog(@NotNull Component parent, String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @Nullable Icon icon, String[] values, String initialValue) {
1978       super(parent, message, title, new String[]{OK_BUTTON, CANCEL_BUTTON}, 0, icon);
1979       myComboBox.setModel(new DefaultComboBoxModel(values));
1980       myComboBox.setSelectedItem(initialValue);
1981     }
1982
1983     public ChooseDialog(String message, @Nls(capitalization = Nls.Capitalization.Title) String title, @Nullable Icon icon, String[] values, String initialValue) {
1984       super(message, title, new String[]{OK_BUTTON, CANCEL_BUTTON}, 0, icon);
1985       myComboBox.setModel(new DefaultComboBoxModel(values));
1986       myComboBox.setSelectedItem(initialValue);
1987     }
1988
1989     @NotNull
1990     @Override
1991     protected Action[] createActions() {
1992       final Action[] actions = new Action[myOptions.length];
1993       for (int i = 0; i < myOptions.length; i++) {
1994         String option = myOptions[i];
1995         final int exitCode = i;
1996         if (i == myDefaultOptionIndex) {
1997           actions[i] = new AbstractAction(option) {
1998             @Override
1999             public void actionPerformed(ActionEvent e) {
2000               if (myValidator == null || myValidator.checkInput(myComboBox.getSelectedItem().toString().trim())) {
2001                 close(exitCode);
2002               }
2003             }
2004           };
2005           actions[i].putValue(DEFAULT_ACTION, Boolean.TRUE);
2006           myComboBox.addItemListener(new ItemListener() {
2007             @Override
2008             public void itemStateChanged(ItemEvent e) {
2009               actions[exitCode].setEnabled(myValidator == null || myValidator.checkInput(myComboBox.getSelectedItem().toString().trim()));
2010             }
2011           });
2012           final JTextField textField = (JTextField)myComboBox.getEditor().getEditorComponent();
2013           textField.getDocument().addDocumentListener(new DocumentAdapter() {
2014             @Override
2015             public void textChanged(DocumentEvent event) {
2016               actions[exitCode].setEnabled(myValidator == null || myValidator.checkInput(textField.getText().trim()));
2017             }
2018           });
2019         }
2020         else { // "Cancel" action
2021           actions[i] = new AbstractAction(option) {
2022             @Override
2023             public void actionPerformed(ActionEvent e) {
2024               close(exitCode);
2025             }
2026           };
2027         }
2028       }
2029       return actions;
2030     }
2031
2032     @Override
2033     protected JComponent createCenterPanel() {
2034       return null;
2035     }
2036
2037     @Override
2038     protected JComponent createNorthPanel() {
2039       JPanel panel = createIconPanel();
2040       JPanel messagePanel = createMessagePanel();
2041
2042       myComboBox = new ComboBox(220);
2043       messagePanel.add(myComboBox, BorderLayout.SOUTH);
2044       panel.add(messagePanel, BorderLayout.CENTER);
2045       return panel;
2046     }
2047
2048     @Override
2049     protected void doOKAction() {
2050       String inputString = myComboBox.getSelectedItem().toString().trim();
2051       if (myValidator == null ||
2052           myValidator.checkInput(inputString) &&
2053           myValidator.canClose(inputString)) {
2054         super.doOKAction();
2055       }
2056     }
2057
2058     @Override
2059     public JComponent getPreferredFocusedComponent() {
2060       return myComboBox;
2061     }
2062
2063     @Nullable
2064     public String getInputString() {
2065       if (getExitCode() == 0) {
2066         return myComboBox.getSelectedItem().toString();
2067       }
2068       return null;
2069     }
2070
2071     public int getSelectedIndex() {
2072       if (getExitCode() == 0) {
2073         return myComboBox.getSelectedIndex();
2074       }
2075       return -1;
2076     }
2077
2078     public JComboBox getComboBox() {
2079       return myComboBox;
2080     }
2081
2082     public void setValidator(@Nullable InputValidator validator) {
2083       myValidator = validator;
2084     }
2085   }
2086 }