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.
18 * Created by IntelliJ IDEA.
22 * To change template for new class use
23 * Code Style | Class Templates options (Tools | IDE Options).
25 package com
.intellij
.refactoring
.memberPullUp
;
27 import com
.intellij
.history
.LocalHistory
;
28 import com
.intellij
.history
.LocalHistoryAction
;
29 import com
.intellij
.openapi
.actionSystem
.DataContext
;
30 import com
.intellij
.openapi
.actionSystem
.PlatformDataKeys
;
31 import com
.intellij
.openapi
.application
.ApplicationManager
;
32 import com
.intellij
.openapi
.command
.CommandProcessor
;
33 import com
.intellij
.openapi
.diagnostic
.Logger
;
34 import com
.intellij
.openapi
.editor
.Editor
;
35 import com
.intellij
.openapi
.editor
.ScrollType
;
36 import com
.intellij
.openapi
.project
.Project
;
37 import com
.intellij
.openapi
.ui
.DialogWrapper
;
38 import com
.intellij
.psi
.*;
39 import com
.intellij
.refactoring
.HelpID
;
40 import com
.intellij
.refactoring
.RefactoringActionHandler
;
41 import com
.intellij
.refactoring
.RefactoringBundle
;
42 import com
.intellij
.refactoring
.classMembers
.MemberInfoBase
;
43 import com
.intellij
.refactoring
.lang
.ElementsHandler
;
44 import com
.intellij
.refactoring
.ui
.ConflictsDialog
;
45 import com
.intellij
.refactoring
.util
.CommonRefactoringUtil
;
46 import com
.intellij
.refactoring
.util
.DocCommentPolicy
;
47 import com
.intellij
.refactoring
.util
.RefactoringHierarchyUtil
;
48 import com
.intellij
.refactoring
.util
.classMembers
.MemberInfo
;
49 import com
.intellij
.refactoring
.util
.classMembers
.MemberInfoStorage
;
50 import com
.intellij
.usageView
.UsageViewUtil
;
51 import com
.intellij
.util
.IncorrectOperationException
;
52 import com
.intellij
.util
.containers
.MultiMap
;
53 import org
.jetbrains
.annotations
.NotNull
;
55 import java
.util
.ArrayList
;
56 import java
.util
.List
;
58 public class JavaPullUpHandler
implements RefactoringActionHandler
, PullUpDialog
.Callback
, ElementsHandler
{
59 private static final Logger LOG
= Logger
.getInstance("#com.intellij.refactoring.memberPullUp.JavaPullUpHandler");
60 public static final String REFACTORING_NAME
= RefactoringBundle
.message("pull.members.up.title");
61 private PsiClass mySubclass
;
62 private Project myProject
;
64 public void invoke(@NotNull Project project
, Editor editor
, PsiFile file
, DataContext dataContext
) {
65 int offset
= editor
.getCaretModel().getOffset();
66 editor
.getScrollingModel().scrollToCaret(ScrollType
.MAKE_VISIBLE
);
67 PsiElement element
= file
.findElementAt(offset
);
70 if (element
== null || element
instanceof PsiFile
) {
71 String message
= RefactoringBundle
72 .getCannotRefactorMessage(RefactoringBundle
.message("the.caret.should.be.positioned.inside.a.class.to.pull.members.from"));
73 CommonRefactoringUtil
.showErrorHint(project
, editor
, message
, REFACTORING_NAME
, HelpID
.MEMBERS_PULL_UP
);
77 if (!CommonRefactoringUtil
.checkReadOnlyStatus(project
, element
)) return;
79 if (element
instanceof PsiClass
|| element
instanceof PsiField
|| element
instanceof PsiMethod
) {
80 invoke(project
, new PsiElement
[]{element
}, dataContext
);
83 element
= element
.getParent();
87 public void invoke(@NotNull final Project project
, @NotNull PsiElement
[] elements
, DataContext dataContext
) {
88 if (elements
.length
!= 1) return;
91 PsiElement element
= elements
[0];
93 PsiElement aMember
= null;
95 if (element
instanceof PsiClass
) {
96 aClass
= (PsiClass
)element
;
98 else if (element
instanceof PsiMethod
) {
99 aClass
= ((PsiMethod
)element
).getContainingClass();
102 else if (element
instanceof PsiField
) {
103 aClass
= ((PsiField
)element
).getContainingClass();
110 Editor editor
= PlatformDataKeys
.EDITOR
.getData(dataContext
);
111 if (aClass
== null) {
113 RefactoringBundle
.getCannotRefactorMessage(RefactoringBundle
.message("is.not.supported.in.the.current.context", REFACTORING_NAME
));
114 CommonRefactoringUtil
.showErrorHint(project
, editor
, message
, REFACTORING_NAME
, HelpID
.MEMBERS_PULL_UP
);
118 ArrayList
<PsiClass
> bases
= RefactoringHierarchyUtil
.createBasesList(aClass
, false, true);
120 if (bases
.isEmpty()) {
121 String message
= RefactoringBundle
.getCannotRefactorMessage(
122 RefactoringBundle
.message("class.does.not.have.base.classes.interfaces.in.current.project", aClass
.getQualifiedName()));
123 CommonRefactoringUtil
.showErrorHint(project
, editor
, message
, REFACTORING_NAME
, HelpID
.MEMBERS_PULL_UP
);
129 MemberInfoStorage memberInfoStorage
= new MemberInfoStorage(mySubclass
, new MemberInfo
.Filter
<PsiMember
>() {
130 public boolean includeMember(PsiMember element
) {
134 List
<MemberInfo
> members
= memberInfoStorage
.getClassMemberInfos(mySubclass
);
135 PsiManager manager
= mySubclass
.getManager();
137 for (MemberInfoBase
<PsiMember
> member
: members
) {
138 if (manager
.areElementsEquivalent(member
.getMember(), aMember
)) {
139 member
.setChecked(true);
144 final PullUpDialog dialog
= new PullUpDialog(project
, aClass
, bases
, memberInfoStorage
, this);
149 if (!dialog
.isOK()) return;
151 CommandProcessor
.getInstance().executeCommand(myProject
, new Runnable() {
153 final Runnable action
= new Runnable() {
155 doRefactoring(dialog
);
158 ApplicationManager
.getApplication().runWriteAction(action
);
160 }, REFACTORING_NAME
, null);
165 private void doRefactoring(PullUpDialog dialog
) {
166 LocalHistoryAction a
= LocalHistory
.startAction(myProject
, getCommandName());
169 PullUpHelper helper
= new PullUpHelper(mySubclass
, dialog
.getSuperClass(), dialog
.getSelectedMemberInfos(),
170 new DocCommentPolicy(dialog
.getJavaDocPolicy()));
171 helper
.moveMembersToBase();
172 helper
.moveFieldInitializations();
178 catch (IncorrectOperationException e
) {
183 private String
getCommandName() {
184 return RefactoringBundle
.message("pullUp.command", UsageViewUtil
.getDescriptiveName(mySubclass
));
187 public boolean checkConflicts(PullUpDialog dialog
) {
188 final MemberInfo
[] infos
= dialog
.getSelectedMemberInfos();
189 PsiClass superClass
= dialog
.getSuperClass();
190 if (!checkWritable(superClass
, infos
)) return false;
191 MultiMap
<PsiElement
,String
> conflicts
= PullUpConflictsUtil
.checkConflicts(infos
, mySubclass
, superClass
, null, null, dialog
.getContainmentVerifier());
192 if (!conflicts
.isEmpty()) {
193 ConflictsDialog conflictsDialog
= new ConflictsDialog(myProject
, conflicts
);
194 conflictsDialog
.show();
195 final boolean ok
= conflictsDialog
.isOK();
196 if (!ok
&& conflictsDialog
.isShowConflicts()) dialog
.close(DialogWrapper
.CANCEL_EXIT_CODE
);
202 private boolean checkWritable(PsiClass superClass
, MemberInfo
[] infos
) {
203 if (!CommonRefactoringUtil
.checkReadOnlyStatus(myProject
, superClass
)) return false;
204 for (MemberInfo info
: infos
) {
205 if (info
.getMember() instanceof PsiClass
&& info
.getOverrides() != null) continue;
206 if (!CommonRefactoringUtil
.checkReadOnlyStatus(myProject
, info
.getMember())) return false;
211 public boolean isEnabledOnElements(PsiElement
[] elements
) {
213 if (elements.length == 1) {
214 return elements[0] instanceof PsiClass || elements[0] instanceof PsiField || elements[0] instanceof PsiMethod;
216 else if (elements.length > 1){
217 for (int idx = 0; idx < elements.length; idx++) {
218 PsiElement element = elements[idx];
219 if (!(element instanceof PsiField || element instanceof PsiMethod)) return false;
225 // todo: multiple selection etc
226 return elements
.length
== 1 && elements
[0] instanceof PsiClass
;