SSR: don't enable "apply constraint within type hierarchy" when not searching java
[idea/community.git] / platform / structuralsearch / source / com / intellij / structuralsearch / plugin / ui / SearchDialog.java
1 package com.intellij.structuralsearch.plugin.ui;
2
3 import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
4 import com.intellij.codeInsight.template.impl.Variable;
5 import com.intellij.find.FindBundle;
6 import com.intellij.find.FindSettings;
7 import com.intellij.ide.IdeBundle;
8 import com.intellij.ide.util.scopeChooser.ScopeChooserCombo;
9 import com.intellij.lang.Language;
10 import com.intellij.lang.LanguageUtil;
11 import com.intellij.openapi.application.ApplicationManager;
12 import com.intellij.openapi.application.Result;
13 import com.intellij.openapi.command.WriteCommandAction;
14 import com.intellij.openapi.diagnostic.Logger;
15 import com.intellij.openapi.editor.Document;
16 import com.intellij.openapi.editor.Editor;
17 import com.intellij.openapi.editor.EditorFactory;
18 import com.intellij.openapi.editor.SelectionModel;
19 import com.intellij.openapi.editor.event.DocumentEvent;
20 import com.intellij.openapi.editor.event.DocumentListener;
21 import com.intellij.openapi.fileEditor.FileEditorManager;
22 import com.intellij.openapi.fileTypes.FileType;
23 import com.intellij.openapi.fileTypes.LanguageFileType;
24 import com.intellij.openapi.fileTypes.impl.FileTypeRenderer;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.ui.ComboBox;
27 import com.intellij.openapi.ui.DialogWrapper;
28 import com.intellij.openapi.util.Disposer;
29 import com.intellij.openapi.util.TextRange;
30 import com.intellij.openapi.wm.ToolWindow;
31 import com.intellij.openapi.wm.ToolWindowId;
32 import com.intellij.openapi.wm.ToolWindowManager;
33 import com.intellij.psi.PsiDocumentManager;
34 import com.intellij.psi.PsiElement;
35 import com.intellij.psi.PsiFile;
36 import com.intellij.psi.codeStyle.CodeStyleManager;
37 import com.intellij.psi.search.GlobalSearchScope;
38 import com.intellij.psi.search.SearchScope;
39 import com.intellij.structuralsearch.*;
40 import com.intellij.structuralsearch.impl.matcher.MatcherImpl;
41 import com.intellij.structuralsearch.plugin.StructuralSearchPlugin;
42 import com.intellij.ui.ComboboxSpeedSearch;
43 import com.intellij.ui.IdeBorderFactory;
44 import com.intellij.ui.ListCellRendererWrapper;
45 import com.intellij.ui.TitledSeparator;
46 import com.intellij.util.Alarm;
47 import org.jetbrains.annotations.NonNls;
48 import org.jetbrains.annotations.NotNull;
49
50 import javax.swing.*;
51 import java.awt.*;
52 import java.awt.event.ActionEvent;
53 import java.awt.event.ItemEvent;
54 import java.awt.event.ItemListener;
55 import java.util.*;
56 import java.util.List;
57
58 /**
59  *  Class to show the user the request for search
60  */
61 @SuppressWarnings({"RefusedBequest", "AssignmentToStaticFieldFromInstanceMethod"})
62 public class SearchDialog extends DialogWrapper {
63   protected SearchContext searchContext;
64
65   // text for search
66   protected Editor searchCriteriaEdit;
67
68   // options of search scope
69   private ScopeChooserCombo myScopeChooserCombo;
70
71   private JCheckBox recursiveMatching;
72   private JCheckBox caseSensitiveMatch;
73
74   private JComboBox fileTypes;
75   private JComboBox contexts;
76   private JComboBox dialects;
77   private JLabel status;
78   private JLabel statusText;
79
80   protected SearchModel model;
81   private JCheckBox openInNewTab;
82   private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
83
84   public static final String USER_DEFINED = SSRBundle.message("new.template.defaultname");
85   protected final ExistingTemplatesComponent existingTemplatesComponent;
86
87   private boolean useLastConfiguration;
88
89   @NonNls private FileType ourFtSearchVariant = StructuralSearchUtil.getDefaultFileType();
90   private static Language ourDialect = null;
91   private static String ourContext = null;
92
93   private final boolean myShowScopePanel;
94   private final boolean myRunFindActionOnClose;
95   private boolean myDoingOkAction;
96
97   private String mySavedEditorText;
98   private JPanel myContentPanel;
99   private JComponent myEditorPanel;
100
101   public SearchDialog(SearchContext searchContext) {
102     this(searchContext, true, true);
103   }
104
105   public SearchDialog(SearchContext searchContext, boolean showScope, boolean runFindActionOnClose) {
106     super(searchContext.getProject(), true);
107
108     if (showScope) setModal(false);
109     myShowScopePanel = showScope;
110     myRunFindActionOnClose = runFindActionOnClose;
111     this.searchContext = (SearchContext)searchContext.clone();
112     setTitle(getDefaultTitle());
113
114     if (runFindActionOnClose) {
115       setOKButtonText(FindBundle.message("find.dialog.find.button"));
116     }
117
118     existingTemplatesComponent = ExistingTemplatesComponent.getInstance(this.searchContext.getProject());
119     model = new SearchModel(createConfiguration());
120
121     init();
122   }
123
124   public void setUseLastConfiguration(boolean useLastConfiguration) {
125     this.useLastConfiguration = useLastConfiguration;
126   }
127
128   public void setSearchPattern(final Configuration config) {
129     model.setShadowConfig(config);
130     setValuesFromConfig(config);
131     initiateValidation();
132   }
133
134   protected Editor createEditor(final SearchContext searchContext, String text) {
135     Editor editor = null;
136
137     if (fileTypes != null) {
138       final FileType fileType = (FileType)fileTypes.getSelectedItem();
139       final Language dialect = (Language)dialects.getSelectedItem();
140
141       final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(fileType);
142       if (profile != null) {
143         editor = profile.createEditor(searchContext, fileType, dialect, text, useLastConfiguration);
144       }
145     }
146
147     if (editor == null) {
148       final EditorFactory factory = EditorFactory.getInstance();
149       final Document document = factory.createDocument("");
150       editor = factory.createEditor(document, searchContext.getProject());
151       editor.getSettings().setFoldingOutlineShown(false);
152     }
153
154     editor.getDocument().addDocumentListener(new DocumentListener() {
155       @Override
156       public void beforeDocumentChange(final DocumentEvent event) {
157       }
158
159       @Override
160       public void documentChanged(final DocumentEvent event) {
161         initiateValidation();
162       }
163     });
164
165     return editor;
166   }
167
168   private void initiateValidation() {
169     myAlarm.cancelAllRequests();
170     myAlarm.addRequest(new Runnable() {
171
172       @Override
173       public void run() {
174         try {
175           ApplicationManager.getApplication().runReadAction(new Runnable() {
176             @Override
177             public void run() {
178               final boolean valid = isValid();
179               ApplicationManager.getApplication().invokeLater(new Runnable() {
180                 @Override
181                 public void run() {
182                   if (!valid) {
183                     getOKAction().setEnabled(false);
184                   }
185                   else {
186                     getOKAction().setEnabled(true);
187                     reportMessage(null, null);
188                   }
189                 }
190               });
191             }
192           });
193         }
194         catch (RuntimeException e) {
195           Logger.getInstance(SearchDialog.class).error(e);
196         }
197       }
198     }, 500);
199   }
200
201   protected void buildOptions(JPanel searchOptions) {
202     recursiveMatching = new JCheckBox(SSRBundle.message("recursive.matching.checkbox"), true);
203     if (isRecursiveSearchEnabled()) {
204       searchOptions.add(UIUtil.createOptionLine(recursiveMatching));
205     }
206
207     caseSensitiveMatch = new JCheckBox(FindBundle.message("find.options.case.sensitive"), true);
208     searchOptions.add(UIUtil.createOptionLine(caseSensitiveMatch));
209
210     final List<FileType> types = new ArrayList<FileType>();
211
212     for (FileType fileType : StructuralSearchUtil.getSuitableFileTypes()) {
213       if (StructuralSearchUtil.getProfileByFileType(fileType) != null) {
214         types.add(fileType);
215       }
216     }
217     Collections.sort(types, new Comparator<FileType>() {
218       @Override
219       public int compare(FileType o1, FileType o2) {
220         return o1.getName().compareToIgnoreCase(o2.getName());
221       }
222     });
223
224     final DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel(types.toArray(new FileType[types.size()]));
225     comboBoxModel.setSelectedItem(ourFtSearchVariant);
226     fileTypes = new ComboBox(comboBoxModel);
227     fileTypes.setRenderer(new FileTypeRenderer());
228     new ComboboxSpeedSearch(fileTypes) {
229       @Override
230       protected String getElementText(Object element) {
231         return ((FileType)element).getName();
232       }
233     };
234     fileTypes.addItemListener(new ItemListener() {
235       @Override
236       public void itemStateChanged(ItemEvent e) {
237         updateDialectsAndContexts();
238         updateEditor();
239       }
240     });
241
242     contexts = new JComboBox(new DefaultComboBoxModel());
243     contexts.setPreferredSize(new Dimension(60, -1));
244
245     dialects = new JComboBox(new DefaultComboBoxModel());
246     dialects.setRenderer(new ListCellRendererWrapper() {
247       @Override
248       public void customize(JList list, Object value, int index, boolean selected, boolean hasFocus) {
249         if (value == null) {
250           setText("None");
251         }
252         else if (value instanceof Language) {
253           setText(((Language)value).getDisplayName());
254         }
255       }
256     });
257     dialects.addItemListener(new ItemListener() {
258       @Override
259       public void itemStateChanged(ItemEvent e) {
260         updateEditor();
261       }
262     });
263     new ComboboxSpeedSearch(dialects);
264     dialects.setPreferredSize(new Dimension(120, -1));
265
266     final JLabel jLabel = new JLabel(SSRBundle.message("search.dialog.file.type.label"));
267     final JLabel jLabel2 = new JLabel(SSRBundle.message("search.dialog.context.label"));
268     final JLabel jLabel3 = new JLabel(SSRBundle.message("search.dialog.file.dialect.label"));
269     searchOptions.add(
270       UIUtil.createOptionLine(
271         new JComponent[]{
272           jLabel,
273           fileTypes,
274           (JComponent)Box.createHorizontalStrut(8),
275           jLabel2,
276           contexts,
277           (JComponent)Box.createHorizontalStrut(8),
278           jLabel3,
279           dialects,
280         }
281       )
282     );
283
284     jLabel.setLabelFor(fileTypes);
285     jLabel2.setLabelFor(contexts);
286     jLabel3.setLabelFor(dialects);
287
288     detectFileTypeAndDialect();
289
290     fileTypes.setSelectedItem(ourFtSearchVariant);
291     fileTypes.addItemListener(new ItemListener() {
292       @Override
293       public void itemStateChanged(ItemEvent e) {
294         if (e.getStateChange() == ItemEvent.SELECTED) initiateValidation();
295       }
296     });
297
298     dialects.setSelectedItem(ourDialect);
299     contexts.setSelectedItem(ourContext);
300
301     updateDialectsAndContexts();
302   }
303
304   private void updateEditor() {
305     if (myContentPanel != null) {
306       if (myEditorPanel != null) {
307         myContentPanel.remove(myEditorPanel);
308       }
309       disposeEditorContent();
310       myEditorPanel = createEditorContent();
311       myContentPanel.add(myEditorPanel, BorderLayout.CENTER);
312       myContentPanel.revalidate();
313     }
314   }
315
316   private void updateDialectsAndContexts() {
317     final FileType fileType = (FileType)fileTypes.getSelectedItem();
318     if (fileType instanceof LanguageFileType) {
319       Language language = ((LanguageFileType)fileType).getLanguage();
320       Language[] languageDialects = LanguageUtil.getLanguageDialects(language);
321       Arrays.sort(languageDialects, new Comparator<Language>() {
322         @Override
323         public int compare(Language o1, Language o2) {
324           return o1.getDisplayName().compareTo(o2.getDisplayName());
325         }
326       });
327       Language[] variants = new Language[languageDialects.length + 1];
328       variants[0] = null;
329       System.arraycopy(languageDialects, 0, variants, 1, languageDialects.length);
330       dialects.setModel(new DefaultComboBoxModel(variants));
331       dialects.setEnabled(variants.length > 1);
332     }
333
334     final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(fileType);
335
336     if (profile instanceof StructuralSearchProfileBase) {
337       final String[] contextNames = ((StructuralSearchProfileBase)profile).getContextNames();
338       if (contextNames.length > 0) {
339         contexts.setModel(new DefaultComboBoxModel(contextNames));
340         contexts.setSelectedItem(contextNames[0]);
341         contexts.setEnabled(true);
342         return;
343       }
344     }
345     contexts.setSelectedItem(null);
346     contexts.setEnabled(false);
347   }
348
349   private void detectFileTypeAndDialect() {
350     final PsiFile file = searchContext.getFile();
351     if (file != null) {
352       PsiElement context = null;
353
354       if (searchContext.getEditor() != null) {
355         context = file.findElementAt(searchContext.getEditor().getCaretModel().getOffset());
356         if (context != null) {
357           context = context.getParent();
358         }
359       }
360       if (context == null) {
361         context = file;
362       }
363
364       FileType detectedFileType = null;
365
366       StructuralSearchProfile profile = StructuralSearchUtil.getProfileByPsiElement(context);
367       if (profile != null) {
368         FileType fileType = profile.detectFileType(context);
369         if (fileType != null) {
370           detectedFileType = fileType;
371         }
372       }
373
374       if (detectedFileType == null) {
375         for (FileType fileType : StructuralSearchUtil.getSuitableFileTypes()) {
376           if (fileType instanceof LanguageFileType && ((LanguageFileType)fileType).getLanguage().equals(context.getLanguage())) {
377             detectedFileType = fileType;
378             break;
379           }
380         }
381       }
382
383       ourFtSearchVariant = detectedFileType != null ?
384                            detectedFileType :
385                            StructuralSearchUtil.getDefaultFileType();
386
387       // todo: detect dialect
388
389       /*if (file.getLanguage() == StdLanguages.HTML ||
390           (file.getFileType() == StdFileTypes.JSP &&
391            contextLanguage == StdLanguages.HTML
392           )
393         ) {
394         ourFileType = "html";
395       }
396       else if (file.getLanguage() == StdLanguages.XHTML ||
397                (file.getFileType() == StdFileTypes.JSPX &&
398                 contextLanguage == StdLanguages.HTML
399                )) {
400         ourFileType = "xml";
401       }
402       else {
403         ourFileType = DEFAULT_TYPE_NAME;
404       }*/
405     }
406   }
407
408   protected boolean isRecursiveSearchEnabled() {
409     return true;
410   }
411
412   public void setValuesFromConfig(Configuration configuration) {
413     //searchCriteriaEdit.putUserData(SubstitutionShortInfoHandler.CURRENT_CONFIGURATION_KEY, configuration);
414
415     setDialogTitle(configuration);
416     final MatchOptions matchOptions = configuration.getMatchOptions();
417
418     UIUtil.setContent(
419       searchCriteriaEdit,
420       matchOptions.getSearchPattern(),
421       0,
422       searchCriteriaEdit.getDocument().getTextLength(),
423       searchContext.getProject()
424     );
425
426     model.getConfig().getMatchOptions().setSearchPattern(
427       matchOptions.getSearchPattern()
428     );
429
430     recursiveMatching.setSelected(
431       isRecursiveSearchEnabled() && matchOptions.isRecursiveSearch()
432     );
433
434     caseSensitiveMatch.setSelected(
435       matchOptions.isCaseSensitiveMatch()
436     );
437
438     model.getConfig().getMatchOptions().clearVariableConstraints();
439     for (String name : matchOptions.getVariableConstraintNames()) {
440       final MatchVariableConstraint constraint = (MatchVariableConstraint)matchOptions.getVariableConstraint(name).clone();
441       model.getConfig().getMatchOptions().addVariableConstraint(constraint);
442     }
443
444     MatchOptions options = configuration.getMatchOptions();
445     StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(options.getFileType());
446     assert profile != null;
447     fileTypes.setSelectedItem(options.getFileType());
448     dialects.setSelectedItem(options.getDialect());
449     if (options.getPatternContext() != null) {
450       contexts.setSelectedItem(options.getPatternContext());
451     }
452   }
453
454   private void setDialogTitle(final Configuration configuration) {
455     setTitle(getDefaultTitle() + " - " + configuration.getName());
456   }
457
458   public Configuration createConfiguration() {
459     SearchConfiguration configuration = new SearchConfiguration();
460     configuration.setName(USER_DEFINED);
461     return configuration;
462   }
463
464   protected void addOrReplaceSelection(final String selection) {
465     addOrReplaceSelectionForEditor(selection, searchCriteriaEdit);
466   }
467
468   protected final void addOrReplaceSelectionForEditor(final String selection, Editor editor) {
469     final Project project = searchContext.getProject();
470     UIUtil.setContent(editor, selection, 0, -1, project);
471     final Document document = editor.getDocument();
472     editor.getSelectionModel().setSelection(0, document.getTextLength());
473     final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
474     documentManager.commitDocument(document);
475     final PsiFile file = documentManager.getPsiFile(document);
476     if (file == null) return;
477
478     new WriteCommandAction(project, file) {
479       @Override protected void run(@NotNull Result result) throws Throwable {
480         CodeStyleManager.getInstance(project).adjustLineIndent(file, new TextRange(0, document.getTextLength()));
481       }
482     }.execute();
483   }
484
485   protected void startSearching() {
486     new SearchCommand(model.getConfig(), searchContext).startSearching();
487   }
488
489   protected String getDefaultTitle() {
490     return SSRBundle.message("structural.search.title");
491   }
492
493   protected JComponent createEditorContent() {
494     JPanel result = new JPanel(new BorderLayout());
495
496     result.add(BorderLayout.NORTH, new JLabel(SSRBundle.message("search.template")));
497     searchCriteriaEdit = createEditor(searchContext, mySavedEditorText != null ? mySavedEditorText : "");
498     result.add(BorderLayout.CENTER, searchCriteriaEdit.getComponent());
499     result.setMinimumSize(new Dimension(150, 100));
500
501     return result;
502   }
503
504   protected int getRowsCount() {
505     return 4;
506   }
507
508   @Override
509   protected JComponent createCenterPanel() {
510     myContentPanel = new JPanel(new BorderLayout());
511     myEditorPanel = createEditorContent();
512     myContentPanel.add(BorderLayout.CENTER, myEditorPanel);
513     myContentPanel.add(BorderLayout.SOUTH, Box.createVerticalStrut(8));
514     JComponent centerPanel = new JPanel(new BorderLayout());
515     {
516       JPanel panel = new JPanel(new BorderLayout());
517       panel.add(BorderLayout.CENTER, myContentPanel);
518       panel.add(BorderLayout.SOUTH, createTemplateManagementButtons());
519       centerPanel.add(BorderLayout.CENTER, panel);
520     }
521
522     JPanel optionsContent = new JPanel(new BorderLayout());
523     centerPanel.add(BorderLayout.SOUTH, optionsContent);
524
525     JPanel searchOptions = new JPanel();
526     searchOptions.setLayout(new GridLayout(getRowsCount(), 1, 0, 0));
527     searchOptions.setBorder(IdeBorderFactory.createTitledBorder(SSRBundle.message("ssdialog.options.group.border"),
528                                                                 true));
529
530     myScopeChooserCombo = new ScopeChooserCombo(
531       searchContext.getProject(),
532       true,
533       false,
534       FindSettings.getInstance().getDefaultScopeName()
535     );
536     Disposer.register(myDisposable, myScopeChooserCombo);
537     JPanel allOptions = new JPanel(new BorderLayout());
538     if (myShowScopePanel) {
539       JPanel scopePanel = new JPanel(new GridBagLayout());
540
541       TitledSeparator separator = new TitledSeparator(SSRBundle.message("search.dialog.scope.label"), myScopeChooserCombo.getComboBox());
542       scopePanel.add(separator, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
543                                                        new Insets(5, 0, 0, 0), 0, 0));
544
545       scopePanel.add(myScopeChooserCombo, new GridBagConstraints(0, 1, 1, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
546                                                                  new Insets(0, 10, 0, 0), 0, 0));
547
548       allOptions.add(
549         scopePanel,
550         BorderLayout.SOUTH
551       );
552
553       myScopeChooserCombo.getComboBox().addItemListener(new ItemListener() {
554         @Override
555         public void itemStateChanged(ItemEvent e) {
556           initiateValidation();
557         }
558       });
559     }
560
561     buildOptions(searchOptions);
562
563     allOptions.add(searchOptions, BorderLayout.CENTER);
564     optionsContent.add(allOptions, BorderLayout.CENTER);
565
566     if (myRunFindActionOnClose) {
567       JPanel panel = new JPanel(new BorderLayout());
568       panel.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 0));
569       openInNewTab = new JCheckBox(FindBundle.message("find.open.in.new.tab.checkbox"));
570       openInNewTab.setSelected(FindSettings.getInstance().isShowResultsInSeparateView());
571       ToolWindow findWindow = ToolWindowManager.getInstance(searchContext.getProject()).getToolWindow(ToolWindowId.FIND);
572       openInNewTab.setEnabled(findWindow != null && findWindow.isAvailable());
573       panel.add(openInNewTab, BorderLayout.EAST);
574
575       optionsContent.add(BorderLayout.SOUTH, panel);
576     }
577
578     updateEditor();
579     return centerPanel;
580   }
581
582
583   @Override
584   protected JComponent createSouthPanel() {
585     final JPanel statusPanel = new JPanel(new BorderLayout(5, 0));
586     statusPanel.add(super.createSouthPanel(), BorderLayout.NORTH);
587     statusPanel.add(statusText = new JLabel(SSRBundle.message("status.message")), BorderLayout.WEST);
588     statusPanel.add(status = new JLabel(), BorderLayout.CENTER);
589     return statusPanel;
590   }
591
592   private JPanel createTemplateManagementButtons() {
593     JPanel panel = new JPanel(null);
594     panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
595     panel.add(Box.createHorizontalGlue());
596
597     panel.add(
598       createJButtonForAction(new AbstractAction() {
599         {
600           putValue(NAME, SSRBundle.message("save.template.text.button"));
601         }
602
603         @Override
604         public void actionPerformed(ActionEvent e) {
605           String name = showSaveTemplateAsDialog();
606
607           if (name != null) {
608             final Project project = searchContext.getProject();
609             final ConfigurationManager configurationManager = StructuralSearchPlugin.getInstance(project).getConfigurationManager();
610             final Collection<Configuration> configurations = configurationManager.getConfigurations();
611
612             if (configurations != null) {
613               name = ConfigurationManager.findAppropriateName(configurations, name, project);
614               if (name == null) return;
615             }
616
617             final Configuration configuration = model.getConfig();
618             configuration.setName(name);
619             setValuesToConfig(configuration);
620             setDialogTitle(configuration);
621
622             if (model.getShadowConfig() == null || model.getShadowConfig().isPredefined()) {
623               filterOutUnusedVariableConstraints(configuration);
624               existingTemplatesComponent.addConfigurationToUserTemplates(configuration);
625             }
626             else {  // ???
627               setValuesToConfig(model.getShadowConfig());
628               model.getShadowConfig().setName(name);
629             }
630           }
631         }
632       })
633     );
634
635     panel.add(
636       Box.createHorizontalStrut(8)
637     );
638
639     panel.add(
640       createJButtonForAction(
641         new AbstractAction() {
642           {
643             putValue(NAME, SSRBundle.message("edit.variables.button"));
644           }
645
646           @Override
647           public void actionPerformed(ActionEvent e) {
648             EditVarConstraintsDialog.setProject(searchContext.getProject());
649             new EditVarConstraintsDialog(
650               searchContext.getProject(),
651               model, getVariablesFromListeners(),
652               (FileType)fileTypes.getSelectedItem()
653             ).show();
654             initiateValidation();
655             EditVarConstraintsDialog.setProject(null);
656           }
657         }
658       )
659     );
660
661     panel.add(
662       Box.createHorizontalStrut(8)
663     );
664
665     panel.add(
666       createJButtonForAction(
667         new AbstractAction() {
668           {
669             putValue(NAME, SSRBundle.message("history.button"));
670           }
671
672           @Override
673           public void actionPerformed(ActionEvent e) {
674             SelectTemplateDialog dialog = new SelectTemplateDialog(searchContext.getProject(), true, isReplaceDialog());
675             if (!dialog.showAndGet()) {
676               return;
677             }
678             Configuration[] configurations = dialog.getSelectedConfigurations();
679             if (configurations.length == 1) {
680               setSearchPattern(configurations[0]);
681             }
682           }
683         }
684       )
685     );
686
687     panel.add(
688       Box.createHorizontalStrut(8)
689     );
690
691     panel.add(
692       createJButtonForAction(
693         new AbstractAction() {
694           {
695             putValue(NAME, SSRBundle.message("copy.existing.template.button"));
696           }
697
698           @Override
699           public void actionPerformed(ActionEvent e) {
700             SelectTemplateDialog dialog = new SelectTemplateDialog(searchContext.getProject(), false, isReplaceDialog());
701             if (!dialog.showAndGet()) {
702               return;
703             }
704             Configuration[] configurations = dialog.getSelectedConfigurations();
705             if (configurations.length == 1) {
706               setSearchPattern(configurations[0]);
707             }
708           }
709         }
710       )
711     );
712
713     return panel;
714   }
715
716   protected List<Variable> getVariablesFromListeners() {
717     return getVarsFrom(searchCriteriaEdit);
718   }
719
720   protected static ArrayList<Variable> getVarsFrom(Editor searchCriteriaEdit) {
721     SubstitutionShortInfoHandler handler = searchCriteriaEdit.getUserData(UIUtil.LISTENER_KEY);
722     return new ArrayList<Variable>(handler.getVariables());
723   }
724
725   public final Project getProject() {
726     return searchContext.getProject();
727   }
728
729   public String showSaveTemplateAsDialog() {
730     return ConfigurationManager.showSaveTemplateAsDialog(
731       model.getShadowConfig() != null ? model.getShadowConfig().getName() : SSRBundle.message("user.defined.category"),
732       searchContext.getProject()
733     );
734   }
735
736   protected boolean isReplaceDialog() {
737     return false;
738   }
739
740   @Override
741   public void show() {
742     StructuralSearchPlugin.getInstance(getProject()).setDialogVisible(true);
743     searchCriteriaEdit.putUserData(
744       SubstitutionShortInfoHandler.CURRENT_CONFIGURATION_KEY,
745       model.getConfig()
746     );
747
748     if (!useLastConfiguration) {
749       final Editor editor = FileEditorManager.getInstance(searchContext.getProject()).getSelectedTextEditor();
750       boolean setSomeText = false;
751
752       if (editor != null) {
753         final SelectionModel selectionModel = editor.getSelectionModel();
754
755         if (selectionModel.hasSelection()) {
756           addOrReplaceSelection(selectionModel.getSelectedText());
757           existingTemplatesComponent.getPatternTree().setSelectionPath(null);
758           existingTemplatesComponent.getHistoryList().setSelectedIndex(-1);
759           setSomeText = true;
760         }
761       }
762
763       if (!setSomeText) {
764         int selection = existingTemplatesComponent.getHistoryList().getSelectedIndex();
765         if (selection != -1) {
766           setValuesFromConfig(
767             (Configuration)existingTemplatesComponent.getHistoryList().getSelectedValue()
768           );
769         }
770       }
771     }
772
773     initiateValidation();
774
775     super.show();
776   }
777
778   @Override
779   public JComponent getPreferredFocusedComponent() {
780     return searchCriteriaEdit.getContentComponent();
781   }
782
783   // Performs ok action
784   @Override
785   protected void doOKAction() {
786     SearchScope selectedScope = getSelectedScope();
787     if (selectedScope == null) return;
788
789     myDoingOkAction = true;
790     boolean result = isValid();
791     myDoingOkAction = false;
792     if (!result) return;
793
794     myAlarm.cancelAllRequests();
795     super.doOKAction();
796     if (!myRunFindActionOnClose) return;
797
798     final FindSettings findSettings = FindSettings.getInstance();
799     findSettings.setDefaultScopeName(selectedScope.getDisplayName());
800     findSettings.setShowResultsInSeparateView(openInNewTab.isSelected());
801
802     try {
803       final Configuration configuration = model.getConfig();
804       if (model.getShadowConfig() != null) {
805         if (model.getShadowConfig().isPredefined()) {
806           configuration.setName(model.getShadowConfig().getName()
807           );
808         } //else {
809         //  // user template, save it
810         //  setValuesToConfig(model.getShadowConfig());
811         //}
812       }
813       filterOutUnusedVariableConstraints(configuration);
814       existingTemplatesComponent.addConfigurationToHistory(configuration);
815
816       startSearching();
817     }
818     catch (MalformedPatternException ex) {
819       reportMessage("this.pattern.is.malformed.message", searchCriteriaEdit, ex.getMessage());
820     }
821   }
822
823   private void filterOutUnusedVariableConstraints(Configuration configuration) {
824     final List<Variable> variables = getVariablesFromListeners();
825     final List<String> variableNames = new ArrayList<String>();
826     for (Variable variable : variables) {
827       variableNames.add(variable.getName());
828     }
829     variableNames.add(Configuration.CONTEXT_VAR_NAME);
830     configuration.getMatchOptions().retainVariableConstraints(variableNames);
831   }
832
833   public Configuration getConfiguration() {
834     return model.getConfig();
835   }
836
837   private SearchScope getSelectedScope() {
838     return myScopeChooserCombo.getSelectedScope();
839   }
840
841   protected boolean isValid() {
842     setValuesToConfig(model.getConfig());
843     boolean result = true;
844
845     try {
846       MatcherImpl.validate(searchContext.getProject(), model.getConfig().getMatchOptions());
847     }
848     catch (MalformedPatternException ex) {
849       if (myRunFindActionOnClose) {
850         reportMessage("this.pattern.is.malformed.message", searchCriteriaEdit, (ex.getMessage() != null) ? ex.getMessage() : "");
851         result = false;
852       }
853     }
854     catch (UnsupportedPatternException ex) {
855       reportMessage("this.pattern.is.unsupported.message", searchCriteriaEdit, ex.getMessage());
856       result = false;
857     }
858
859     return result;
860   }
861
862   protected void reportMessage(@NonNls final String messageId, final Editor editor, final Object... params) {
863     com.intellij.util.ui.UIUtil.invokeLaterIfNeeded(new Runnable() {
864       @Override
865       public void run() {
866         final String message = messageId != null ? SSRBundle.message(messageId, params) : "";
867         status.setText(message);
868         status.setToolTipText(message);
869         status.revalidate();
870         statusText.setLabelFor(editor != null ? editor.getContentComponent() : null);
871       }
872     });
873   }
874
875   protected void setValuesToConfig(Configuration config) {
876
877     MatchOptions options = config.getMatchOptions();
878
879     boolean searchWithinHierarchy = IdeBundle.message("scope.class.hierarchy").equals(myScopeChooserCombo.getSelectedScopeName());
880     // We need to reset search within hierarchy scope during online validation since the scope works with user participation
881     options.setScope(
882       searchWithinHierarchy && !myDoingOkAction ? GlobalSearchScope.projectScope(getProject()) : myScopeChooserCombo.getSelectedScope());
883     options.setLooseMatching(true);
884     options.setRecursiveSearch(isRecursiveSearchEnabled() && recursiveMatching.isSelected());
885
886     ourFtSearchVariant = (FileType)fileTypes.getSelectedItem();
887     ourDialect = (Language)dialects.getSelectedItem();
888     ourContext = (String)contexts.getSelectedItem();
889     FileType fileType = ourFtSearchVariant;
890     options.setFileType(fileType);
891     options.setDialect(ourDialect);
892     options.setPatternContext(ourContext);
893
894     options.setSearchPattern(searchCriteriaEdit.getDocument().getText());
895     options.setCaseSensitiveMatch(caseSensitiveMatch.isSelected());
896   }
897
898   @Override
899   protected String getDimensionServiceKey() {
900     return "#com.intellij.structuralsearch.plugin.ui.SearchDialog";
901   }
902
903   @Override
904   public void dispose() {
905     disposeEditorContent();
906
907     myAlarm.cancelAllRequests();
908
909     super.dispose();
910     StructuralSearchPlugin.getInstance(getProject()).setDialogVisible(false);
911   }
912
913   protected void disposeEditorContent() {
914     mySavedEditorText = searchCriteriaEdit.getDocument().getText();
915
916     // this will remove from myExcludedSet
917     final PsiFile file = PsiDocumentManager.getInstance(searchContext.getProject()).getPsiFile(searchCriteriaEdit.getDocument());
918     if (file != null) {
919       DaemonCodeAnalyzer.getInstance(searchContext.getProject()).setHighlightingEnabled(file, true);
920     }
921
922     EditorFactory.getInstance().releaseEditor(searchCriteriaEdit);
923   }
924
925   @Override
926   protected String getHelpId() {
927     return "find.structuredSearch";
928   }
929
930   public SearchContext getSearchContext() {
931     return searchContext;
932   }
933 }