show hint when refactoring cannot be invoked
[fedora-idea.git] / platform / lang-impl / src / com / intellij / refactoring / rename / PsiElementRenameHandler.java
blob2bc7b26147060e24de0930ebe684cba5927d5ec5
1 /*
2 * Copyright 2000-2009 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.
17 package com.intellij.refactoring.rename;
19 import com.intellij.featureStatistics.FeatureUsageTracker;
20 import com.intellij.openapi.actionSystem.DataContext;
21 import com.intellij.openapi.actionSystem.DataKey;
22 import com.intellij.openapi.actionSystem.PlatformDataKeys;
23 import com.intellij.openapi.application.ApplicationManager;
24 import com.intellij.openapi.diagnostic.Logger;
25 import com.intellij.openapi.editor.Editor;
26 import com.intellij.openapi.editor.ScrollType;
27 import com.intellij.openapi.extensions.ExtensionPointName;
28 import com.intellij.openapi.extensions.Extensions;
29 import com.intellij.openapi.project.Project;
30 import com.intellij.openapi.util.Condition;
31 import com.intellij.psi.*;
32 import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
33 import com.intellij.psi.meta.PsiMetaOwner;
34 import com.intellij.psi.meta.PsiWritableMetaData;
35 import com.intellij.refactoring.RefactoringBundle;
36 import com.intellij.refactoring.actions.BaseRefactoringAction;
37 import com.intellij.refactoring.util.CommonRefactoringUtil;
38 import com.intellij.usageView.UsageViewUtil;
39 import com.intellij.codeInsight.daemon.impl.CollectHighlightsUtil;
40 import org.jetbrains.annotations.NotNull;
41 import org.jetbrains.annotations.Nullable;
43 /**
44 * created at Nov 13, 2001
46 * @author Jeka, dsl
48 public class PsiElementRenameHandler implements RenameHandler {
49 private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.rename.PsiElementRenameHandler");
51 public static final ExtensionPointName<Condition<PsiElement>> VETO_RENAME_CONDITION_EP = ExtensionPointName.create("com.intellij.vetoRenameCondition");
52 public static DataKey<String> DEFAULT_NAME = DataKey.create("DEFAULT_NAME");
54 public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
55 PsiElement element = getElement(dataContext);
56 editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
57 final PsiElement nameSuggestionContext = file.findElementAt(editor.getCaretModel().getOffset());
58 invoke(element, project, nameSuggestionContext, editor);
61 public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) {
62 PsiElement element = elements.length == 1 ? elements[0] : null;
63 if (element == null) element = getElement(dataContext);
64 LOG.assertTrue(element != null);
65 Editor editor = PlatformDataKeys.EDITOR.getData(dataContext);
66 if (ApplicationManager.getApplication().isUnitTestMode()) {
67 final String newName = DEFAULT_NAME.getData(dataContext);
68 LOG.assertTrue(newName != null);
69 rename(element, project, element, editor, newName);
71 else {
72 invoke(element, project, element, editor);
76 public static void invoke(PsiElement element, Project project, PsiElement nameSuggestionContext, Editor editor) {
77 if (element != null && !canRename(project, editor, element)) {
78 return;
80 FeatureUsageTracker.getInstance().triggerFeatureUsed("refactoring.rename");
82 rename(element, project, nameSuggestionContext, editor);
85 static boolean canRename(Project project, Editor editor, PsiElement element) {
86 if (element == null) return false;
87 if (!(element instanceof PsiFile) && CollectHighlightsUtil.isOutsideSourceRootJavaFile(element.getContainingFile())) return false;
88 boolean hasRenameProcessor = RenamePsiElementProcessor.forElement(element) != RenamePsiElementProcessor.DEFAULT;
89 boolean hasWritableMetaData = element instanceof PsiMetaOwner && ((PsiMetaOwner)element).getMetaData() instanceof PsiWritableMetaData;
91 if (!hasRenameProcessor && !hasWritableMetaData && !(element instanceof PsiNamedElement)) {
92 String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("error.wrong.caret.position.symbol.to.rename"));
93 if (!ApplicationManager.getApplication().isUnitTestMode()) {
94 showErrorMessage(project, editor, message);
96 return false;
99 if (!PsiManager.getInstance(project).isInProject(element) && element.isPhysical()) {
100 String message = RefactoringBundle
101 .getCannotRefactorMessage(RefactoringBundle.message("error.out.of.project.element", UsageViewUtil.getType(element)));
102 showErrorMessage(project, editor, message);
103 return false;
106 if (InjectedLanguageUtil.isInInjectedLanguagePrefixSuffix(element)) {
107 String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("error.in.injected.lang.prefix.suffix", UsageViewUtil.getType(element)));
108 showErrorMessage(project, editor, message);
109 return false;
112 return true;//CommonRefactoringUtil.checkReadOnlyStatus(project, element);
115 private static void showErrorMessage(Project project, Editor editor, String message) {
116 CommonRefactoringUtil.showErrorHint(project, editor, message, RefactoringBundle.message("rename.title"), null);
119 public static void rename(PsiElement element, final Project project, PsiElement nameSuggestionContext, Editor editor) {
120 rename(element, project, nameSuggestionContext, editor, null);
123 private static void rename(PsiElement element, final Project project, PsiElement nameSuggestionContext, Editor editor, final String defaultName) {
124 RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(element);
125 element = processor.substituteElementToRename(element, editor);
126 if (element == null) return;
128 final RenameDialog dialog = new RenameDialog(project, element, nameSuggestionContext, editor);
129 if (defaultName != null) {
130 dialog.performRename(defaultName);
132 else {
133 dialog.show();
137 public boolean isAvailableOnDataContext(DataContext dataContext) {
138 return !isVetoed(getElement(dataContext));
141 public static boolean isVetoed(PsiElement element) {
142 if (element == null || element instanceof SyntheticElement) return true;
143 for(Condition<PsiElement> condition: Extensions.getExtensions(VETO_RENAME_CONDITION_EP)) {
144 if (condition.value(element)) return true;
146 return false;
149 @Nullable
150 public static PsiElement getElement(final DataContext dataContext) {
151 PsiElement[] elementArray = BaseRefactoringAction.getPsiElementArray(dataContext);
153 if (elementArray.length != 1) {
154 return null;
156 return elementArray[0];
159 public boolean isRenaming(DataContext dataContext) {
160 return isAvailableOnDataContext(dataContext);