Java tutorial
/* * Copyright 2000-2009 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.refactoring.move.moveClassesOrPackages; import java.awt.CardLayout; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Pass; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiJavaPackage; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiModifier; import com.intellij.psi.PsiNameHelper; import com.intellij.psi.search.ProjectScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.HelpID; import com.intellij.refactoring.JavaRefactoringSettings; import com.intellij.refactoring.MoveDestination; import com.intellij.refactoring.PackageWrapper; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.move.MoveCallback; import com.intellij.refactoring.move.MoveClassesOrPackagesCallback; import com.intellij.refactoring.move.MoveHandler; import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil; import com.intellij.refactoring.ui.ClassNameReferenceEditor; import com.intellij.refactoring.ui.PackageNameReferenceEditorCombo; import com.intellij.refactoring.ui.RefactoringDialog; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.ui.ComboboxWithBrowseButton; import com.intellij.ui.RecentsManager; import com.intellij.ui.ReferenceEditorComboWithBrowseButton; import com.intellij.ui.ReferenceEditorWithBrowseButton; import com.intellij.usageView.UsageViewUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.ui.UIUtil; public class MoveClassesOrPackagesDialog extends RefactoringDialog { @NonNls private static final String RECENTS_KEY = "MoveClassesOrPackagesDialog.RECENTS_KEY"; private final PsiElement[] myElementsToMove; private final MoveCallback myMoveCallback; private static final Logger LOG = Logger .getInstance("#com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesDialog"); private JLabel myNameLabel; private ReferenceEditorComboWithBrowseButton myWithBrowseButtonReference; private JCheckBox myCbSearchInComments; private JCheckBox myCbSearchTextOccurences; private String myHelpID; private final boolean mySearchTextOccurencesEnabled; private final PsiManager myManager; private JPanel myMainPanel; private JRadioButton myToPackageRadioButton; private JRadioButton myMakeInnerClassOfRadioButton; private ReferenceEditorComboWithBrowseButton myClassPackageChooser; private JPanel myCardPanel; private ReferenceEditorWithBrowseButton myInnerClassChooser; private JPanel myMoveClassPanel; private JPanel myMovePackagePanel; private ComboboxWithBrowseButton myDestinationFolderCB; private JPanel myTargetPanel; private JLabel myTargetDestinationLabel; private boolean myHavePackages; private boolean myTargetDirectoryFixed; private boolean mySuggestToMoveToAnotherRoot; public MoveClassesOrPackagesDialog(Project project, boolean searchTextOccurences, PsiElement[] elementsToMove, final PsiElement initialTargetElement, MoveCallback moveCallback) { super(project, true); myElementsToMove = elementsToMove; myMoveCallback = moveCallback; myManager = PsiManager.getInstance(myProject); setTitle(MoveHandler.REFACTORING_NAME); mySearchTextOccurencesEnabled = searchTextOccurences; selectInitialCard(); init(); if (initialTargetElement instanceof PsiClass) { myMakeInnerClassOfRadioButton.setSelected(true); myInnerClassChooser.setText(((PsiClass) initialTargetElement).getQualifiedName()); ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { myInnerClassChooser.requestFocus(); } }, ModalityState.stateForComponent(myMainPanel)); } else if (initialTargetElement instanceof PsiJavaPackage) { myClassPackageChooser.setText(((PsiJavaPackage) initialTargetElement).getQualifiedName()); } updateControlsEnabled(); myToPackageRadioButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { updateControlsEnabled(); myClassPackageChooser.requestFocus(); } }); myMakeInnerClassOfRadioButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { updateControlsEnabled(); myInnerClassChooser.requestFocus(); } }); } private void updateControlsEnabled() { myClassPackageChooser.setEnabled(myToPackageRadioButton.isSelected()); myInnerClassChooser.setEnabled(myMakeInnerClassOfRadioButton.isSelected()); UIUtil.setEnabled(myTargetPanel, isMoveToPackage() && getSourceRoots().length > 1 && !myTargetDirectoryFixed, true); validateButtons(); } private void selectInitialCard() { myHavePackages = false; for (PsiElement psiElement : myElementsToMove) { if (!(psiElement instanceof PsiClass)) { myHavePackages = true; break; } } CardLayout cardLayout = (CardLayout) myCardPanel.getLayout(); cardLayout.show(myCardPanel, myHavePackages ? "Package" : "Class"); } public JComponent getPreferredFocusedComponent() { return myHavePackages ? myWithBrowseButtonReference.getChildComponent() : myClassPackageChooser.getChildComponent(); } protected JComponent createCenterPanel() { final VirtualFile[] sourceRoots = getSourceRoots(); boolean isDestinationVisible = sourceRoots.length > 1; myDestinationFolderCB.setVisible(isDestinationVisible); myTargetDestinationLabel.setVisible(isDestinationVisible); return null; } private void createUIComponents() { myMainPanel = new JPanel(); myWithBrowseButtonReference = createPackageChooser(); myClassPackageChooser = createPackageChooser(); myInnerClassChooser = new ClassNameReferenceEditor(myProject, null, ProjectScope.getProjectScope(myProject)); myInnerClassChooser.addDocumentListener(new DocumentAdapter() { public void documentChanged(DocumentEvent e) { validateButtons(); } }); // override CardLayout sizing behavior myCardPanel = new JPanel() { public Dimension getMinimumSize() { return myHavePackages ? myMovePackagePanel.getMinimumSize() : myMoveClassPanel.getMinimumSize(); } public Dimension getPreferredSize() { return myHavePackages ? myMovePackagePanel.getPreferredSize() : myMoveClassPanel.getPreferredSize(); } }; myDestinationFolderCB = new DestinationFolderComboBox() { @Override public String getTargetPackage() { return MoveClassesOrPackagesDialog.this.getTargetPackage(); } }; } private ReferenceEditorComboWithBrowseButton createPackageChooser() { final ReferenceEditorComboWithBrowseButton packageChooser = new PackageNameReferenceEditorCombo("", myProject, RECENTS_KEY, RefactoringBundle.message("choose.destination.package")); final Document document = packageChooser.getChildComponent().getDocument(); document.addDocumentListener(new DocumentAdapter() { public void documentChanged(DocumentEvent e) { validateButtons(); } }); return packageChooser; } protected JComponent createNorthPanel() { if (!mySearchTextOccurencesEnabled) { myCbSearchTextOccurences.setEnabled(false); myCbSearchTextOccurences.setVisible(false); myCbSearchTextOccurences.setSelected(false); } return myMainPanel; } protected String getDimensionServiceKey() { return myHavePackages ? "#com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesDialog.packages" : "#com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesDialog.classes"; } public void setData(PsiElement[] psiElements, String targetPackageName, PsiDirectory initialTargetDirectory, boolean isTargetDirectoryFixed, boolean suggestToMoveToAnotherRoot, boolean searchInComments, boolean searchForTextOccurences, String helpID) { myTargetDirectoryFixed = isTargetDirectoryFixed; mySuggestToMoveToAnotherRoot = suggestToMoveToAnotherRoot; if (targetPackageName.length() != 0) { myWithBrowseButtonReference.prependItem(targetPackageName); myClassPackageChooser.prependItem(targetPackageName); } String nameFromCallback = myMoveCallback instanceof MoveClassesOrPackagesCallback ? ((MoveClassesOrPackagesCallback) myMoveCallback).getElementsToMoveName() : null; if (nameFromCallback != null) { myNameLabel.setText(nameFromCallback); } else if (psiElements.length == 1) { PsiElement firstElement = psiElements[0]; if (firstElement instanceof PsiClass) { LOG.assertTrue(!MoveClassesOrPackagesImpl.isClassInnerOrLocal((PsiClass) firstElement)); } else { PsiElement parent = firstElement.getParent(); LOG.assertTrue(parent != null); } myNameLabel.setText(RefactoringBundle.message("move.single.class.or.package.name.label", UsageViewUtil.getType(firstElement), UsageViewUtil.getLongName(firstElement))); } else if (psiElements.length > 1) { myNameLabel.setText( psiElements[0] instanceof PsiClass ? RefactoringBundle.message("move.specified.classes") : RefactoringBundle.message("move.specified.packages")); } selectInitialCard(); myCbSearchInComments.setSelected(searchInComments); myCbSearchTextOccurences.setSelected(searchForTextOccurences); if (initialTargetDirectory != null && JavaMoveClassesOrPackagesHandler .packageHasMultipleDirectoriesInModule(myProject, initialTargetDirectory)) { initialTargetDirectory = null; } ((DestinationFolderComboBox) myDestinationFolderCB).setData(myProject, initialTargetDirectory, new Pass<String>() { @Override public void pass(String s) { setErrorText(s); } }, myHavePackages ? myWithBrowseButtonReference.getChildComponent() : myClassPackageChooser.getChildComponent()); UIUtil.setEnabled(myTargetPanel, getSourceRoots().length > 0 && isMoveToPackage() && !isTargetDirectoryFixed, true); validateButtons(); myHelpID = helpID; } protected void doHelpAction() { HelpManager.getInstance().invokeHelp(myHelpID); } protected final boolean isSearchInComments() { return myCbSearchInComments.isSelected(); } @Override protected void canRun() throws ConfigurationException { if (isMoveToPackage()) { String name = getTargetPackage().trim(); if (name.length() != 0 && !PsiNameHelper.getInstance(myManager.getProject()).isQualifiedName(name)) { throw new ConfigurationException("\'" + name + "\' is invalid destination package name"); } } else { if (findTargetClass() == null) throw new ConfigurationException("Destination class not found"); final String validationError = getValidationError(); if (validationError != null) throw new ConfigurationException(validationError); } } protected void validateButtons() { super.validateButtons(); setErrorText(getValidationError()); } @Nullable private String getValidationError() { if (!isMoveToPackage()) { return verifyInnerClassDestination(); } return null; } @Nullable private PsiClass findTargetClass() { String name = myInnerClassChooser.getText().trim(); return JavaPsiFacade.getInstance(myManager.getProject()).findClass(name, ProjectScope.getProjectScope(myProject)); } protected boolean isMoveToPackage() { return myHavePackages || myToPackageRadioButton.isSelected(); } protected String getTargetPackage() { return myHavePackages ? myWithBrowseButtonReference.getText() : myClassPackageChooser.getText(); } @Nullable private static String verifyDestinationForElement(final PsiElement element, final MoveDestination moveDestination) { final String message; if (element instanceof PsiDirectory) { message = moveDestination.verify((PsiDirectory) element); } else if (element instanceof PsiJavaPackage) { message = moveDestination.verify((PsiJavaPackage) element); } else { message = moveDestination.verify(element.getContainingFile()); } return message; } protected void doAction() { if (isMoveToPackage()) { invokeMoveToPackage(); } else { invokeMoveToInner(); } } private void invokeMoveToPackage() { final MoveDestination destination = selectDestination(); if (destination == null) return; saveRefactoringSettings(); for (final PsiElement element : myElementsToMove) { String message = verifyDestinationForElement(element, destination); if (message != null) { String helpId = HelpID.getMoveHelpID(myElementsToMove[0]); CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("error.title"), message, helpId, getProject()); return; } } try { for (PsiElement element : myElementsToMove) { if (element instanceof PsiClass) { final PsiClass aClass = (PsiClass) element; LOG.assertTrue(aClass.isPhysical(), aClass); /*PsiElement toAdd; if (aClass.getContainingFile() instanceof PsiJavaFile && ((PsiJavaFile)aClass.getContainingFile()).getClasses().length > 1) { toAdd = aClass; } else { toAdd = aClass.getContainingFile(); }*/ final PsiDirectory targetDirectory = destination.getTargetIfExists(element.getContainingFile()); if (targetDirectory != null) { MoveFilesOrDirectoriesUtil.checkMove(aClass, targetDirectory); } } } MoveClassesOrPackagesProcessor processor = createMoveToPackageProcessor(destination, myElementsToMove, myMoveCallback); if (processor.verifyValidPackageName()) { invokeRefactoring(processor); } } catch (IncorrectOperationException e) { String helpId = HelpID.getMoveHelpID(myElementsToMove[0]); CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("error.title"), e.getMessage(), helpId, getProject()); } } //for scala plugin protected MoveClassesOrPackagesProcessor createMoveToPackageProcessor(MoveDestination destination, final PsiElement[] elementsToMove, final MoveCallback callback) { return new MoveClassesOrPackagesProcessor(getProject(), elementsToMove, destination, isSearchInComments(), isSearchInNonJavaFiles(), callback); } private void saveRefactoringSettings() { final JavaRefactoringSettings refactoringSettings = JavaRefactoringSettings.getInstance(); final boolean searchInComments = isSearchInComments(); final boolean searchForTextOccurences = isSearchInNonJavaFiles(); refactoringSettings.MOVE_SEARCH_IN_COMMENTS = searchInComments; refactoringSettings.MOVE_SEARCH_FOR_TEXT = searchForTextOccurences; refactoringSettings.MOVE_PREVIEW_USAGES = isPreviewUsages(); } @Nullable private String verifyInnerClassDestination() { PsiClass targetClass = findTargetClass(); if (targetClass == null) return null; for (PsiElement element : myElementsToMove) { if (PsiTreeUtil.isAncestor(element, targetClass, false)) { return RefactoringBundle.message("move.class.to.inner.move.to.self.error"); } final Language targetClassLanguage = targetClass.getLanguage(); if (!element.getLanguage().equals(targetClassLanguage)) { return RefactoringBundle.message("move.to.different.language", UsageViewUtil.getType(element), ((PsiClass) element).getQualifiedName(), targetClass.getQualifiedName()); } } while (targetClass != null) { if (targetClass.getContainingClass() != null && !targetClass.hasModifierProperty(PsiModifier.STATIC)) { return RefactoringBundle.message("move.class.to.inner.nonstatic.error"); } targetClass = targetClass.getContainingClass(); } return null; } private void invokeMoveToInner() { saveRefactoringSettings(); final PsiClass targetClass = findTargetClass(); final PsiClass[] classesToMove = new PsiClass[myElementsToMove.length]; for (int i = 0; i < myElementsToMove.length; i++) { classesToMove[i] = (PsiClass) myElementsToMove[i]; } invokeRefactoring(createMoveToInnerProcessor(targetClass, classesToMove, myMoveCallback)); } //for scala plugin protected MoveClassToInnerProcessor createMoveToInnerProcessor(PsiClass destination, @NotNull PsiClass[] classesToMove, @Nullable final MoveCallback callback) { return new MoveClassToInnerProcessor(getProject(), classesToMove, destination, isSearchInComments(), isSearchInNonJavaFiles(), callback); } protected final boolean isSearchInNonJavaFiles() { return myCbSearchTextOccurences.isSelected(); } @Nullable private MoveDestination selectDestination() { final String packageName = getTargetPackage().trim(); if (packageName.length() > 0 && !PsiNameHelper.getInstance(myManager.getProject()).isQualifiedName(packageName)) { Messages.showErrorDialog(myProject, RefactoringBundle.message("please.enter.a.valid.target.package.name"), RefactoringBundle.message("move.title")); return null; } RecentsManager.getInstance(myProject).registerRecentEntry(RECENTS_KEY, packageName); PackageWrapper targetPackage = new PackageWrapper(myManager, packageName); if (!targetPackage.exists()) { final int ret = Messages.showYesNoDialog(myProject, RefactoringBundle.message("package.does.not.exist", packageName), RefactoringBundle.message("move.title"), Messages.getQuestionIcon()); if (ret != 0) return null; } return ((DestinationFolderComboBox) myDestinationFolderCB).selectDirectory(targetPackage, mySuggestToMoveToAnotherRoot); } private VirtualFile[] getSourceRoots() { return ProjectRootManager.getInstance(myProject).getContentSourceRoots(); } }