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.
16 package com
.intellij
.refactoring
.copy
;
18 import com
.intellij
.codeInsight
.actions
.OptimizeImportsProcessor
;
19 import com
.intellij
.codeInsight
.daemon
.impl
.CollectHighlightsUtil
;
20 import com
.intellij
.featureStatistics
.FeatureUsageTracker
;
21 import com
.intellij
.ide
.util
.EditorHelper
;
22 import com
.intellij
.openapi
.application
.ApplicationManager
;
23 import com
.intellij
.openapi
.command
.CommandProcessor
;
24 import com
.intellij
.openapi
.project
.Project
;
25 import com
.intellij
.openapi
.ui
.Messages
;
26 import com
.intellij
.openapi
.wm
.ToolWindowManager
;
27 import com
.intellij
.psi
.*;
28 import com
.intellij
.psi
.search
.LocalSearchScope
;
29 import com
.intellij
.psi
.search
.searches
.ReferencesSearch
;
30 import com
.intellij
.refactoring
.RefactoringBundle
;
31 import com
.intellij
.util
.IncorrectOperationException
;
32 import org
.jetbrains
.annotations
.Nullable
;
34 public class CopyClassesHandler
implements CopyHandlerDelegate
{
35 public boolean canCopy(PsiElement
[] elements
) {
36 return canCopyClass(elements
);
39 public static boolean canCopyClass(PsiElement
... elements
) {
40 return convertToTopLevelClass(elements
) != null;
44 private static PsiClass
convertToTopLevelClass(final PsiElement
[] elements
) {
45 if (elements
.length
== 1 && !CollectHighlightsUtil
.isOutsideSourceRootJavaFile(elements
[0].getContainingFile())) {
46 return getTopLevelClass(elements
[0]);
51 public void doCopy(PsiElement
[] elements
, PsiDirectory defaultTargetDirectory
) {
52 FeatureUsageTracker
.getInstance().triggerFeatureUsed("refactoring.copyClass");
53 PsiClass aClass
= convertToTopLevelClass(elements
);
54 assert aClass
!= null;
55 Project project
= aClass
.getProject();
56 if (defaultTargetDirectory
== null) {
57 defaultTargetDirectory
= aClass
.getContainingFile().getContainingDirectory();
59 CopyClassDialog dialog
= new CopyClassDialog(aClass
, defaultTargetDirectory
, project
, false);
60 dialog
.setTitle(RefactoringBundle
.message("copy.handler.copy.class"));
63 PsiDirectory targetDirectory
= dialog
.getTargetDirectory();
64 String className
= dialog
.getClassName();
65 copyClassImpl(className
, project
, aClass
, targetDirectory
, RefactoringBundle
.message("copy.handler.copy.class"), false);
69 public void doClone(PsiElement element
) {
70 FeatureUsageTracker
.getInstance().triggerFeatureUsed("refactoring.copyClass");
71 PsiClass aClass
= getTopLevelClass(element
);
72 Project project
= element
.getProject();
74 CopyClassDialog dialog
= new CopyClassDialog(aClass
, null, project
, true);
75 dialog
.setTitle(RefactoringBundle
.message("copy.handler.clone.class"));
78 String className
= dialog
.getClassName();
79 PsiDirectory targetDirectory
= element
.getContainingFile().getContainingDirectory();
80 copyClassImpl(className
, project
, aClass
, targetDirectory
, RefactoringBundle
.message("copy.handler.clone.class"), true);
84 private static void copyClassImpl(final String copyClassName
, final Project project
, final PsiClass aClass
, final PsiDirectory targetDirectory
, String commandName
, final boolean selectInActivePanel
) {
85 if (copyClassName
== null || copyClassName
.length() == 0) return;
86 final boolean[] result
= new boolean[] {false};
87 Runnable command
= new Runnable() {
89 final Runnable action
= new Runnable() {
92 PsiElement newElement
= doCopyClass(aClass
, copyClassName
, targetDirectory
);
93 CopyHandler
.updateSelectionInActiveProjectView(newElement
, project
, selectInActivePanel
);
94 EditorHelper
.openInEditor(newElement
);
98 catch (final IncorrectOperationException ex
) {
99 ApplicationManager
.getApplication().invokeLater(new Runnable() {
101 Messages
.showMessageDialog(project
, ex
.getMessage(), RefactoringBundle
.message("error.title"), Messages
.getErrorIcon());
107 ApplicationManager
.getApplication().runWriteAction(action
);
110 CommandProcessor processor
= CommandProcessor
.getInstance();
111 processor
.executeCommand(project
, command
, commandName
, null);
114 ToolWindowManager
.getInstance(project
).invokeLater(new Runnable() {
116 ToolWindowManager
.getInstance(project
).activateEditorComponent();
122 public static PsiElement
doCopyClass(final PsiClass aClass
, final String copyClassName
, final PsiDirectory targetDirectory
)
123 throws IncorrectOperationException
{
124 PsiElement elementToCopy
= aClass
.getNavigationElement();
126 final PsiClass classCopy
= (PsiClass
)elementToCopy
.copy();
127 classCopy
.setName(copyClassName
);
129 final String fileName
= copyClassName
+ "." + elementToCopy
.getContainingFile().getOriginalFile().getViewProvider().getVirtualFile().getExtension();
130 final PsiFile createdFile
= targetDirectory
.copyFileFrom(fileName
, elementToCopy
.getContainingFile());
131 PsiElement newElement
= createdFile
;
132 if (createdFile
instanceof PsiClassOwner
) {
133 for (final PsiClass psiClass
: ((PsiClassOwner
)createdFile
).getClasses()) {
134 if (!(psiClass
instanceof SyntheticElement
)) {
135 createdFile
.deleteChildRange(psiClass
, psiClass
);
139 final PsiClass newClass
= (PsiClass
)createdFile
.add(classCopy
);
141 for (final PsiReference reference
: ReferencesSearch
.search(aClass
, new LocalSearchScope(newClass
)).findAll()) {
142 reference
.bindToElement(newClass
);
145 new OptimizeImportsProcessor(aClass
.getProject(), createdFile
).run();
147 newElement
= newClass
;
153 private static PsiClass
getTopLevelClass(PsiElement element
) {
155 if (element
== null || element
instanceof PsiFile
) break;
156 if (element
instanceof PsiClass
&& element
.getParent() instanceof PsiFile
) break;
157 element
= element
.getParent();
159 if (element
instanceof PsiClassOwner
) {
160 PsiClass
[] classes
= ((PsiClassOwner
)element
).getClasses();
161 if (classes
.length
> 0) {
162 for (final PsiClass aClass
: classes
) {
163 if (aClass
instanceof SyntheticElement
) {
168 element
= classes
[0];
171 return element
instanceof PsiClass ?
(PsiClass
)element
: null;