| /* |
| * Copyright 2000-2011 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.testIntegration.createTest; |
| |
| import com.intellij.CommonBundle; |
| import com.intellij.codeInsight.CodeInsightBundle; |
| import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix; |
| import com.intellij.icons.AllIcons; |
| import com.intellij.ide.util.PackageUtil; |
| import com.intellij.ide.util.PropertiesComponent; |
| import com.intellij.ide.util.TreeClassChooser; |
| import com.intellij.ide.util.TreeClassChooserFactory; |
| import com.intellij.openapi.actionSystem.AnAction; |
| import com.intellij.openapi.actionSystem.AnActionEvent; |
| import com.intellij.openapi.actionSystem.CustomShortcutSet; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.application.ReadAction; |
| import com.intellij.openapi.application.Result; |
| import com.intellij.openapi.command.WriteCommandAction; |
| import com.intellij.openapi.editor.event.DocumentAdapter; |
| import com.intellij.openapi.editor.event.DocumentEvent; |
| import com.intellij.openapi.extensions.Extensions; |
| import com.intellij.openapi.help.HelpManager; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.roots.ModuleRootManager; |
| import com.intellij.openapi.ui.DialogWrapper; |
| import com.intellij.openapi.ui.Messages; |
| import com.intellij.openapi.util.Pair; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.psi.*; |
| import com.intellij.refactoring.PackageWrapper; |
| import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesUtil; |
| import com.intellij.refactoring.ui.MemberSelectionTable; |
| import com.intellij.refactoring.ui.PackageNameReferenceEditorCombo; |
| import com.intellij.refactoring.util.RefactoringMessageUtil; |
| import com.intellij.refactoring.util.RefactoringUtil; |
| import com.intellij.refactoring.util.classMembers.MemberInfo; |
| import com.intellij.testIntegration.JavaTestFramework; |
| import com.intellij.testIntegration.TestFramework; |
| import com.intellij.testIntegration.TestIntegrationUtils; |
| import com.intellij.ui.EditorTextField; |
| import com.intellij.ui.RecentsManager; |
| import com.intellij.ui.ReferenceEditorComboWithBrowseButton; |
| import com.intellij.ui.ScrollPaneFactory; |
| import com.intellij.util.IncorrectOperationException; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes; |
| import org.jetbrains.jps.model.java.JavaSourceRootType; |
| |
| import javax.swing.*; |
| import java.awt.*; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import java.awt.event.InputEvent; |
| import java.awt.event.KeyEvent; |
| import java.util.*; |
| import java.util.List; |
| |
| public class CreateTestDialog extends DialogWrapper { |
| private static final String RECENTS_KEY = "CreateTestDialog.RecentsKey"; |
| private static final String RECENT_SUPERS_KEY = "CreateTestDialog.Recents.Supers"; |
| private static final String DEFAULT_LIBRARY_NAME_PROPERTY = CreateTestDialog.class.getName() + ".defaultLibrary"; |
| private static final String SHOW_INHERITED_MEMBERS_PROPERTY = CreateTestDialog.class.getName() + ".includeInheritedMembers"; |
| |
| private final Project myProject; |
| private final PsiClass myTargetClass; |
| private final Module myTargetModule; |
| |
| private PsiDirectory myTargetDirectory; |
| private TestFramework mySelectedFramework; |
| |
| private final List<JRadioButton> myLibraryButtons = new ArrayList<JRadioButton>(); |
| private EditorTextField myTargetClassNameField; |
| private ReferenceEditorComboWithBrowseButton mySuperClassField; |
| private ReferenceEditorComboWithBrowseButton myTargetPackageField; |
| private JCheckBox myGenerateBeforeBox; |
| private JCheckBox myGenerateAfterBox; |
| private JCheckBox myShowInheritedMethodsBox; |
| private MemberSelectionTable myMethodsTable; |
| private JButton myFixLibraryButton; |
| private JPanel myFixLibraryPanel; |
| private JLabel myFixLibraryLabel; |
| |
| private JRadioButton myDefaultLibraryButton; |
| |
| public CreateTestDialog(@NotNull Project project, |
| @NotNull String title, |
| PsiClass targetClass, |
| PsiPackage targetPackage, |
| Module targetModule) { |
| super(project, true); |
| myProject = project; |
| |
| myTargetClass = targetClass; |
| myTargetModule = targetModule; |
| |
| initControls(targetClass, targetPackage); |
| setTitle(title); |
| init(); |
| |
| myDefaultLibraryButton.doClick(); |
| } |
| |
| private void initControls(PsiClass targetClass, PsiPackage targetPackage) { |
| ButtonGroup group = new ButtonGroup(); |
| |
| Map<String, JRadioButton> nameToButtonMap = new HashMap<String, JRadioButton>(); |
| List<Pair<String, JRadioButton>> attachedLibraries = new ArrayList<Pair<String, JRadioButton>>(); |
| |
| for (final TestFramework descriptor : Extensions.getExtensions(TestFramework.EXTENSION_NAME)) { |
| final JRadioButton b = new JRadioButton(descriptor.getName()); |
| if (descriptor instanceof JavaTestFramework) { |
| final char mnemonic = ((JavaTestFramework)descriptor).getMnemonic(); |
| if (mnemonic > -1) { |
| b.setMnemonic(mnemonic); |
| } |
| } |
| myLibraryButtons.add(b); |
| group.add(b); |
| |
| nameToButtonMap.put(descriptor.getName(), b); |
| if (descriptor.isLibraryAttached(myTargetModule)) { |
| attachedLibraries.add(Pair.create(descriptor.getName(), b)); |
| } |
| |
| b.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| if (b.isSelected()) onLibrarySelected(descriptor); |
| } |
| }); |
| } |
| |
| String defaultLibrary = getDefaultLibraryName(); |
| if (attachedLibraries.isEmpty()) { |
| if (defaultLibrary != null) { |
| myDefaultLibraryButton = nameToButtonMap.get(defaultLibrary); |
| } |
| } |
| else { |
| if (defaultLibrary != null) { |
| for (Pair<String, JRadioButton> each : attachedLibraries) { |
| if (each.first.equals(defaultLibrary)) { |
| myDefaultLibraryButton = each.second; |
| } |
| } |
| } |
| if (myDefaultLibraryButton == null) { |
| myDefaultLibraryButton = attachedLibraries.get(0).second; |
| } |
| } |
| if (myDefaultLibraryButton == null) { |
| myDefaultLibraryButton = myLibraryButtons.get(0); |
| } |
| |
| myFixLibraryButton = new JButton(CodeInsightBundle.message("intention.create.test.dialog.fix.library")); |
| myFixLibraryButton.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| ApplicationManager.getApplication().runWriteAction(new Runnable() { |
| public void run() { |
| OrderEntryFix.addJarToRoots(mySelectedFramework.getLibraryPath(), myTargetModule, null); |
| } |
| }); |
| myFixLibraryPanel.setVisible(false); |
| } |
| }); |
| |
| myTargetClassNameField = new EditorTextField(targetClass.getName() + "Test"); |
| myTargetClassNameField.getDocument().addDocumentListener(new DocumentAdapter() { |
| @Override |
| public void documentChanged(DocumentEvent e) { |
| getOKAction().setEnabled(JavaPsiFacade.getInstance(myProject).getNameHelper().isIdentifier(getClassName())); |
| } |
| }); |
| |
| mySuperClassField = new ReferenceEditorComboWithBrowseButton(new MyChooseSuperClassAction(), null, myProject, true, |
| JavaCodeFragment.VisibilityChecker.EVERYTHING_VISIBLE, RECENT_SUPERS_KEY); |
| mySuperClassField.setMinimumSize(mySuperClassField.getPreferredSize()); |
| |
| String targetPackageName = targetPackage != null ? targetPackage.getQualifiedName() : ""; |
| myTargetPackageField = new PackageNameReferenceEditorCombo(targetPackageName, myProject, RECENTS_KEY, CodeInsightBundle.message("dialog.create.class.package.chooser.title")); |
| |
| new AnAction() { |
| public void actionPerformed(AnActionEvent e) { |
| myTargetPackageField.getButton().doClick(); |
| } |
| }.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_DOWN_MASK)), |
| myTargetPackageField.getChildComponent()); |
| |
| myGenerateBeforeBox = new JCheckBox("setUp/@Before"); |
| myGenerateAfterBox = new JCheckBox("tearDown/@After"); |
| |
| myShowInheritedMethodsBox = new JCheckBox(CodeInsightBundle.message("intention.create.test.dialog.show.inherited")); |
| myShowInheritedMethodsBox.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| updateMethodsTable(); |
| } |
| }); |
| restoreShowInheritedMembersStatus(); |
| myMethodsTable = new MemberSelectionTable(Collections.<MemberInfo>emptyList(), null); |
| updateMethodsTable(); |
| } |
| |
| private void onLibrarySelected(TestFramework descriptor) { |
| String text = CodeInsightBundle.message("intention.create.test.dialog.library.not.found", descriptor.getName()); |
| myFixLibraryLabel.setText(text); |
| myFixLibraryPanel.setVisible(!descriptor.isLibraryAttached(myTargetModule)); |
| |
| String superClass = descriptor.getDefaultSuperClass(); |
| mySuperClassField.appendItem(superClass == null ? "" : superClass); |
| mySelectedFramework = descriptor; |
| } |
| |
| private void updateMethodsTable() { |
| List<MemberInfo> methods = TestIntegrationUtils.extractClassMethods( |
| myTargetClass, myShowInheritedMethodsBox.isSelected()); |
| |
| Set<PsiMember> selectedMethods = new HashSet<PsiMember>(); |
| for (MemberInfo each : myMethodsTable.getSelectedMemberInfos()) { |
| selectedMethods.add(each.getMember()); |
| } |
| for (MemberInfo each : methods) { |
| each.setChecked(selectedMethods.contains(each.getMember())); |
| } |
| |
| myMethodsTable.setMemberInfos(methods); |
| } |
| |
| private String getDefaultLibraryName() { |
| return getProperties().getValue(DEFAULT_LIBRARY_NAME_PROPERTY); |
| } |
| |
| private void saveDefaultLibraryName() { |
| getProperties().setValue(DEFAULT_LIBRARY_NAME_PROPERTY, mySelectedFramework.getName()); |
| } |
| |
| private void restoreShowInheritedMembersStatus() { |
| String v = getProperties().getValue(SHOW_INHERITED_MEMBERS_PROPERTY); |
| myShowInheritedMethodsBox.setSelected(v != null && v.equals("true")); |
| } |
| |
| private void saveShowInheritedMembersStatus() { |
| boolean v = myShowInheritedMethodsBox.isSelected(); |
| getProperties().setValue(SHOW_INHERITED_MEMBERS_PROPERTY, Boolean.toString(v)); |
| } |
| |
| private PropertiesComponent getProperties() { |
| return PropertiesComponent.getInstance(myProject); |
| } |
| |
| @Override |
| protected String getDimensionServiceKey() { |
| return getClass().getName(); |
| } |
| |
| @NotNull |
| protected Action[] createActions() { |
| return new Action[]{getOKAction(), getCancelAction(), getHelpAction()}; |
| } |
| |
| public JComponent getPreferredFocusedComponent() { |
| return myTargetClassNameField; |
| } |
| |
| protected JComponent createCenterPanel() { |
| JPanel panel = new JPanel(new GridBagLayout()); |
| |
| GridBagConstraints constr = new GridBagConstraints(); |
| |
| constr.fill = GridBagConstraints.HORIZONTAL; |
| constr.anchor = GridBagConstraints.WEST; |
| |
| JPanel librariesPanel = new JPanel(); |
| BoxLayout l = new BoxLayout(librariesPanel, BoxLayout.X_AXIS); |
| librariesPanel.setLayout(l); |
| |
| for (JRadioButton b : myLibraryButtons) { |
| librariesPanel.add(b); |
| } |
| |
| |
| int gridy = 1; |
| |
| constr.insets = insets(4); |
| constr.gridy = gridy++; |
| constr.gridx = 0; |
| constr.weightx = 0; |
| panel.add(new JLabel(CodeInsightBundle.message("intention.create.test.dialog.testing.library")), constr); |
| |
| constr.gridx = 1; |
| constr.weightx = 1; |
| constr.gridwidth = GridBagConstraints.REMAINDER; |
| panel.add(librariesPanel, constr); |
| |
| myFixLibraryPanel = new JPanel(new BorderLayout()); |
| myFixLibraryLabel = new JLabel(); |
| myFixLibraryLabel.setIcon(AllIcons.Actions.IntentionBulb); |
| myFixLibraryPanel.add(myFixLibraryLabel, BorderLayout.CENTER); |
| myFixLibraryPanel.add(myFixLibraryButton, BorderLayout.EAST); |
| |
| constr.insets = insets(1); |
| constr.gridy = gridy++; |
| constr.gridx = 0; |
| panel.add(myFixLibraryPanel, constr); |
| |
| constr.gridheight = 1; |
| |
| constr.insets = insets(6); |
| constr.gridy = gridy++; |
| constr.gridx = 0; |
| constr.weightx = 0; |
| constr.gridwidth = 1; |
| panel.add(new JLabel(CodeInsightBundle.message("intention.create.test.dialog.class.name")), constr); |
| |
| constr.gridx = 1; |
| constr.weightx = 1; |
| panel.add(myTargetClassNameField, constr); |
| |
| constr.insets = insets(1); |
| constr.gridy = gridy++; |
| constr.gridx = 0; |
| constr.weightx = 0; |
| panel.add(new JLabel(CodeInsightBundle.message("intention.create.test.dialog.super.class")), constr); |
| |
| constr.gridx = 1; |
| constr.weightx = 1; |
| panel.add(mySuperClassField, constr); |
| |
| constr.insets = insets(1); |
| constr.gridy = gridy++; |
| constr.gridx = 0; |
| constr.weightx = 0; |
| panel.add(new JLabel(CodeInsightBundle.message("dialog.create.class.destination.package.label")), constr); |
| |
| constr.gridx = 1; |
| constr.weightx = 1; |
| |
| JPanel targetPackagePanel = new JPanel(new BorderLayout()); |
| targetPackagePanel.add(myTargetPackageField, BorderLayout.CENTER); |
| panel.add(targetPackagePanel, constr); |
| |
| constr.insets = insets(6); |
| constr.gridy = gridy++; |
| constr.gridx = 0; |
| constr.weightx = 0; |
| panel.add(new JLabel(CodeInsightBundle.message("intention.create.test.dialog.generate")), constr); |
| |
| constr.gridx = 1; |
| constr.weightx = 1; |
| panel.add(myGenerateBeforeBox, constr); |
| |
| constr.insets = insets(1); |
| constr.gridy = gridy++; |
| panel.add(myGenerateAfterBox, constr); |
| |
| constr.insets = insets(6); |
| constr.gridy = gridy++; |
| constr.gridx = 0; |
| constr.weightx = 0; |
| panel.add(new JLabel(CodeInsightBundle.message("intention.create.test.dialog.select.methods")), constr); |
| |
| constr.gridx = 1; |
| constr.weightx = 1; |
| panel.add(myShowInheritedMethodsBox, constr); |
| |
| constr.insets = insets(1, 8); |
| constr.gridy = gridy++; |
| constr.gridx = 0; |
| constr.gridwidth = GridBagConstraints.REMAINDER; |
| constr.fill = GridBagConstraints.BOTH; |
| constr.weighty = 1; |
| panel.add(ScrollPaneFactory.createScrollPane(myMethodsTable), constr); |
| |
| return panel; |
| } |
| |
| private static Insets insets(int top) { |
| return insets(top, 0); |
| } |
| |
| private static Insets insets(int top, int bottom) { |
| return new Insets(top, 8, bottom, 8); |
| } |
| |
| public String getClassName() { |
| return myTargetClassNameField.getText(); |
| } |
| |
| @Nullable |
| public String getSuperClassName() { |
| String result = mySuperClassField.getText().trim(); |
| if (result.length() == 0) return null; |
| return result; |
| } |
| |
| public PsiDirectory getTargetDirectory() { |
| return myTargetDirectory; |
| } |
| |
| public Collection<MemberInfo> getSelectedMethods() { |
| return myMethodsTable.getSelectedMemberInfos(); |
| } |
| |
| public boolean shouldGeneratedAfter() { |
| return myGenerateAfterBox.isSelected(); |
| } |
| |
| public boolean shouldGeneratedBefore() { |
| return myGenerateBeforeBox.isSelected(); |
| } |
| |
| public TestFramework getSelectedTestFrameworkDescriptor() { |
| return mySelectedFramework; |
| } |
| |
| protected void doOKAction() { |
| RecentsManager.getInstance(myProject).registerRecentEntry(RECENTS_KEY, myTargetPackageField.getText()); |
| RecentsManager.getInstance(myProject).registerRecentEntry(RECENT_SUPERS_KEY, mySuperClassField.getText()); |
| |
| String errorMessage; |
| try { |
| myTargetDirectory = selectTargetDirectory(); |
| if (myTargetDirectory == null) return; |
| errorMessage = RefactoringMessageUtil.checkCanCreateClass(myTargetDirectory, getClassName()); |
| } |
| catch (IncorrectOperationException e) { |
| errorMessage = e.getMessage(); |
| } |
| |
| if (errorMessage != null) { |
| Messages.showMessageDialog(myProject, errorMessage, CommonBundle.getErrorTitle(), Messages.getErrorIcon()); |
| } |
| |
| saveDefaultLibraryName(); |
| saveShowInheritedMembersStatus(); |
| super.doOKAction(); |
| } |
| |
| @Nullable |
| private PsiDirectory selectTargetDirectory() throws IncorrectOperationException { |
| final String packageName = getPackageName(); |
| final PackageWrapper targetPackage = new PackageWrapper(PsiManager.getInstance(myProject), packageName); |
| |
| final VirtualFile selectedRoot = new ReadAction<VirtualFile>() { |
| protected void run(Result<VirtualFile> result) throws Throwable { |
| final HashSet<VirtualFile> testFolders = new HashSet<VirtualFile>(); |
| CreateTestAction.checkForTestRoots(myTargetModule, testFolders); |
| List<VirtualFile> roots; |
| if (testFolders.isEmpty()) { |
| roots = ModuleRootManager.getInstance(myTargetModule).getSourceRoots(JavaModuleSourceRootTypes.SOURCES); |
| if (roots.isEmpty()) return; |
| } else { |
| roots = new ArrayList<VirtualFile>(testFolders); |
| } |
| |
| if (roots.size() == 1) { |
| result.setResult(roots.get(0)); |
| } |
| else { |
| PsiDirectory defaultDir = chooseDefaultDirectory(packageName); |
| result.setResult(MoveClassesOrPackagesUtil.chooseSourceRoot(targetPackage, roots, defaultDir)); |
| } |
| } |
| }.execute().getResultObject(); |
| |
| if (selectedRoot == null) return null; |
| |
| return new WriteCommandAction<PsiDirectory>(myProject, CodeInsightBundle.message("create.directory.command")) { |
| protected void run(Result<PsiDirectory> result) throws Throwable { |
| result.setResult(RefactoringUtil.createPackageDirectoryInSourceRoot(targetPackage, selectedRoot)); |
| } |
| }.execute().getResultObject(); |
| } |
| |
| @Nullable |
| private PsiDirectory chooseDefaultDirectory(String packageName) { |
| List<PsiDirectory> dirs = new ArrayList<PsiDirectory>(); |
| for (VirtualFile file : ModuleRootManager.getInstance(myTargetModule).getSourceRoots(JavaSourceRootType.TEST_SOURCE)) { |
| final PsiDirectory dir = PsiManager.getInstance(myProject).findDirectory(file); |
| if (dir != null) { |
| dirs.add(dir); |
| } |
| } |
| if (!dirs.isEmpty()) { |
| for (PsiDirectory dir : dirs) { |
| final String dirName = dir.getVirtualFile().getPath(); |
| if (dirName.contains("generated")) continue; |
| return dir; |
| } |
| return dirs.get(0); |
| } |
| return PackageUtil.findPossiblePackageDirectoryInModule(myTargetModule, packageName); |
| } |
| |
| private String getPackageName() { |
| String name = myTargetPackageField.getText(); |
| return name != null ? name.trim() : ""; |
| } |
| |
| @Override |
| protected void doHelpAction() { |
| HelpManager.getInstance().invokeHelp("reference.dialogs.createTest"); |
| } |
| |
| private class MyChooseSuperClassAction implements ActionListener { |
| public void actionPerformed(ActionEvent e) { |
| TreeClassChooserFactory f = TreeClassChooserFactory.getInstance(myProject); |
| TreeClassChooser dialog = |
| f.createAllProjectScopeChooser(CodeInsightBundle.message("intention.create.test.dialog.choose.super.class")); |
| dialog.showDialog(); |
| PsiClass aClass = dialog.getSelected(); |
| if (aClass != null) { |
| mySuperClassField.setText(aClass.getQualifiedName()); |
| } |
| } |
| } |
| } |