1 package com
.intellij
.testIntegration
.createTest
;
3 import com
.intellij
.CommonBundle
;
4 import com
.intellij
.codeInsight
.CodeInsightBundle
;
5 import com
.intellij
.codeInsight
.daemon
.impl
.quickfix
.OrderEntryFix
;
6 import com
.intellij
.ide
.util
.*;
7 import com
.intellij
.openapi
.actionSystem
.AnAction
;
8 import com
.intellij
.openapi
.actionSystem
.AnActionEvent
;
9 import com
.intellij
.openapi
.actionSystem
.CustomShortcutSet
;
10 import com
.intellij
.openapi
.application
.ApplicationManager
;
11 import com
.intellij
.openapi
.application
.ReadAction
;
12 import com
.intellij
.openapi
.application
.Result
;
13 import com
.intellij
.openapi
.command
.WriteCommandAction
;
14 import com
.intellij
.openapi
.extensions
.Extensions
;
15 import com
.intellij
.openapi
.help
.HelpManager
;
16 import com
.intellij
.openapi
.module
.Module
;
17 import com
.intellij
.openapi
.project
.Project
;
18 import com
.intellij
.openapi
.roots
.ContentEntry
;
19 import com
.intellij
.openapi
.roots
.ModuleRootManager
;
20 import com
.intellij
.openapi
.roots
.SourceFolder
;
21 import com
.intellij
.openapi
.ui
.DialogWrapper
;
22 import com
.intellij
.openapi
.ui
.Messages
;
23 import com
.intellij
.openapi
.util
.IconLoader
;
24 import com
.intellij
.openapi
.util
.Pair
;
25 import com
.intellij
.openapi
.vfs
.VirtualFile
;
26 import com
.intellij
.psi
.*;
27 import com
.intellij
.refactoring
.PackageWrapper
;
28 import com
.intellij
.refactoring
.move
.moveClassesOrPackages
.MoveClassesOrPackagesUtil
;
29 import com
.intellij
.refactoring
.ui
.MemberSelectionTable
;
30 import com
.intellij
.refactoring
.util
.RefactoringMessageUtil
;
31 import com
.intellij
.refactoring
.util
.RefactoringUtil
;
32 import com
.intellij
.refactoring
.util
.classMembers
.MemberInfo
;
33 import com
.intellij
.testIntegration
.TestFrameworkDescriptor
;
34 import com
.intellij
.testIntegration
.TestIntegrationUtils
;
35 import com
.intellij
.ui
.*;
36 import com
.intellij
.util
.IncorrectOperationException
;
37 import org
.jetbrains
.annotations
.NotNull
;
40 import javax
.swing
.event
.DocumentEvent
;
42 import java
.awt
.event
.ActionEvent
;
43 import java
.awt
.event
.ActionListener
;
44 import java
.awt
.event
.InputEvent
;
45 import java
.awt
.event
.KeyEvent
;
47 import java
.util
.List
;
49 public class CreateTestDialog
extends DialogWrapper
{
50 private static final String RECENTS_KEY
= "CreateTestDialog.RecentsKey";
51 private static final String DEFAULT_LIBRARY_NAME_PROPERTY
= CreateTestDialog
.class.getName() + ".defaultLibrary";
52 private static final String SHOW_INHERITED_MEMBERS_PROPERTY
= CreateTestDialog
.class.getName() + ".includeInheritedMembers";
54 private final Project myProject
;
55 private final PsiClass myTargetClass
;
56 private final Module myTargetModule
;
58 private PsiDirectory myTargetDirectory
;
59 private TestFrameworkDescriptor mySelectedTestDescriptor
;
61 private final List
<JRadioButton
> myLibraryButtons
= new ArrayList
<JRadioButton
>();
62 private JTextField myTargetClassNameField
;
63 private ReferenceEditorWithBrowseButton mySuperClassField
;
64 private ReferenceEditorComboWithBrowseButton myTargetPackageField
;
65 private JCheckBox myGenerateBeforeBox
;
66 private JCheckBox myGenerateAfterBox
;
67 private JCheckBox myShowInheritedMethodsBox
;
68 private MemberSelectionTable myMethodsTable
;
69 private JButton myFixLibraryButton
;
70 private JPanel myFixLibraryPanel
;
71 private JLabel myFixLibraryLabel
;
73 private JRadioButton myDefaultLibraryButton
;
75 public CreateTestDialog(@NotNull Project project
,
76 @NotNull String title
,
78 PsiPackage targetPackage
,
79 Module targetModule
) {
83 myTargetClass
= targetClass
;
84 myTargetModule
= targetModule
;
86 initControls(targetClass
, targetPackage
);
90 myDefaultLibraryButton
.doClick();
93 private void initControls(PsiClass targetClass
, PsiPackage targetPackage
) {
94 ButtonGroup group
= new ButtonGroup();
96 Map
<String
, JRadioButton
> nameToButtonMap
= new HashMap
<String
, JRadioButton
>();
97 List
<Pair
<String
, JRadioButton
>> attachedLibraries
= new ArrayList
<Pair
<String
, JRadioButton
>>();
99 for (final TestFrameworkDescriptor descriptor
: Extensions
.getExtensions(TestFrameworkDescriptor
.EXTENSION_NAME
)) {
100 final JRadioButton b
= new JRadioButton(descriptor
.getName());
101 myLibraryButtons
.add(b
);
104 nameToButtonMap
.put(descriptor
.getName(), b
);
105 if (descriptor
.isLibraryAttached(myTargetModule
)) {
106 attachedLibraries
.add(Pair
.create(descriptor
.getName(), b
));
109 b
.addActionListener(new ActionListener() {
110 public void actionPerformed(ActionEvent e
) {
111 if (b
.isSelected()) onLibrarySelected(descriptor
);
116 String defaultLibrary
= getDefaultLibraryName();
117 if (attachedLibraries
.isEmpty()) {
118 if (defaultLibrary
!= null) {
119 myDefaultLibraryButton
= nameToButtonMap
.get(defaultLibrary
);
123 if (defaultLibrary
!= null) {
124 for (Pair
<String
, JRadioButton
> each
: attachedLibraries
) {
125 if (each
.first
.equals(defaultLibrary
)) {
126 myDefaultLibraryButton
= each
.second
;
130 myDefaultLibraryButton
= attachedLibraries
.get(0).second
;
132 if (myDefaultLibraryButton
== null) {
133 myDefaultLibraryButton
= myLibraryButtons
.get(0);
136 myFixLibraryButton
= new JButton(CodeInsightBundle
.message("intention.create.test.dialog.fix.library"));
137 myFixLibraryButton
.addActionListener(new ActionListener() {
138 public void actionPerformed(ActionEvent e
) {
139 ApplicationManager
.getApplication().runWriteAction(new Runnable() {
141 OrderEntryFix
.addJarToRoots(mySelectedTestDescriptor
.getLibraryPath(), myTargetModule
);
144 myFixLibraryPanel
.setVisible(false);
148 myTargetClassNameField
= new JTextField(targetClass
.getName() + "Test");
149 setPreferredSize(myTargetClassNameField
);
150 myTargetClassNameField
.getDocument().addDocumentListener(new DocumentAdapter() {
151 protected void textChanged(DocumentEvent e
) {
152 getOKAction().setEnabled(JavaPsiFacade
.getInstance(myProject
).getNameHelper().isIdentifier(getClassName()));
156 mySuperClassField
= JavaReferenceEditorUtil
157 .createReferenceEditorWithBrowseButton(new MyChooseSuperClassAction(), "", PsiManager
.getInstance(myProject
), true);
158 mySuperClassField
.setMinimumSize(mySuperClassField
.getPreferredSize());
160 String targetPackageName
= targetPackage
!= null ? targetPackage
.getQualifiedName() : "";
161 myTargetPackageField
= new ReferenceEditorComboWithBrowseButton(new ActionListener() {
162 public void actionPerformed(final ActionEvent e
) {
165 }, targetPackageName
, PsiManager
.getInstance(myProject
), false, RECENTS_KEY
);
168 public void actionPerformed(AnActionEvent e
) {
169 myTargetPackageField
.getButton().doClick();
171 }.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke
.getKeyStroke(KeyEvent
.VK_ENTER
, InputEvent
.SHIFT_DOWN_MASK
)),
172 myTargetPackageField
.getChildComponent());
174 myGenerateBeforeBox
= new JCheckBox("setUp/@Before");
175 myGenerateAfterBox
= new JCheckBox("tearDown/@After");
177 myShowInheritedMethodsBox
= new JCheckBox(CodeInsightBundle
.message("intention.create.test.dialog.show.inherited"));
178 myShowInheritedMethodsBox
.addActionListener(new ActionListener() {
179 public void actionPerformed(ActionEvent e
) {
180 updateMethodsTable();
183 restoreShowInheritedMembersStatus();
184 myMethodsTable
= new MemberSelectionTable(Collections
.<MemberInfo
>emptyList(), null);
185 updateMethodsTable();
188 private void onLibrarySelected(TestFrameworkDescriptor descriptor
) {
189 String text
= CodeInsightBundle
.message("intention.create.test.dialog.library.not.found", descriptor
.getName());
190 myFixLibraryLabel
.setText(text
);
191 myFixLibraryPanel
.setVisible(!descriptor
.isLibraryAttached(myTargetModule
));
193 String superClass
= descriptor
.getDefaultSuperClass();
194 mySuperClassField
.setText(superClass
== null ?
"" : superClass
);
195 mySelectedTestDescriptor
= descriptor
;
198 private void setPreferredSize(JTextField field
) {
199 Dimension size
= field
.getPreferredSize();
200 FontMetrics fontMetrics
= field
.getFontMetrics(field
.getFont());
201 size
.width
= fontMetrics
.charWidth('a') * 40;
202 field
.setPreferredSize(size
);
205 private void updateMethodsTable() {
206 List
<MemberInfo
> methods
= TestIntegrationUtils
.extractClassMethods(
207 myTargetClass
, myShowInheritedMethodsBox
.isSelected());
209 Set
<PsiMember
> selectedMethods
= new HashSet
<PsiMember
>();
210 for (MemberInfo each
: myMethodsTable
.getSelectedMemberInfos()) {
211 selectedMethods
.add(each
.getMember());
213 for (MemberInfo each
: methods
) {
214 each
.setChecked(selectedMethods
.contains(each
.getMember()));
217 myMethodsTable
.setMemberInfos(methods
);
220 private void doSelectPackage() {
221 PackageChooserDialog d
= new PackageChooserDialog(CodeInsightBundle
.message("dialog.create.class.package.chooser.title"), myProject
);
222 d
.selectPackage(myTargetPackageField
.getText());
224 PsiPackage p
= d
.getSelectedPackage();
225 if (p
!= null) myTargetPackageField
.setText(p
.getQualifiedName());
228 private String
getDefaultLibraryName() {
229 return getProperties().getValue(DEFAULT_LIBRARY_NAME_PROPERTY
);
232 private void saveDefaultLibraryName() {
233 getProperties().setValue(DEFAULT_LIBRARY_NAME_PROPERTY
, mySelectedTestDescriptor
.getName());
236 private void restoreShowInheritedMembersStatus() {
237 String v
= getProperties().getValue(SHOW_INHERITED_MEMBERS_PROPERTY
);
238 myShowInheritedMethodsBox
.setSelected(v
!= null && v
.equals("true"));
241 private void saveShowInheritedMembersStatus() {
242 boolean v
= myShowInheritedMethodsBox
.isSelected();
243 getProperties().setValue(SHOW_INHERITED_MEMBERS_PROPERTY
, Boolean
.toString(v
));
246 private PropertiesComponent
getProperties() {
247 return PropertiesComponent
.getInstance(myProject
);
251 protected String
getDimensionServiceKey() {
252 return getClass().getName();
255 protected Action
[] createActions() {
256 return new Action
[]{getOKAction(), getCancelAction(), getHelpAction()};
259 public JComponent
getPreferredFocusedComponent() {
260 return myTargetClassNameField
;
263 protected JComponent
createCenterPanel() {
264 JPanel panel
= new JPanel(new GridBagLayout());
265 panel
.setBorder(IdeBorderFactory
.createBorder());
267 GridBagConstraints constr
= new GridBagConstraints();
269 constr
.fill
= GridBagConstraints
.HORIZONTAL
;
270 constr
.anchor
= GridBagConstraints
.WEST
;
272 JPanel librariesPanel
= new JPanel();
273 BoxLayout l
= new BoxLayout(librariesPanel
, BoxLayout
.X_AXIS
);
274 librariesPanel
.setLayout(l
);
276 for (JRadioButton b
: myLibraryButtons
) {
277 librariesPanel
.add(b
);
280 constr
.insets
= insets(4);
284 panel
.add(new JLabel(CodeInsightBundle
.message("intention.create.test.dialog.testing.library")), constr
);
288 constr
.gridwidth
= GridBagConstraints
.REMAINDER
;
289 panel
.add(librariesPanel
, constr
);
291 myFixLibraryPanel
= new JPanel(new BorderLayout());
292 myFixLibraryLabel
= new JLabel();
293 myFixLibraryLabel
.setIcon(IconLoader
.getIcon("/actions/intentionBulb.png"));
294 myFixLibraryPanel
.add(myFixLibraryLabel
, BorderLayout
.CENTER
);
295 myFixLibraryPanel
.add(myFixLibraryButton
, BorderLayout
.EAST
);
297 constr
.insets
= insets(1);
300 panel
.add(myFixLibraryPanel
, constr
);
302 constr
.gridheight
= 1;
304 constr
.insets
= insets(6);
308 constr
.gridwidth
= 1;
309 panel
.add(new JLabel(CodeInsightBundle
.message("intention.create.test.dialog.class.name")), constr
);
313 panel
.add(myTargetClassNameField
, constr
);
315 constr
.insets
= insets(1);
319 panel
.add(new JLabel(CodeInsightBundle
.message("intention.create.test.dialog.super.class")), constr
);
323 panel
.add(mySuperClassField
, constr
);
325 constr
.insets
= insets(1);
329 panel
.add(new JLabel(CodeInsightBundle
.message("dialog.create.class.destination.package.label")), constr
);
334 JPanel targetPackagePanel
= new JPanel(new BorderLayout());
335 targetPackagePanel
.add(myTargetPackageField
, BorderLayout
.CENTER
);
336 panel
.add(targetPackagePanel
, constr
);
338 constr
.insets
= insets(6);
342 panel
.add(new JLabel(CodeInsightBundle
.message("intention.create.test.dialog.generate")), constr
);
346 panel
.add(myGenerateBeforeBox
, constr
);
348 constr
.insets
= insets(1);
350 panel
.add(myGenerateAfterBox
, constr
);
352 constr
.insets
= insets(6);
356 panel
.add(new JLabel(CodeInsightBundle
.message("intention.create.test.dialog.select.methods")), constr
);
360 panel
.add(myShowInheritedMethodsBox
, constr
);
362 constr
.insets
= insets(1, 8);
365 constr
.gridwidth
= GridBagConstraints
.REMAINDER
;
366 constr
.fill
= GridBagConstraints
.BOTH
;
368 panel
.add(new JScrollPane(myMethodsTable
), constr
);
373 private static Insets
insets(int top
) {
374 return insets(top
, 0);
377 private static Insets
insets(int top
, int bottom
) {
378 return new Insets(top
, 8, bottom
, 8);
381 public String
getClassName() {
382 return myTargetClassNameField
.getText();
385 public String
getSuperClassName() {
386 String result
= mySuperClassField
.getText().trim();
387 if (result
.length() == 0) return null;
391 public PsiDirectory
getTargetDirectory() {
392 return myTargetDirectory
;
395 public Collection
<MemberInfo
> getSelectedMethods() {
396 return myMethodsTable
.getSelectedMemberInfos();
399 public boolean shouldGeneratedAfter() {
400 return myGenerateAfterBox
.isSelected();
403 public boolean shouldGeneratedBefore() {
404 return myGenerateBeforeBox
.isSelected();
407 public TestFrameworkDescriptor
getSelectedTestFrameworkDescriptor() {
408 return mySelectedTestDescriptor
;
411 protected void doOKAction() {
412 RecentsManager
.getInstance(myProject
).registerRecentEntry(RECENTS_KEY
, myTargetPackageField
.getText());
414 String errorMessage
= null;
416 myTargetDirectory
= selectTargetDirectory();
417 if (myTargetDirectory
== null) return;
418 errorMessage
= RefactoringMessageUtil
.checkCanCreateClass(myTargetDirectory
, getClassName());
420 catch (IncorrectOperationException e
) {
421 errorMessage
= e
.getMessage();
424 if (errorMessage
!= null) {
425 Messages
.showMessageDialog(myProject
, errorMessage
, CommonBundle
.getErrorTitle(), Messages
.getErrorIcon());
428 saveDefaultLibraryName();
429 saveShowInheritedMembersStatus();
433 private PsiDirectory
selectTargetDirectory() throws IncorrectOperationException
{
434 final String packageName
= getPackageName();
435 final PackageWrapper targetPackage
= new PackageWrapper(PsiManager
.getInstance(myProject
), packageName
);
437 final VirtualFile selectedRoot
= new ReadAction
<VirtualFile
>() {
438 protected void run(Result
<VirtualFile
> result
) throws Throwable
{
439 VirtualFile
[] roots
= ModuleRootManager
.getInstance(myTargetModule
).getSourceRoots();
440 if (roots
.length
== 0) return;
442 if (roots
.length
== 1) {
443 result
.setResult(roots
[0]);
446 PsiDirectory defaultDir
= chooseDefaultDirectory(packageName
);
447 result
.setResult(MoveClassesOrPackagesUtil
.chooseSourceRoot(targetPackage
, roots
, defaultDir
));
450 }.execute().getResultObject();
452 if (selectedRoot
== null) return null;
454 return new WriteCommandAction
<PsiDirectory
>(myProject
, CodeInsightBundle
.message("create.directory.command")) {
455 protected void run(Result
<PsiDirectory
> result
) throws Throwable
{
456 result
.setResult(RefactoringUtil
.createPackageDirectoryInSourceRoot(targetPackage
, selectedRoot
));
458 }.execute().getResultObject();
461 private PsiDirectory
chooseDefaultDirectory(String packageName
) {
462 for (ContentEntry e
: ModuleRootManager
.getInstance(myTargetModule
).getContentEntries()) {
463 for (SourceFolder f
: e
.getSourceFolders()) {
464 if (f
.getFile() != null && f
.isTestSource()) {
465 return PsiManager
.getInstance(myProject
).findDirectory(f
.getFile());
469 return PackageUtil
.findPossiblePackageDirectoryInModule(myTargetModule
, packageName
);
472 private String
getPackageName() {
473 String name
= myTargetPackageField
.getText();
474 return name
!= null ? name
.trim() : "";
478 protected void doHelpAction() {
479 HelpManager
.getInstance().invokeHelp("reference.dialogs.createTest");
482 private class MyChooseSuperClassAction
implements ActionListener
{
483 public void actionPerformed(ActionEvent e
) {
484 TreeClassChooserFactory f
= TreeClassChooserFactory
.getInstance(myProject
);
485 TreeClassChooser dialog
=
486 f
.createAllProjectScopeChooser(CodeInsightBundle
.message("intention.create.test.dialog.choose.super.class"));
488 PsiClass aClass
= dialog
.getSelectedClass();
489 if (aClass
!= null) {
490 mySuperClassField
.setText(aClass
.getQualifiedName());