update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / memberPullUp / JavaPullUpHandler.java
blob8d11c60cfe468611c16295d76c6bff37fe86f57e
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.
18 * Created by IntelliJ IDEA.
19 * User: dsl
20 * Date: 18.06.2002
21 * Time: 12:45:30
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);
69 while (true) {
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);
74 return;
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);
81 return;
83 element = element.getParent();
87 public void invoke(@NotNull final Project project, @NotNull PsiElement[] elements, DataContext dataContext) {
88 if (elements.length != 1) return;
89 myProject = project;
91 PsiElement element = elements[0];
92 PsiClass aClass;
93 PsiElement aMember = null;
95 if (element instanceof PsiClass) {
96 aClass = (PsiClass)element;
98 else if (element instanceof PsiMethod) {
99 aClass = ((PsiMethod)element).getContainingClass();
100 aMember = element;
102 else if (element instanceof PsiField) {
103 aClass = ((PsiField)element).getContainingClass();
104 aMember = element;
106 else {
107 return;
110 Editor editor = PlatformDataKeys.EDITOR.getData(dataContext);
111 if (aClass == null) {
112 String message =
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);
115 return;
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);
124 return;
128 mySubclass = aClass;
129 MemberInfoStorage memberInfoStorage = new MemberInfoStorage(mySubclass, new MemberInfo.Filter<PsiMember>() {
130 public boolean includeMember(PsiMember element) {
131 return true;
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);
140 break;
144 final PullUpDialog dialog = new PullUpDialog(project, aClass, bases, memberInfoStorage, this);
147 dialog.show();
149 if (!dialog.isOK()) return;
151 CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
152 public void run() {
153 final Runnable action = new Runnable() {
154 public void run() {
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());
167 try {
168 try {
169 PullUpHelper helper = new PullUpHelper(mySubclass, dialog.getSuperClass(), dialog.getSelectedMemberInfos(),
170 new DocCommentPolicy(dialog.getJavaDocPolicy()));
171 helper.moveMembersToBase();
172 helper.moveFieldInitializations();
174 finally {
175 a.finish();
178 catch (IncorrectOperationException e) {
179 LOG.error(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);
197 return ok;
199 return true;
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;
208 return true;
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;
221 return true;
223 return false;
225 // todo: multiple selection etc
226 return elements.length == 1 && elements[0] instanceof PsiClass;