1 package com
.intellij
.refactoring
.move
.moveMembers
;
3 import com
.intellij
.ide
.util
.PackageUtil
;
4 import com
.intellij
.ide
.util
.TreeClassChooser
;
5 import com
.intellij
.ide
.util
.TreeClassChooserFactory
;
6 import com
.intellij
.openapi
.application
.ApplicationManager
;
7 import com
.intellij
.openapi
.command
.CommandProcessor
;
8 import com
.intellij
.openapi
.help
.HelpManager
;
9 import com
.intellij
.openapi
.options
.ConfigurationException
;
10 import com
.intellij
.openapi
.project
.Project
;
11 import com
.intellij
.openapi
.ui
.Messages
;
12 import com
.intellij
.openapi
.util
.Computable
;
13 import com
.intellij
.openapi
.util
.Ref
;
14 import com
.intellij
.psi
.*;
15 import com
.intellij
.psi
.search
.GlobalSearchScope
;
16 import com
.intellij
.psi
.util
.PsiTreeUtil
;
17 import com
.intellij
.refactoring
.HelpID
;
18 import com
.intellij
.refactoring
.JavaRefactoringSettings
;
19 import com
.intellij
.refactoring
.RefactoringBundle
;
20 import com
.intellij
.refactoring
.classMembers
.MemberInfoChange
;
21 import com
.intellij
.refactoring
.move
.MoveCallback
;
22 import com
.intellij
.refactoring
.ui
.MemberSelectionTable
;
23 import com
.intellij
.refactoring
.ui
.RefactoringDialog
;
24 import com
.intellij
.refactoring
.ui
.VisibilityPanel
;
25 import com
.intellij
.refactoring
.util
.CommonRefactoringUtil
;
26 import com
.intellij
.refactoring
.util
.classMembers
.MemberInfo
;
27 import com
.intellij
.refactoring
.util
.classMembers
.UsesAndInterfacesDependencyMemberInfoModel
;
28 import com
.intellij
.ui
.IdeBorderFactory
;
29 import com
.intellij
.ui
.RecentsManager
;
30 import com
.intellij
.ui
.ReferenceEditorComboWithBrowseButton
;
31 import com
.intellij
.ui
.ScrollPaneFactory
;
32 import com
.intellij
.usageView
.UsageViewUtil
;
33 import com
.intellij
.util
.IncorrectOperationException
;
34 import org
.jetbrains
.annotations
.NonNls
;
37 import javax
.swing
.border
.Border
;
39 import java
.awt
.event
.ActionEvent
;
40 import java
.awt
.event
.ActionListener
;
41 import java
.util
.ArrayList
;
42 import java
.util
.Collection
;
43 import java
.util
.List
;
46 public class MoveMembersDialog
extends RefactoringDialog
implements MoveMembersOptions
{
47 @NonNls private static final String RECENTS_KEY
= "MoveMembersDialog.RECENTS_KEY";
48 private MyMemberInfoModel myMemberInfoModel
;
50 private final Project myProject
;
51 private final PsiClass mySourceClass
;
52 private final String mySourceClassName
;
53 private final List
<MemberInfo
> myMemberInfos
;
54 private final ReferenceEditorComboWithBrowseButton myTfTargetClassName
;
55 private MemberSelectionTable myTable
;
56 private final MoveCallback myMoveCallback
;
58 VisibilityPanel myVisibilityPanel
;
59 private final JCheckBox myIntroduceEnumConstants
= new JCheckBox(RefactoringBundle
.message("move.enum.constant.cb"), true);
61 public MoveMembersDialog(Project project
,
63 final PsiClass initialTargetClass
,
64 Set
<PsiMember
> preselectMembers
,
65 MoveCallback moveCallback
) {
68 mySourceClass
= sourceClass
;
69 myMoveCallback
= moveCallback
;
70 setTitle(MoveMembersImpl
.REFACTORING_NAME
);
72 mySourceClassName
= mySourceClass
.getQualifiedName();
74 PsiField
[] fields
= mySourceClass
.getFields();
75 PsiMethod
[] methods
= mySourceClass
.getMethods();
76 PsiClass
[] innerClasses
= mySourceClass
.getInnerClasses();
77 ArrayList
<MemberInfo
> memberList
= new ArrayList
<MemberInfo
>(fields
.length
+ methods
.length
);
79 for (PsiClass innerClass
: innerClasses
) {
80 if (!innerClass
.hasModifierProperty(PsiModifier
.STATIC
)) continue;
81 MemberInfo info
= new MemberInfo(innerClass
);
82 if (preselectMembers
.contains(innerClass
)) {
83 info
.setChecked(true);
87 boolean hasConstantFields
= false;
88 for (PsiField field
: fields
) {
89 if (field
.hasModifierProperty(PsiModifier
.STATIC
)) {
90 MemberInfo info
= new MemberInfo(field
);
91 if (preselectMembers
.contains(field
)) {
92 info
.setChecked(true);
95 hasConstantFields
= true;
98 if (!hasConstantFields
) myIntroduceEnumConstants
.setVisible(false);
99 for (PsiMethod method
: methods
) {
100 if (method
.hasModifierProperty(PsiModifier
.STATIC
)) {
101 MemberInfo info
= new MemberInfo(method
);
102 if (preselectMembers
.contains(method
)) {
103 info
.setChecked(true);
105 memberList
.add(info
);
108 myMemberInfos
= memberList
;
109 String fqName
= initialTargetClass
!= null && !sourceClass
.equals(initialTargetClass
) ? initialTargetClass
.getQualifiedName() : "";
110 myTfTargetClassName
= new ReferenceEditorComboWithBrowseButton(new ChooseClassAction(), fqName
, PsiManager
.getInstance(myProject
), true, RECENTS_KEY
);
115 public String
getMemberVisibility() {
116 return myVisibilityPanel
.getVisibility();
119 public boolean makeEnumConstant() {
120 return myIntroduceEnumConstants
.isVisible() && myIntroduceEnumConstants
.isEnabled() && myIntroduceEnumConstants
.isSelected();
123 protected String
getDimensionServiceKey() {
124 return "#com.intellij.refactoring.move.moveMembers.MoveMembersDialog";
127 private JTable
createTable() {
128 myMemberInfoModel
= new MyMemberInfoModel();
129 myTable
= new MemberSelectionTable(myMemberInfos
, null);
130 myTable
.setMemberInfoModel(myMemberInfoModel
);
131 myTable
.addMemberInfoChangeListener(myMemberInfoModel
);
132 myMemberInfoModel
.memberInfoChanged(new MemberInfoChange
<PsiMember
, MemberInfo
>(myMemberInfos
));
136 protected JComponent
createNorthPanel() {
137 JPanel panel
= new JPanel(new BorderLayout());
140 Box box
= Box
.createVerticalBox();
142 _panel
= new JPanel(new BorderLayout());
143 JTextField sourceClassField
= new JTextField();
144 sourceClassField
.setText(mySourceClassName
);
145 sourceClassField
.setEditable(false);
146 _panel
.add(new JLabel(RefactoringBundle
.message("move.members.move.members.from.label")), BorderLayout
.NORTH
);
147 _panel
.add(sourceClassField
, BorderLayout
.CENTER
);
150 box
.add(Box
.createVerticalStrut(10));
152 _panel
= new JPanel(new BorderLayout());
153 JLabel label
= new JLabel(RefactoringBundle
.message("move.members.to.fully.qualified.name.label"));
154 label
.setLabelFor(myTfTargetClassName
);
155 _panel
.add(label
, BorderLayout
.NORTH
);
156 _panel
.add(myTfTargetClassName
, BorderLayout
.CENTER
);
157 _panel
.add(myIntroduceEnumConstants
, BorderLayout
.SOUTH
);
160 myTfTargetClassName
.getChildComponent().getDocument().addDocumentListener(new com
.intellij
.openapi
.editor
.event
.DocumentAdapter() {
161 public void documentChanged(com
.intellij
.openapi
.editor
.event
.DocumentEvent e
) {
162 myMemberInfoModel
.updateTargetClass();
167 panel
.add(box
, BorderLayout
.CENTER
);
168 panel
.add(Box
.createVerticalStrut(10), BorderLayout
.SOUTH
);
174 protected JComponent
createCenterPanel() {
175 JPanel panel
= new JPanel(new BorderLayout());
176 JTable table
= createTable();
177 if (table
.getRowCount() > 0) {
178 table
.getSelectionModel().addSelectionInterval(0, 0);
180 JScrollPane scrollPane
= ScrollPaneFactory
.createScrollPane(table
);
181 Border titledBorder
= IdeBorderFactory
.createTitledBorder(RefactoringBundle
.message("move.members.members.to.be.moved.border.title"));
182 Border emptyBorder
= BorderFactory
.createEmptyBorder(0, 5, 5, 5);
183 Border border
= BorderFactory
.createCompoundBorder(titledBorder
, emptyBorder
);
184 scrollPane
.setBorder(border
);
185 panel
.add(scrollPane
, BorderLayout
.CENTER
);
187 myVisibilityPanel
= new VisibilityPanel(true, true);
188 myVisibilityPanel
.setVisibility(null);
189 panel
.add(myVisibilityPanel
, BorderLayout
.EAST
);
194 public JComponent
getPreferredFocusedComponent() {
195 return myTfTargetClassName
.getChildComponent();
198 public PsiMember
[] getSelectedMembers() {
199 final Collection
<MemberInfo
> selectedMemberInfos
= myTable
.getSelectedMemberInfos();
200 ArrayList
<PsiMember
> list
= new ArrayList
<PsiMember
>();
201 for (MemberInfo selectedMemberInfo
: selectedMemberInfos
) {
202 list
.add(selectedMemberInfo
.getMember());
204 return list
.toArray(new PsiMember
[list
.size()]);
207 public String
getTargetClassName() {
208 return myTfTargetClassName
.getText();
211 protected void doAction() {
212 String message
= validateInputData();
214 if (message
!= null) {
215 if (message
.length() != 0) {
216 CommonRefactoringUtil
.showErrorMessage(
217 MoveMembersImpl
.REFACTORING_NAME
,
225 invokeRefactoring(new MoveMembersProcessor(getProject(), myMoveCallback
, new MoveMembersOptions() {
226 public String
getMemberVisibility() {
227 return MoveMembersDialog
.this.getMemberVisibility();
230 public boolean makeEnumConstant() {
231 return MoveMembersDialog
.this.makeEnumConstant();
234 public PsiMember
[] getSelectedMembers() {
235 return MoveMembersDialog
.this.getSelectedMembers();
238 public String
getTargetClassName() {
239 return MoveMembersDialog
.this.getTargetClassName();
243 JavaRefactoringSettings
.getInstance().MOVE_PREVIEW_USAGES
= isPreviewUsages();
247 protected void canRun() throws ConfigurationException
{
248 if (getTargetClassName().length() == 0) throw new ConfigurationException("Destination class name not found");
251 private String
validateInputData() {
252 final PsiManager manager
= PsiManager
.getInstance(myProject
);
253 final String fqName
= getTargetClassName();
254 if ("".equals(fqName
)) {
255 return RefactoringBundle
.message("no.destination.class.specified");
258 if (!JavaPsiFacade
.getInstance(manager
.getProject()).getNameHelper().isQualifiedName(fqName
)) {
259 return RefactoringBundle
.message("0.is.not.a.legal.fq.name", fqName
);
262 RecentsManager
.getInstance(myProject
).registerRecentEntry(RECENTS_KEY
, fqName
);
263 final PsiClass
[] targetClass
= new PsiClass
[]{null};
264 CommandProcessor
.getInstance().executeCommand(myProject
, new Runnable() {
267 targetClass
[0] = findOrCreateTargetClass(manager
, fqName
);
269 catch (IncorrectOperationException e
) {
270 CommonRefactoringUtil
.showErrorMessage(
271 MoveMembersImpl
.REFACTORING_NAME
,
278 }, RefactoringBundle
.message("create.class.command", fqName
), null);
280 if (targetClass
[0] == null) {
284 if (mySourceClass
.equals(targetClass
[0])) {
285 return RefactoringBundle
.message("source.and.destination.classes.should.be.different");
286 } else if (!mySourceClass
.getLanguage().equals(targetClass
[0].getLanguage())) {
287 return RefactoringBundle
.message("move.to.different.language", UsageViewUtil
.getType(mySourceClass
), mySourceClass
.getQualifiedName(), targetClass
[0].getQualifiedName());
290 for (MemberInfo info
: myMemberInfos
) {
291 if (!info
.isChecked()) continue;
292 if (PsiTreeUtil
.isAncestor(info
.getMember(), targetClass
[0], false)) {
293 return RefactoringBundle
.message("cannot.move.inner.class.0.into.itself", info
.getDisplayName());
297 if (!targetClass
[0].isWritable()) {
298 if (!CommonRefactoringUtil
.checkReadOnlyStatus(myProject
, targetClass
[0])) return "";
308 private PsiClass
findOrCreateTargetClass(final PsiManager manager
, final String fqName
) throws IncorrectOperationException
{
309 final String className
;
310 final String packageName
;
311 int dotIndex
= fqName
.lastIndexOf('.');
313 packageName
= fqName
.substring(0, dotIndex
);
314 className
= (dotIndex
+ 1 < fqName
.length())? fqName
.substring(dotIndex
+ 1) : "";
322 PsiClass aClass
= JavaPsiFacade
.getInstance(manager
.getProject()).findClass(fqName
, GlobalSearchScope
.projectScope(myProject
));
323 if (aClass
!= null) return aClass
;
325 final PsiDirectory directory
= PackageUtil
.findOrCreateDirectoryForPackage(
328 mySourceClass
.getContainingFile().getContainingDirectory(),
331 if (directory
== null) {
335 int answer
= Messages
.showYesNoDialog(
337 RefactoringBundle
.message("class.0.does.not.exist", fqName
),
338 MoveMembersImpl
.REFACTORING_NAME
,
339 Messages
.getQuestionIcon()
341 if (answer
!= 0) return null;
342 final Ref
<IncorrectOperationException
> eRef
= new Ref
<IncorrectOperationException
>();
343 final PsiClass newClass
= ApplicationManager
.getApplication().runWriteAction(new Computable
<PsiClass
>() {
344 public PsiClass
compute() {
346 return JavaDirectoryService
.getInstance().createClass(directory
, className
);
348 catch (IncorrectOperationException e
) {
354 if (!eRef
.isNull()) throw eRef
.get();
358 protected void doHelpAction() {
359 HelpManager
.getInstance().invokeHelp(HelpID
.MOVE_MEMBERS
);
362 private class ChooseClassAction
implements ActionListener
{
363 public void actionPerformed(ActionEvent e
) {
364 TreeClassChooser chooser
= TreeClassChooserFactory
.getInstance(myProject
).createWithInnerClassesScopeChooser(
365 RefactoringBundle
.message("choose.destination.class"), GlobalSearchScope
.projectScope(myProject
), new TreeClassChooser
.ClassFilter() {
366 public boolean isAccepted(PsiClass aClass
) {
367 return aClass
.getParent() instanceof PsiFile
|| aClass
.hasModifierProperty(PsiModifier
.STATIC
);
370 final String targetClassName
= getTargetClassName();
371 if (targetClassName
!= null) {
372 final PsiClass aClass
= JavaPsiFacade
.getInstance(myProject
).findClass(targetClassName
, GlobalSearchScope
.allScope(myProject
));
373 if (aClass
!= null) {
374 chooser
.selectDirectory(aClass
.getContainingFile().getContainingDirectory());
376 chooser
.selectDirectory(mySourceClass
.getContainingFile().getContainingDirectory());
380 chooser
.showDialog();
381 PsiClass aClass
= chooser
.getSelectedClass();
382 if (aClass
!= null) {
383 myTfTargetClassName
.setText(aClass
.getQualifiedName());
384 myMemberInfoModel
.updateTargetClass();
389 private class MyMemberInfoModel
extends UsesAndInterfacesDependencyMemberInfoModel
{
390 PsiClass myTargetClass
= null;
391 public MyMemberInfoModel() {
392 super(mySourceClass
, null, false, DEFAULT_CONTAINMENT_VERIFIER
);
395 public Boolean
isFixedAbstract(MemberInfo member
) {
399 public boolean isCheckedWhenDisabled(MemberInfo member
) {
403 public boolean isMemberEnabled(MemberInfo member
) {
404 if(myTargetClass
!= null && myTargetClass
.isInterface()) {
405 return !(member
.getMember() instanceof PsiMethod
);
407 return super.isMemberEnabled(member
);
410 public void updateTargetClass() {
411 final PsiManager manager
= PsiManager
.getInstance(myProject
);
413 JavaPsiFacade
.getInstance(manager
.getProject()).findClass(getTargetClassName(), GlobalSearchScope
.projectScope(myProject
));
414 myTable
.fireExternalDataChange();
415 myIntroduceEnumConstants
.setEnabled(myTargetClass
!= null && myTargetClass
.isEnum());