refactoring, support css zen-coding selectors
[idea/community.git] / platform / lang-impl / src / com / intellij / codeInsight / template / impl / SurroundWithTemplateHandler.java
1 /*
2  * Copyright 2000-2009 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
17 package com.intellij.codeInsight.template.impl;
18
19 import com.intellij.codeInsight.CodeInsightActionHandler;
20 import com.intellij.codeInsight.CodeInsightBundle;
21 import com.intellij.codeInsight.CodeInsightUtilBase;
22 import com.intellij.codeInsight.hint.HintManager;
23 import com.intellij.codeInsight.template.CustomLiveTemplate;
24 import com.intellij.ide.DataManager;
25 import com.intellij.openapi.actionSystem.DefaultActionGroup;
26 import com.intellij.openapi.editor.Editor;
27 import com.intellij.openapi.project.Project;
28 import com.intellij.openapi.ui.popup.JBPopupFactory;
29 import com.intellij.openapi.ui.popup.ListPopup;
30 import com.intellij.psi.PsiDocumentManager;
31 import com.intellij.psi.PsiFile;
32 import org.jetbrains.annotations.NotNull;
33
34 import java.util.*;
35
36 /**
37  * @author mike
38  */
39 public class SurroundWithTemplateHandler implements CodeInsightActionHandler {
40   public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull PsiFile file) {
41     if (!editor.getSelectionModel().hasSelection()) {
42       editor.getSelectionModel().selectLineAtCaret();
43       if (!editor.getSelectionModel().hasSelection()) return;
44     }
45     PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
46     List<CustomLiveTemplate> customTemplates = getApplicableCustomTemplates(editor, file);
47     ArrayList<TemplateImpl> templates = getApplicableTemplates(editor, file, true);
48     if (templates.isEmpty() && customTemplates.isEmpty()) {
49       HintManager.getInstance().showErrorHint(editor, CodeInsightBundle.message("templates.surround.no.defined"));
50       return;
51     }
52
53     if (!CodeInsightUtilBase.preparePsiElementForWrite(file)) return;
54
55     Set<Character> usedMnemonicsSet = new HashSet<Character>();
56     DefaultActionGroup group = new DefaultActionGroup();
57     for (CustomLiveTemplate customTemplate : customTemplates) {
58       group.add(new WrapWithCustomTemplateAction(customTemplate, editor, file, usedMnemonicsSet));
59     }
60     for (TemplateImpl template : templates) {
61       group.add(new InvokeTemplateAction(template, editor, project, usedMnemonicsSet));
62     }
63
64     final ListPopup popup = JBPopupFactory.getInstance()
65       .createActionGroupPopup(CodeInsightBundle.message("templates.select.template.chooser.title"), group,
66                               DataManager.getInstance().getDataContext(editor.getContentComponent()),
67                               JBPopupFactory.ActionSelectionAid.MNEMONICS, false);
68
69     popup.showInBestPositionFor(editor);
70   }
71
72   public boolean startInWriteAction() {
73     return true;
74   }
75
76   public static List<CustomLiveTemplate> getApplicableCustomTemplates(Editor editor, PsiFile file) {
77     List<CustomLiveTemplate> result = new ArrayList<CustomLiveTemplate>();
78     int offset = editor.getCaretModel().getOffset();
79     for (CustomLiveTemplate template : CustomLiveTemplate.EP_NAME.getExtensions()) {
80       if (template.supportsWrapping() && template.isApplicable(file, offset)) {
81         result.add(template);
82       }
83     }
84     return result;
85   }
86
87   public static ArrayList<TemplateImpl> getApplicableTemplates(Editor editor, PsiFile file, boolean selection) {
88     int offset = editor.getCaretModel().getOffset();
89     int startOffset = offset;
90     if (selection && editor.getSelectionModel().hasSelection()) {
91       final int selStart = editor.getSelectionModel().getSelectionStart();
92       final int selEnd = editor.getSelectionModel().getSelectionEnd();
93       startOffset = (offset == selStart) ? selEnd : selStart;
94     }
95     Set<TemplateImpl> array = new LinkedHashSet<TemplateImpl>();
96     for (TemplateImpl template : TemplateSettings.getInstance().getTemplates()) {
97       if (!template.isDeactivated() &&
98           template.isSelectionTemplate() == selection &&
99           (TemplateManagerImpl.isApplicable(file, offset, template) ||
100            (selection && TemplateManagerImpl.isApplicable(file, startOffset, template)))) {
101         array.add(template);
102       }
103     }
104     final ArrayList<TemplateImpl> list = new ArrayList<TemplateImpl>(array);
105     Collections.sort(list, new Comparator<TemplateImpl>() {
106       public int compare(TemplateImpl o1, TemplateImpl o2) {
107         return o1.getKey().compareTo(o2.getKey());
108       }
109     });
110     return list;
111   }
112 }