bc9f0e5796c703f1d3ac0880e85418b71e561ad7
[idea/community.git] / platform / lang-impl / src / com / intellij / codeInsight / template / CustomTemplateCallback.java
1 /*
2  * Copyright 2000-2010 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.codeInsight.template;
17
18 import com.intellij.codeInsight.template.impl.TemplateImpl;
19 import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
20 import com.intellij.codeInsight.template.impl.TemplateSettings;
21 import com.intellij.openapi.editor.Editor;
22 import com.intellij.openapi.fileTypes.FileType;
23 import com.intellij.openapi.project.Project;
24 import com.intellij.psi.PsiElement;
25 import com.intellij.psi.PsiFile;
26 import com.intellij.psi.PsiFileFactory;
27 import com.intellij.util.LocalTimeCounter;
28 import com.intellij.util.containers.HashMap;
29 import org.jetbrains.annotations.NotNull;
30 import org.jetbrains.annotations.Nullable;
31
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.List;
35 import java.util.Map;
36
37 /**
38  * @author Eugene.Kudelevsky
39  */
40 public class CustomTemplateCallback {
41   private final TemplateManager myTemplateManager;
42   private final Editor myEditor;
43   private final PsiFile myFile;
44   private int myStartOffset;
45   private final Project myProject;
46   private LiveTemplateBuilder.Marker myEndOffsetMarker;
47   private final Map<Object, LiveTemplateBuilder.Marker> myCheckpoints = new HashMap<Object, LiveTemplateBuilder.Marker>();
48
49   private FileType myFileType;
50
51   private final LiveTemplateBuilder myBuilder = new LiveTemplateBuilder();
52   private int myOffset = 0;
53
54   public CustomTemplateCallback(Editor editor, PsiFile file) {
55     myEditor = editor;
56     myFile = file;
57     myProject = file.getProject();
58     myTemplateManager = TemplateManagerImpl.getInstance(myProject);
59     fixInitialState();
60   }
61
62   @Nullable
63   public PsiElement getContext() {
64     int offset = myStartOffset;
65     return myFile.findElementAt(offset > 0 ? offset - 1 : offset);
66   }
67
68   public void fixInitialState() {
69     myStartOffset = myEditor.getCaretModel().getOffset();
70   }
71
72   public void fixEndOffset() {
73     if (myEndOffsetMarker == null) {
74       myEndOffsetMarker = myBuilder.createMarker(myOffset);
75     }
76   }
77
78   public boolean isLiveTemplateApplicable(@NotNull String key) {
79     return findApplicableTemplate(key) != null;
80   }
81
82   @Nullable
83   public TemplateImpl findApplicableTemplate(@NotNull String key) {
84     List<TemplateImpl> templates = getMatchingTemplates(key);
85     templates = filterApplicableCandidates(templates);
86     return templates.size() > 0 ? templates.get(0) : null;
87   }
88
89   private List<TemplateImpl> filterApplicableCandidates(Collection<TemplateImpl> candidates) {
90     List<TemplateImpl> result = new ArrayList<TemplateImpl>();
91     for (TemplateImpl candidate : candidates) {
92       if (TemplateManagerImpl.isApplicable(myFile, myStartOffset, candidate)) {
93         result.add(candidate);
94       }
95     }
96     return result;
97   }
98
99   /**
100    * @param key
101    * @param predefinedVarValues
102    * @param listener            @return returns if template invokation is finished
103    */
104   public void startTemplate(@NotNull String key,
105                             Map<String, String> predefinedVarValues) {
106     List<TemplateImpl> templates = getMatchingTemplates(key);
107     templates = filterApplicableCandidates(templates);
108     if (templates.size() > 0) {
109       TemplateImpl template = templates.get(0);
110       startTemplate(template, predefinedVarValues);
111     }
112   }
113
114   /**
115    * @param template
116    * @param predefinedVarValues
117    * @param listener
118    * @return returns if template invokation is finished
119    */
120   /*public boolean startTemplate(@NotNull Template template,
121                                Map<String, String> predefinedVarValues,
122                                @Nullable final TemplateInvokationListener listener) {
123     final boolean[] templateEnded = new boolean[]{false};
124     final boolean[] templateFinished = new boolean[]{false};
125     myTemplateManager.startTemplate(myEditor, template, false, predefinedVarValues, new TemplateEditingAdapter() {
126       @Override
127       public void templateFinished(Template template, final boolean brokenOff) {
128         ApplicationManager.getApplication().runWriteAction(new Runnable() {
129           public void run() {
130             if (brokenOff) {
131               reformat();
132             }
133           }
134         });
135         if (brokenOff) return;
136         templateFinished[0] = true;
137         if (templateEnded[0] && listener != null) {
138           listener.finished(true);
139         }
140       }
141
142       @Override
143       public void waitingForInput(Template template) {
144         reformat();
145       }
146     });
147     templateEnded[0] = true;
148     if (templateFinished[0] && listener != null) {
149       listener.finished(false);
150     }
151     return templateFinished[0];
152   }*/
153   public void startTemplate(@NotNull TemplateImpl template,
154                             Map<String, String> predefinedVarValues) {
155     int offset = myBuilder.insertTemplate(myOffset, template, predefinedVarValues);
156     moveToOffset(offset);
157   }
158
159   /*private void reformat() {
160     CodeStyleManager style = CodeStyleManager.getInstance(myProject);
161     style.reformatText(myFile, myGlobalMarker.getStartOffset(), myGlobalMarker.getEndOffset());
162   }*/
163
164   public void fixStartOfTemplate(@NotNull Object key) {
165     LiveTemplateBuilder.Marker marker = myBuilder.createMarker(myOffset);
166     myCheckpoints.put(key, marker);
167   }
168
169   public void gotoEndOfTemplate(@NotNull Object key) {
170     moveToOffset(getEndOfTemplate(key));
171   }
172
173   public int getEndOfTemplate(@NotNull Object key) {
174     LiveTemplateBuilder.Marker marker = myCheckpoints.get(key);
175     if (marker == null) {
176       throw new IllegalArgumentException();
177     }
178     return marker.getEndOffset();
179   }
180
181   public int getStartOfTemplate(@NotNull Object key) {
182     LiveTemplateBuilder.Marker marker = myCheckpoints.get(key);
183     if (marker == null) {
184       throw new IllegalArgumentException();
185     }
186     return marker.getStartOffset();
187   }
188
189   public void gotoEndOffset() {
190     if (myEndOffsetMarker != null) {
191       moveToOffset(myEndOffsetMarker.getStartOffset());
192     }
193   }
194
195   public void finish() {
196     /*myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
197     final CodeStyleManager style = CodeStyleManager.getInstance(myProject);
198     if (myGlobalMarker != null) {
199       style.reformatText(myFile, myGlobalMarker.getStartOffset(), myGlobalMarker.getEndOffset());
200     }*/
201     gotoEndOffset();
202     if (myOffset < myBuilder.getText().length()) {
203       myBuilder.insertVariableSegment(myOffset, TemplateImpl.END);
204     }
205     TemplateImpl template = myBuilder.buildTemplate();
206     myTemplateManager.startTemplate(myEditor, template, false, myBuilder.getPredefinedValues(), null);
207   }
208
209   private static List<TemplateImpl> getMatchingTemplates(@NotNull String templateKey) {
210     TemplateSettings settings = TemplateSettings.getInstance();
211     return settings.collectMatchingCandidates(templateKey, settings.getDefaultShortcutChar(), false);
212   }
213
214   @NotNull
215   public Editor getEditor() {
216     return myEditor;
217   }
218
219   @NotNull
220   public FileType getFileType() {
221     if (myFileType == null) {
222       myFileType = myFile.getFileType();
223     }
224     return myFileType;
225   }
226
227   public int getOffset() {
228     return myOffset;
229   }
230
231   @NotNull
232   public PsiFile parseCurrentText(FileType fileType) {
233     return PsiFileFactory.getInstance(myProject)
234       .createFileFromText("dummy.xml", fileType, myBuilder.getText(), LocalTimeCounter.currentTime(), false);
235   }
236
237   public Project getProject() {
238     return myProject;
239   }
240
241   public void moveToOffset(int offset) {
242     myOffset = offset;
243   }
244
245   public void insertString(int offset, String text) {
246     myBuilder.insertText(offset, text);
247   }
248 }