2 * Copyright 2000-2012 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.refactoring.rename.inplace;
18 import com.intellij.codeInsight.completion.InsertHandler;
19 import com.intellij.codeInsight.completion.InsertionContext;
20 import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
21 import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl;
22 import com.intellij.codeInsight.highlighting.HighlightManager;
23 import com.intellij.codeInsight.lookup.LookupElement;
24 import com.intellij.codeInsight.lookup.LookupElementBuilder;
25 import com.intellij.codeInsight.lookup.LookupManager;
26 import com.intellij.codeInsight.lookup.impl.LookupImpl;
27 import com.intellij.codeInsight.template.*;
28 import com.intellij.codeInsight.template.Result;
29 import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
30 import com.intellij.codeInsight.template.impl.TemplateState;
31 import com.intellij.injected.editor.VirtualFileWindow;
32 import com.intellij.openapi.actionSystem.Shortcut;
33 import com.intellij.openapi.application.*;
34 import com.intellij.openapi.command.CommandProcessor;
35 import com.intellij.openapi.command.WriteCommandAction;
36 import com.intellij.openapi.command.impl.FinishMarkAction;
37 import com.intellij.openapi.command.impl.StartMarkAction;
38 import com.intellij.openapi.diagnostic.Logger;
39 import com.intellij.openapi.editor.Document;
40 import com.intellij.openapi.editor.Editor;
41 import com.intellij.openapi.editor.RangeMarker;
42 import com.intellij.openapi.editor.colors.EditorColors;
43 import com.intellij.openapi.editor.colors.EditorColorsManager;
44 import com.intellij.openapi.editor.markup.RangeHighlighter;
45 import com.intellij.openapi.editor.markup.TextAttributes;
46 import com.intellij.openapi.extensions.Extensions;
47 import com.intellij.openapi.fileEditor.FileEditor;
48 import com.intellij.openapi.fileEditor.FileEditorManager;
49 import com.intellij.openapi.fileEditor.OpenFileDescriptor;
50 import com.intellij.openapi.fileEditor.TextEditor;
51 import com.intellij.openapi.keymap.Keymap;
52 import com.intellij.openapi.keymap.KeymapManager;
53 import com.intellij.openapi.keymap.KeymapUtil;
54 import com.intellij.openapi.project.Project;
55 import com.intellij.openapi.roots.ProjectRootManager;
56 import com.intellij.openapi.ui.DialogWrapper;
57 import com.intellij.openapi.ui.Messages;
58 import com.intellij.openapi.util.Key;
59 import com.intellij.openapi.util.Pair;
60 import com.intellij.openapi.util.TextRange;
61 import com.intellij.openapi.vfs.VirtualFile;
62 import com.intellij.psi.*;
63 import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
64 import com.intellij.psi.search.LocalSearchScope;
65 import com.intellij.psi.search.ProjectScope;
66 import com.intellij.psi.search.PsiSearchHelper;
67 import com.intellij.psi.search.SearchScope;
68 import com.intellij.psi.search.searches.ReferencesSearch;
69 import com.intellij.psi.util.PsiTreeUtil;
70 import com.intellij.refactoring.rename.NameSuggestionProvider;
71 import com.intellij.refactoring.util.CommonRefactoringUtil;
72 import com.intellij.util.containers.Stack;
73 import org.jetbrains.annotations.NonNls;
74 import org.jetbrains.annotations.NotNull;
75 import org.jetbrains.annotations.Nullable;
76 import org.jetbrains.annotations.TestOnly;
84 public abstract class InplaceRefactoring {
85 protected static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.rename.inplace.VariableInplaceRenamer");
86 @NonNls protected static final String PRIMARY_VARIABLE_NAME = "PrimaryVariable";
87 @NonNls protected static final String OTHER_VARIABLE_NAME = "OtherVariable";
88 protected static final Stack<InplaceRefactoring> ourRenamersStack = new Stack<InplaceRefactoring>();
89 public static final Key<InplaceRefactoring> INPLACE_RENAMER = Key.create("EditorInplaceRenamer");
90 protected PsiNamedElement myElementToRename;
91 protected final Editor myEditor;
92 protected final Project myProject;
93 protected RangeMarker myRenameOffset;
94 private String myAdvertisementText;
95 private ArrayList<RangeHighlighter> myHighlighters;
96 protected String myInitialName;
97 protected final String myOldName;
98 protected RangeMarker myBeforeRevert = null;
99 protected String myInsertedName;
100 protected LinkedHashSet<String> myNameSuggestions;
102 protected StartMarkAction myMarkAction;
103 protected PsiElement myScope;
105 public InplaceRefactoring(Editor editor, PsiNamedElement elementToRename, Project project) {
106 this(editor, elementToRename, project, elementToRename != null ? elementToRename.getName() : null,
107 elementToRename != null ? elementToRename.getName() : null);
110 public InplaceRefactoring(Editor editor, PsiNamedElement elementToRename, Project project, final String oldName) {
111 this(editor, elementToRename, project, elementToRename != null ? elementToRename.getName() : null, oldName);
114 public InplaceRefactoring(
115 Editor editor, PsiNamedElement elementToRename, Project project, String initialName, final String oldName) {
116 myEditor = /*(editor instanceof EditorWindow)? ((EditorWindow)editor).getDelegate() : */editor;
117 myElementToRename = elementToRename;
120 if (myElementToRename != null) {
121 myInitialName = initialName;
122 final PsiFile containingFile = myElementToRename.getContainingFile();
123 if (!notSameFile(getTopLevelVirtualFile(containingFile.getViewProvider()), containingFile)) {
124 myRenameOffset = myElementToRename != null && myElementToRename.getTextRange() != null ? myEditor.getDocument()
125 .createRangeMarker(myElementToRename.getTextRange()) : null;
130 public void setAdvertisementText(String advertisementText) {
131 myAdvertisementText = advertisementText;
135 public boolean performInplaceRefactoring(final LinkedHashSet<String> nameSuggestions) {
136 myNameSuggestions = nameSuggestions;
137 if (InjectedLanguageUtil.isInInjectedLanguagePrefixSuffix(myElementToRename)) {
141 final FileViewProvider fileViewProvider = myElementToRename.getContainingFile().getViewProvider();
142 VirtualFile file = getTopLevelVirtualFile(fileViewProvider);
144 SearchScope referencesSearchScope = getReferencesSearchScope(file);
146 final Collection<PsiReference> refs = collectRefs(referencesSearchScope);
148 addReferenceAtCaret(refs);
150 for (PsiReference ref : refs) {
151 final PsiFile containingFile = ref.getElement().getContainingFile();
153 if (notSameFile(file, containingFile)) {
158 final PsiElement scope = checkLocalScope();
161 return false; // Should have valid local search scope for inplace rename
164 final PsiFile containingFile = scope.getContainingFile();
165 if (containingFile == null) {
166 return false; // Should have valid local search scope for inplace rename
168 //no need to process further when file is read-only
169 if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, containingFile)) return true;
171 myEditor.putUserData(INPLACE_RENAMER, this);
172 ourRenamersStack.push(this);
174 final List<Pair<PsiElement, TextRange>> stringUsages = new ArrayList<Pair<PsiElement, TextRange>>();
175 collectAdditionalElementsToRename(stringUsages);
176 return buildTemplateAndStart(refs, stringUsages, scope, containingFile);
179 protected boolean notSameFile(@Nullable VirtualFile file, PsiFile containingFile) {
180 return getTopLevelVirtualFile(containingFile.getViewProvider()) != file;
183 protected SearchScope getReferencesSearchScope(VirtualFile file) {
184 return file == null || ProjectRootManager.getInstance(myProject).getFileIndex().isInContent(file)
185 ? ProjectScope.getProjectScope(myElementToRename.getProject())
186 : new LocalSearchScope(myElementToRename.getContainingFile());
190 protected PsiElement checkLocalScope() {
191 final SearchScope searchScope = PsiSearchHelper.SERVICE.getInstance(myElementToRename.getProject()).getUseScope(myElementToRename);
192 if (searchScope instanceof LocalSearchScope) {
193 final PsiElement[] elements = ((LocalSearchScope)searchScope).getScope();
194 return PsiTreeUtil.findCommonParent(elements);
200 protected abstract void collectAdditionalElementsToRename(final List<Pair<PsiElement, TextRange>> stringUsages);
202 protected abstract boolean shouldSelectAll();
204 protected abstract LookupElement[] createLookupItems(LookupElement[] lookupItems, String name);
206 protected Collection<PsiReference> collectRefs(SearchScope referencesSearchScope) {
207 return ReferencesSearch.search(myElementToRename, referencesSearchScope, false).findAll();
210 protected boolean buildTemplateAndStart(final Collection<PsiReference> refs,
211 final Collection<Pair<PsiElement, TextRange>> stringUsages,
212 final PsiElement scope,
213 final PsiFile containingFile) {
214 final PsiElement context = containingFile.getContext();
215 myScope = context != null ? context.getContainingFile() : scope;
216 final TemplateBuilderImpl builder = new TemplateBuilderImpl(myScope);
218 PsiElement nameIdentifier = getNameIdentifier();
219 int offset = myEditor.getCaretModel().getOffset();
220 PsiElement selectedElement = getSelectedInEditorElement(nameIdentifier, refs, stringUsages, offset);
222 if (nameIdentifier != null) addVariable(nameIdentifier, selectedElement, builder);
223 for (PsiReference ref : refs) {
224 addVariable(ref, selectedElement, builder, offset);
226 for (Pair<PsiElement, TextRange> usage : stringUsages) {
227 addVariable(usage.first, usage.second, selectedElement, builder);
229 addAdditionalVariables(builder);
231 myMarkAction = startRename();
233 catch (final StartMarkAction.AlreadyStartedException e) {
234 final Document oldDocument = e.getDocument();
235 if (oldDocument != myEditor.getDocument()) {
236 final int exitCode = Messages.showOkCancelDialog(myProject, e.getMessage(), getCommandName(),
237 "Navigate to continue", "Cancel started", Messages.getErrorIcon());
238 if (exitCode == -1) return true;
239 navigateToAlreadyStarted(oldDocument, exitCode);
248 beforeTemplateStart();
250 new WriteCommandAction(myProject, getCommandName()) {
252 protected void run(com.intellij.openapi.application.Result result) throws Throwable {
253 startTemplate(builder);
259 protected abstract void beforeTemplateStart();
261 private void startTemplate(final TemplateBuilderImpl builder) {
263 final DaemonCodeAnalyzer daemonCodeAnalyzer = DaemonCodeAnalyzer.getInstance(myProject);
265 final boolean previousUpdate;
266 if (daemonCodeAnalyzer != null) {
267 previousUpdate = ((DaemonCodeAnalyzerImpl)daemonCodeAnalyzer).isUpdateByTimerEnabled();
268 daemonCodeAnalyzer.setUpdateByTimerEnabled(false);
271 previousUpdate = false;
274 final MyTemplateListener templateListener = new MyTemplateListener() {
276 protected void restoreDaemonUpdateState() {
277 if (daemonCodeAnalyzer != null) {
278 daemonCodeAnalyzer.setUpdateByTimerEnabled(previousUpdate);
283 final int offset = myEditor.getCaretModel().getOffset();
285 Template template = builder.buildInlineTemplate();
286 template.setToShortenLongNames(false);
287 TextRange range = myScope.getTextRange();
288 assert range != null;
289 myHighlighters = new ArrayList<RangeHighlighter>();
290 Editor topLevelEditor = InjectedLanguageUtil.getTopLevelEditor(myEditor);
291 topLevelEditor.getCaretModel().moveToOffset(range.getStartOffset());
293 TemplateManager.getInstance(myProject).startTemplate(topLevelEditor, template, templateListener);
294 restoreOldCaretPositionAndSelection(offset);
295 highlightTemplateVariables(template, topLevelEditor);
298 private void highlightTemplateVariables(Template template, Editor topLevelEditor) {
300 if (myHighlighters != null) { // can be null if finish is called during testing
301 Map<TextRange, TextAttributes> rangesToHighlight = new HashMap<TextRange, TextAttributes>();
302 final TemplateState templateState = TemplateManagerImpl.getTemplateState(topLevelEditor);
303 if (templateState != null) {
304 EditorColorsManager colorsManager = EditorColorsManager.getInstance();
305 for (int i = 0; i < templateState.getSegmentsCount(); i++) {
306 final TextRange segmentOffset = templateState.getSegmentRange(i);
307 final String name = template.getSegmentName(i);
308 TextAttributes attributes = null;
309 if (name.equals(PRIMARY_VARIABLE_NAME)) {
310 attributes = colorsManager.getGlobalScheme().getAttributes(EditorColors.WRITE_SEARCH_RESULT_ATTRIBUTES);
312 else if (name.equals(OTHER_VARIABLE_NAME)) {
313 attributes = colorsManager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
315 if (attributes == null) continue;
316 rangesToHighlight.put(segmentOffset, attributes);
319 addHighlights(rangesToHighlight, topLevelEditor, myHighlighters, HighlightManager.getInstance(myProject));
323 private void restoreOldCaretPositionAndSelection(final int offset) {
325 Runnable runnable = new Runnable() {
327 myEditor.getCaretModel().moveToOffset(restoreCaretOffset(offset));
332 final LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myEditor);
333 if (lookup != null && lookup.getLookupStart() <= (restoreCaretOffset(offset))) {
334 lookup.setFocused(false);
335 lookup.performGuardedChange(runnable);
342 protected void restoreSelection() {
345 protected int restoreCaretOffset(int offset) {
349 protected void navigateToAlreadyStarted(Document oldDocument, int exitCode) {
350 final PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(oldDocument);
352 final VirtualFile virtualFile = file.getVirtualFile();
353 if (virtualFile != null) {
354 final FileEditor[] editors = FileEditorManager.getInstance(myProject).getEditors(virtualFile);
355 for (FileEditor editor : editors) {
356 if (editor instanceof TextEditor) {
357 final Editor textEditor = ((TextEditor)editor).getEditor();
358 final TemplateState templateState = TemplateManagerImpl.getTemplateState(textEditor);
359 if (templateState != null) {
360 if (exitCode == DialogWrapper.OK_EXIT_CODE) {
361 final TextRange range = templateState.getVariableRange(PRIMARY_VARIABLE_NAME);
363 new OpenFileDescriptor(myProject, virtualFile, range.getStartOffset()).navigate(true);
368 templateState.gotoEnd();
379 protected PsiElement getNameIdentifier() {
380 return myElementToRename instanceof PsiNameIdentifierOwner ? ((PsiNameIdentifierOwner)myElementToRename).getNameIdentifier() : null;
384 protected StartMarkAction startRename() throws StartMarkAction.AlreadyStartedException {
385 final StartMarkAction[] markAction = new StartMarkAction[1];
386 final StartMarkAction.AlreadyStartedException[] ex = new StartMarkAction.AlreadyStartedException[1];
387 CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
391 markAction[0] = StartMarkAction.start(myEditor, myProject, getCommandName());
393 catch (StartMarkAction.AlreadyStartedException e) {
397 }, getCommandName(), null);
398 if (ex[0] != null) throw ex[0];
399 return markAction[0];
403 protected PsiNamedElement getVariable() {
404 if (myElementToRename != null && myElementToRename.isValid()) return myElementToRename;
405 final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(myEditor.getDocument());
406 if (psiFile != null) {
407 return PsiTreeUtil.getParentOfType(psiFile.findElementAt(myRenameOffset.getStartOffset()), PsiNameIdentifierOwner.class);
409 return myElementToRename;
413 * Called after the completion of the refactoring, either a successful or a failed one.
415 * @param success true if the refactoring was accepted, false if it was cancelled (by undo or Esc)
417 protected void moveOffsetAfter(boolean success) {
420 protected void addAdditionalVariables(TemplateBuilderImpl builder) {
423 protected void addReferenceAtCaret(Collection<PsiReference> refs) {
424 PsiFile myEditorFile = PsiDocumentManager.getInstance(myProject).getPsiFile(myEditor.getDocument());
425 // Note, that myEditorFile can be different from myElement.getContainingFile() e.g. in injections: myElement declaration in one
426 // file / usage in another !
427 final PsiReference reference = (myEditorFile != null ?
428 myEditorFile : myElementToRename.getContainingFile())
429 .findReferenceAt(myEditor.getCaretModel().getOffset());
430 if (reference != null && !refs.contains(reference)) {
435 protected void showDialogAdvertisement(final String actionId) {
436 final Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
437 final Shortcut[] shortcuts = keymap.getShortcuts(actionId);
438 if (shortcuts.length > 0) {
439 setAdvertisementText("Press " + KeymapUtil.getShortcutText(shortcuts[0]) + " to show dialog");
443 public String getInitialName() {
444 if (myInitialName == null) {
445 final PsiNamedElement variable = getVariable();
446 if (variable != null) {
447 return variable.getName();
450 return myInitialName;
453 protected void revertState() {
454 CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
456 final Editor topLevelEditor = InjectedLanguageUtil.getTopLevelEditor(myEditor);
457 ApplicationManager.getApplication().runWriteAction(new Runnable() {
459 final TemplateState state = TemplateManagerImpl.getTemplateState(topLevelEditor);
460 assert state != null;
461 final int segmentsCount = state.getSegmentsCount();
462 final Document document = topLevelEditor.getDocument();
463 for (int i = 0; i < segmentsCount; i++) {
464 final TextRange segmentRange = state.getSegmentRange(i);
465 document.replaceString(segmentRange.getStartOffset(), segmentRange.getEndOffset(), myOldName);
469 if (!myProject.isDisposed() && myProject.isOpen()) {
470 PsiDocumentManager.getInstance(myProject).commitDocument(topLevelEditor.getDocument());
473 }, getCommandName(), null);
477 * Returns the name of the command performed by the refactoring.
479 * @return command name
481 protected abstract String getCommandName();
483 public void finish() {
484 if (!ourRenamersStack.isEmpty() && ourRenamersStack.peek() == this) {
485 ourRenamersStack.pop();
487 if (myHighlighters != null) {
488 if (!myProject.isDisposed()) {
489 final HighlightManager highlightManager = HighlightManager.getInstance(myProject);
490 for (RangeHighlighter highlighter : myHighlighters) {
491 highlightManager.removeSegmentHighlighter(myEditor, highlighter);
495 myHighlighters = null;
496 myEditor.putUserData(INPLACE_RENAMER, null);
500 protected void addHighlights(@NotNull Map<TextRange, TextAttributes> ranges,
501 @NotNull Editor editor,
502 @NotNull Collection<RangeHighlighter> highlighters,
503 @NotNull HighlightManager highlightManager) {
504 for (Map.Entry<TextRange, TextAttributes> entry : ranges.entrySet()) {
505 TextRange range = entry.getKey();
506 TextAttributes attributes = entry.getValue();
507 highlightManager.addOccurrenceHighlight(editor, range.getStartOffset(), range.getEndOffset(), attributes, 0, highlighters, null);
510 for (RangeHighlighter highlighter : highlighters) {
511 highlighter.setGreedyToLeft(true);
512 highlighter.setGreedyToRight(true);
516 protected abstract boolean performRefactoring();
518 private void addVariable(final PsiReference reference,
519 final PsiElement selectedElement,
520 final TemplateBuilderImpl builder,
522 if (reference.getElement() == selectedElement &&
523 contains(reference.getRangeInElement().shiftRight(selectedElement.getTextRange().getStartOffset()), offset)) {
524 Expression expression = new MyExpression(getInitialName(), myNameSuggestions);
525 builder.replaceElement(reference, PRIMARY_VARIABLE_NAME, expression, true);
528 builder.replaceElement(reference, OTHER_VARIABLE_NAME, PRIMARY_VARIABLE_NAME, false);
532 private void addVariable(final PsiElement element,
533 final PsiElement selectedElement,
534 final TemplateBuilderImpl builder) {
535 addVariable(element, null, selectedElement, builder);
538 private void addVariable(final PsiElement element,
539 @Nullable final TextRange textRange,
540 final PsiElement selectedElement,
541 final TemplateBuilderImpl builder) {
542 if (element == selectedElement) {
543 Expression expression = new MyExpression(getInitialName(), myNameSuggestions);
544 builder.replaceElement(element, PRIMARY_VARIABLE_NAME, expression, true);
546 else if (textRange != null) {
547 builder.replaceElement(element, textRange, OTHER_VARIABLE_NAME, PRIMARY_VARIABLE_NAME, false);
550 builder.replaceElement(element, OTHER_VARIABLE_NAME, PRIMARY_VARIABLE_NAME, false);
555 public void setElementToRename(PsiNamedElement elementToRename) {
556 myElementToRename = elementToRename;
559 protected static VirtualFile getTopLevelVirtualFile(final FileViewProvider fileViewProvider) {
560 VirtualFile file = fileViewProvider.getVirtualFile();
561 if (file instanceof VirtualFileWindow) file = ((VirtualFileWindow)file).getDelegate();
566 public static void checkCleared() {
568 assert ourRenamersStack.isEmpty() : ourRenamersStack;
571 ourRenamersStack.clear();
575 private static PsiElement getSelectedInEditorElement(@Nullable PsiElement nameIdentifier,
576 final Collection<PsiReference> refs,
577 Collection<Pair<PsiElement, TextRange>> stringUsages,
579 if (nameIdentifier != null) {
580 final TextRange range = nameIdentifier.getTextRange();
581 if (contains(range, offset)) return nameIdentifier;
584 for (PsiReference ref : refs) {
585 final PsiElement element = ref.getElement();
586 if (contains(ref.getRangeInElement().shiftRight(element.getTextRange().getStartOffset()), offset)) return element;
589 for (Pair<PsiElement, TextRange> stringUsage : stringUsages) {
590 final PsiElement element = stringUsage.first;
591 if (contains(stringUsage.second.shiftRight(element.getTextRange().getStartOffset()), offset)) return element;
594 LOG.assertTrue(false);
598 private static boolean contains(final TextRange range, final int offset) {
599 return range.getStartOffset() <= offset && offset <= range.getEndOffset();
602 protected class MyExpression extends Expression {
603 private final String myName;
604 private final LookupElement[] myLookupItems;
606 protected MyExpression(String name, LinkedHashSet<String> names) {
609 names = new LinkedHashSet<String>();
610 for (NameSuggestionProvider provider : Extensions.getExtensions(NameSuggestionProvider.EP_NAME)) {
611 provider.getSuggestedNames(myElementToRename, myElementToRename, names);
614 myLookupItems = new LookupElement[names.size()];
615 final Iterator<String> iterator = names.iterator();
616 for (int i = 0; i < myLookupItems.length; i++) {
617 final String suggestion = iterator.next();
618 myLookupItems[i] = LookupElementBuilder.create(suggestion).setInsertHandler(new InsertHandler<LookupElement>() {
620 public void handleInsert(InsertionContext context, LookupElement item) {
621 if (shouldSelectAll()) return;
622 final Editor topLevelEditor = InjectedLanguageUtil.getTopLevelEditor(myEditor);
623 final TemplateState templateState = TemplateManagerImpl.getTemplateState(topLevelEditor);
624 if (templateState != null) {
625 final TextRange range = templateState.getCurrentVariableRange();
627 topLevelEditor.getDocument().replaceString(range.getStartOffset(), range.getEndOffset(), suggestion);
635 public LookupElement[] calculateLookupItems(ExpressionContext context) {
636 return createLookupItems(myLookupItems, myName);
639 public Result calculateQuickResult(ExpressionContext context) {
640 return calculateResult(context);
643 public Result calculateResult(ExpressionContext context) {
644 TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor);
645 final TextResult insertedValue = templateState != null ? templateState.getVariableValue(PRIMARY_VARIABLE_NAME) : null;
646 if (insertedValue != null) {
647 if (!insertedValue.getText().isEmpty()) return insertedValue;
649 return new TextResult(myName);
653 public String getAdvertisingText() {
654 return myAdvertisementText;
658 private abstract class MyTemplateListener extends TemplateEditingAdapter {
660 protected abstract void restoreDaemonUpdateState();
662 public void beforeTemplateFinished(final TemplateState templateState, Template template) {
664 final TextResult value = templateState.getVariableValue(PRIMARY_VARIABLE_NAME);
665 myInsertedName = value != null ? value.toString() : null;
667 final int currentOffset = myEditor.getCaretModel().getOffset();
669 myRenameOffset != null && myRenameOffset.getEndOffset() >= currentOffset && myRenameOffset.getStartOffset() <= currentOffset
670 ? myEditor.getDocument().createRangeMarker(myRenameOffset.getStartOffset(), currentOffset)
672 if (myBeforeRevert != null) {
673 myBeforeRevert.setGreedyToRight(true);
678 restoreDaemonUpdateState();
683 public void templateFinished(Template template, final boolean brokenOff) {
684 boolean bind = false;
686 super.templateFinished(template, brokenOff);
688 bind = performRefactoring();
690 moveOffsetAfter(!brokenOff);
694 FinishMarkAction.finish(myProject, myEditor, myMarkAction);
695 if (myBeforeRevert != null) {
696 myBeforeRevert.dispose();
702 public void templateCancelled(Template template) {
704 final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject);
705 documentManager.commitAllDocuments();
707 moveOffsetAfter(false);
708 ApplicationManager.getApplication().runWriteAction(new Runnable() {
710 documentManager.doPostponedOperationsAndUnblockDocument(myEditor.getDocument());
716 restoreDaemonUpdateState();
719 FinishMarkAction.finish(myProject, myEditor, myMarkAction);