From f08501ef5de3ed335b9ebad3e216e68bbe965d97 Mon Sep 17 00:00:00 2001 From: "kirill.safonov" Date: Thu, 12 Jan 2012 16:27:17 +0400 Subject: [PATCH 01/45] SDK combobox - better API for 'New' and 'Edit' buttons --- .../roots/ui/configuration/JdkComboBox.java | 37 ++++++++----------- .../configuration/ModuleJdkConfigurable.java | 18 ++++++--- .../configuration/ProjectJdkConfigurable.java | 10 ++++- .../src/messages/ApplicationBundle.properties | 2 +- .../src/messages/ProjectBundle.properties | 2 +- 5 files changed, 37 insertions(+), 32 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java index e70b585dac5b..d06839e6df6c 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java @@ -18,7 +18,6 @@ package com.intellij.openapi.roots.ui.configuration; import com.intellij.ide.DataManager; import com.intellij.ide.util.projectWizard.ProjectJdkListRenderer; import com.intellij.openapi.actionSystem.DefaultActionGroup; -import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.Sdk; @@ -48,7 +47,6 @@ import java.util.Comparator; * @since May 18, 2005 */ class JdkComboBox extends ComboBoxWithWidePopup { - private final JButton myEditButton = new JButton(ApplicationBundle.message("button.edit")); public JdkComboBox(@NotNull final ProjectSdksModel jdkModel) { super(new JdkComboBoxModel(jdkModel)); @@ -101,17 +99,12 @@ class JdkComboBox extends ComboBoxWithWidePopup { return minSize; } - public JButton createSetupButton(final Project project, final ProjectSdksModel jdksModel, final JdkComboBoxItem firstItem) { - return createSetupButton(project, jdksModel, firstItem, null, false); - } - - - public JButton createSetupButton(final Project project, - final ProjectSdksModel jdksModel, - final JdkComboBoxItem firstItem, - @Nullable final Condition additionalSetup, - final boolean moduleJdkSetup) { - final JButton setUpButton = new JButton(ApplicationBundle.message("button.new")); + public void setSetupButton(final JButton setUpButton, + final Project project, + final ProjectSdksModel jdksModel, + final JdkComboBoxItem firstItem, + @Nullable final Condition additionalSetup, + final boolean moduleJdkSetup) { setUpButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { final JdkListConfigurable configurable = JdkListConfigurable.getInstance(project); @@ -130,15 +123,15 @@ class JdkComboBox extends ComboBoxWithWidePopup { }); JBPopupFactory.getInstance() .createActionGroupPopup(ProjectBundle.message("project.roots.set.up.jdk.title", moduleJdkSetup ? 1 : 2), group, - DataManager.getInstance().getDataContext(JdkComboBox.this), JBPopupFactory.ActionSelectionAid.MNEMONICS, false) + DataManager.getInstance().getDataContext(JdkComboBox.this), JBPopupFactory.ActionSelectionAid.MNEMONICS, + false) .showUnderneathOf(setUpButton); } }); - return setUpButton; } - public void appendEditButton(final Project project, final JPanel panel, GridBagConstraints gc, final Computable retrieveJDK){ - myEditButton.addActionListener(new ActionListener() { + public void setEditButton(final JButton editButton, final Project project, final Computable retrieveJDK){ + editButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { final Sdk projectJdk = retrieveJDK.compute(); if (projectJdk != null) { @@ -146,17 +139,17 @@ class JdkComboBox extends ComboBoxWithWidePopup { } } }); - addActionListener(new ActionListener(){ + addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { final JdkComboBoxItem selectedItem = getSelectedItem(); if (selectedItem instanceof ProjectJdkComboBoxItem) { - myEditButton.setEnabled(ProjectStructureConfigurable.getInstance(project).getProjectJdksModel().getProjectSdk() != null); - } else { - myEditButton.setEnabled(!(selectedItem instanceof InvalidJdkComboBoxItem) && selectedItem != null && selectedItem.getJdk() != null); + editButton.setEnabled(ProjectStructureConfigurable.getInstance(project).getProjectJdksModel().getProjectSdk() != null); + } + else { + editButton.setEnabled(!(selectedItem instanceof InvalidJdkComboBoxItem) && selectedItem != null && selectedItem.getJdk() != null); } } }); - panel.add(myEditButton, gc); } public JdkComboBoxItem getSelectedItem() { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java index 718f923efcea..3dd421d20568 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java @@ -17,6 +17,7 @@ package com.intellij.openapi.roots.ui.configuration; import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; @@ -119,17 +120,18 @@ public abstract class ModuleJdkConfigurable implements Disposable { GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(6, 6, 12, 0), 0, 0)); final Project project = getRootModel().getModule().getProject(); - final JButton setUpButton = myCbModuleJdk - .createSetupButton(project, myJdksModel, new JdkComboBox.ProjectJdkComboBoxItem(), new Condition(){ + final JButton setUpButton = new JButton(ApplicationBundle.message("button.new")); + myCbModuleJdk + .setSetupButton(setUpButton, project, myJdksModel, new JdkComboBox.ProjectJdkComboBoxItem(), new Condition() { public boolean value(Sdk jdk) { final Sdk projectJdk = myJdksModel.getProjectSdk(); - if (projectJdk == null){ + if (projectJdk == null) { final int res = Messages.showYesNoDialog(myJdkPanel, ProjectBundle.message("project.roots.no.jdk.on.project.message"), - ProjectBundle.message("project.roots.no.jdk.on.projecct.title"), + ProjectBundle.message("project.roots.no.jdk.on.project.title"), Messages.getInformationIcon()); - if (res == DialogWrapper.OK_EXIT_CODE){ + if (res == DialogWrapper.OK_EXIT_CODE) { myJdksModel.setProjectSdk(jdk); return true; } @@ -140,12 +142,16 @@ public abstract class ModuleJdkConfigurable implements Disposable { myJdkPanel.add(setUpButton, new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 4, 7, 0), 0, 0)); - myCbModuleJdk.appendEditButton(getRootModel().getModule().getProject(), myJdkPanel, new GridBagConstraints(GridBagConstraints.RELATIVE, 0, 1, 1, 1.0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 4, 7, 0), 0, 0) , new Computable() { + final JButton editButton = new JButton(ApplicationBundle.message("button.edit")); + myCbModuleJdk.setEditButton(editButton, getRootModel().getModule().getProject(), new Computable() { @Nullable public Sdk compute() { return getRootModel().getSdk(); } }); + myJdkPanel.add(editButton, + new GridBagConstraints(GridBagConstraints.RELATIVE, 0, 1, 1, 1.0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, + new Insets(0, 4, 7, 0), 0, 0)); } private void clearCaches() { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java index 54a36d3c569f..ade16cb422a5 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java @@ -16,6 +16,7 @@ package com.intellij.openapi.roots.ui.configuration; +import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.module.Module; import com.intellij.openapi.options.UnnamedConfigurable; import com.intellij.openapi.project.Project; @@ -90,14 +91,19 @@ public class ProjectJdkConfigurable implements UnnamedConfigurable { }); myJdkPanel.add(new JLabel(ProjectBundle.message("module.libraries.target.jdk.project.radio")), new GridBagConstraints(0, 0, 3, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 4, 0), 0, 0)); myJdkPanel.add(myCbProjectJdk, new GridBagConstraints(0, 1, 1, 1, 0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 4, 0, 0), 0, 0)); - final JButton setUpButton = myCbProjectJdk.createSetupButton(myProject, myJdksModel, new JdkComboBox.NoneJdkComboBoxItem()); + final JButton setUpButton = new JButton(ApplicationBundle.message("button.new")); + myCbProjectJdk.setSetupButton(setUpButton, myProject, myJdksModel, new JdkComboBox.NoneJdkComboBoxItem(), null, false); myJdkPanel.add(setUpButton, new GridBagConstraints(1, 1, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 4, 0, 0), 0, 0)); - myCbProjectJdk.appendEditButton(myProject, myJdkPanel, new GridBagConstraints(GridBagConstraints.RELATIVE, 1, 1, 1, 1.0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 4, 0, 0), 0, 0), new Computable() { + final JButton editButton = new JButton(ApplicationBundle.message("button.edit")); + myCbProjectJdk.setEditButton(editButton, myProject, new Computable() { @Nullable public Sdk compute() { return myJdksModel.getProjectSdk(); } }); + + myJdkPanel.add(editButton, new GridBagConstraints(GridBagConstraints.RELATIVE, 1, 1, 1, 1.0, 0, GridBagConstraints.NORTHWEST, + GridBagConstraints.NONE, new Insets(0, 4, 0, 0), 0, 0)); } return myJdkPanel; } diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index 6d98d4313ea2..d47af0ff6eec 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -528,7 +528,7 @@ exclude.from.imports.no.exclusions=No exclude patterns inline.elements=Inline elements: don.t.break.if.inline.content=Don't break if inline content: edit.code.folding.options=Open code folding options -button.new=&New +button.new=&New... building.include.indices=Building include indices... loading.include.indices=Loading include indices... use.external.annotations=Use &external annotations diff --git a/platform/platform-resources-en/src/messages/ProjectBundle.properties b/platform/platform-resources-en/src/messages/ProjectBundle.properties index ab1c4ae0ee85..9786327eed59 100644 --- a/platform/platform-resources-en/src/messages/ProjectBundle.properties +++ b/platform/platform-resources-en/src/messages/ProjectBundle.properties @@ -297,7 +297,7 @@ facet.banner.text=Facet ''{0}'' project.roots.project.banner.text=General Settings for Project ''{0}'' project.roots.set.up.jdk.title=Set up {0, choice, 1#module|2#project} SDK project.roots.no.jdk.on.project.message=Set up created sdk on project? -project.roots.no.jdk.on.projecct.title=No project sdk set up +project.roots.no.jdk.on.project.title=Create SDK project.roots.jdks.node.text=JDK stands for the Java Development Kit, a software development package that is required to write, test and debug Java applications. \ JDK also contains classes and runtime environment that are used to execute the target application.

\ Mobile SDK contains emulator of mobile phone as well as embedded Java SDK to compile/pack/run/debug J2ME applications.

\ From 8cf1e71fdbe3ef490488d79c60883ed41bd3575e Mon Sep 17 00:00:00 2001 From: "kirill.safonov" Date: Mon, 16 Jan 2012 22:30:13 +0400 Subject: [PATCH 02/45] Flex build configurations in IDEA project setup UI --- .../roots/ui/configuration/JdkComboBox.java | 29 +++++++++++++++---- .../roots/impl/ModuleJdkOrderEntryImpl.java | 25 ++++++++++++++-- .../src/messages/ProjectBundle.properties | 2 +- .../src/META-INF/LangExtensionPoints.xml | 2 ++ 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java index d06839e6df6c..97807b9292df 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java @@ -46,7 +46,7 @@ import java.util.Comparator; * @author Eugene Zhuravlev * @since May 18, 2005 */ -class JdkComboBox extends ComboBoxWithWidePopup { +public class JdkComboBox extends ComboBoxWithWidePopup { public JdkComboBox(@NotNull final ProjectSdksModel jdkModel) { super(new JdkComboBoxModel(jdkModel)); @@ -105,6 +105,16 @@ class JdkComboBox extends ComboBoxWithWidePopup { final JdkComboBoxItem firstItem, @Nullable final Condition additionalSetup, final boolean moduleJdkSetup) { + setSetupButton(setUpButton, project, jdksModel, firstItem, additionalSetup, + ProjectBundle.message("project.roots.set.up.jdk.title", moduleJdkSetup ? 1 : 2)); + } + + public void setSetupButton(final JButton setUpButton, + final Project project, + final ProjectSdksModel jdksModel, + final JdkComboBoxItem firstItem, + @Nullable final Condition additionalSetup, + final String actionGroupTitle) { setUpButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { final JdkListConfigurable configurable = JdkListConfigurable.getInstance(project); @@ -122,7 +132,7 @@ class JdkComboBox extends ComboBoxWithWidePopup { } }); JBPopupFactory.getInstance() - .createActionGroupPopup(ProjectBundle.message("project.roots.set.up.jdk.title", moduleJdkSetup ? 1 : 2), group, + .createActionGroupPopup(actionGroupTitle, group, DataManager.getInstance().getDataContext(JdkComboBox.this), JBPopupFactory.ActionSelectionAid.MNEMONICS, false) .showUnderneathOf(setUpButton); @@ -253,6 +263,11 @@ class JdkComboBox extends ComboBoxWithWidePopup { return myJdk; } + @Nullable + public String getSdkName() { + return myJdk != null ? myJdk.getName() : null; + } + public String toString() { return myJdk.getName(); } @@ -279,15 +294,19 @@ class JdkComboBox extends ComboBoxWithWidePopup { } private static class InvalidJdkComboBoxItem extends JdkComboBoxItem { - private final String myName; + private final String mySdkName; public InvalidJdkComboBoxItem(String name) { super(null); - myName = ProjectBundle.message("jdk.combo.box.invalid.item", name); + mySdkName = name; + } + + public String getSdkName() { + return mySdkName; } public String toString() { - return myName; + return ProjectBundle.message("jdk.combo.box.invalid.item", mySdkName); } } } diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/ModuleJdkOrderEntryImpl.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/ModuleJdkOrderEntryImpl.java index b923084c275d..c90b321c1e3d 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/ModuleJdkOrderEntryImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/ModuleJdkOrderEntryImpl.java @@ -16,6 +16,7 @@ package com.intellij.openapi.roots.impl; +import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ModuleJdkOrderEntry; @@ -29,6 +30,7 @@ import org.jdom.Attribute; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author dsl @@ -62,8 +64,7 @@ public class ModuleJdkOrderEntryImpl extends LibraryOrderEntryBaseImpl implement final String jdkName = jdkNameAttribute.getValue(); final String jdkType = element.getAttributeValue(JDK_TYPE_ATTR); - final ProjectJdkTable projectJdkTable = ProjectJdkTable.getInstance(); - final Sdk jdkByName = projectJdkTable.findJdk(jdkName, jdkType); + final Sdk jdkByName = findJdk(jdkName, jdkType); if (jdkByName == null) { init(null, jdkName, jdkType); } @@ -72,6 +73,26 @@ public class ModuleJdkOrderEntryImpl extends LibraryOrderEntryBaseImpl implement } } + public abstract static class SdkFinder { + private static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.sdkFinder"); + + @Nullable + public Sdk findSdk(String name, String sdkType) { + return null; + } + } + + @Nullable + private static Sdk findJdk(final String jdkName, final String jdkType) { + for (SdkFinder sdkFinder : SdkFinder.EP_NAME.getExtensions()) { + final Sdk sdk = sdkFinder.findSdk(jdkName, jdkType); + if (sdk != null) { + return sdk; + } + } + final ProjectJdkTable projectJdkTable = ProjectJdkTable.getInstance(); + return projectJdkTable.findJdk(jdkName, jdkType); + } private ModuleJdkOrderEntryImpl(ModuleJdkOrderEntryImpl that, RootModelImpl rootModel, ProjectRootManagerImpl projectRootManager) { diff --git a/platform/platform-resources-en/src/messages/ProjectBundle.properties b/platform/platform-resources-en/src/messages/ProjectBundle.properties index 9786327eed59..c76b9e4d5ef3 100644 --- a/platform/platform-resources-en/src/messages/ProjectBundle.properties +++ b/platform/platform-resources-en/src/messages/ProjectBundle.properties @@ -295,7 +295,7 @@ module.library.display.name=Module {0, choice, 1#Library|2#Libraries} project.roots.library.banner.text= {1} ''{0}'' facet.banner.text=Facet ''{0}'' project.roots.project.banner.text=General Settings for Project ''{0}'' -project.roots.set.up.jdk.title=Set up {0, choice, 1#module|2#project} SDK +project.roots.set.up.jdk.title=Set up {0, choice, 1#Module|2#Project} SDK project.roots.no.jdk.on.project.message=Set up created sdk on project? project.roots.no.jdk.on.project.title=Create SDK project.roots.jdks.node.text=JDK stands for the Java Development Kit, a software development package that is required to write, test and debug Java applications. \ diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 9f001e7a2620..60a3aadc231a 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -313,6 +313,8 @@ + + Date: Tue, 17 Jan 2012 18:17:04 +0400 Subject: [PATCH 03/45] new Flex project/module wizard --- .../openapi/projectRoots/ui/ProjectJdksEditor.java | 6 +++++- .../roots/ui/configuration/ProjectJdksConfigurable.java | 9 ++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/projectRoots/ui/ProjectJdksEditor.java b/java/idea-ui/src/com/intellij/openapi/projectRoots/ui/ProjectJdksEditor.java index bb416ccb4047..2739fdea8d4a 100644 --- a/java/idea-ui/src/com/intellij/openapi/projectRoots/ui/ProjectJdksEditor.java +++ b/java/idea-ui/src/com/intellij/openapi/projectRoots/ui/ProjectJdksEditor.java @@ -39,8 +39,12 @@ public class ProjectJdksEditor extends DialogWrapper { public ProjectJdksEditor(final Sdk jdk, Project project, Component parent) { + this(jdk, parent, new ProjectJdksConfigurable(project)); + } + + public ProjectJdksEditor(final Sdk jdk, Component parent, ProjectJdksConfigurable configurable) { super(parent, true); - myConfigurable = new ProjectJdksConfigurable(project); + myConfigurable = configurable; SwingUtilities.invokeLater(new Runnable(){ public void run() { myConfigurable.selectNodeInTree(jdk != null ? jdk.getName() : null); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java index 456a15a004ea..ac6d5cd9ca80 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java @@ -57,13 +57,16 @@ public class ProjectJdksConfigurable extends MasterDetailsComponent { private final ProjectSdksModel myProjectJdksModel; private final Project myProject; - @NonNls + @NonNls private static final String SPLITTER_PROPORTION = "project.jdk.splitter"; public ProjectJdksConfigurable(Project project) { - super(); + this(project, ProjectStructureConfigurable.getInstance(project).getProjectJdksModel()); + } + + public ProjectJdksConfigurable(Project project, ProjectSdksModel sdksModel) { myProject = project; - myProjectJdksModel = ProjectStructureConfigurable.getInstance(project).getProjectJdksModel(); + myProjectJdksModel = sdksModel; initTree(); } From 91c7543d8cd4c2157ac224238522765d02859490 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 17 Jan 2012 20:07:21 +0400 Subject: [PATCH 04/45] perform checks for java sdks only(cherry picked from commit 6fd765f) --- .../javaCompiler/javac/JavacCompiler.java | 65 ++++++++++--------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacCompiler.java b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacCompiler.java index 85133995723e..ab6d143ed41f 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacCompiler.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacCompiler.java @@ -79,48 +79,49 @@ public class JavacCompiler extends ExternalCompiler { final Set checkedJdks = new HashSet(); for (final Module module : modules) { final Sdk jdk = ModuleRootManager.getInstance(module).getSdk(); - if (jdk == null) { + if (jdk == null || checkedJdks.contains(jdk)) { continue; } - if (checkedJdks.contains(jdk)) { + checkedJdks.add(jdk); + final SdkType sdkType = jdk.getSdkType(); + if (!(sdkType instanceof JavaSdkType)) { continue; } final VirtualFile homeDirectory = jdk.getHomeDirectory(); if (homeDirectory == null) { - Messages.showMessageDialog(myProject, CompilerBundle.jdkHomeNotFoundMessage(jdk), - CompilerBundle.message("compiler.javac.name"), Messages.getErrorIcon()); + Messages.showMessageDialog( + myProject, CompilerBundle.jdkHomeNotFoundMessage(jdk), CompilerBundle.message("compiler.javac.name"), Messages.getErrorIcon() + ); return false; } - final SdkType sdkType = jdk.getSdkType(); + final String vmExecutablePath = ((JavaSdkType)sdkType).getVMExecutablePath(jdk); + if (vmExecutablePath == null) { + Messages.showMessageDialog( + myProject, CompilerBundle.message("javac.error.vm.executable.missing", jdk.getName()), CompilerBundle.message("compiler.javac.name"), Messages.getErrorIcon() + ); + return false; + } + final String toolsJarPath = ((JavaSdkType)sdkType).getToolsPath(jdk); + if (toolsJarPath == null) { + Messages.showMessageDialog( + myProject, CompilerBundle.message("javac.error.tools.jar.missing", jdk.getName()), CompilerBundle.message("compiler.javac.name"), Messages.getErrorIcon() + ); + return false; + } + final String versionString = jdk.getVersionString(); + if (versionString == null) { + Messages.showMessageDialog( + myProject, CompilerBundle.message("javac.error.unknown.jdk.version", jdk.getName()), CompilerBundle.message("compiler.javac.name"), Messages.getErrorIcon() + ); + return false; + } - if (sdkType instanceof JavaSdkType){ - final String vmExecutablePath = ((JavaSdkType)sdkType).getVMExecutablePath(jdk); - if (vmExecutablePath == null) { - Messages.showMessageDialog(myProject, - CompilerBundle.message("javac.error.vm.executable.missing", jdk.getName()), - CompilerBundle.message("compiler.javac.name"), Messages.getErrorIcon()); - return false; - } - final String toolsJarPath = ((JavaSdkType)sdkType).getToolsPath(jdk); - if (toolsJarPath == null) { - Messages.showMessageDialog(myProject, - CompilerBundle.message("javac.error.tools.jar.missing", jdk.getName()), CompilerBundle.message("compiler.javac.name"), - Messages.getErrorIcon()); - return false; - } - final String versionString = jdk.getVersionString(); - if (versionString == null) { - Messages.showMessageDialog(myProject, CompilerBundle.message("javac.error.unknown.jdk.version", jdk.getName()), - CompilerBundle.message("compiler.javac.name"), Messages.getErrorIcon()); - return false; - } - - if (CompilerUtil.isOfVersion(versionString, "1.0")) { - Messages.showMessageDialog(myProject, CompilerBundle.message("javac.error.1_0_compilation.not.supported"), CompilerBundle.message("compiler.javac.name"), Messages.getErrorIcon()); - return false; - } + if (CompilerUtil.isOfVersion(versionString, "1.0")) { + Messages.showMessageDialog( + myProject, CompilerBundle.message("javac.error.1_0_compilation.not.supported"), CompilerBundle.message("compiler.javac.name"), Messages.getErrorIcon() + ); + return false; } - checkedJdks.add(jdk); } return true; From 98da9890a7b5e7577da7dc2bcc45194cbdad5a04 Mon Sep 17 00:00:00 2001 From: Alexander Doroshko Date: Fri, 20 Jan 2012 19:44:57 +0400 Subject: [PATCH 05/45] step validation fixed --- .../util/projectWizard/ProjectNameStep.java | 27 +++++++++++++------ .../src/messages/IdeBundle.properties | 1 + 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/java/idea-ui/src/com/intellij/ide/util/projectWizard/ProjectNameStep.java b/java/idea-ui/src/com/intellij/ide/util/projectWizard/ProjectNameStep.java index 30f2e572413f..0d7cdbb3621d 100644 --- a/java/idea-ui/src/com/intellij/ide/util/projectWizard/ProjectNameStep.java +++ b/java/idea-ui/src/com/intellij/ide/util/projectWizard/ProjectNameStep.java @@ -21,6 +21,7 @@ import com.intellij.ide.highlighter.ModuleFileType; import com.intellij.openapi.application.ApplicationInfo; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.io.FileUtil; @@ -32,6 +33,8 @@ import java.awt.*; import java.io.File; import java.util.List; +import static com.intellij.openapi.components.StorageScheme.DIRECTORY_BASED; + /** * @author Eugene Zhuravlev * Date: Jan 21, 2004 @@ -73,7 +76,7 @@ public class ProjectNameStep extends ModuleWizardStep { public void updateStep() { super.updateStep(); - myNamePathComponent.setPath(myWizardContext.getProjectFileDirectory()); + myNamePathComponent.setPath(FileUtil.toSystemDependentName(myWizardContext.getProjectFileDirectory())); String name = myWizardContext.getProjectName(); if (name == null) { List components = StringUtil.split(FileUtil.toSystemIndependentName(myWizardContext.getProjectFileDirectory()), "/"); @@ -115,13 +118,21 @@ public class ProjectNameStep extends ModuleWizardStep { } boolean shouldContinue = true; - final File projectFile = new File(getProjectFilePath()); + + final String path = myWizardContext.isCreatingNewProject() && myWizardContext.getProjectStorageFormat() == DIRECTORY_BASED + ? getProjectFileDirectory() + "/" + ProjectUtil.DIRECTORY_BASED_PROJECT_DIR + : getProjectFilePath(); + final File projectFile = new File(path); if (projectFile.exists()) { - int answer = Messages.showYesNoDialog( - IdeBundle.message("prompt.overwrite.project.file", projectFile.getAbsolutePath(), myWizardContext.getPresentationName()), - IdeBundle.message("title.file.already.exists"), - Messages.getQuestionIcon() - ); + final String title = myWizardContext.isCreatingNewProject() + ? IdeBundle.message("title.new.project") + : IdeBundle.message("title.add.module"); + final String message = myWizardContext.isCreatingNewProject() && myWizardContext.getProjectStorageFormat() == DIRECTORY_BASED + ? IdeBundle.message("prompt.overwrite.project.folder", ProjectUtil.DIRECTORY_BASED_PROJECT_DIR, + projectFile.getParentFile().getAbsolutePath()) + : IdeBundle.message("prompt.overwrite.project.file", projectFile.getAbsolutePath(), + myWizardContext.getPresentationName()); + int answer = Messages.showYesNoDialog(message, title, Messages.getQuestionIcon()); shouldContinue = answer == 0; } @@ -135,7 +146,7 @@ public class ProjectNameStep extends ModuleWizardStep { } public String getProjectFileDirectory() { - return myNamePathComponent.getPath(); + return FileUtil.toSystemIndependentName(myNamePathComponent.getPath()); } public String getProjectName() { diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index 6569aa43ef02..930e05c21b14 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -744,6 +744,7 @@ prompt.new.project.file.name=Enter a file name to create a new {0} {1} prompt.enter.project.file.location=Enter {0} file location directory.project.file.directory=The {0} file directory\n prompt.overwrite.project.file=The {1} file \n''{0}''\nalready exists.\nWould you like to overwrite it? +prompt.overwrite.project.folder={0} folder already exists in {1}.\nIts content may be overwritten.\nContinue? warning.message.the.module.file.0.already.exist.and.will.be.overwritten=The module file ''{0}'' already exist. warning.text.0.do.you.want.to.overwrite.these.files={0}\nWould you like to overwrite {1,choice,1#it|2#these files}? title.select.jdk=Select JDK From bb0e3cf632fc7b9368b850e987f59a3329295ac9 Mon Sep 17 00:00:00 2001 From: Alexander Doroshko Date: Fri, 20 Jan 2012 19:45:31 +0400 Subject: [PATCH 06/45] layout and controls visibility fixed --- .../project/MavenImportingConfigurable.java | 2 +- .../project/MavenImportingSettingsForm.form | 50 ++++++++++++------- .../project/MavenImportingSettingsForm.java | 12 ++--- .../maven/wizards/MavenProjectImportStep.java | 2 +- 4 files changed, 38 insertions(+), 28 deletions(-) diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingConfigurable.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingConfigurable.java index d237d20b257c..97ce892739b1 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingConfigurable.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingConfigurable.java @@ -30,7 +30,7 @@ import java.util.List; public class MavenImportingConfigurable implements SearchableConfigurable { private final MavenImportingSettings myImportingSettings; - private final MavenImportingSettingsForm mySettingsForm = new MavenImportingSettingsForm(false); + private final MavenImportingSettingsForm mySettingsForm = new MavenImportingSettingsForm(false, false); private final List myAdditionalConfigurables; public MavenImportingConfigurable(Project project, MavenImportingSettings importingSettings) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form index afbaec959a37..b139c1710d06 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form @@ -1,6 +1,6 @@
- + @@ -10,7 +10,7 @@ - + @@ -18,7 +18,7 @@ - + @@ -29,22 +29,20 @@ - - + - - + @@ -52,16 +50,16 @@ - + - + - + @@ -101,7 +99,7 @@ - + @@ -110,7 +108,7 @@ - + @@ -118,13 +116,13 @@ - + - + - + @@ -155,7 +153,7 @@ - + @@ -178,13 +176,13 @@ - + - + - + @@ -211,6 +209,20 @@ + + + + + + + + + + + + + + diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.java index 9b636230d2be..a87e516cf075 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.java @@ -49,13 +49,11 @@ public class MavenImportingSettingsForm { private JPanel myAdditionalSettingsPanel; private JPanel mySeparateModulesDirPanel; - public MavenImportingSettingsForm(boolean isImportStep) { - if (!isImportStep) { - mySearchRecursivelyCheckBox.setVisible(false); - myProjectFormatLabel.setVisible(false); - myProjectFormatComboBox.setVisible(false); - mySeparateModulesDirPanel.setVisible(false); - } + public MavenImportingSettingsForm(boolean isImportStep, boolean isCreatingNewProject) { + mySearchRecursivelyCheckBox.setVisible(isImportStep); + myProjectFormatLabel.setVisible(isImportStep && isCreatingNewProject); + myProjectFormatComboBox.setVisible(isImportStep && isCreatingNewProject); + mySeparateModulesDirPanel.setVisible(isImportStep); ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent e) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenProjectImportStep.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenProjectImportStep.java index 07d6df0736c4..046a0ee1d38f 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenProjectImportStep.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenProjectImportStep.java @@ -41,7 +41,7 @@ public class MavenProjectImportStep extends ProjectImportWizardStep { public MavenProjectImportStep(WizardContext wizardContext) { super(wizardContext); - myImportingSettingsForm = new MavenImportingSettingsForm(true) { + myImportingSettingsForm = new MavenImportingSettingsForm(true, wizardContext.isCreatingNewProject()) { public String getDefaultModuleDir() { return myRootPathComponent.getPath(); } From 40d8223f1dce3077efd19d791f48c343bbb551be Mon Sep 17 00:00:00 2001 From: Alexander Doroshko Date: Fri, 20 Jan 2012 19:45:53 +0400 Subject: [PATCH 07/45] Maven importer should be able to create module of any type --- .../idea/maven/importing/MavenImporter.java | 8 +++ .../maven/importing/MavenProjectImporter.java | 66 +++++++++++++------ .../idea/maven/project/MavenProject.java | 13 ++++ .../project/MavenProjectsManagerWatcher.java | 9 +++ .../main/resources/ProjectBundle.properties | 9 ++- 5 files changed, 79 insertions(+), 26 deletions(-) diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java index 2e3b6dd3f1ba..b46464c7fd95 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java @@ -17,9 +17,12 @@ package org.jetbrains.idea.maven.importing; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleType; +import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import org.jdom.Element; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.model.MavenArtifact; import org.jetbrains.idea.maven.project.*; @@ -57,6 +60,11 @@ public abstract class MavenImporter { return mavenProject.findPlugin(myPluginGroupID, myPluginArtifactID) != null; } + @NotNull + public ModuleType getModuleType() { + return StdModuleTypes.JAVA; + } + public void getSupportedPackagings(Collection result) { } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenProjectImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenProjectImporter.java index 32c3051362cf..af639dae5c95 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenProjectImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenProjectImporter.java @@ -176,50 +176,74 @@ public class MavenProjectImporter { } private boolean deleteIncompatibleModules() { - final List> incompatible = collectIncompatibleModulesWithProjects(); - if (incompatible.isEmpty()) return false; + final Pair>, List>> incompatible = collectIncompatibleModulesWithProjects(); + final List> incompatibleMavenized = incompatible.first; + final List> incompatibleNotMavenized = incompatible.second; + + if (incompatibleMavenized.isEmpty() && incompatibleNotMavenized.isEmpty()) return false; + + boolean changed = false; + + // For already mavenized modules the type may change because maven project plugins were resolved and MavenImporter asked to create a module of a different type. + // In such cases we must change module type silently. + for (Pair each : incompatibleMavenized) { + myFileToModuleMapping.remove(each.first.getFile()); + myModuleModel.disposeModule(each.second); + changed |= true; + } + + if (incompatibleNotMavenized.isEmpty()) return changed; final int[] result = new int[1]; MavenUtil.invokeAndWait(myProject, myModelsProvider.getModalityStateForQuestionDialogs(), new Runnable() { public void run() { String message = ProjectBundle.message("maven.import.incompatible.modules", - formatProjectsWithModules(incompatible), - incompatible.size() == 1 ? "" : "s"); + incompatibleNotMavenized.size(), + formatProjectsWithModules(incompatibleNotMavenized)); String[] options = { ProjectBundle.message("maven.import.incompatible.modules.recreate"), ProjectBundle.message("maven.import.incompatible.modules.ignore") }; result[0] = Messages.showOkCancelDialog(myProject, message, - ProjectBundle.message("maven.tab.importing"), - options[0], options[1], Messages.getQuestionIcon()); + ProjectBundle.message("maven.project.import.title"), + options[0], options[1], Messages.getQuestionIcon()); } }); if (result[0] == 0) { - for (Pair each : incompatible) { + for (Pair each : incompatibleNotMavenized) { myFileToModuleMapping.remove(each.first.getFile()); myModuleModel.disposeModule(each.second); } - return true; + changed |= true; } else { - myProjectsTree.setIgnoredState(MavenUtil.collectFirsts(incompatible), true, true); - return false; + myProjectsTree.setIgnoredState(MavenUtil.collectFirsts(incompatibleNotMavenized), true, true); + changed |= false; } + + return changed; } - private List> collectIncompatibleModulesWithProjects() { - List> incompatible = new ArrayList>(); + /** + * Collects modules that need to change module type + * @return the first List in returned Pair contains already mavenized modules, the second List - not mavenized + */ + private Pair>, List>> collectIncompatibleModulesWithProjects() { + List> incompatibleMavenized = new ArrayList>(); + List> incompatibleNotMavenized = new ArrayList>(); + + MavenProjectsManager manager = MavenProjectsManager.getInstance(myProject); for (MavenProject each : myAllProjects) { Module module = myFileToModuleMapping.get(each.getFile()); if (module == null) continue; - if (shouldCreateModuleFor(each) && !(ModuleType.get(module) instanceof JavaModuleType)) { - incompatible.add(Pair.create(each, module)); + if (shouldCreateModuleFor(each) && !(ModuleType.get(module).equals(each.getModuleType()))) { + (manager.isMavenizedModule(module) ? incompatibleMavenized : incompatibleNotMavenized).add(Pair.create(each, module)); } } - return incompatible; + return Pair.create(incompatibleMavenized, incompatibleNotMavenized); } private static String formatProjectsWithModules(List> projectsWithModules) { @@ -230,9 +254,8 @@ public class MavenProjectImporter { return ModuleType.get(module).getName() + " '" + module.getName() + - "' for Maven project '" + - project.getMavenId().getDisplayString() + - "'"; + "' for Maven project " + + project.getMavenId().getDisplayString(); } }, "
"); } @@ -248,7 +271,7 @@ public class MavenProjectImporter { public void run() { result[0] = Messages.showYesNoDialog(myProject, ProjectBundle.message("maven.import.message.delete.obsolete", formatModules(obsoleteModules)), - ProjectBundle.message("maven.tab.importing"), + ProjectBundle.message("maven.project.import.title"), Messages.getQuestionIcon()); } }); @@ -271,8 +294,9 @@ public class MavenProjectImporter { } List obsolete = new ArrayList(); + final MavenProjectsManager manager = MavenProjectsManager.getInstance(myProject); for (Module each : remainingModules) { - if (MavenProjectsManager.getInstance(myProject).isMavenizedModule(each)) { + if (manager.isMavenizedModule(each)) { obsolete.add(each); } } @@ -440,7 +464,7 @@ public class MavenProjectImporter { // have to remove it beforehand. deleteExistingImlFile(path); - final Module module = myModuleModel.newModule(path, StdModuleTypes.JAVA); + final Module module = myModuleModel.newModule(path, project.getModuleType()); myMavenProjectToModule.put(project, module); myCreatedModules.add(module); return true; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java index 69f03c707e9e..04f1bbccfe48 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java @@ -15,6 +15,8 @@ */ package org.jetbrains.idea.maven.project; +import com.intellij.openapi.module.ModuleType; +import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Condition; @@ -796,6 +798,17 @@ public class MavenProject { return MavenImporter.getSuitableImporters(this); } + @NotNull + public ModuleType getModuleType() { + ModuleType typeFromImporter = null; + for (MavenImporter each : getSuitableImporters()) { + final ModuleType moduleType = each.getModuleType(); + assert typeFromImporter == null || typeFromImporter.equals(moduleType); + typeFromImporter = moduleType; + } + return typeFromImporter != null ? typeFromImporter : StdModuleTypes.JAVA; + } + @NotNull public Pair getClassifierAndExtension(@NotNull MavenArtifact artifact, @NotNull MavenExtraArtifactType type) { for (MavenImporter each : getSuitableImporters()) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManagerWatcher.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManagerWatcher.java index 13ce80de07a1..4e57e68faecf 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManagerWatcher.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManagerWatcher.java @@ -111,6 +111,15 @@ public class MavenProjectsManagerWatcher { MavenProject mavenProject = myManager.findProject(module); if (mavenProject != null) myManager.setIgnoredState(Collections.singletonList(mavenProject), true); } + + public void moduleAdded(final Project project, final Module module) { + // this method is needed to return non-ignored status for modules that were deleted (and thus ignored) and then created again with a different module type + if (myManager.isMavenizedModule(module)) { + MavenProject mavenProject = myManager.findProject(module); + if (mavenProject != null) myManager.setIgnoredState(Collections.singletonList(mavenProject), false); + } + + } }); DocumentAdapter myDocumentListener = new DocumentAdapter() { diff --git a/plugins/maven/src/main/resources/ProjectBundle.properties b/plugins/maven/src/main/resources/ProjectBundle.properties index bfe49297fd4f..d5d6c4c9b4bb 100644 --- a/plugins/maven/src/main/resources/ProjectBundle.properties +++ b/plugins/maven/src/main/resources/ProjectBundle.properties @@ -24,6 +24,7 @@ maven.project.changed=Maven projects need to be imported maven.project.importChanged=Import Changes maven.project.enableAutoImport=Enable Auto-Import maven.project.importing=Importing Maven projects +maven.project.import.title=Import Maven Projects maven.project.importing.finished=Finished importing Maven projects maven.project.import.waiting.for.active.process=Waiting for an active process maven.post.processing=Configuring Maven projects @@ -37,11 +38,9 @@ maven.import.environment.settings.title=Maven environment maven.import.title.module.dir=Select directory for IDEA module files (*.iml) maven.import.incompatible.modules=\ - Maven import needs to recreate
{0}

\ - Maven Integration supports only Java modules. Your modules will be recreated as
\ - Java modules and configured according to settings in your pom.xml files.
\ - If you do not want the modules to be recreated, corresponding Maven projects will be marked as
\ - ''Ignored'' and you can unignore them afterwards in the Maven Projects tool window. + The following {0,choice,1#module has|2#modules have} incorrect type and {0,choice,1#needs|2#need} to be recreated:

{1}

\ + If you do not want the {0,choice,1#module|2#modules} to be recreated, corresponding Maven projects will be marked as ignored,
\ + you will be able to unignore them afterwards in the Maven Projects tool window. maven.import.incompatible.modules.recreate=Recreate maven.import.incompatible.modules.ignore=Ignore These Projects From 8ca403aef60022a748c75e6407370a8feb3b14dc Mon Sep 17 00:00:00 2001 From: Alexander Doroshko Date: Fri, 20 Jan 2012 21:12:27 +0400 Subject: [PATCH 08/45] error reporting --- .../java/org/jetbrains/idea/maven/project/MavenProject.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java index 04f1bbccfe48..cb5a81b73cdd 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java @@ -803,7 +803,11 @@ public class MavenProject { ModuleType typeFromImporter = null; for (MavenImporter each : getSuitableImporters()) { final ModuleType moduleType = each.getModuleType(); - assert typeFromImporter == null || typeFromImporter.equals(moduleType); + if (typeFromImporter != null && !typeFromImporter.equals(moduleType)) { + MavenLog.LOG.error("Incompatible plugins: " + each.getClass().getName() + " wants to create " + + moduleType.getName() + " for project " + getName() + " whereas some other importer requires " + + typeFromImporter.getName()); + } typeFromImporter = moduleType; } return typeFromImporter != null ? typeFromImporter : StdModuleTypes.JAVA; From 79f81627e09d0cc751f53fd5a16ede5397d3e031 Mon Sep 17 00:00:00 2001 From: "kirill.safonov" Date: Wed, 25 Jan 2012 16:56:07 +0400 Subject: [PATCH 09/45] synchronize to prevent test form hanging --- .../xml/util/ColorSampleLookupValue.java | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/xml/impl/src/com/intellij/xml/util/ColorSampleLookupValue.java b/xml/impl/src/com/intellij/xml/util/ColorSampleLookupValue.java index bf21f20bb868..916c3fcaf3d5 100644 --- a/xml/impl/src/com/intellij/xml/util/ColorSampleLookupValue.java +++ b/xml/impl/src/com/intellij/xml/util/ColorSampleLookupValue.java @@ -323,48 +323,51 @@ public class ColorSampleLookupValue implements LookupValueWithUIHint, DeferredUs public static ColorSampleLookupValue[] getColors() { if (ourColors == null) { - ourColorNameToHexCodeMap = new HashMap(25); - ourHexCodeToColorNameMap = new HashMap(25); - List colorsList = new LinkedList(); - StringTokenizer tokenizer = new StringTokenizer(systemColorsString, "\n"); + synchronized (ColorSampleLookupValue.class) { + if (ourColors == null) { + ourColorNameToHexCodeMap = new HashMap(25); + ourHexCodeToColorNameMap = new HashMap(25); + List colorsList = new LinkedList(); + StringTokenizer tokenizer = new StringTokenizer(systemColorsString, "\n"); - while (tokenizer.hasMoreTokens()) { - String name = tokenizer.nextToken(); - colorsList.add(new ColorSampleLookupValue(name, name, false)); - tokenizer.nextToken(); - } + while (tokenizer.hasMoreTokens()) { + String name = tokenizer.nextToken(); + colorsList.add(new ColorSampleLookupValue(name, name, false)); + tokenizer.nextToken(); + } - tokenizer = new StringTokenizer(standardColorsString, ", \n"); - HashMap standardColors = new HashMap(); + tokenizer = new StringTokenizer(standardColorsString, ", \n"); + HashMap standardColors = new HashMap(); - while (tokenizer.hasMoreTokens()) { - String name = tokenizer.nextToken(); - String value = tokenizer.nextToken(); - standardColors.put(name, name); - ourColorNameToHexCodeMap.put(name, value); - ourHexCodeToColorNameMap.put(value, name); + while (tokenizer.hasMoreTokens()) { + String name = tokenizer.nextToken(); + String value = tokenizer.nextToken(); + standardColors.put(name, name); + ourColorNameToHexCodeMap.put(name, value); + ourHexCodeToColorNameMap.put(value, name); - colorsList.add(new ColorSampleLookupValue(name, value, true)); - } + colorsList.add(new ColorSampleLookupValue(name, value, true)); + } - tokenizer = new StringTokenizer(colorsString, " \t\n"); + tokenizer = new StringTokenizer(colorsString, " \t\n"); - while (tokenizer.hasMoreTokens()) { - String name = tokenizer.nextToken(); - String hexValue = tokenizer.nextToken(); + while (tokenizer.hasMoreTokens()) { + String name = tokenizer.nextToken(); + String hexValue = tokenizer.nextToken(); - tokenizer.nextToken(); // skip rgb + tokenizer.nextToken(); // skip rgb - if (!standardColors.containsKey(name)) { - colorsList.add(new ColorSampleLookupValue(name, hexValue, false)); - ourColorNameToHexCodeMap.put(name, hexValue); - ourHexCodeToColorNameMap.put(hexValue, name); + if (!standardColors.containsKey(name)) { + colorsList.add(new ColorSampleLookupValue(name, hexValue, false)); + ourColorNameToHexCodeMap.put(name, hexValue); + ourHexCodeToColorNameMap.put(hexValue, name); + } + } + + colorsList.toArray(ourColors = new ColorSampleLookupValue[colorsList.size()]); } } - - colorsList.toArray(ourColors = new ColorSampleLookupValue[colorsList.size()]); } - return ourColors; } @@ -389,12 +392,12 @@ public class ColorSampleLookupValue implements LookupValueWithUIHint, DeferredUs return myName == null || Character.isLowerCase(myName.charAt(0)) ? HIGHER : NORMAL; } - public static String getHexCodeForColorName(String colorName) { + public static synchronized String getHexCodeForColorName(String colorName) { getColors(); // to guarantee initialization return ourColorNameToHexCodeMap.get(colorName); } - public static String getColorNameForHexCode(String colorName) { + public static synchronized String getColorNameForHexCode(String colorName) { getColors(); // to guarantee initialization return ourHexCodeToColorNameMap.get(colorName); } From e9902fc5a37bcda923acfaaaa6ec3e2bd9d5fc0c Mon Sep 17 00:00:00 2001 From: "kirill.safonov" Date: Wed, 25 Jan 2012 18:42:46 +0400 Subject: [PATCH 10/45] fixing Flex test to work with new project model --- .../fixtures/CodeInsightFixtureTestCase.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightFixtureTestCase.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightFixtureTestCase.java index 45ca8249e70d..d4e56c07982a 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightFixtureTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightFixtureTestCase.java @@ -22,6 +22,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; import com.intellij.testFramework.UsefulTestCase; import com.intellij.testFramework.builders.EmptyModuleFixtureBuilder; +import com.intellij.testFramework.builders.ModuleFixtureBuilder; import org.jetbrains.annotations.NonNls; import java.io.File; @@ -29,7 +30,7 @@ import java.io.File; /** * @author yole */ -public abstract class CodeInsightFixtureTestCase extends UsefulTestCase { +public abstract class CodeInsightFixtureTestCase extends UsefulTestCase { protected CodeInsightTestFixture myFixture; protected Module myModule; @@ -39,7 +40,7 @@ public abstract class CodeInsightFixtureTestCase extends UsefulTestCase { final TestFixtureBuilder projectBuilder = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(); myFixture = IdeaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(projectBuilder.getFixture()); - final EmptyModuleFixtureBuilder moduleFixtureBuilder = projectBuilder.addModule(EmptyModuleFixtureBuilder.class); + final T moduleFixtureBuilder = projectBuilder.addModule(getModuleBuilderClass()); moduleFixtureBuilder.addSourceContentRoot(myFixture.getTempDirPath()); tuneFixture(moduleFixtureBuilder); @@ -48,6 +49,10 @@ public abstract class CodeInsightFixtureTestCase extends UsefulTestCase { myModule = moduleFixtureBuilder.getFixture().getModule(); } + protected Class getModuleBuilderClass() { + return (Class)EmptyModuleFixtureBuilder.class; + } + @Override protected void tearDown() throws Exception { myFixture.tearDown(); @@ -56,7 +61,7 @@ public abstract class CodeInsightFixtureTestCase extends UsefulTestCase { super.tearDown(); } - protected void tuneFixture(final EmptyModuleFixtureBuilder moduleBuilder) {} + protected void tuneFixture(final T moduleBuilder) {} /** * Return relative path to the test data. Path is relative to the From 87876eefca3c698e798127dc0863105bd43a188f Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 30 Jan 2012 15:51:17 +0400 Subject: [PATCH 11/45] Cosmetics --- plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java index 2e6309a2ed9b..107a36922402 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java @@ -65,12 +65,9 @@ class GitBranchPopup { } /** - * - * @param project * @param currentRepository Current repository, which means the repository of the currently open or selected file. * In the case of synchronized branch operations current repository matter much less, but sometimes is used, * for example, it is preselected in the repositories combobox in the compare branches dialog. - * @return */ static GitBranchPopup getInstance(@NotNull Project project, @NotNull GitRepository currentRepository) { return new GitBranchPopup(project, currentRepository); From 894f63ec7084ffebe47b7d8de45c152dc25fa10f Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 30 Jan 2012 12:53:57 +0100 Subject: [PATCH 12/45] file structure base test case --- .../ide/actions/ViewStructureAction.java | 2 +- .../intellij/ide/util/FileStructurePopup.java | 85 ++++++++----- .../ide/util/treeView/AbstractTreeUi.java | 18 ++- .../filtered/FilteringTreeBuilder.java | 39 ++++-- .../testFramework/FileStructureTestBase.java | 119 ++++++++++++++++++ 5 files changed, 215 insertions(+), 48 deletions(-) create mode 100644 platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java diff --git a/platform/lang-impl/src/com/intellij/ide/actions/ViewStructureAction.java b/platform/lang-impl/src/com/intellij/ide/actions/ViewStructureAction.java index a1e115a7f014..4e64b7c3983c 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/ViewStructureAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/ViewStructureAction.java @@ -90,7 +90,7 @@ public class ViewStructureAction extends AnAction { } @Nullable - private static FileStructurePopup createPopup(final Editor editor, Project project, Navigatable navigatable, final FileEditor fileEditor) { + public static FileStructurePopup createPopup(final Editor editor, Project project, @Nullable Navigatable navigatable, final FileEditor fileEditor) { final StructureViewBuilder structureViewBuilder = fileEditor.getStructureViewBuilder(); if (structureViewBuilder == null) return null; StructureView structureView = structureViewBuilder.createStructureView(fileEditor, project); diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java index 2285504fe806..9d885b1e49d8 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java @@ -149,6 +149,7 @@ public class FileStructurePopup implements Disposable { myTree = new JBTreeWithHintProvider(new DefaultMutableTreeNode(myTreeStructure.getRootElement())) { @Override protected PsiElement getPsiElementForHint(Object selectedValue) { + //noinspection ConstantConditions return getPsi((FilteringTreeStructure.FilteringNode)((DefaultMutableTreeNode)selectedValue).getUserObject()); } }; @@ -218,12 +219,13 @@ public class FileStructurePopup implements Disposable { return current.isEmpty() ? null : findClosestTo(myInitialPsiElement, current); } + @Nullable private Object findClosestTo(PsiElement path, ArrayList paths) { if (path == null || myInitialPsiElement == null) { return paths.get(0).node; } final Set parents = getAllParents(myInitialPsiElement); - Object cur = paths.get(0).node; + ArrayList cur = new ArrayList(); int max = -1; for (ObjectWithWeight p : paths) { final Object last = ((TreePath)p.node).getLastPathComponent(); @@ -238,14 +240,21 @@ public class FileStructurePopup implements Disposable { final int size = ContainerUtil.intersection(parents, elements).size(); if (size > max) { max = size; - cur = p.node; - } else if (size == max && size == parents.size()) { - cur = p.node; + cur.clear(); + cur.add((TreePath)p.node); + } else if (size == max) { + cur.add((TreePath)p.node); } } } - return cur; + Collections.sort(cur, new Comparator() { + @Override + public int compare(TreePath o1, TreePath o2) { + return o2.getPathCount() - o1.getPathCount(); + } + }); + return cur.isEmpty() ? null : cur.get(0); } class ObjectWithWeight { @@ -285,7 +294,7 @@ public class FileStructurePopup implements Disposable { mySpeedSearch.setComparator(new SpeedSearchComparator(false, true)); final FileStructurePopupFilter filter = new FileStructurePopupFilter(); - myFilteringStructure = new FilteringTreeStructure(filter, myTreeStructure, false); + myFilteringStructure = new FilteringTreeStructure(filter, myTreeStructure, ApplicationManager.getApplication().isUnitTestMode()); myAbstractTreeBuilder = new FilteringTreeBuilder(myTree, filter, myFilteringStructure, null) { @Override protected boolean validateNode(Object child) { @@ -385,35 +394,37 @@ public class FileStructurePopup implements Disposable { }); } }); - final Alarm alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, myPopup); - alarm.addRequest(new Runnable() { - String filter = ""; + if (!ApplicationManager.getApplication().isUnitTestMode()) { + final Alarm alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, myPopup); + alarm.addRequest(new Runnable() { + String filter = ""; - @Override - public void run() { - alarm.cancelAllRequests(); - String prefix = mySpeedSearch.getEnteredPrefix(); - myTree.getEmptyText().setText(StringUtil.isEmpty(prefix) ? "Nothing to show" : "Can't find '" + prefix + "'"); - if (prefix == null) prefix = ""; + @Override + public void run() { + alarm.cancelAllRequests(); + String prefix = mySpeedSearch.getEnteredPrefix(); + myTree.getEmptyText().setText(StringUtil.isEmpty(prefix) ? "Nothing to show" : "Can't find '" + prefix + "'"); + if (prefix == null) prefix = ""; - if (!filter.equals(prefix)) { - filter = prefix; - myAbstractTreeBuilder.refilter(null, false, false).doWhenProcessed(new Runnable() { - @Override - public void run() { - myTree.repaint(); - //if (mySpeedSearch.isPopupActive()) { - // mySpeedSearch.refreshSelection(); - //} - } - }); + if (!filter.equals(prefix)) { + filter = prefix; + myAbstractTreeBuilder.refilter(null, false, false).doWhenProcessed(new Runnable() { + @Override + public void run() { + myTree.repaint(); + //if (mySpeedSearch.isPopupActive()) { + // mySpeedSearch.refreshSelection(); + //} + } + }); + } + alarm.addRequest(this, 300); } - alarm.addRequest(this, 300); - } - }, 300); + }, 300); + } } - private void selectPsiElement(PsiElement element) { + public void selectPsiElement(PsiElement element) { Set parents = getAllParents(element); FilteringTreeStructure.FilteringNode node = (FilteringTreeStructure.FilteringNode)myAbstractTreeBuilder.getRootElement(); @@ -478,7 +489,7 @@ public class FileStructurePopup implements Disposable { } @Nullable - protected PsiElement getCurrentElement(@Nullable final PsiFile psiFile) { + public PsiElement getCurrentElement(@Nullable final PsiFile psiFile) { if (psiFile == null) return null; PsiDocumentManager.getInstance(myProject).commitAllDocuments(); @@ -718,6 +729,18 @@ public class FileStructurePopup implements Disposable { myTitle = title; } + public Tree getTree() { + return myTree; + } + + public TreeSpeedSearch getSpeedSearch() { + return mySpeedSearch; + } + + public FilteringTreeBuilder getTreeBuilder() { + return myAbstractTreeBuilder; + } + private class FileStructurePopupFilter implements ElementFilter { private String myLastFilter = null; private HashSet myVisibleParents = new HashSet(); diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java index ced3ab62d05d..43423a359932 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java @@ -2362,7 +2362,7 @@ public class AbstractTreeUi { final ActionCallback done = new ActionCallback(); - invokeLaterIfNeeded(new Runnable() { + final Runnable cancelUpdate = new Runnable() { public void run() { if (isReleased()) { done.setRejected(); @@ -2371,21 +2371,29 @@ public class AbstractTreeUi { if (myResettingToReadyNow.get()) { _getReady().notify(done); - } else if (isReady()) { + } + else if (isReady()) { resetToReadyNow(); done.setDone(); - } else { + } + else { if (isIdle() && hasPendingWork()) { resetToReadyNow(); done.setDone(); - } else { + } + else { _getReady().notify(done); } } maybeReady(); } - }, false); + }; + if (ApplicationManager.getApplication().isUnitTestMode()) { + cancelUpdate.run(); + } else { + invokeLaterIfNeeded(cancelUpdate, false); + } if (isEdt() || isPassthroughMode()) { maybeReady(); diff --git a/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeBuilder.java b/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeBuilder.java index 941dafef44eb..71f152e5fc58 100644 --- a/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeBuilder.java +++ b/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeBuilder.java @@ -18,6 +18,7 @@ package com.intellij.ui.treeStructure.filtered; import com.intellij.ide.util.treeView.AbstractTreeBuilder; import com.intellij.ide.util.treeView.AbstractTreeStructure; import com.intellij.ide.util.treeView.NodeDescriptor; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Disposer; import com.intellij.ui.speedSearch.ElementFilter; @@ -120,7 +121,7 @@ public class FilteringTreeBuilder extends AbstractTreeBuilder { myRefilterQueue.cancelAllUpdates(); } final ActionCallback callback = new ActionCallback(); - getUi().cancelUpdate().doWhenProcessed(new Runnable() { + final Runnable afterCancelUpdate = new Runnable() { @Override public void run() { if (myRefilterQueue == null || now) { @@ -145,7 +146,12 @@ public class FilteringTreeBuilder extends AbstractTreeBuilder { }); } } - }); + }; + if (!ApplicationManager.getApplication().isUnitTestMode()) { + getUi().cancelUpdate().doWhenProcessed(afterCancelUpdate); + } else { + afterCancelUpdate.run(); + } return callback; } @@ -155,7 +161,7 @@ public class FilteringTreeBuilder extends AbstractTreeBuilder { final ActionCallback selectionDone = new ActionCallback(); getFilteredStructure().refilter(); - queueUpdate().doWhenProcessed(new Runnable() { + final Runnable selectionRunnable = new Runnable() { public void run() { revalidateTree(); @@ -173,25 +179,36 @@ public class FilteringTreeBuilder extends AbstractTreeBuilder { selectionDone.setDone(); } }); - } else { + } + else { TreeUtil.ensureSelection(myTree); selectionDone.setDone(); } - } else { + } + else { selectionDone.setDone(); } } - }); + }; + if (!ApplicationManager.getApplication().isUnitTestMode()) { + queueUpdate().doWhenProcessed(selectionRunnable); + } else { + selectionRunnable.run(); + } final ActionCallback result = new ActionCallback(); selectionDone.doWhenDone(new Runnable() { public void run() { - scrollSelectionToVisible(new Runnable() { - public void run() { - getReady(this).notify(result); - } - }, false); + if (!ApplicationManager.getApplication().isUnitTestMode()) { + scrollSelectionToVisible(new Runnable() { + public void run() { + getReady(this).notify(result); + } + }, false); + } else { + result.setDone(); + } } }).doWhenRejected(new Runnable() { @Override diff --git a/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java b/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java new file mode 100644 index 000000000000..3f991b0cb683 --- /dev/null +++ b/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java @@ -0,0 +1,119 @@ +/* + * Copyright 2000-2012 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.testFramework; + +import com.intellij.ide.actions.ViewStructureAction; +import com.intellij.ide.util.FileStructurePopup; +import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase; +import com.intellij.ui.TreeSpeedSearch; +import com.intellij.ui.treeStructure.Tree; +import com.intellij.ui.treeStructure.filtered.FilteringTreeBuilder; +import com.intellij.ui.treeStructure.filtered.FilteringTreeStructure; +import com.intellij.util.ui.tree.TreeUtil; +import junit.framework.Assert; +import org.junit.Before; + +import java.io.File; + +/** + * @author Konstantin Bulenkov + */ +public abstract class FileStructureTestBase extends CodeInsightFixtureTestCase { + FileStructurePopup myPopup; + + @Before + public void setUp() throws Exception { + super.setUp(); + myFixture.configureByFile(getFileName(getFileExtension())); + myPopup = ViewStructureAction.createPopup(myFixture.getEditor(), + myFixture.getProject(), + null, + TextEditorProvider.getInstance().getTextEditor(myFixture.getEditor())); + update(); + } + + protected abstract String getFileExtension(); + + @Override + public void tearDown() throws Exception { + Disposer.dispose(myPopup); + super.tearDown(); + } + + private String getFileName(String ext) { + return getTestName(false) + (StringUtil.isEmpty(ext) ? "" : "." + ext); + } + + protected String getTreeFileName() { + return getFileName("tree"); + } + + protected void checkTree() throws Exception { + final String expected = FileUtil.loadFile(new File(getTestDataPath() + "/" + getTreeFileName())); + Assert.assertEquals(expected, PlatformTestUtil.print(getTree(), true)); + } + + + private void update() throws InterruptedException { + myPopup.getTreeBuilder().refilter().doWhenProcessed(new Runnable() { + @Override + public void run() { + getStructure().rebuild(); + updateTree(); + TreeUtil.expandAll(getTree()); + myPopup.selectPsiElement(getFile()); + } + }); + } + + protected Tree getTree() { + return myPopup.getTree(); + } + + protected FilteringTreeBuilder getBuilder() { + return myPopup.getTreeBuilder(); + } + + protected TreeSpeedSearch getSpeedSearch() { + return myPopup.getSpeedSearch(); + } + + + protected void updateTree() { + updateRecursively(getRootNode()); + } + + protected FilteringTreeStructure getStructure() { + final FilteringTreeStructure structure = (FilteringTreeStructure)getBuilder().getTreeStructure(); + assert structure != null; + return structure; + } + + protected FilteringTreeStructure.FilteringNode getRootNode() { + return (FilteringTreeStructure.FilteringNode)getStructure().getRootElement(); + } + + protected void updateRecursively(final FilteringTreeStructure.FilteringNode node) { + node.update(); + for (FilteringTreeStructure.FilteringNode child : node.children()) { + updateRecursively(child); + } + } +} From d33ec0506941b94f881b5ed257716d16e19883a6 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 30 Jan 2012 14:10:21 +0400 Subject: [PATCH 13/45] less synchronization --- .../intellij/openapi/vcs/persistent/SmallMapSerializer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/persistent/SmallMapSerializer.java b/platform/vcs-api/src/com/intellij/openapi/vcs/persistent/SmallMapSerializer.java index 004dee277a1b..41d28da4acb8 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/persistent/SmallMapSerializer.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/persistent/SmallMapSerializer.java @@ -20,7 +20,9 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.DataOutputStream; import com.intellij.util.io.KeyDescriptor; +import com.intellij.util.io.UnsyncByteArrayInputStream; import org.jetbrains.annotations.NotNull; import java.io.*; @@ -51,7 +53,7 @@ public class SmallMapSerializer implements Forceable { private void init() { try { final byte[] bytes = FileUtil.loadFileBytes(myFile); - final DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bytes)); + final DataInputStream dis = new DataInputStream(new UnsyncByteArrayInputStream(bytes)); final int size = dis.readInt(); for (int i = 0; i < size; i++) { final KeyWrapper keyWrapper = new KeyWrapper(myKeyDescriptor, myKeyDescriptor.read(dis)); From 7c835859fceb3db882dea8ab30fec95b64d90fae Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 30 Jan 2012 16:01:55 +0400 Subject: [PATCH 14/45] avoid exception on trying to detect injection inside another injection (WI-9523) --- .../psi/impl/source/tree/injected/InjectedLanguageUtil.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java index 050f1efad069..7baf631f9661 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java @@ -132,6 +132,8 @@ public class InjectedLanguageUtil { if (file == null || !file.isPhysical() && file.getOriginalFile() == file) return; } + if (containingFile.getViewProvider() instanceof InjectedFileViewProvider) return; // no injection inside injection + PsiElement inTree = loadTree(host, containingFile); if (inTree != host) { host = inTree; From eb135916126805f9d7473ad56eaf8fa8177e214e Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 30 Jan 2012 16:03:08 +0400 Subject: [PATCH 15/45] smaller upper limit for mapped byte buffers on x64 when using btree based enumerator --- platform/util/src/com/intellij/util/io/PagedFileStorage.java | 2 +- .../src/com/intellij/util/io/PersistentEnumeratorDelegate.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/platform/util/src/com/intellij/util/io/PagedFileStorage.java b/platform/util/src/com/intellij/util/io/PagedFileStorage.java index a8acc9b21219..4cf6dfbde294 100644 --- a/platform/util/src/com/intellij/util/io/PagedFileStorage.java +++ b/platform/util/src/com/intellij/util/io/PagedFileStorage.java @@ -49,7 +49,7 @@ public class PagedFileStorage implements Forceable { static { final int lower = 100; - final int upper = SystemInfo.is64Bit ? 500 : 200; + final int upper = SystemInfo.is64Bit && !PersistentEnumeratorDelegate.useBtree() ? 500 : 200; BUFFER_SIZE = Math.max(1, SystemInfo.getIntProperty("idea.paged.storage.page.size", 10)) * MB; if (ByteBufferWrapper.NO_MMAP) { diff --git a/platform/util/src/com/intellij/util/io/PersistentEnumeratorDelegate.java b/platform/util/src/com/intellij/util/io/PersistentEnumeratorDelegate.java index c7c689eedae5..7dc5f0a802da 100644 --- a/platform/util/src/com/intellij/util/io/PersistentEnumeratorDelegate.java +++ b/platform/util/src/com/intellij/util/io/PersistentEnumeratorDelegate.java @@ -16,7 +16,6 @@ package com.intellij.util.io; import com.intellij.openapi.Forceable; -import com.intellij.openapi.util.SystemInfo; import org.jetbrains.annotations.Nullable; import java.io.Closeable; @@ -32,7 +31,7 @@ public class PersistentEnumeratorDelegate implements Closeable, Forceable new PersistentEnumerator(file, dataDescriptor, initialSize); } - private boolean useBtree() { + static boolean useBtree() { String property = System.getProperty("idea.use.btree"); return !"false".equals(property); } From bdb12e05b880ff6d7725ab3742379d7332574168 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 30 Jan 2012 16:09:21 +0400 Subject: [PATCH 16/45] IDEA-80258 Git: sort repositories when performing multi-repo actions Return repositories from the repository manager already sorted. The order matters => change Collection to List in GitBranchPopup and GitBranchOperationsProcessor --- .../branch/GitBranchOperationsProcessor.java | 11 +++--- .../git4idea/repo/GitRepositoryManager.java | 6 ++- .../ui/branch/GitBranchPopupActions.java | 39 +++++++++---------- .../ui/branch/GitMultiRootBranchConfig.java | 5 ++- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java index 392554efbcf8..df1989fdc3de 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java @@ -38,7 +38,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.Collection; import java.util.Collections; import java.util.List; @@ -52,7 +51,7 @@ public final class GitBranchOperationsProcessor { private static final Logger LOG = Logger.getInstance(GitBranchOperationsProcessor.class); private final Project myProject; - private final Collection myRepositories; + private final List myRepositories; @Nullable private final Runnable myCallInAwtAfterExecution; private final GitRepository mySelectedRepository; @@ -61,16 +60,16 @@ public final class GitBranchOperationsProcessor { } public GitBranchOperationsProcessor(@NotNull GitRepository repository, @Nullable Runnable callInAwtAfterExecution) { - this(repository.getProject(), Collections.singleton(repository), repository, callInAwtAfterExecution); + this(repository.getProject(), Collections.singletonList(repository), repository, callInAwtAfterExecution); } - public GitBranchOperationsProcessor(@NotNull Project project, @NotNull Collection repositories, + public GitBranchOperationsProcessor(@NotNull Project project, @NotNull List repositories, @NotNull GitRepository selectedRepository) { this(project, repositories, selectedRepository, null); } public GitBranchOperationsProcessor(@NotNull Project project, - @NotNull Collection repositories, + @NotNull List repositories, @NotNull GitRepository selectedRepository, @Nullable Runnable callInAwtAfterExecution) { myProject = project; @@ -205,7 +204,7 @@ public final class GitBranchOperationsProcessor { }.runInBackground(); } - private GitCommitCompareInfo loadCommitsToCompare(Collection repositories, String branchName) { + private GitCommitCompareInfo loadCommitsToCompare(List repositories, String branchName) { GitCommitCompareInfo compareInfo = new GitCommitCompareInfo(); for (GitRepository repository : repositories) { compareInfo.put(repository, loadCommitsToCompare(repository, branchName)); diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java index fe5fc065c808..eb6276183333 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java @@ -33,6 +33,8 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.locks.ReentrantReadWriteLock; +import static git4idea.GitUtil.sortRepositories; + /** * GitRepositoryManager initializes and stores {@link GitRepository GitRepositories} for Git roots defined in the project. * @author Kirill Likhodedov @@ -152,10 +154,10 @@ public final class GitRepositoryManager extends AbstractProjectComponent impleme * @return all repositories tracked by the manager. */ @NotNull - public Collection getRepositories() { + public List getRepositories() { try { REPO_LOCK.readLock().lock(); - return myRepositories.values(); + return sortRepositories(myRepositories.values()); } finally { REPO_LOCK.readLock().unlock(); diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java index 42be940eaf37..8f8bcb176f4f 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java @@ -33,7 +33,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; @@ -56,7 +55,7 @@ class GitBranchPopupActions { DefaultActionGroup popupGroup = new DefaultActionGroup(null, false); popupGroup.addAction(new CurrentBranchAction(GitBranchUiUtil.getDisplayableBranchText(myRepository), "in root " + GitUIUtil.getShortRepositoryName(myRepository))); - popupGroup.addAction(new NewBranchAction(myProject, Collections.singleton(myRepository), myRepository)); + popupGroup.addAction(new NewBranchAction(myProject, Collections.singletonList(myRepository), myRepository)); popupGroup.addAction(new CheckoutRevisionActions(myProject, myRepository)); if (toInsert != null) { @@ -68,7 +67,7 @@ class GitBranchPopupActions { Collections.sort(localBranches); for (GitBranch localBranch : localBranches) { if (!localBranch.equals(myRepository.getCurrentBranch())) { // don't show current branch in the list - popupGroup.add(new LocalBranchActions(myProject, Collections.singleton(myRepository), localBranch.getName(), myRepository)); + popupGroup.add(new LocalBranchActions(myProject, Collections.singletonList(myRepository), localBranch.getName(), myRepository)); } } @@ -76,7 +75,7 @@ class GitBranchPopupActions { List remoteBranches = new ArrayList(myRepository.getBranches().getRemoteBranches()); Collections.sort(remoteBranches); for (GitBranch remoteBranch : remoteBranches) { - popupGroup.add(new RemoteBranchActions(myProject, Collections.singleton(myRepository), remoteBranch.getName(), myRepository)); + popupGroup.add(new RemoteBranchActions(myProject, Collections.singletonList(myRepository), remoteBranch.getName(), myRepository)); } return popupGroup; @@ -101,10 +100,10 @@ class GitBranchPopupActions { static class NewBranchAction extends DumbAwareAction { private final Project myProject; - private final Collection myRepositories; + private final List myRepositories; @NotNull private final GitRepository mySelectedRepository; - NewBranchAction(@NotNull Project project, @NotNull Collection repositories, @NotNull GitRepository selectedRepository) { + NewBranchAction(@NotNull Project project, @NotNull List repositories, @NotNull GitRepository selectedRepository) { super("New Branch", "Create and checkout new branch", IconLoader.getIcon("/general/add.png")); myProject = project; myRepositories = repositories; @@ -175,11 +174,11 @@ class GitBranchPopupActions { static class LocalBranchActions extends ActionGroup { private final Project myProject; - private final Collection myRepositories; + private final List myRepositories; private String myBranchName; @NotNull private final GitRepository mySelectedRepository; - LocalBranchActions(@NotNull Project project, @NotNull Collection repositories, @NotNull String branchName, + LocalBranchActions(@NotNull Project project, @NotNull List repositories, @NotNull String branchName, @NotNull GitRepository selectedRepository) { super("", true); myProject = project; @@ -202,11 +201,11 @@ class GitBranchPopupActions { private static class CheckoutAction extends DumbAwareAction { private final Project myProject; - private final Collection myRepositories; + private final List myRepositories; private final String myBranchName; @NotNull private final GitRepository mySelectedRepository; - CheckoutAction(@NotNull Project project, @NotNull Collection repositories, @NotNull String branchName, + CheckoutAction(@NotNull Project project, @NotNull List repositories, @NotNull String branchName, @NotNull GitRepository selectedRepository) { super("Checkout"); myProject = project; @@ -224,11 +223,11 @@ class GitBranchPopupActions { private static class CheckoutAsNewBranch extends DumbAwareAction { private final Project myProject; - private final Collection myRepositories; + private final List myRepositories; private final String myBranchName; @NotNull private final GitRepository mySelectedRepository; - CheckoutAsNewBranch(@NotNull Project project, @NotNull Collection repositories, @NotNull String branchName, + CheckoutAsNewBranch(@NotNull Project project, @NotNull List repositories, @NotNull String branchName, @NotNull GitRepository selectedRepository) { super("Checkout as new branch"); myProject = project; @@ -254,11 +253,11 @@ class GitBranchPopupActions { */ private static class DeleteAction extends DumbAwareAction { private final Project myProject; - private final Collection myRepositories; + private final List myRepositories; private final String myBranchName; private final GitRepository mySelectedRepository; - DeleteAction(Project project, Collection repositories, String branchName, GitRepository selectedRepository) { + DeleteAction(Project project, List repositories, String branchName, GitRepository selectedRepository) { super("Delete"); myProject = project; myRepositories = repositories; @@ -279,11 +278,11 @@ class GitBranchPopupActions { static class RemoteBranchActions extends ActionGroup { private final Project myProject; - private final Collection myRepositories; + private final List myRepositories; private String myBranchName; @NotNull private final GitRepository mySelectedRepository; - RemoteBranchActions(@NotNull Project project, @NotNull Collection repositories, @NotNull String branchName, + RemoteBranchActions(@NotNull Project project, @NotNull List repositories, @NotNull String branchName, @NotNull GitRepository selectedRepository) { super("", true); myProject = project; @@ -304,11 +303,11 @@ class GitBranchPopupActions { private static class CheckoutRemoteBranchAction extends DumbAwareAction { private final Project myProject; - private final Collection myRepositories; + private final List myRepositories; private final String myRemoteBranchName; @NotNull private final GitRepository mySelectedRepository; - public CheckoutRemoteBranchAction(@NotNull Project project, @NotNull Collection repositories, + public CheckoutRemoteBranchAction(@NotNull Project project, @NotNull List repositories, @NotNull String remoteBranchName, @NotNull GitRepository selectedRepository) { super("Checkout as new local branch"); myProject = project; @@ -339,12 +338,12 @@ class GitBranchPopupActions { private static class CompareAction extends DumbAwareAction { private final Project myProject; - private final Collection myRepositories; + private final List myRepositories; private final String myBranchName; private final GitRepository mySelectedRepository; public CompareAction(@NotNull Project project, - @NotNull Collection repositories, + @NotNull List repositories, @NotNull String branchName, GitRepository selectedRepository) { super("Compare"); diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java b/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java index 4e45aed7a5b4..c45b886bd1f2 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java @@ -24,15 +24,16 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Collections; +import java.util.List; /** * @author Kirill Likhodedov */ public class GitMultiRootBranchConfig { - private final Collection myRepositories; + private final List myRepositories; - public GitMultiRootBranchConfig(@NotNull Collection repositories) { + public GitMultiRootBranchConfig(@NotNull List repositories) { myRepositories = repositories; } From 596e18db2c7e6056432f82acacd0d9805c407645 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 30 Jan 2012 16:02:20 +0400 Subject: [PATCH 17/45] IDEA-79817 Better detection of rejected push; fix setStderrSuppressed in setSilent. For branches with hyphens, for example. [Reviewed by irengrig] (cherry picked from commit 9d67aa2f6c29e260d8e44d94577c4cac691c83f0) --- plugins/git4idea/src/git4idea/commands/GitHandler.java | 4 ++-- .../git4idea/src/git4idea/push/GitPushRejectedDetector.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/git4idea/src/git4idea/commands/GitHandler.java b/plugins/git4idea/src/git4idea/commands/GitHandler.java index 79e0779f14d8..dd7ac999af35 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitHandler.java @@ -502,8 +502,8 @@ public abstract class GitHandler { public void setSilent(final boolean silent) { checkNotStarted(); mySilent = silent; - setStderrSuppressed(true); - setStdoutSuppressed(true); + setStderrSuppressed(silent); + setStdoutSuppressed(silent); } /** diff --git a/plugins/git4idea/src/git4idea/push/GitPushRejectedDetector.java b/plugins/git4idea/src/git4idea/push/GitPushRejectedDetector.java index 0dc47f2cdeb8..ca96475cfeec 100644 --- a/plugins/git4idea/src/git4idea/push/GitPushRejectedDetector.java +++ b/plugins/git4idea/src/git4idea/push/GitPushRejectedDetector.java @@ -28,7 +28,7 @@ import java.util.regex.Pattern; */ class GitPushRejectedDetector implements GitLineHandlerListener { - private static final Pattern REJECTED_PATTERN = Pattern.compile("\\s+! \\[rejected\\]\\s+(\\w+) -> (\\w+) .*"); + private static final Pattern REJECTED_PATTERN = Pattern.compile("\\s+! \\[rejected\\]\\s+(\\S+) -> (\\S+) .*"); private final Collection myRejectedRefs = new ArrayList(); From 0f930e9950e6f18a83d2d74e2976779127aee888 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 30 Jan 2012 16:15:54 +0400 Subject: [PATCH 18/45] Compile fix List -> Collection --- plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java | 4 ++-- .../tests/git4idea/branch/GitBranchOperationsTest.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java index 107a36922402..c31352bbd3a2 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java @@ -39,7 +39,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.event.HyperlinkEvent; -import java.util.Collection; +import java.util.List; /** *

@@ -154,7 +154,7 @@ class GitBranchPopup { } private void fillWithCommonRepositoryActions(DefaultActionGroup popupGroup, GitRepositoryManager repositoryManager) { - Collection repositories = repositoryManager.getRepositories(); + List repositories = repositoryManager.getRepositories(); String currentBranch = myMultiRootBranchConfig.getCurrentBranch(); assert currentBranch != null : "Current branch can't be null if branches have not diverged"; popupGroup.add(new GitBranchPopupActions.CurrentBranchAction(currentBranch, " in all roots")); diff --git a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java index d10e26f0f000..2209fdc834d9 100644 --- a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java +++ b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java @@ -36,7 +36,7 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; -import java.util.Collection; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import static git4idea.test.GitExec.*; @@ -51,7 +51,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { private static final String NEW_BRANCH = "new_branch"; private static final String MASTER = "master"; - private Collection myRepositories; + private List myRepositories; private GitRepository myUltimate; private GitRepository myCommunity; private GitRepository myContrib; From a3580be8322831f00cec39aed66f2a28f2463524 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Mon, 30 Jan 2012 14:08:04 +0400 Subject: [PATCH 19/45] testing auto import --- .../codeInsight/daemon/impl/quickfix/ImportClassFixBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java index dccdb0628494..ee4b5eae23a9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java @@ -186,7 +186,7 @@ public abstract class ImportClassFixBase im && (JspPsiUtil.isInJspFile(psiFile) ? CodeInsightSettings.getInstance().JSP_ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY : CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY) - && codeAnalyzer.canChangeFileSilently(psiFile) + && (ApplicationManager.getApplication().isUnitTestMode() || codeAnalyzer.canChangeFileSilently(psiFile)) && !autoImportWillInsertUnexpectedCharacters(classes[0]) ) { CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() { From 6fe0da100067a7e293b0a06d4fe485380a2f3c9a Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Mon, 30 Jan 2012 15:54:32 +0400 Subject: [PATCH 20/45] @Nullable --- .../com/intellij/psi/impl/source/resolve/ResolveClassUtil.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ResolveClassUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ResolveClassUtil.java index 1e3be2dfc81f..1ced09018224 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ResolveClassUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ResolveClassUtil.java @@ -21,10 +21,12 @@ import com.intellij.psi.*; import com.intellij.psi.impl.source.PsiJavaCodeReferenceElementImpl; import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.util.PsiUtil; +import org.jetbrains.annotations.Nullable; public class ResolveClassUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.resolve.ResolveClassUtil"); + @Nullable public static PsiClass resolveClass(PsiJavaCodeReferenceElement ref) { if (ref instanceof PsiJavaCodeReferenceElementImpl && ((PsiJavaCodeReferenceElementImpl)ref).getKind() == PsiJavaCodeReferenceElementImpl.CLASS_IN_QUALIFIED_NEW_KIND){ PsiElement parent = ref.getParent(); From 3899096e796292d3ba5369fe6ae6e8bb0cd439f3 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Mon, 30 Jan 2012 15:55:00 +0400 Subject: [PATCH 21/45] @Nullable --- .../src/com/intellij/psi/scope/util/PsiScopesUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java b/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java index 016e9782e9d7..d44097d038d4 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java @@ -138,7 +138,7 @@ public class PsiScopesUtil { } } - public static boolean resolveAndWalk(PsiScopeProcessor processor, PsiJavaCodeReferenceElement ref, PsiElement maxScope) { + public static boolean resolveAndWalk(PsiScopeProcessor processor, PsiJavaCodeReferenceElement ref, @Nullable PsiElement maxScope) { return resolveAndWalk(processor, ref, maxScope, false); } From 30bf039e26e0caecd0cfea23c331f98dfafa555b Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Mon, 30 Jan 2012 16:19:45 +0400 Subject: [PATCH 22/45] IDEA-80313: Import in JSPs not working - from version 9 to 11 --- .../intellij/psi/impl/JavaCodeBlockModificationListener.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java b/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java index d3aed9767503..ba8fffebe15c 100644 --- a/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java +++ b/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java @@ -68,7 +68,9 @@ public class JavaCodeBlockModificationListener implements PsiTreeChangePreproces private void processChange(final PsiElement parent, final PsiElement child1, final PsiElement child2) { try { if (!isInsideCodeBlock(parent)) { - if (parent != null && isClassOwner(parent.getContainingFile()) || isClassOwner(child1) || isClassOwner(child2) || isSourceDir(parent)) { + if (parent != null && isClassOwner(parent.getContainingFile()) || + isClassOwner(child1) || isClassOwner(child2) || isSourceDir(parent) || + (parent != null && isClassOwner(parent.getParent()))) { myModificationTracker.incCounter(); } else { From 107d63d7fc1d39c2433e24f8ea3d7f4a5ef83552 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Fri, 27 Jan 2012 17:21:00 +0400 Subject: [PATCH 23/45] Upgraded to the jmock 2.5.1 --- lib/dev/hamcrest-api-1.0.jar | Bin 5681 -> 0 bytes lib/dev/hamcrest-core-1.1.jar | Bin 0 -> 33395 bytes lib/dev/hamcrest-library-1.0.jar | Bin 63762 -> 0 bytes lib/dev/hamcrest-library-1.1.jar | Bin 0 -> 46692 bytes .../{jmock-2.3.0-RC2.jar => jmock-2.5.1.jar} | Bin 201201 -> 241000 bytes lib/dev/jmock-junit4-2.3.0-RC2.jar | Bin 8305 -> 0 bytes lib/dev/jmock-junit4-2.5.1.jar | Bin 0 -> 10247 bytes 7 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lib/dev/hamcrest-api-1.0.jar create mode 100644 lib/dev/hamcrest-core-1.1.jar delete mode 100644 lib/dev/hamcrest-library-1.0.jar create mode 100644 lib/dev/hamcrest-library-1.1.jar rename lib/dev/{jmock-2.3.0-RC2.jar => jmock-2.5.1.jar} (54%) delete mode 100644 lib/dev/jmock-junit4-2.3.0-RC2.jar create mode 100644 lib/dev/jmock-junit4-2.5.1.jar diff --git a/lib/dev/hamcrest-api-1.0.jar b/lib/dev/hamcrest-api-1.0.jar deleted file mode 100644 index 5df3f19d924fe7022180543df451706c83dd0b71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5681 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íK>0FSofW22mD9Rv65WKwY%;O@%t50!DG)4nkbEx2XU%(jPHf#t6W;7 zS%uAG=xZtM=q>iy3alm;^u!jI;4LgjIca}p3g%nReJ8Qhm2jU+dn}Bboo~XBX+xwP zsWJM=UR{e8M`&G%>O%#vucO}kv-;^@b7MgDNmGpDNrGsyhB(f50B_uy1g?>$QU)f` zz*qNnHuJQ@#k@-7=uxu*p}NX+aHn`n{!BXcjlb??L0_@kEtBSMM`9iVv?pJA7Vg+r zDIt$jT~h*^?urv5#x+a4jD&sB#HhRy`cyncs^Z%9WA*5O4d(8Xibq|ty!(u(H-HF;_ zzydf6IXM~rqdc9eqU$^_j>dNuKjMT&31&>?NYqUJjYE_e%_7GjOW0x_2V@1FK9k?( zoE*7Gl0efi>#66SvY9dGR9gRbW=b%?jiTS#U&3Ev{YPWrhk|E?9aj)BVGg@~ z-Lxu|tHD-1Tw9+*;|!#oRVcAzza7ew!(#nFPR%6y?!rqJAa}NMbLR-g9q#3l2lX;c z=zYp%pWS924Su45QP$Qec3(!*iPFc>fALqZ_-JsmSy2i-3RHj?-ryVL~il%VEYjZW${_+brH*KEVC znaQJ4Ol!aqL1yn!U~tx!K&ByCik5T7K8p#gGO-l){-`_qb(* zc34W*k#lC61y0;P$EG^GdwumTRU^!$ReQKJ4ugSKFhe@F3~hT|L0D%{9eec-Fu*+Z zIX5qV(w%I)&8NNES-2m&OJ4n6_B-|-IQ4gv{$~1F+Q5AL)pFtlDc_6atS%AlTEpK2 zz)tYjZi^Pl)l=eI5x;w(GsVT^?v-g>Q`)rptlX{%(Dl?$dA!nec1Qe!^q@oQpj;V6 zz8Zi4qH+VsaL`NWks@X=?vcdef0C)(S& z7AaxvsO7tWKRysIa-ffrcD5-f+aWPK)7 zeSu#6ZNV?UVmbZ$(0WNdY~?TEBkiO;2SyWeunMn!1d+EYn*B?D1>Zcq*$jDW66R`Af~az6aQj zzA>6tJ=W(yo%2yWbq0BKdIxFDqUuUcDGY_b6{|Y}__U`2KbcPFgr<#Kb!v{UIYIqt zXyZq~v?~;Q2Mv0(K&iPCj?|7i*dAx8_gW-hto8OW%DB4HHsEIq&EV47TX9;;@njj18RBai5~L@I ze1`~2KeL2z)}$}5l+O{qY9ZT`tY=FJobQ5e=%4SH5|}T~{Ub7WT#>SxIKVtNr%jaCaP8 zB8e%lSyg&p(nuU^O154o8~xwtioTUBbhtj5ZwufGOiMJXrIA}E;OKNiql#{A3o7z( zK%PQ99#MnE{4^8lWROwcZv^$QF(0enhEwSyDdnIuR(gFDk*HFXc%C#dexbHnd+i7t z<2m};U{SZa2Kv$sso&XR+-8DN�AXD_w45daGL99;F%HDn%FWYPHhFl9dM}^hUT+ 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

aDFp%+4BH=*^Y-v>G~}Wn`;I zeYnk%T@LcGvT;o$=#v31q;NAW`QAs83x*{<85g^pf!-MWj+=DPEHm|;-w@F_554ViMLlXL==!*r&|OJx^J zfAGo`kzlcw-MH#eN-tTe^D8&vZ#h4nF)Qo8Q&U_^_-d1q8=q(>ISHy9tmZaO(&CVt zi8d+Cps7=Mk!UD~vG=y%D2qlu>~oVgw~~pVqU%L}Uq#da>!4v!$-PGpN>ylC4s9&`h5K#Bq$vKijfy3Fy|}I)2W*U-&#>vlb{T?f zhJ)ZJU}{!8lgroROs+THO4Fh_M`GoWYcg4b4dvvqe>%xU=%t$*6y*kYYo@1!=2yP` z9xE~h?d~&EP-wQmxM4|+Au?Kj0{KG2m~Y^)+dBnIO^Rv zf0S~0N_(0zXo^#7V`2njsd6^J76;C&hwxo_I7P^4n=^>seJpn)Zz2^MW};+j4bZeaAqii98Aj_<@raDp>XQ5jGT3=!*8K&Bu}G9Rp3OXrP7;z5 zriG#d(t*xb1lbt9h4lNuCnJQfa5cu%BNrc|a%&diCK-ZWc`U^`hCW*nw`=A!Vx3*Q zo$t3VX|UEZ`w0|x9y{0GNJER=9kIywq*DDG8CxzQ<9VuATvnMxVq>itYJ^$MFx_Q2 z`g!q|FRiIaL_skDjej>R(o-og_vS6lo*} z4Xg)Kocqq~c4tm|DL=_Rf_;Hu9MgG_-2>*C`v~X=*?&p-Rb4e?RsH^h#!UyURnY(t zwhz#-{8v4qnEn5s>wf`kzhXDQ#R1?CNg47TYH%q*Cs;Gi3A7dERChIp?=q~1$jov$ z#=u%Q)*F{hRrrmiQwq%$9rT#QkcZ} z-Fxk@H3D6Vwwn!uua83R1noM>$%M8cI=SvFr%inRL3W6QZ*cqT>jXpfFsiU4gV~W3b z2!kUA*VVn*W$fB7xf7z~=UqMOkm+xJ&Mq9DYLpgTuU=o7xxdPOHjZC9UIs*brKMZx z6u9}LtP_{K#LEK8xh~+r`!CA+|2a3H8XE`rIl%C4b0|1`Rn67~4kjxQV}j^=*m>BQ zJm%;KJ`s@u`dKWwV|}qN4)jGtZCG`m(S|siXk?SvXS<0@&u|Cv@T~&{BjgCXC zf0jCrLn0>VGxtgP#ge z9THT21%9aCj)ln3E_oXWh=@WUEzM{HEMFw8Q{`+9gG(X%5uK!m;*Pi&srsUZ zwV$1hu^l>3yiE?jecYaN_+Yf(<)J-trQGR_z@yP~gV3IfKrm>Hfzbwo-`q}xi{NlR z#MA9|BeihfZ(#^Tn_`418HSWw-fCvawJ446o!7b6Qj?|W8DhL39gYtZ_`8c$K?H3u z2_chtf*QdswJmEW9^?GPn==Zg-#}2Q5sd8CMlf2I70=CPfFV_zZLhU-l$d5}yW`!z z^TA(OPR)@ST7i05K0%j919-N%S|(e6>q%BF{mXC|)Truvv&{ybM0Iy$kP$hPoT6l4 z!1!O@!K##@98*wg+lCS>X}6Xu9pskbwT9-0E9q9}o%;GImO?0Lj`&!%u9hF|8?+;O zLb0&XT2l+;7^s3Edz@}zDnEb9?VC*$Gn?_(B|VPxn2z7IR!W({{*1h|Yrx+Da}=Nx zB-Sz;pxGjgL)<_UL|^n*;f)wjIIDMYsYVw>o%DC{{SGWaAE9kZgwb=J45uesh~6qm z5mXuQy``EonaibATOxY8$mL$}(6v-R9#;MWuV_+C*< zu!-9@HI}fH3Sw&)>L0Tx@|6Y`a!KaKl5#WB?h}dk$pgH(ruGu76hGQ6m#G_!|fj%=tvjR4@>nU!X@wk z>?P55rm(}e&@xh8X)8vbU3KhGiz+`#hYz`{D-NL)L>K50Hl7zVWoD1y>m3|S(%2qi z1*oQvzYjzBaLENpydQA#*fthGr)wcz;CZ%k-KFY7(R3v|Rb-j`0rcTwxV4}MbUZpc zD)QvpVDLT1xJynJ^fWBBB0gjUNGm_#1tO5yXRHwqIcJ(_Gyr*yKgdB)@v!}UCCKmP zF}aXz3dWoN;A0Wj!7qkY@HgYYu$aDOpDzMGegXp}#95?TCR+!ga(jp{Pz?>2=yBP*#bd@}Ih6-YO(6-8|g(j88B5}}dE5#5#vj`}Rc&h^oQb-Oy z?9Tx{a4Nf@Hi>xM(!B6jq{g<(X@!YtZ2dn%S9#Rt4f+awi1y2lfTo0hV#6HE;*9pzFS$pIfvJG-7h3lTHupxD zSlzWl;QN-9(1n0%5QW9sd0_O@@%Ne=t&}kIPTf!RnaqognAGnkP(|B{(_7Q^Lr7)H z6!xh1E1-;<>nqbe>Qrg$+wzlOskeSeF*W{FM|1y_wKH$+rR}g&oKuYCpRWgbl9qCIt;sRVP`R7`sa$4TRLs3M(9LFWfyDVdhp`9c%&1Ot8`n=8 zdj{jQILoB5PTv82rz8!BJ}}8bq7hpfBod~3^8?PfAjb4=?|Ax{Tvi;i#k3hlzo=X} ztyONDnTB1mBY+HLA?Qg&cWlI#-M7XOn5X{sj*Qbr$m& z!qSq`tiwI~<^p!6c)LYfQdyXXTxu|f?}FlZ!_@8nmWbB9>>p)I5N z3fHlIK{KX#EfO60+L&B1Y)-z>_@EV~HTh|58s!Pw%6tQ@dW)kJ$o-H9G#H1zhOm!d zCo%02KZsf6)s-*cX*%aJA9P`HH03I;aOL7QCUtGN`&xMskznY`V$dM(W2i1)q%3? z0=a=#Ea%_+Fhf=#_js}FzEnNMRO!tGuMuGBGG&DdW#MD`@Opu<`KVMiZL;OixF&k8<2dB;eFY+#AVI>Apj;qSX06f_I=X+L4wr#8>^6g=y2J^{b{ z?%V29jwyOUqJlXSZ6TE{+~KRa81}@kA@zRep64$Q>@Kntzda&k6I*VVzKati7dkX$ zACAe${d|D2!jo{SYZhoDu2t=qiuQ^M(ZoN&sD(zHppuMlAR20{s^3<|=hss0fsjq$ z+#Zu7&JFO0-`GiGIifx$4}HJ{2i(FXmM~IWbFujq+MvY`C#un zSS7`n`3%}i72%NFa@j&JxSEmYf&`rp{{(~zDcWxD{RdqNz-OE41C&2qz?moQ{}84A zDuRhWC9G$8zjca?c%$2uWXc!qbothY%%GNl7Yh=&ZLlJ_>(-rKL}C5t^EO`4B6Y&S zd-%4>QDxofYCsRx%p_!Jn1m!~3S&)8Lqqd)NVTVzspgP?o(>C6n*{?NDC!*o<7*vP zk#a>U73{ywTM4aSLenmgtfm^n=;o%eTbIo!;?DmfmTzF;$j@E{l@W?^;Q<34f4!6! z$VSN;L-}oMNIcWm!Dq5SmKQ95xet}^4%47es)EP?)RfvG$f8^~UV?wnRe#1#mO4Qa z|7Q=Ii_PQ4u0XZd%?d*mtR&P)fj?J>avl4Y`_q2S*I&aR2hq;ams^ymfKN+dR>vmv zT2h}y@Z}l#23I63ca5mZJ%8Qli_}25yssA2N4Ma{q9JFiTZ+ne1JLd7s zRtiYqzgySIs7HsU)CR#X&o_Gc+7;A#tW>nUPedp;`Qrfu#HUkKu6X*M=}5jLYYBIR zinP)e7+zeLWG-@igvqS+GgWV0Yx*dB8f^nzD}Vyw$1MpJwXWQGUMmV*o(r;!GoRO` z7I`wY>GjzRj9P~U+5j0c=7OVRCQW_miX_{uBMm~hqMD}r4@~K=7-H+ml|jKw%~8_l zB-}t-{X@h*PVv>Z)&w(Mp%?Gn;e`*m5rn!e*$=HEg`Yg~&GMSHA-w(OS!C?fd&DXR z9;43QVc0F@-pb_Mq(&WD|XY|;(hy=-y|=I{F2zKZ~IC&tB>%wR@K}O|Aw2{MN5Vcl3Lg-mvLo} zjqNZKd_^;TN-5&^RP)>UR4hIHb43P7y2DetvPoyLe}KpPkG*S2TZ#S+U`)FT7#NcL zry21d3)jD|r~VeNM8>U~{fj)sTR69!rZJl;RNyvLXq$$CUDp!h_4|E8Swoy^8+MWu zj#FLEOnCXh?Zcu)76J;2+Z9Z~RhODXA~mhKlxlyFvB~zy_WJm=i2FrG7J5s!e-P#Z zM5TY_#{$5DYDnwaCc1k)N&JLFpkd*q3*IGf@@Esmv0~}Pf^d5Gve*M?uZ9H0wHfPC zh(omV%U(%+T*~7rXW~Gkw8*2uK=p?Bj8)zsxGe?!`qYlB`hj#VV=~36-c_A0>1ZaH zQx5AqGI%>~CRm4;w^;loI{G|}!t|jU3B~DfG)#Cyr0JNv1y+c~{tM%t%PUPwlsf?v zl}K$_Gfp8CiwY{3h6PaI8?4d%7C77 z+Nu`%@7cjZ$q>~i`~%v{ZLbh;7f~@K2Wppl?Yx|8DM&VK|M@;z9`dm6cr)$qTI|JW zDtVt1{;uC?XURN)YtzW4pquZ<39B#bDYu|J{ny+RYsDcY&0pZ@Dfh44WXB_Ad1kA4JqkE=AfzcGOCOL|msAIHt`x;!pp?m{ zv`Jm105C4W^5rwvDY3+t#zvm%N-STMif!h}TddDDKL1QTyEwHA51EhEhx zaJ6GK1GhMx9dqu`J54bHkg5vs0vvc$Ee_6#J~lo4%5o+*OSFd1p8jyCRI^gi*#`W@ z<^PYw6tXg~|I1$f?=@tcru8h~1XbHvb;dv!Yh4W;HxCPUg`F?3d966$TN?$Q+#KY^ z+8Cp7iT`)wF7KVMM14dtPe5;EeYR<^D=2&f%iM#Pt`lsH-fwR&*j<`yP+Pj|gPfJ1 zCVF{cQt*qwwToP9IyR5_afQ9In&7-Xg~5KhC6tLSanWG> zJcs@PoDEi(*ZGqT^-jkQl0O)N#;r<&&r_lasOV>zcQVOSqvv#;@TA&Dw~U|hC^Jx< zNZ9s~ML3T$L$W$wBw}eW(Dz{)M4MwvM)aP8bREszQR^s1zM`wu>BI-}9FT+sHugX4 z$=b%7o7LWK`nnqjV*6EajV8ttPA8}4>$_(wnhg{%Fp}`Sa?+Q0$?);fj5`uN6mT6T z4$rph&ju9tz}EyA!m|i4%IX6yCBzmz)E(B|7AvO4$73?qc$blTZyc1DvcdPez2H(R z{0Dr>;VABat;`S6&yXr8RI=&F+7HRh5b!H7^-)|=p~K8q@q+wsixbOViAOh0J%#t7 z54baSG~#^nf6IN4j|_^3stI)nt`{x~kIiR9E5x_~K@P4G_mLif)><5KrJZMe!rs!T z4cZg|C4YQ*62j{0|NkmG3#h1?HjdLRC5j;3N_Xi>cL|7;BGSUr5~4^qNT(nmp{}kd zArcZ264IU04T4LEh~Gth-2F$P_Agne|$vQo$+4U{#>I zH?C0d1$tnR-2KBm{CALif0K{VRK?^ctzY|0aWA8UaFvIyLRXHoGBlVVBY(kFv{XIO zyw5Oae6%QSKh7^*R%yf1+d<%r%ZH|$whoI5(F^?cuqS1qEwt2zH`=8M=4=BibZHkf zpHQtE)5uLYq;Oayrhjtgsf<23*B=)?$r)-t(AXu=&P=zqE>g|KaLoVqDDNPF8X9AW zXh{?Xeo>)J!z%pCU?zpE*Vm`Q)MdG(e53g7Zgh|cp%8WF5wkL0<*l8IAu%fL;V&mV zim39Jp#g8q9?<4CX$(F>pGz+|nPE0-++tp1(nD7H6*qM8usZ12Ss6vEM~w)@d>uS;Q)(NTZU08hozxdBvMsQxw-p}~BX>c09@Os_ z?TrCFTmno(jw9Ab9amFlSJV^nWxz7*Y2Z4434cc){@J=21=fHf7zVj?`iHh-dF%0P z@0@V<*munp6*joV}g*|jH@dXVbC*sIL=A{i5V-wXy0TyJUM1og)&&1-HXWk;uhhONU6)h z8JO6tjqBN4ySuy=Z_Ka73+pn?7|t5Ryb~qj9G2`(mgeX2%>vS$mh3bdH->8EjVKWd zz*XfV-S#CNzf}~-7W7(K~+7q`4{4TtO-k)}2;MeRDeH?Bc&TYF^8 zr1WrwchO%Jdtq#a>IoZX@)wMGh8apJ!Df}@Gq6>i)H&-M3nFgS-_m-qH`-^_^XA&@ z+f#F~SS(*7HySzUDLH!xs81{szh}Fiw|e`&j}R9N4fHbUgUqCN0$JNOB3}EVt#7Q; ztJATJKVyCv7V&A(D^&4f?!5#|LxZ(Vlf$dw{%)=kH zI%{_bZ1dsd(0X50G8vi4ATgrQ!Zc5)T$*lFOLE6p`qN`8I0+2Fa_d&#s;12GtNmAq zpTZ0o^lVGpKJ7I-h-#U^lJDmv!ti3b7PTr(QLYPL~5@*QIXOp)CUnhfP zJxU!&vQ(a&nW$H!ou^e&_c7k&rb1sqtHHO`@$|uHrj~{VIhsVV&<-!PC~#^WlfX?w zx5F|RfhAJkPBSl|yGqzsE&@*KERO=nd^4h z4s+{*o9k=L?WzeZ9oaAAvR6Dh*9i~z@zusmqH93^P6B&OznO_RiWYCZI=iSl@T5AGD; z)8VvL>er#|(lplE*1G-PyYS0*rw)-9(CWH7wEX7B4EwC2!x``4c6o~V`?-c)v{Sk( z81{^Vj(`5@^V!ev86hg|Tv_kBa1r;^dgp@eSn1&xG%e#6$t@Wq&o5K;h^7Z!OXfC+ z@))=64=|b#Hc~3pNFTnmYS=|0da267lgKtVYM86UqkNU1op*O~fH$#S!n5(~E!9#v zItSdm%d@z(kd&^siZaEwJ1zOBYhmSj>bep{ErU)`ucV(Y8PT%OOZJ_D@^NWs<`srA z+mj3rU%1A1#ngpr(@-yI;+ET2rj>@F(dV>bW%NZb8ixoNZG$z91#H2wYA#mSXo~xi zMw!ea>61d2496t22JuD|h zR{08wLgzecqVG=&@bhwB{&qn=D7Pi5hP0{KhD$B(K~!D&l?kD<0c~2P^Ek#L)oA*=4nvJL~DCHIErF;$C39e>$Fb`ixR%s#HLq z*bIB7&U@jFS=_+@5nQZ9Io90V48~cvkjFC{cjO=>>q24vPsyT0>N*QZCr9e8hkQCy z*EFrOcm~e#ZZiv8;jF~RDjD(m2tSgCd6AjsbTBMIre>m0fzm)$zDo(0aWgNBQZRf@ z73gMMhehkR&)k(>dz*aDe~Y9D643WTrU)SsA~*Yd!v15`Ht2M0<8(?V6u1)v0IS7s z?gZdb`u)im=~gCLOuo2EBvuW#CVy61{ZI?QsT=#VxIHIwENl?7Yz*fOR0=XLn_rBzwYEz?a|TVYofz9+ zYyLdT%_Y@JdY_ISmUJ(D(sL}di}>DtXw*i}8AqY++aDG5vKZ#49OI2^RYQ5Qo~ODV zzlQlJUR=hM+6}=To!Uedo}wG88BInXiclIh(sUQS{a`7Z!F@fa+33|X!JrWA0Q#Wp zQil$Sw=Bud961WYTXT(`qN)Shp @_Hgha@QhXHHOV}HykhI0v>slD2r7`>cqHLH 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 H2Y>w!sRTga literal 0 HcmV?d00001 diff --git a/lib/dev/jmock-2.3.0-RC2.jar b/lib/dev/jmock-2.5.1.jar similarity index 54% rename from lib/dev/jmock-2.3.0-RC2.jar rename to lib/dev/jmock-2.5.1.jar index 77aef4b1915683700dc38a8c0eb20ceb0428e577..4415dfbc94f8515bef4495976bcdb0fa5e6b5981 100644 GIT binary patch delta 67876 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

ecVEv`Q?kuH6$(R}+ar^O&FIRiHSO= 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 D@5)egviMyf#US&i< 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 I0XX~r07XCsUjP6A diff --git a/lib/dev/jmock-junit4-2.3.0-RC2.jar b/lib/dev/jmock-junit4-2.3.0-RC2.jar deleted file mode 100644 index cfb2fbdebf6871ce7607ca9697546c8ac7033940..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8305 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 PK5Q?Z$JxUv5&i!H3**Vk diff --git a/lib/dev/jmock-junit4-2.5.1.jar b/lib/dev/jmock-junit4-2.5.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..fb3697af4bfae4c900a75d6dec89950f12ed8faf GIT binary patch literal 10247 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 E0o}N=^8f$< literal 0 HcmV?d00001 From ab99be7396b35882a1614bcf80fd5762da7d5f45 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Mon, 30 Jan 2012 15:47:15 +0400 Subject: [PATCH 24/45] IDEA-76142: Gradle support - cannot update IDEA projects once one of build.gradle files changes Gradle tool window is shown all the time when 'gradle' plugin is enabled (used to be hidden because there were no content) --- .../jetbrains/plugins/gradle/bootstrap/GradleBootstrap.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/bootstrap/GradleBootstrap.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/bootstrap/GradleBootstrap.java index 762c18a47488..254145d26a65 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/bootstrap/GradleBootstrap.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/bootstrap/GradleBootstrap.java @@ -15,7 +15,7 @@ import org.jetbrains.plugins.gradle.ui.GradleIcons; import org.jetbrains.plugins.gradle.util.GradleBundle; /** - * // TODO den add doc + * Encapsulates initialisation routine of the gradle integration. * * @author Denis Zhdanov * @since 11/3/11 4:01 PM @@ -42,10 +42,6 @@ public class GradleBootstrap extends AbstractProjectComponent { } private void initToolWindow() { - // TODO den don't show tool window if no gradle project is associated with the current project. - if (!Boolean.getBoolean("gradle.show.tool.window")) { - return; - } final ToolWindowManagerEx manager = ToolWindowManagerEx.getInstanceEx(myProject); ToolWindow toolWindow = manager.registerToolWindow(GRADLE_TOOL_WINDOW_ID, false, ToolWindowAnchor.RIGHT); toolWindow.setIcon(GradleIcons.GRADLE_ICON); From 263ec389b79348c27fd1b09d453a92b3ebceb62a Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Mon, 30 Jan 2012 15:49:26 +0400 Subject: [PATCH 25/45] IDEA-76142: Gradle support - cannot update IDEA projects once one of build.gradle files changes 1. Test DSL for testing gradle changes model is introduced; 2. Test for the 'merge local' changes use-case is added; 3. More gradle class dependencies are configured via IoC now; --- .../util/containers/ConcurrentHashSet.java | 7 +- plugins/gradle/src/META-INF/plugin.xml | 7 +- .../plugins/gradle/diff/GradleDiffUtil.java | 93 ++++++------------ ...yDependencyStructureChangesCalculator.java | 14 ++- ...radleModuleStructureChangesCalculator.java | 48 +++++----- ...adleProjectStructureChangesCalculator.java | 76 +++++++-------- .../diff/GradleProjectStructureHelper.java | 37 ++++++++ .../GradleProjectStructureHelperImpl.java | 38 ++++++++ .../GradleStructureChangesCalculator.java | 61 ++++++++++-- .../GradleProjectStructureChangeListener.java | 6 +- .../GradleProjectStructureChangesModel.java | 30 ++++-- .../GradleProjectStructureChangesPanel.java | 94 ++++++++++++++++++- .../gradle/task/GradleResolveProjectTask.java | 7 +- ...dleProjectStructureChangesModelTest.groovy | 76 +++++++++++++++ .../testutil/AbstractProjectBuilder.groovy | 68 ++++++++++++++ .../gradle/testutil/ChangeBuilder.groovy | 47 ++++++++++ .../testutil/GradleProjectBuilder.groovy | 46 +++++++++ .../testutil/IntellijProjectBuilder.groovy | 49 ++++++++++ 18 files changed, 642 insertions(+), 162 deletions(-) create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureHelper.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureHelperImpl.java create mode 100644 plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy create mode 100644 plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy create mode 100644 plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy create mode 100644 plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy create mode 100644 plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentHashSet.java b/platform/util/src/com/intellij/util/containers/ConcurrentHashSet.java index a792361c4cf2..3db9efffae82 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentHashSet.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentHashSet.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -92,5 +92,10 @@ public class ConcurrentHashSet implements Set { public void clear() { map.clear(); } + + @Override + public String toString() { + return map.keySet().toString(); + } } diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index 1487b063dbc5..36d93560b32e 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -36,7 +36,12 @@ - + + + + diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java index bbafe4cd653a..a6b51a7b8204 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java @@ -25,11 +25,10 @@ public class GradleDiffUtil { * Example: particular module has been added at the gradle side. We want to mark that module, its content root(s), dependencies etc * as gradle-local changes. * - * @param entity target gradle-local entity - * @return collection of gradle-local changes for the given entity and its interested sub-entities + * @param entity target gradle-local entity + * @param currentChanges holder for the changes built during the current call */ - public static Set buildLocalChanges(@NotNull GradleEntity entity) { - final Set result = new HashSet(); + public static void buildLocalChanges(@NotNull GradleEntity entity, @NotNull final Set currentChanges) { entity.invite(new GradleEntityVisitor() { @Override public void visit(@NotNull GradleProject project) { @@ -38,7 +37,7 @@ public class GradleDiffUtil { @Override public void visit(@NotNull GradleModule module) { - result.add(new GradleModulePresenceChange(module, null)); + currentChanges.add(new GradleModulePresenceChange(module, null)); for (GradleDependency dependency : module.getDependencies()) { dependency.invite(this); } @@ -61,79 +60,52 @@ public class GradleDiffUtil { @Override public void visit(@NotNull GradleLibraryDependency dependency) { - result.add(new GradleLibraryDependencyPresenceChange(dependency, null)); + currentChanges.add(new GradleLibraryDependencyPresenceChange(dependency, null)); } }); - return result; } /** * Analogues to {@link #buildLocalChanges} but targets intellij entity. * - * @param module target intellij-local module that doesn't present at the gradle side - * @return collection of intellij-local changes for the given entity and its interested sub-entities + * @param module target intellij-local module that doesn't present at the gradle side + * @param currentChanges holder for the changes built during the current call */ - public static Set buildLocalChanges(@NotNull Module module) { - Set result = new HashSet(); - result.add(new GradleModulePresenceChange(null, module)); + public static void buildLocalChanges(@NotNull Module module, @NotNull Set currentChanges) { + currentChanges.add(new GradleModulePresenceChange(null, module)); // TODO den process module sub-entities here (content roots and dependencies). - return result; } /** * Analogues to {@link #buildLocalChanges} but targets intellij entity. * * @param libraryDependency target intellij-local library dependency that doesn't present at the gradle side - * @return collection of intellij-local changes for the given entity and its interested sub-entities + * @param currentChanges holder for the changes built during the current call */ - public static Set buildLocalChanges(@NotNull LibraryOrderEntry libraryDependency) { - return Collections.singleton(new GradleLibraryDependencyPresenceChange(null, libraryDependency)); + public static void buildLocalChanges(@NotNull LibraryOrderEntry libraryDependency, + @NotNull Set currentChanges) + { + currentChanges.add(new GradleLibraryDependencyPresenceChange(null, libraryDependency)); } /** * Performs argument type-based dispatch and delegates to one of strongly typed 'buildLocalChanges()' methods. * - * @param entity target intellij-local entity that doesn't present at the gradle side - * @return collection of intellij-local changes for the given entity and its interested sub-entities + * @param entity target intellij-local entity that doesn't present at the gradle side + * @param currentChanges holder for the changes built during the current call */ - @NotNull - public static Set buildLocalChanges(@NotNull Object entity) { + public static void buildLocalChanges(@NotNull Object entity, + @NotNull Set currentChanges) + { if (entity instanceof GradleEntity) { - return buildLocalChanges((GradleEntity)entity); + buildLocalChanges((GradleEntity)entity, currentChanges); } else if (entity instanceof Module) { - return buildLocalChanges((Module)entity); + buildLocalChanges((Module)entity, currentChanges); } else if (entity instanceof LibraryOrderEntry) { - return buildLocalChanges((LibraryOrderEntry)entity); + buildLocalChanges((LibraryOrderEntry)entity, currentChanges); } - else { - return Collections.emptySet(); - } - } - - /** - * Concatenates given entities into the single collection and returns it. - *

- * The main idea behind this method is that most of the time we don't expect changes at all, hence, corresponding changes calculators - * can use {@link Collections#emptySet()}. However, if some sub-nodes do have changes, attempt - * to {@link Collection#addAll(Collection) merge} them within the empty set mentioned above would cause an exception. - *

- * That's why we provide dedicated method for creating new collection as a merge result. - * - * @param collections collections to merge - * @return merge result - */ - @NotNull - public static Set concatenate(Collection... collections) { - Set result = null; - for (Collection collection : collections) { - if (result == null) { - result = new HashSet(); - } - result.addAll(collection); - } - return result == null ? Collections.emptySet() : result; } /** @@ -146,39 +118,34 @@ public class GradleDiffUtil { * @param gradleEntities entities available at the gradle side * @param intellijEntities entities available at the intellij side * @param knownChanges collection that contains known changes about the entities + * @param currentChanges holder for the changes discovered during the current call * @param target intellij entity type * @param target gradle entity type - * @return set of changes between the given entity collections */ - @NotNull - public static Set calculate( + public static void calculate( @NotNull GradleStructureChangesCalculator calculator, @NotNull Iterable gradleEntities, @NotNull Iterable intellijEntities, - @NotNull Set knownChanges) + @NotNull Set knownChanges, + @NotNull Set currentChanges) { - Set result = Collections.emptySet(); Map intellijEntitiesByKeys = new HashMap(); for (I entity : intellijEntities) { - final I previous = intellijEntitiesByKeys.put(calculator.getIntellijKey(entity, knownChanges), entity); + final I previous = intellijEntitiesByKeys.put(calculator.getIntellijKey(entity), entity); assert previous == null; } for (G gradleEntity: gradleEntities) { I intellijEntity = intellijEntitiesByKeys.remove(calculator.getGradleKey(gradleEntity, knownChanges)); - Set changesToMerge; if (intellijEntity == null) { - changesToMerge = buildLocalChanges(gradleEntity); + buildLocalChanges(gradleEntity, currentChanges); } else { - changesToMerge = calculator.calculate(gradleEntity, intellijEntity, knownChanges); + calculator.calculate(gradleEntity, intellijEntity, knownChanges, currentChanges); } - result = concatenate(result, changesToMerge); } for (I entity : intellijEntitiesByKeys.values()) { - result = concatenate(result, buildLocalChanges(entity)); + buildLocalChanges(entity, currentChanges); } - - return result; } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java index 4c2490a48af3..077f58b88e90 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java @@ -4,7 +4,6 @@ import com.intellij.openapi.roots.LibraryOrderEntry; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.model.GradleLibraryDependency; -import java.util.Collections; import java.util.Set; /** @@ -14,20 +13,19 @@ import java.util.Set; public class GradleLibraryDependencyStructureChangesCalculator implements GradleStructureChangesCalculator { - @NotNull + @Override - public Set calculate(@NotNull GradleLibraryDependency gradleEntity, - @NotNull LibraryOrderEntry intellijEntity, - @NotNull Set knownChanges) + public void calculate(@NotNull GradleLibraryDependency gradleEntity, + @NotNull LibraryOrderEntry intellijEntity, + @NotNull Set knownChanges, + @NotNull Set currentChanges) { // TODO den implement - return Collections.emptySet(); } @NotNull @Override - public Object getIntellijKey(@NotNull LibraryOrderEntry entity, @NotNull Set knownChanges) { - // TODO den consider the known changes + public Object getIntellijKey(@NotNull LibraryOrderEntry entity) { final String result = entity.getLibraryName(); return result == null ? "" : result; } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleStructureChangesCalculator.java index 84c62ec4ff42..28f5ec482cba 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleStructureChangesCalculator.java @@ -34,24 +34,30 @@ import java.util.Set; */ public class GradleModuleStructureChangesCalculator implements GradleStructureChangesCalculator { - private final GradleLibraryDependencyStructureChangesCalculator myLibraryDependencyCalculator - = new GradleLibraryDependencyStructureChangesCalculator(); - - @NotNull + private final GradleLibraryDependencyStructureChangesCalculator myLibraryDependencyCalculator; + private final GradleProjectStructureHelper myStructureHelper; + + public GradleModuleStructureChangesCalculator(@NotNull GradleLibraryDependencyStructureChangesCalculator libraryDependencyCalculator, + @NotNull GradleProjectStructureHelper structureHelper) + { + myLibraryDependencyCalculator = libraryDependencyCalculator; + myStructureHelper = structureHelper; + } + @Override - public Set calculate(@NotNull GradleModule gradleEntity, - @NotNull Module intellijEntity, - @NotNull Set knownChanges) + public void calculate(@NotNull GradleModule gradleEntity, + @NotNull Module intellijEntity, + @NotNull Set knownChanges, + @NotNull Set currentChanges) { //TODO den process module-local settings - //TODO den process content roots - return checkDependencies(gradleEntity, intellijEntity, knownChanges); + //TODO den process content roots + checkDependencies(gradleEntity, intellijEntity, knownChanges, currentChanges); } @NotNull @Override - public Object getIntellijKey(@NotNull Module entity, @NotNull Set knownChanges) { - // TODO den consider the known changes + public Object getIntellijKey(@NotNull Module entity) { return entity.getName(); } @@ -62,9 +68,10 @@ public class GradleModuleStructureChangesCalculator implements GradleStructureCh return entity.getName(); } - private Set checkDependencies(@NotNull GradleModule gradleModule, - @NotNull Module intellijModule, - @NotNull Set knownChanges) + private void checkDependencies(@NotNull GradleModule gradleModule, + @NotNull Module intellijModule, + @NotNull Set knownChanges, + @NotNull Set currentChanges) { // Prepare intellij part. final List intellijModuleDependencies = new ArrayList(); @@ -82,11 +89,10 @@ public class GradleModuleStructureChangesCalculator implements GradleStructureCh return libraryOrderEntry; } }; - final ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(intellijModule); - for (OrderEntry orderEntry : moduleRootManager.getOrderEntries()) { + for (OrderEntry orderEntry : myStructureHelper.getOrderEntries(intellijModule)) { orderEntry.accept(policy, null); } - + // Prepare gradle part. final List gradleModuleDependencies = new ArrayList(); final List gradleLibraryDependencies = new ArrayList(); @@ -104,12 +110,10 @@ public class GradleModuleStructureChangesCalculator implements GradleStructureCh for (GradleDependency dependency : gradleModule.getDependencies()) { dependency.invite(visitor); } - + // Calculate changes. // TODO den process module dependencies here as well. - final Set libraryChanges - = GradleDiffUtil.calculate(myLibraryDependencyCalculator, gradleLibraryDependencies, intellijLibraryDependencies, knownChanges); - return libraryChanges; - + GradleDiffUtil.calculate(myLibraryDependencyCalculator, gradleLibraryDependencies, intellijLibraryDependencies, + knownChanges, currentChanges); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java index 9c099280cecf..ad9bc2827854 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java @@ -1,21 +1,15 @@ package org.jetbrains.plugins.gradle.diff; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.pom.java.LanguageLevel; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.model.GradleModule; import org.jetbrains.plugins.gradle.model.GradleProject; -import java.util.Collections; -import java.util.List; +import java.util.Collection; import java.util.Set; -import static java.util.Arrays.asList; -import static org.jetbrains.plugins.gradle.diff.GradleDiffUtil.concatenate; - /** * Encapsulates functionality of calculating changes between Gradle and IntelliJ IDEA project hierarchies. *

@@ -26,25 +20,31 @@ import static org.jetbrains.plugins.gradle.diff.GradleDiffUtil.concatenate; */ public class GradleProjectStructureChangesCalculator implements GradleStructureChangesCalculator { - private final GradleModuleStructureChangesCalculator myModuleChangesCalculator = new GradleModuleStructureChangesCalculator(); + private final GradleModuleStructureChangesCalculator myModuleChangesCalculator; + private final GradleProjectStructureHelper myStructureHelper; + + public GradleProjectStructureChangesCalculator(@NotNull GradleModuleStructureChangesCalculator moduleCalculator, + @NotNull GradleProjectStructureHelper structureHelper) { + myModuleChangesCalculator = moduleCalculator; + myStructureHelper = structureHelper; + } - @NotNull @Override - public Set calculate(@NotNull GradleProject gradleEntity, - @NotNull Project intellijEntity, - @NotNull Set knownChanges) + public void calculate(@NotNull GradleProject gradleEntity, + @NotNull Project intellijEntity, + @NotNull Set knownChanges, + @NotNull Set currentChanges) { - final Set result = calculateProjectChanges(gradleEntity, intellijEntity, knownChanges); + calculateProjectChanges(gradleEntity, intellijEntity, currentChanges); final Set gradleSubEntities = gradleEntity.getModules(); - final List intellijSubEntities = asList(ModuleManager.getInstance(intellijEntity).getModules()); - return concatenate(result, GradleDiffUtil.calculate(myModuleChangesCalculator, gradleSubEntities, intellijSubEntities, knownChanges)); + final Collection intellijSubEntities = myStructureHelper.getModules(intellijEntity); + GradleDiffUtil.calculate(myModuleChangesCalculator, gradleSubEntities, intellijSubEntities, knownChanges, currentChanges); } @NotNull @Override - public Object getIntellijKey(@NotNull Project entity, @NotNull Set knownChanges) { - // TODO den consider the known changes + public Object getIntellijKey(@NotNull Project entity) { return entity.getName(); } @@ -55,43 +55,33 @@ public class GradleProjectStructureChangesCalculator implements GradleStructureC return entity.getName(); } - @NotNull - private static Set calculateProjectChanges(@NotNull GradleProject gradleProject, - @NotNull Project intellijProject, - @NotNull Set knownChanges) + private void calculateProjectChanges(@NotNull GradleProject gradleProject, + @NotNull Project intellijProject, + @NotNull Set currentChanges) { - final Set nameChanges = checkName(gradleProject, intellijProject, knownChanges); - final Set levelChanges = checkLanguageLevel(gradleProject, intellijProject, knownChanges); - return concatenate(nameChanges, levelChanges); + checkName(gradleProject, intellijProject, currentChanges); + checkLanguageLevel(gradleProject, intellijProject, currentChanges); } - @NotNull - private static Set checkName(@NotNull GradleProject gradleProject, - @NotNull Project intellijProject, - @NotNull Set knownChanges) + private static void checkName(@NotNull GradleProject gradleProject, + @NotNull Project intellijProject, + @NotNull Set currentChanges) { String gradleName = gradleProject.getName(); String intellijName = intellijProject.getName(); - if (gradleName.equals(intellijName)) { - return Collections.emptySet(); + if (!gradleName.equals(intellijName)) { + currentChanges.add(new GradleRenameChange(GradleRenameChange.Entity.PROJECT, gradleName, intellijName)); } - final GradleRenameChange change = new GradleRenameChange(GradleRenameChange.Entity.PROJECT, gradleName, intellijName); - return knownChanges.contains(change) ? Collections.emptySet() - : Collections.singleton(change); } - @NotNull - private static Set checkLanguageLevel(@NotNull GradleProject gradleProject, - @NotNull Project intellijProject, - @NotNull Set knownChanges) + private void checkLanguageLevel(@NotNull GradleProject gradleProject, + @NotNull Project intellijProject, + @NotNull Set currentChanges) { LanguageLevel gradleLevel = gradleProject.getLanguageLevel(); - LanguageLevel intellijLevel = LanguageLevelProjectExtension.getInstance(intellijProject).getLanguageLevel(); - if (gradleLevel == intellijLevel) { - return Collections.emptySet(); + LanguageLevel intellijLevel = myStructureHelper.getLanguageLevel(intellijProject); + if (gradleLevel != intellijLevel) { + currentChanges.add(new GradleLanguageLevelChange(gradleLevel, intellijLevel)); } - final GradleLanguageLevelChange change = new GradleLanguageLevelChange(gradleLevel, intellijLevel); - return knownChanges.contains(change) ? Collections.emptySet() - : Collections.singleton(change); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureHelper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureHelper.java new file mode 100644 index 000000000000..f0c81df79111 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureHelper.java @@ -0,0 +1,37 @@ +package org.jetbrains.plugins.gradle.diff; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.OrderEntry; +import com.intellij.pom.java.LanguageLevel; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; + +/** + * IntelliJ code provides a lot of statical bindings to the interested pieces of data. For example we need to execute code + * like below to get list of modules for the target project: + *

+ *   ModuleManager.getInstance(project).getModules()
+ * 
+ * That means that it's not possible to test target classes in isolation if corresponding infrastructure is not set up. + * However, we don't want to set it up if we execute a simple standalone test. + *

+ * This interface is intended to encapsulate access to the underlying project infrastructure. + *

+ * Implementations of this interface are expected to be thread-safe. + * + * @author Denis Zhdanov + * @since 1/26/12 11:32 AM + */ +public interface GradleProjectStructureHelper { + + @NotNull + LanguageLevel getLanguageLevel(@NotNull Project project); + + @NotNull + Collection getModules(@NotNull Project project); + + @NotNull + Collection getOrderEntries(@NotNull Module module); +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureHelperImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureHelperImpl.java new file mode 100644 index 000000000000..6b30b59c57f6 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureHelperImpl.java @@ -0,0 +1,38 @@ +package org.jetbrains.plugins.gradle.diff; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.OrderEntry; +import com.intellij.pom.java.LanguageLevel; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Collection; + +/** + * @author Denis Zhdanov + * @since 1/26/12 11:54 AM + */ +public class GradleProjectStructureHelperImpl implements GradleProjectStructureHelper { + + @NotNull + @Override + public LanguageLevel getLanguageLevel(@NotNull Project project) { + return LanguageLevelProjectExtension.getInstance(project).getLanguageLevel(); + } + + @NotNull + @Override + public Collection getModules(@NotNull Project project) { + return Arrays.asList(ModuleManager.getInstance(project).getModules()); + } + + @NotNull + @Override + public Collection getOrderEntries(@NotNull Module module) { + return Arrays.asList(ModuleRootManager.getInstance(module).getOrderEntries()); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleStructureChangesCalculator.java index 778d4cc1fdbd..362e0cf18fb7 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleStructureChangesCalculator.java @@ -18,17 +18,60 @@ import java.util.Set; */ public interface GradleStructureChangesCalculator { - // TODO den add doc - @NotNull - Set calculate(@NotNull G gradleEntity, - @NotNull I intellijEntity, - @NotNull Set knownChanges); + /** + * Calculates changes between the given entities. + * + * @param gradleEntity target gradle entity + * @param intellijEntity target intellij entity + * @param knownChanges changes between the gradle and intellij project structure that has been known up until now + * @param currentChanges holder for the changes between the given entities discovered by the current call. Note that + * it must contain the change objects that have been known (contained at the 'knownChanges') + * but are still in place + */ + void calculate(@NotNull G gradleEntity, + @NotNull I intellijEntity, + @NotNull Set knownChanges, + @NotNull Set currentChanges); - // TODO den add doc + /** + * There are three possible situations when we compare a set of gradle entities with a set of intellij entities: + *

+   * 
    + *
  • particular entity presents only at the gradle side;
  • + *
  • particular entity presents only at the intellij side;
  • + *
  • particular gradle entity is matched to particular intellij entity (they may have difference in their settings though);
  • + *
+ *
+ *

+ * The general idea is to map evey item at the given sets of gradle and intellij entities to particular key (both gradle and + * intellij keys are expected to belong to the same class) and then compare them. Matched keys shows that corresponding + * entities should be {@link #calculate(GradleEntity, Object, Set) compared to each other}; non-matched indicate that corresponding + * entities are gradle- or intellij-local. + *

+ * This method allows to match intellij entity to the target key. + * + * @param entity intellij entity to match + * @return key for the given entity + * @see #getGradleKey(GradleEntity, Set) + */ @NotNull - Object getIntellijKey(@NotNull I entity, @NotNull Set knownChanges); - - // TODO den add doc + Object getIntellijKey(@NotNull I entity); + + /** + * Serves the same purpose as {@link #getIntellijKey(Object)} but targets gradle entities. + *

+ * There is a possible case that two corresponding gradle and intellij entities differ from each other by the setting that + * affects the resulting key (e.g. we may use module name as a key for 'module' entities and intellij module name differs from + * the name of the corresponding gradle module). We need to match only in one direction then (e.g. consider a situation when + * particular module is named differently at gradle and intellij. We shouldn't consider that change during both + * {@code intellij-entity -> key} and {@code gradle-entity -> key} mappings because that would produce two different keys). + * So, we take into consideration the known changes only during {@code gradle-entity -> key} processing. + * + * @param entity target gradle entity that should be mapped to a key + * @param knownChanges known changes between the gradle and intellij structures + * @return key for the given entity + * @see #getIntellijKey(Object) + */ @NotNull Object getGradleKey(@NotNull G entity, @NotNull Set knownChanges); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangeListener.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangeListener.java index fe167530b145..1a6065339169 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangeListener.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangeListener.java @@ -18,7 +18,9 @@ public interface GradleProjectStructureChangeListener { /** * Notifies current listener on the newly discovered changes between the gradle and intellij project models. * - * @param changes newly discovered changes between the gradle and intellij project models. + * @param oldChanges changes between the gradle and intellij project models that had been known prior to the current update + * @param currentChanges the most up-to-date changes between the gradle and intellij project models */ - void onChanges(@NotNull Collection changes); + void onChanges(@NotNull Collection oldChanges, + @NotNull Collection currentChanges); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java index 7825821034ee..f1ee0022e65d 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java @@ -2,15 +2,15 @@ package org.jetbrains.plugins.gradle.sync; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.project.Project; -import com.intellij.util.containers.ConcurrentHashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.diff.GradleProjectStructureChange; -import org.jetbrains.plugins.gradle.diff.GradleProjectStructureChangesCalculator; +import org.jetbrains.plugins.gradle.diff.GradleStructureChangesCalculator; import org.jetbrains.plugins.gradle.model.GradleProject; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicReference; /** * // TODO den add doc @@ -23,11 +23,14 @@ import java.util.concurrent.CopyOnWriteArraySet; public class GradleProjectStructureChangesModel extends AbstractProjectComponent { private final Set myListeners = new CopyOnWriteArraySet(); - private final Set myChanges = new ConcurrentHashSet(); + private final AtomicReference> myChanges + = new AtomicReference>(new HashSet()); - private final GradleProjectStructureChangesCalculator myChangesCalculator; + private final GradleStructureChangesCalculator myChangesCalculator; - public GradleProjectStructureChangesModel(@NotNull Project project, @NotNull GradleProjectStructureChangesCalculator changesCalculator) { + public GradleProjectStructureChangesModel(@NotNull Project project, + @NotNull GradleStructureChangesCalculator changesCalculator) + { super(project); myChangesCalculator = changesCalculator; } @@ -44,15 +47,22 @@ public class GradleProjectStructureChangesModel extends AbstractProjectComponent * *

  • {@link #addListener(GradleProjectStructureChangeListener) Registered listeners} are notified if any new change is detected;
  • * + *

    + * Note: it's very important that the listeners are notified after the actual state change, i.e. {@link #getChanges()} + * during the update returns up-to-date data. * * @param gradleProject gradle project to sync with */ public void update(@NotNull GradleProject gradleProject) { - Set knownChanges = new HashSet(myChanges); - final Set newChanges = myChangesCalculator.calculate(gradleProject, myProject, knownChanges); - myChanges.addAll(newChanges); + Set knownChanges = new HashSet(myChanges.get()); + Set currentChanges = new HashSet(); + myChangesCalculator.calculate(gradleProject, myProject, knownChanges, currentChanges); + if (currentChanges.equals(knownChanges)) { + return; + } + myChanges.set(currentChanges); for (GradleProjectStructureChangeListener listener : myListeners) { - listener.onChanges(newChanges); + listener.onChanges(knownChanges, currentChanges); } } @@ -72,6 +82,6 @@ public class GradleProjectStructureChangesModel extends AbstractProjectComponent */ @NotNull public Set getChanges() { - return myChanges; + return myChanges.get(); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java index 27fc80804c02..b2d0a5ce81eb 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java @@ -8,6 +8,7 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.roots.RootPolicy; import com.intellij.ui.treeStructure.Tree; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.hash.HashMap; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -25,6 +26,8 @@ import org.jetbrains.plugins.gradle.util.GradleConstants; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.MutableTreeNode; +import javax.swing.tree.TreeNode; import java.awt.*; import java.util.ArrayList; import java.util.Collection; @@ -51,6 +54,9 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { */ private final Map myModuleDependencies = new HashMap(); private final Map myModules = new HashMap(); + + private final TreeNode[] myNodeHolder = new TreeNode[1]; + private final int[] myIndexHolder = new int[1]; private final GradleProjectStructureChangesModel myChangesModel; @@ -62,11 +68,15 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { myChangesModel = model; myChangesModel.addListener(new GradleProjectStructureChangeListener() { @Override - public void onChanges(@NotNull final Collection changes) { + public void onChanges(@NotNull final Collection oldChanges, + @NotNull final Collection currentChanges) + { UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { - updateTree(changes); + updateTree(currentChanges); + processObsoleteChanges(ContainerUtil.subtract(oldChanges, currentChanges)); + } }); } @@ -84,6 +94,7 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { constraints.fill = GridBagConstraints.BOTH; constraints.weightx = constraints.weighty = 1; myContent.add(tree, constraints); + myContent.setBackground(tree.getBackground()); return treeModel; } @@ -237,4 +248,83 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { }); } } + + /** + * Updates the tree state considering that the given changes are obsolete. + *

    + * Example: + *

    +   * 
      + *
    1. There is a particular intellij-local library (change from the gradle project structure);
    2. + *
    3. Corresponding node is shown at the current UI;
    4. + *
    5. The library is removed, i.e. corresponding change has become obsolete;
    6. + *
    7. This method is notified within the obsolete change and is expected to remove the corresponding node;
    8. + *
    + *
    + */ + private void processObsoleteChanges(Collection changes) { + for (GradleProjectStructureChange change : changes) { + change.invite(new GradleProjectStructureChangeVisitor() { + @Override + public void visit(@NotNull GradleRenameChange change) { + // TODO den implement + } + + @Override + public void visit(@NotNull GradleProjectStructureChange change) { + // TODO den implement + } + + @Override + public void visit(@NotNull GradleModulePresenceChange change) { + // TODO den implement + } + + @Override + public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { + // We need to remove the corresponding node then. + String moduleName; + Object library; + final GradleLibraryDependency gradleEntity = change.getGradleEntity(); + final LibraryOrderEntry intellijEntity = change.getIntellijEntity(); + assert gradleEntity != null || intellijEntity != null; + if (gradleEntity == null) { + moduleName = intellijEntity.getOwnerModule().getName(); + library = intellijEntity; + } + else { + moduleName = gradleEntity.getOwnerModule().getName(); + library = gradleEntity; + } + final DefaultMutableTreeNode holder = myModuleDependencies.get(moduleName); + if (holder == null) { + return; + } + for (DefaultMutableTreeNode node = holder.getFirstLeaf(); node != null; node = node.getNextSibling()) { + GradleProjectStructureNodeDescriptor descriptor = (GradleProjectStructureNodeDescriptor)node.getUserObject(); + if (descriptor.getElement().equals(library)) { + removeNode(node); + return; + } + } + } + }); + } + } + + private void removeNode(@NotNull TreeNode node) { + final MutableTreeNode parent = (MutableTreeNode)node.getParent(); + if (parent == null) { + return; + } + int i = parent.getIndex(node); + if (i <= 0) { + assert false : node; + return; + } + parent.remove(i); + myIndexHolder[0] = i; + myNodeHolder[0] = node; + myTreeModel.nodesWereRemoved(parent, myIndexHolder, myNodeHolder); + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/task/GradleResolveProjectTask.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/task/GradleResolveProjectTask.java index a8d7bd868f8e..ff8f163eb147 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/task/GradleResolveProjectTask.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/task/GradleResolveProjectTask.java @@ -43,7 +43,12 @@ public class GradleResolveProjectTask extends AbstractGradleTask { return; } final GradleProjectStructureChangesModel model = myIntellijProject.getComponent(GradleProjectStructureChangesModel.class); - model.update(project); + if (model != null) { + // This task may be called during the 'import from gradle' processing, hence, no project-level IoC is up. + // Model update is necessary for the correct tool window project structure diff showing but we don't have + // gradle tool window on this stage. + model.update(project); + } } @Nullable diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy new file mode 100644 index 000000000000..abe61ee80f15 --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy @@ -0,0 +1,76 @@ +package org.jetbrains.plugins.gradle.sync; + + +import com.intellij.openapi.project.Project +import org.jetbrains.plugins.gradle.testutil.ChangeBuilder +import org.jetbrains.plugins.gradle.testutil.GradleProjectBuilder +import org.jetbrains.plugins.gradle.testutil.IntellijProjectBuilder +import org.junit.Before +import org.junit.Test +import org.picocontainer.defaults.DefaultPicoContainer +import org.jetbrains.plugins.gradle.diff.* +import static org.junit.Assert.assertEquals + +/** + * @author Denis Zhdanov + * @since 01/25/2012 + */ +public class GradleProjectStructureChangesModelTest { + + private GradleProjectStructureChangesModel myModel; + def gradle; + def intellij; + def changes; + + @Before + public void setUp() { + gradle = new GradleProjectBuilder() + intellij = new IntellijProjectBuilder() + changes = new ChangeBuilder() + def container = new DefaultPicoContainer() + container.registerComponentInstance(Project, intellij.project) + container.registerComponentInstance(GradleProjectStructureHelper, intellij.projectStructureHelper as GradleProjectStructureHelper) + container.registerComponentImplementation(GradleProjectStructureChangesModel) + container.registerComponentImplementation(GradleStructureChangesCalculator, GradleProjectStructureChangesCalculator) + container.registerComponentImplementation(GradleModuleStructureChangesCalculator) + container.registerComponentImplementation(GradleLibraryDependencyStructureChangesCalculator) + + myModel = container.getComponentInstance(GradleProjectStructureChangesModel.class) as GradleProjectStructureChangesModel + } + + @Test + public void mergeGradleLocalToIntellij() { + gradle { + module { + dependencies { + lib(name: "lib1") + lib(name: "lib2") + } } } + + intellij { + module { + dependencies { + lib(name: "lib1") + } } } + + myModel.update(gradle.project) + checkChanges { + presence { + lib(gradle: gradle.modules.dependencies.flatten().findAll { it.name == "lib2" }) + } + } + + gradle { + module { + dependencies { + lib(name: "lib1") + } } } + myModel.update(gradle.project) + assertEquals([].toSet(), myModel.changes) + } + + private def checkChanges(c) { + c.delegate = changes + assertEquals(c(), myModel.changes) + } +} diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy new file mode 100644 index 000000000000..6e4d1f3fd140 --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy @@ -0,0 +1,68 @@ +package org.jetbrains.plugins.gradle.testutil + +import com.intellij.pom.java.LanguageLevel; + +/** + * @author Denis Zhdanov + * @since 1/25/12 4:06 PM + */ +public abstract class AbstractProjectBuilder extends BuilderSupport { + + private static final def SAME_TOKEN = "same" + private static int COUNTER + + def project + def modules = [] + def libraries = [:].withDefault { createLibrary(it.name?: same, it.paths?: [:]) } + def dependencies = [:].withDefault {[]} + + @Override + protected void setParent(Object parent, Object child) { + } + + @Override + protected Object createNode(Object name) { + switch (name) { + case "call": return createNode("project", [name: same]) + case "module": return createNode(name, [name: same]) + case "dependencies": return getCurrent() // Assuming that 'current' is a module object + } + } + + @Override + protected Object createNode(Object name, Object value) { + return null + } + + @Override + protected Object createNode(Object name, Map attributes) { + switch (name) { + case "project": + reset() + return project = createProject(attributes.name?: same, attributes.langLevel?: LanguageLevel.JDK_1_6) + case "module": def module = createModule(attributes.name?: same); modules << module; return module + case "lib": + def module = getCurrent() + def dep = createLibraryDependency(module, libraries[attributes]) + dependencies[module] << dep + return dep + } + } + + @Override + protected Object createNode(Object name, Map attributes, Object value) { + return null + } + + protected abstract def createProject(String name, LanguageLevel languageLevel) + protected abstract def createModule(String name) + protected abstract def createLibrary(String name, Map paths) + protected abstract def createLibraryDependency(module, library) + + protected String getUnique() { "./${COUNTER++}" } + protected String getSame() { SAME_TOKEN } + + private def reset() { + [modules, dependencies, libraries]*.clear() + } +} diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy new file mode 100644 index 000000000000..700bcac3111a --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy @@ -0,0 +1,47 @@ +package org.jetbrains.plugins.gradle.testutil; + + +import org.jetbrains.plugins.gradle.diff.GradleLibraryDependencyPresenceChange + +/** + * @author Denis Zhdanov + * @since 1/26/12 3:25 PM + */ +public class ChangeBuilder extends BuilderSupport { + + def changes = [] + + @Override + protected void setParent(Object parent, Object child) { + } + + @Override + protected Object createNode(Object name) { + if (current == null) { + changes = [] + } + changes + } + + @Override + protected Object createNode(Object name, Object value) { changes } + + @Override + protected Object createNode(Object name, Map attributes) { + switch (name) { + case "presence": return changes + case "lib": + changes.addAll attributes.gradle.collect { new GradleLibraryDependencyPresenceChange(it, null)} + changes.addAll attributes.intellij.collect { new GradleLibraryDependencyPresenceChange(null, it)} + return + } + } + + @Override + protected Object createNode(Object name, Map attributes, Object value) { changes } + + @Override + protected Object postNodeCompletion(Object parent, Object node) { + parent == null ? changes.toSet() : node + } +} diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy new file mode 100644 index 000000000000..e889543406fa --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy @@ -0,0 +1,46 @@ +package org.jetbrains.plugins.gradle.testutil + +import org.jetbrains.plugins.gradle.model.GradleProject +import org.jetbrains.plugins.gradle.model.GradleModule +import org.jetbrains.plugins.gradle.model.GradleLibraryDependency +import org.jetbrains.plugins.gradle.model.GradleLibrary +import org.jetbrains.plugins.gradle.model.LibraryPathType +import com.intellij.pom.java.LanguageLevel + +/** + * @author Denis Zhdanov + * @since 1/25/12 1:29 PM + */ +class GradleProjectBuilder extends AbstractProjectBuilder { + + @Override + protected createProject(String name, LanguageLevel languageLevel) { + def result = new GradleProject(same, same) + result.name = name + result.languageLevel = languageLevel + result + } + + @Override + protected createModule(String name) { + def result = new GradleModule(name, unique) + project.addModule(result) + result + } + + @Override + protected createLibrary(String name, Map paths) { + def result = new GradleLibrary(name) + (paths.bin?: [same]).each { result.addPath(LibraryPathType.BINARY, it) } + (paths.src?: [same]).each { result.addPath(LibraryPathType.SOURCE, it) } + (paths.doc?: [same]).each { result.addPath(LibraryPathType.DOC, it) } + result + } + + @Override + protected createLibraryDependency(module, library) { + def result = new GradleLibraryDependency(module, library) + module.addDependency(result) + result + } +} diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy new file mode 100644 index 000000000000..92fad0749c64 --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy @@ -0,0 +1,49 @@ +package org.jetbrains.plugins.gradle.testutil + +import com.intellij.pom.java.LanguageLevel +import com.intellij.openapi.module.Module +import com.intellij.openapi.roots.RootPolicy +import com.intellij.openapi.roots.libraries.Library +import com.intellij.openapi.roots.LibraryOrderEntry +import groovy.mock.interceptor.StubFor +import com.intellij.openapi.project.Project + +/** + * @author Denis Zhdanov + * @since 1/25/12 3:09 PM + */ +class IntellijProjectBuilder extends AbstractProjectBuilder { + + def projectStub = [:] + def project = projectStub as Project + def projectStructureHelper = [ + getModules: { modules }, + getOrderEntries: { dependencies[it] } + ] + + @Override + protected createProject(String name, LanguageLevel languageLevel) { + projectStub.getName = { name } + projectStructureHelper.getLanguageLevel = { languageLevel } + project + } + + @Override + protected createModule(String name) { + [ getName: { name } ] as Module + } + + @Override + protected createLibrary(String name, Map paths) { + [ getName: { name } ] as Library + } + + @Override + protected createLibraryDependency(module, library) { + def stub = [:] + def result = stub as LibraryOrderEntry + stub.accept = { policy, defaultValue -> policy.visitLibraryOrderEntry(result, defaultValue) } + stub.getLibraryName = { library.name } + result + } +} From 66ea48257dfba93fc35692e83f9461dca566aa2d Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Mon, 30 Jan 2012 16:57:25 +0400 Subject: [PATCH 26/45] Upgraded to the jmock 2.5.1 --- lib/dev/jmock-legacy-2.5.1.jar | Bin 0 -> 18739 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/dev/jmock-legacy-2.5.1.jar diff --git a/lib/dev/jmock-legacy-2.5.1.jar b/lib/dev/jmock-legacy-2.5.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..c26cc0d25483e405569144c873ac9e18117bcfac GIT binary patch literal 18739 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 Date: Mon, 30 Jan 2012 17:03:15 +0400 Subject: [PATCH 27/45] IDEA-80255 Cosmetic fixes in GitBranchOperations messages. --- .../src/git4idea/branch/GitBranchOperation.java | 11 +++++++++-- .../branch/GitCheckoutNewBranchOperation.java | 2 +- .../src/git4idea/branch/GitCheckoutOperation.java | 8 ++++---- .../src/git4idea/branch/GitDeleteBranchOperation.java | 2 +- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java index 3a4177a529d2..1116915687cd 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java @@ -37,6 +37,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.concurrent.atomic.AtomicBoolean; +import static com.intellij.openapi.util.text.StringUtil.pluralize; + /** * Common class for Git operations with branches aware of multi-root configuration, * which means showing combined error information, proposing to rollback, etc. @@ -154,7 +156,7 @@ abstract class GitBranchOperation { UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { - String description = message + getRollbackProposal(); + String description = "" + message + ".
    " + getRollbackProposal() + ""; ok.set(Messages.OK == MessageManager.showYesNoDialog(myProject, description, title, "Rollback", "Don't rollback", Messages.getErrorIcon())); } @@ -190,11 +192,16 @@ abstract class GitBranchOperation { } } + @NotNull + protected String repositories() { + return pluralize("repository", getSuccessfulRepositories().size()); + } + private void showUnmergedFilesDialogWithRollback() { final AtomicBoolean ok = new AtomicBoolean(); UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { - String description = "You have to resolve all merge conflicts before checkout.
    " + getRollbackProposal(); + String description = "You have to resolve all merge conflicts before checkout.
    " + getRollbackProposal() + ""; // suppressing: this message looks ugly if capitalized by words //noinspection DialogTitleCapitalization ok.set(Messages.OK == MessageManager.showYesNoDialog(myProject, description, UNMERGED_FILES_ERROR_TITLE, "Rollback", "Don't rollback", Messages.getErrorIcon())); diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java index fb6b50305e38..28396fdde88c 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java @@ -93,7 +93,7 @@ public class GitCheckoutNewBranchOperation extends GitBranchOperation { @NotNull @Override protected String getRollbackProposal() { - return "However checkout has succeeded for the following repositories:
    " + + return "However checkout has succeeded for the following " + repositories() + ":
    " + successfulRepositoriesJoined() + "
    You may rollback (checkout back to " + myPreviousBranch + ") not to let branches diverge."; } diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java index 966e26487b5d..9be5f1e1f0e9 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java @@ -23,7 +23,6 @@ import com.intellij.openapi.ui.VerticalFlowLayout; import com.intellij.openapi.util.Clock; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangeListManager; @@ -55,6 +54,7 @@ import javax.swing.*; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; +import static com.intellij.openapi.util.text.StringUtil.*; import static git4idea.commands.GitMessageWithFilesDetector.Event.LOCAL_CHANGES_OVERWRITTEN_BY_CHECKOUT; import static git4idea.commands.GitMessageWithFilesDetector.Event.UNTRACKED_FILES_OVERWRITTEN_BY; import static git4idea.util.GitUIUtil.code; @@ -203,7 +203,7 @@ public class GitCheckoutOperation extends GitBranchOperation { String description = UntrackedFilesNotifier.createUntrackedFilesOverwrittenDescription("checkout", true); final SelectFilesDialog dialog = new UntrackedFilesDialog(myProject, new ArrayList(untrackedFiles), - StringUtil.stripHtml(description, true)); + stripHtml(description, true)); dialog.setTitle(title); UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override @@ -238,7 +238,7 @@ public class GitCheckoutOperation extends GitBranchOperation { @NotNull @Override protected String getRollbackProposal() { - return "However checkout has succeeded for the following repositories:
    " + + return "However checkout has succeeded for the following " + repositories() + ":
    " + successfulRepositoriesJoined() + "
    You may rollback (checkout back to " + myPreviousBranch + ") not to let branches diverge."; } @@ -376,7 +376,7 @@ public class GitCheckoutOperation extends GitBranchOperation { LOG.info("Couldn't save local changes", e); notifyError("Couldn't save uncommitted changes.", String.format("Tried to save uncommitted changes in %s before checkout, but failed with an error.
    %s", - saver.getSaverName(), StringUtil.join(e.getMessages()))); + saver.getSaverName(), join(e.getMessages()))); return false; } } diff --git a/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java index 6c22234e051f..dd75f9342d96 100644 --- a/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java @@ -137,7 +137,7 @@ class GitDeleteBranchOperation extends GitBranchOperation { @NotNull @Override protected String getRollbackProposal() { - return "However branch deletion has succeeded for the following repositories.:
    " + + return "However branch deletion has succeeded for the following " + repositories() + ":
    " + successfulRepositoriesJoined() + "
    You may rollback (recreate " + myBranchName + " in these roots) not to let branches diverge."; } From 73032621446f6d47467376b1318b167400b01f7d Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Mon, 30 Jan 2012 17:07:57 +0400 Subject: [PATCH 28/45] IDEA-53476: Gradle integration (Maven's level - dependencies, modules, repositories) New gradle icon is added --- plugins/gradle/resources/icons/gradle.png | Bin 529 -> 500 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/plugins/gradle/resources/icons/gradle.png b/plugins/gradle/resources/icons/gradle.png index b76b4ba5b8a8af9d9e526a708370b1c5d845e8bd..af8da119630b6f705720ff360e36dc2f7296d8b5 100644 GIT binary patch delta 437 zcmV;m0ZRUn1oQ)tNq?3}L_t(|+G70w|33pIfCWTsy?lhhZ%RJHKZseLKpYOl7CF+(=d{R^Cy7y0`yV=GWt6iu@n5IX^J5tI)$1ndH!0e@g;0}V;ocjGjJ&*XfD z@4tUybHQ~W)_}Ss3Fw0DEKmuMpW}fBNdOJ;I9xWD;q1ff3_KiM4C>!(Jby5&GD0o4OHzyeCMf(T=IO$L+J7?4xbpyIQpMOXG^Ep1-`WT!&CVgZi@XlVZc z;zA_nf;6kc*nerZL4A+jK4&;`=YsR2cP|(~7})@VfSHMjp*<)UL!1dIo;iTHA4zT& z5Z{F2SujChIPC@E|3G{L*##${&UFGxL;wSF1u%sBfc!pW+dy(q|HJgaU9b`wH6T!r z$0zkj32G&>3${a37%1d5K+XixkFX>pP#X9NRl6NM5H72rbRv>7@g`+#u>g`dOl)R? fCuK?iK!5=NucVT^Na@Qq00000NkvXXu0mjfOo6+o delta 466 zcmV;@0WJRY1Ca!fNq@6RL_t(|+G70w|33pd$P3jm22zbcY=k7-0K~H=t-gYyfdz|Z zRUoz5!%~6A(^8R_k?}vn#oKRwEZcdb>HE(=ASJVq)iW_*f*E#(GF4kAdMIQrPq_KKh&i2f%8;KcL>f{~!jmWjjdz|MwRxRy*VHb7H&zw*Bv4hylA# z+&ljl=%R;jeqwb2*nsf#I*IlbSO2?3v-H2n7$oJbgcF$*xf{Vm3@ ze*Ya5zaG2v3=u{UwYta#XbbXlf*Iexeqwmapa^uEB1`so1Ii2Xfz@gv8^FiIE65O? zUd2EHkV8oackkY1AQ5n*81U`$M+R~L+ Date: Mon, 30 Jan 2012 17:53:15 +0400 Subject: [PATCH 29/45] IDEA-80510 --- .../intellij/uiDesigner/wizard/BeanStep.form | 46 +++++++------------ .../intellij/uiDesigner/wizard/BeanStep.java | 5 ++ .../src/messages/UIDesignerBundle.properties | 2 +- 3 files changed, 23 insertions(+), 30 deletions(-) diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BeanStep.form b/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BeanStep.form index ba53947f26c6..e2167c3b53d4 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BeanStep.form +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BeanStep.form @@ -1,18 +1,16 @@ - + - - + - - + @@ -20,26 +18,24 @@ - - + + - - + - + - - + @@ -48,31 +44,27 @@ - - + - - + - - + - + - - + @@ -80,29 +72,25 @@ - - + - - + - - + - - + diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BeanStep.java b/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BeanStep.java index 22922f454dd7..9d093818b78d 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BeanStep.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BeanStep.java @@ -48,11 +48,16 @@ final class BeanStep extends StepAdapter{ private JRadioButton myRbBindToExistingBean; JTextField myTfShortClassName; private TextFieldWithBrowseButton myTfWithBtnChoosePackage; + private JLabel myPackageLabel; + private JLabel myExistClassLabel; private final WizardData myData; public BeanStep(@NotNull final WizardData data) { myData = data; + myPackageLabel.setLabelFor(myTfWithBtnChoosePackage.getTextField()); + myExistClassLabel.setLabelFor(myTfWitgBtnChooseClass.getTextField()); + final ItemListener itemListener = new ItemListener() { public void itemStateChanged(final ItemEvent e) { final boolean state = myRbBindToNewBean.isSelected(); diff --git a/plugins/ui-designer/src/messages/UIDesignerBundle.properties b/plugins/ui-designer/src/messages/UIDesignerBundle.properties index cd0ead7837a8..883a27e82812 100644 --- a/plugins/ui-designer/src/messages/UIDesignerBundle.properties +++ b/plugins/ui-designer/src/messages/UIDesignerBundle.properties @@ -179,7 +179,7 @@ error.cannot.create.field.reason=Cannot create field ''{0}''.\nReason: {1} tooltip.press.accelerator=Click or press {0} property.not.defined= editbox.class.2=C&lass: -radio.bind.to.existing.bean=Bind to &existing bean +radio.bind.to.existing.bean=Bind to existing &bean editbox.package=&Package: radio.create.new.bean=Cre&ate new bean column.form.field=Form Field From 7d508e1a710dd07082da2c5ada805e17ada86341 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 30 Jan 2012 13:33:23 +0400 Subject: [PATCH 30/45] IDEA-80508 [http://www.eclipse.org/eclipse/platform-core/runtime/runtime.html] --- .../conversion/EclipseClasspathReader.java | 65 +++++++++++++++++-- .../importWizard/EclipseImportBuilder.java | 5 +- 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java index b633502aefd5..db948129570d 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java @@ -31,6 +31,7 @@ import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -45,25 +46,29 @@ import org.jetbrains.idea.eclipse.config.EclipseModuleManager; import org.jetbrains.idea.eclipse.importWizard.EclipseProjectFinder; import org.jetbrains.idea.eclipse.util.ErrorLog; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; +import java.io.*; +import java.util.*; +import java.util.jar.Manifest; import java.util.regex.PatternSyntaxException; -import static org.jetbrains.idea.eclipse.conversion.EPathUtil.*; +import static org.jetbrains.idea.eclipse.conversion.EPathUtil.expandEclipsePath2Url; public class EclipseClasspathReader { private final String myRootPath; private final Project myProject; @Nullable private final List myCurrentRoots; private ContentEntry myContentEntry; + @Nullable private final Set myModuleNames; public EclipseClasspathReader(final String rootPath, final Project project, @Nullable List currentRoots) { + this(rootPath, project, currentRoots, null); + } + + public EclipseClasspathReader(final String rootPath, final Project project, @Nullable List currentRoots, @Nullable Set moduleNames) { myRootPath = FileUtil.toSystemIndependentName(rootPath); myProject = project; myCurrentRoots = currentRoots; + myModuleNames = moduleNames; } public void init(ModifiableRootModel model) { @@ -236,6 +241,7 @@ public class EclipseClasspathReader { } else if (kind.equals(EclipseXml.CON_KIND)) { if (path.equals(EclipseXml.ECLIPSE_PLATFORM)) { + readRequiredBundles(rootModel, refsToModules); addNamedLibrary(rootModel, unknownLibraries, exported, IdeaXml.ECLIPSE_LIBRARY, LibraryTablesRegistrar.APPLICATION_LEVEL); } else if (path.startsWith(EclipseXml.JRE_CONTAINER)) { @@ -276,6 +282,53 @@ public class EclipseClasspathReader { } } + private void readRequiredBundles(ModifiableRootModel rootModel, Set refsToModules) throws ConversionException { + if (myModuleNames == null) { + return; + } + + final File manifestFile = new File(myRootPath, "META-INF/MANIFEST.MF"); + if (!manifestFile.exists()) { + return; + } + + InputStream in = null; + try { + in = new BufferedInputStream(new FileInputStream(manifestFile)); + final Manifest manifest = new Manifest(in); + final String attributes = manifest.getMainAttributes().getValue("Require-Bundle"); + if (!StringUtil.isEmpty(attributes)) { + final StringTokenizer tokenizer = new StringTokenizer(attributes, ","); + while (tokenizer.hasMoreTokens()) { + String bundle = tokenizer.nextToken().trim(); + if (!bundle.isEmpty()) { + final int constraintIndex = bundle.indexOf(';'); + if (constraintIndex != -1) { + bundle = bundle.substring(0, constraintIndex).trim(); + } + + if (myModuleNames.contains(bundle)) { + refsToModules.add(bundle); + rootModel.addInvalidModuleEntry(bundle); + } + } + } + } + } + catch (IOException e) { + throw new ConversionException(e.getMessage()); + } + finally { + if (in != null) { + try { + in.close(); + } + catch (IOException ignored) { + } + } + } + } + private static int rearrangeOrderEntryOfType(ModifiableRootModel rootModel, Class orderEntryClass) { OrderEntry[] orderEntries = rootModel.getOrderEntries(); int moduleSourcesIdx = 0; diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/importWizard/EclipseImportBuilder.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importWizard/EclipseImportBuilder.java index aff404771e3f..b5e1beb045d6 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/importWizard/EclipseImportBuilder.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importWizard/EclipseImportBuilder.java @@ -50,6 +50,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.packaging.artifacts.ModifiableArtifactModel; import com.intellij.projectImport.ProjectImportBuilder; import com.intellij.util.Function; +import gnu.trove.THashSet; import org.jdom.Element; import org.jdom.JDOMException; import org.jetbrains.annotations.NotNull; @@ -198,12 +199,14 @@ public class EclipseImportBuilder extends ProjectImportBuilder implement final ModifiableModuleModel moduleModel = model != null ? model : ModuleManager.getInstance(project).getModifiableModel(); final ModifiableRootModel[] rootModels = new ModifiableRootModel[getParameters().projectsToConvert.size()]; final Set files = new HashSet(); + final Set moduleNames = new THashSet(getParameters().projectsToConvert.size()); for (String path : getParameters().projectsToConvert) { String modulesDirectory = getParameters().converterOptions.commonModulesDirectory; if (modulesDirectory == null) { modulesDirectory = path; } final String moduleName = EclipseProjectFinder.findProjectName(path); + moduleNames.add(moduleName); final File imlFile = new File(modulesDirectory + File.separator + moduleName + IdeaXml.IML_EXT); if (imlFile.isFile()) { files.add(imlFile); @@ -266,7 +269,7 @@ public class EclipseImportBuilder extends ProjectImportBuilder implement rootModels[idx++] = rootModel; final File classpathFile = new File(path, EclipseXml.DOT_CLASSPATH_EXT); - final EclipseClasspathReader classpathReader = new EclipseClasspathReader(path, project, getParameters().projectsToConvert); + final EclipseClasspathReader classpathReader = new EclipseClasspathReader(path, project, getParameters().projectsToConvert, moduleNames); classpathReader.init(rootModel); if (classpathFile.exists()) { final Element classpathElement = JDOMUtil.loadDocument(classpathFile).getRootElement(); From b6c9bd0b0bd11c44f326527599baabb107948ac8 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 30 Jan 2012 14:10:46 +0400 Subject: [PATCH 31/45] IDEA-79533 "Pull members up" should be smarter about the default destination --- .../memberPullUp/PullUpDialog.java | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpDialog.java b/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpDialog.java index abc477fed6fe..5d06e931eab2 100644 --- a/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpDialog.java @@ -17,7 +17,10 @@ package com.intellij.refactoring.memberPullUp; import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; +import com.intellij.psi.statistics.StatisticsInfo; +import com.intellij.psi.statistics.StatisticsManager; import com.intellij.refactoring.HelpID; import com.intellij.refactoring.JavaRefactoringSettings; import com.intellij.refactoring.RefactoringBundle; @@ -57,6 +60,7 @@ public class PullUpDialog extends RefactoringDialog { private List myMemberInfos; private DocCommentPanel myJavaDocPanel; private JComboBox myClassCombo; + private static final String PULL_UP_STATISTICS_KEY = "pull.up##"; public interface Callback { boolean checkConflicts(PullUpDialog dialog); @@ -127,11 +131,10 @@ public class PullUpDialog extends RefactoringDialog { myClassCombo.setRenderer(new ClassCellRenderer(myClassCombo.getRenderer())); classComboLabel.setText(RefactoringBundle.message("pull.up.members.to", UsageViewUtil.getLongName(myClass))); classComboLabel.setLabelFor(myClassCombo); - - PsiClass nearestBase = RefactoringHierarchyUtil.getNearestBaseClass(myClass, false); + final PsiClass preselection = getPreselection(); int indexToSelect = 0; - if (nearestBase != null) { - indexToSelect = mySuperClasses.indexOf(nearestBase); + if (preselection != null) { + indexToSelect = mySuperClasses.indexOf(preselection); } myClassCombo.setSelectedIndex(indexToSelect); myClassCombo.addItemListener(new ItemListener() { @@ -152,6 +155,27 @@ public class PullUpDialog extends RefactoringDialog { return panel; } + private PsiClass getPreselection() { + PsiClass preselection = RefactoringHierarchyUtil.getNearestBaseClass(myClass, false); + + final String statKey = PULL_UP_STATISTICS_KEY + myClass.getQualifiedName(); + for (StatisticsInfo info : StatisticsManager.getInstance().getAllValues(statKey)) { + final String superClassName = info.getValue(); + PsiClass superClass = null; + for (PsiClass aClass : mySuperClasses) { + if (Comparing.strEqual(superClassName, aClass.getQualifiedName())) { + superClass = aClass; + break; + } + } + if (superClass != null && StatisticsManager.getInstance().getUseCount(info) > 0) { + preselection = superClass; + break; + } + } + return preselection; + } + protected void doHelpAction() { HelpManager.getInstance().invokeHelp(HelpID.MEMBERS_PULL_UP); } @@ -168,7 +192,9 @@ public class PullUpDialog extends RefactoringDialog { protected void doAction() { if (!myCallback.checkConflicts(this)) return; JavaRefactoringSettings.getInstance().PULL_UP_MEMBERS_JAVADOC = myJavaDocPanel.getPolicy(); - + StatisticsManager + .getInstance().incUseCount(new StatisticsInfo(PULL_UP_STATISTICS_KEY + myClass.getQualifiedName(), getSuperClass().getQualifiedName())); + invokeRefactoring(new PullUpHelper(myClass, getSuperClass(), getSelectedMemberInfos(), new DocCommentPolicy(getJavaDocPolicy()))); close(OK_EXIT_CODE); From 6028286aeae096e9436b7a24498cd35c3e1f15bb Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 30 Jan 2012 15:37:29 +0400 Subject: [PATCH 32/45] execution: extract check for alternative jre; check for working directory (IDEA-77754) --- .../application/ApplicationConfiguration.java | 12 ++------ .../execution/util/JavaParametersUtil.java | 13 ++++++++ .../execution/util/ProgramParametersUtil.java | 30 ++++++++++++++----- .../execution/junit/TestDirectory.java | 19 +++++------- .../intellij/execution/junit/TestObject.java | 12 ++------ .../configuration/TestNGConfiguration.java | 4 +++ 6 files changed, 53 insertions(+), 37 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java index 1f9444abfad1..69d02d778256 100644 --- a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java +++ b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java @@ -24,6 +24,7 @@ import com.intellij.execution.junit.RefactoringListeners; import com.intellij.execution.process.OSProcessHandler; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.util.JavaParametersUtil; +import com.intellij.execution.util.ProgramParametersUtil; import com.intellij.openapi.components.PathMacroManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; @@ -31,7 +32,6 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.options.SettingsEditorGroup; import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; @@ -138,19 +138,13 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration expanded = new HashMap(); + for (Map.Entry each : parameters.getEnv().entrySet()) { + expanded.put(each.getKey(), expandPath(each.getValue(), module, project)); + } + parameters.setEnv(expanded); + } + } + + public static String getWorkingDir(CommonProgramRunConfigurationParameters configuration, Project project, Module module) { String workingDirectory = configuration.getWorkingDirectory(); VirtualFile baseDir = project.getBaseDir(); @@ -46,15 +61,14 @@ public class ProgramParametersUtil { if (!FileUtil.isAbsolute(workingDirectory) && baseDir != null) { workingDirectory = baseDir.getPath() + "/" + workingDirectory; } - parameters.setWorkingDirectory(workingDirectory); + return workingDirectory; + } - parameters.setupEnvs(configuration.getEnvs(), configuration.isPassParentEnvs()); - if (parameters.getEnv() != null) { - Map expanded = new HashMap(); - for (Map.Entry each : parameters.getEnv().entrySet()) { - expanded.put(each.getKey(), expandPath(each.getValue(), module, project)); - } - parameters.setEnv(expanded); + public static void checkWorkingDirectoryExist(CommonProgramRunConfigurationParameters configuration, Project project, Module module) + throws RuntimeConfigurationWarning { + final String workingDir = getWorkingDir(configuration, project, module); + if (!new File(workingDir).exists()) { + throw new RuntimeConfigurationWarning("Working directory '" + workingDir + "' doesn't exist"); } } diff --git a/plugins/junit/src/com/intellij/execution/junit/TestDirectory.java b/plugins/junit/src/com/intellij/execution/junit/TestDirectory.java index a6d4607f9cc1..057ab85becf0 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestDirectory.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestDirectory.java @@ -16,16 +16,19 @@ package com.intellij.execution.junit; import com.intellij.execution.CantRunException; -import com.intellij.execution.ExecutionBundle; import com.intellij.execution.configurations.*; import com.intellij.execution.testframework.SourceScope; +import com.intellij.execution.util.JavaParametersUtil; +import com.intellij.execution.util.ProgramParametersUtil; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.JavaSdk; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; +import com.intellij.psi.JavaDirectoryService; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiManager; +import com.intellij.psi.PsiPackage; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScopes; @@ -80,14 +83,8 @@ class TestDirectory extends TestPackage { @Override public void checkConfiguration() throws RuntimeConfigurationException { - if (myConfiguration.isAlternativeJrePathEnabled()) { - if (myConfiguration.getAlternativeJrePath() == null || - myConfiguration.getAlternativeJrePath().length() == 0 || - !JavaSdk.checkForJre(myConfiguration.getAlternativeJrePath())) { - throw new RuntimeConfigurationWarning( - ExecutionBundle.message("jre.path.is.not.valid.jre.home.error.mesage", myConfiguration.getAlternativeJrePath())); - } - } + JavaParametersUtil.checkAlternativeJRE(myConfiguration); + ProgramParametersUtil.checkWorkingDirectoryExist(myConfiguration, myConfiguration.getProject(), myConfiguration.getConfigurationModule().getModule()); final String dirName = myConfiguration.getPersistentData().getDirName(); if (dirName == null || dirName.isEmpty()) { throw new RuntimeConfigurationError("Directory is not specified"); diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index 7c063b643958..b3a288099cb6 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -36,13 +36,13 @@ import com.intellij.execution.runners.ProgramRunner; import com.intellij.execution.testframework.*; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.execution.util.JavaParametersUtil; +import com.intellij.execution.util.ProgramParametersUtil; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.JavaSdk; import com.intellij.openapi.projectRoots.JavaSdkType; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.ex.JavaSdkUtil; @@ -179,14 +179,8 @@ public abstract class TestObject implements JavaCommandLine { }; public void checkConfiguration() throws RuntimeConfigurationException{ - if (myConfiguration.isAlternativeJrePathEnabled()){ - if (myConfiguration.getAlternativeJrePath() == null || - myConfiguration.getAlternativeJrePath().length() == 0 || - !JavaSdk.checkForJre(myConfiguration.getAlternativeJrePath())){ - throw new RuntimeConfigurationWarning( - ExecutionBundle.message("jre.path.is.not.valid.jre.home.error.mesage", myConfiguration.getAlternativeJrePath())); - } - } + JavaParametersUtil.checkAlternativeJRE(myConfiguration); + ProgramParametersUtil.checkWorkingDirectoryExist(myConfiguration, myConfiguration.getProject(), myConfiguration.getConfigurationModule().getModule()); } public SourceScope getSourceScope() { diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfiguration.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfiguration.java index 9021ecea90b2..52bc39ee1adf 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfiguration.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfiguration.java @@ -29,6 +29,8 @@ import com.intellij.execution.configurations.*; import com.intellij.execution.junit.RefactoringListeners; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.testframework.SourceScope; +import com.intellij.execution.util.JavaParametersUtil; +import com.intellij.execution.util.ProgramParametersUtil; import com.intellij.openapi.components.PathMacroManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.options.SettingsEditor; @@ -338,6 +340,8 @@ public class TestNGConfiguration extends ModuleBasedConfiguration Date: Mon, 30 Jan 2012 16:07:26 +0400 Subject: [PATCH 33/45] testng: detect tests in "factory" classes (IDEA-78053) --- .../testng/src/com/theoryinpractice/testng/util/TestNGUtil.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java b/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java index 6e5d96ffc4bf..baf52860e7c7 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java +++ b/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java @@ -93,6 +93,7 @@ public class TestNGUtil } public static final String TEST_ANNOTATION_FQN = Test.class.getName(); + public static final String FACTORY_ANNOTATION_FQN = Factory.class.getName(); public static final String[] CONFIG_ANNOTATIONS_FQN = { Configuration.class.getName(), Factory.class.getName(), @@ -199,6 +200,7 @@ public class TestNGUtil PsiClass psiClass = (PsiClass) element; for (PsiMethod method : psiClass.getAllMethods()) { if (AnnotationUtil.isAnnotated(method, TEST_ANNOTATION_FQN, false, true)) return true; + if (AnnotationUtil.isAnnotated(method, FACTORY_ANNOTATION_FQN, false, true)) return true; if (hasTestJavaDoc(method, checkJavadoc)) return true; } } else if (element instanceof PsiMethod) { From a059eb824778e648add11338659809b168240111 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 30 Jan 2012 16:08:10 +0400 Subject: [PATCH 34/45] testng: distinguish methods processed by factory --- .../src/com/theoryinpractice/testng/ui/TestNGResults.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGResults.java b/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGResults.java index c75ec170d5bf..08e7421d877c 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGResults.java +++ b/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGResults.java @@ -211,7 +211,7 @@ public class TestNGResults extends TestResultsPanel implements TestFrameworkRunn dups.add(proxy); } } - final String testMethodDescriptor = result.getTestClass() + result.getMethod(); + final String testMethodDescriptor = TestProxy.toDisplayText(result, project); if (startedMethods.contains(testMethodDescriptor)) { total++; } From 78372a5c82423e40875027b72d3be5ae99d592e0 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 30 Jan 2012 18:24:54 +0400 Subject: [PATCH 35/45] IDEA-76794 Add "force checkout" option to the smart checkout dialog. --- .../branch/GitCheckoutNewBranchOperation.java | 2 +- .../git4idea/branch/GitCheckoutOperation.java | 23 ++++++++------ ...GitWouldBeOverwrittenByCheckoutDialog.java | 31 ++++++++++++++----- .../git4idea/src/git4idea/commands/Git.java | 7 ++++- 4 files changed, 44 insertions(+), 19 deletions(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java index 28396fdde88c..f7bfa21ecd7c 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java @@ -104,7 +104,7 @@ public class GitCheckoutNewBranchOperation extends GitBranchOperation { GitCompoundResult deleteResult = new GitCompoundResult(myProject); Collection repositories = getSuccessfulRepositories(); for (GitRepository repository : repositories) { - GitCommandResult result = Git.checkout(repository, myPreviousBranch, null); + GitCommandResult result = Git.checkout(repository, myPreviousBranch, null, true); checkoutResult.append(repository, result); if (result.success()) { deleteResult.append(repository, Git.branchDelete(repository, myNewBranchName, false)); diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java index 9be5f1e1f0e9..06f93d1c9233 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java @@ -96,7 +96,7 @@ public class GitCheckoutOperation extends GitBranchOperation { GitSimpleEventDetector unmergedFiles = new GitSimpleEventDetector(GitSimpleEventDetector.Event.UNMERGED); GitMessageWithFilesDetector untrackedOverwrittenByCheckout = new GitMessageWithFilesDetector(UNTRACKED_FILES_OVERWRITTEN_BY, root); - GitCommandResult result = Git.checkout(repository, myStartPointReference, myNewBranch, + GitCommandResult result = Git.checkout(repository, myStartPointReference, myNewBranch, false, localChangesOverwrittenByCheckout, unmergedFiles, untrackedOverwrittenByCheckout); if (result.success()) { refresh(repository); @@ -134,13 +134,14 @@ public class GitCheckoutOperation extends GitBranchOperation { // get all other conflicting changes Map> conflictingChangesInRepositories = collectLocalChangesOnAllOtherRepositories(repository); Set otherProblematicRepositories = conflictingChangesInRepositories.keySet(); - Collection allConflictingRepositories = new ArrayList(otherProblematicRepositories); + List allConflictingRepositories = new ArrayList(otherProblematicRepositories); allConflictingRepositories.add(repository); for (List changes : conflictingChangesInRepositories.values()) { affectedChanges.addAll(changes); } - if (GitWouldBeOverwrittenByCheckoutDialog.showAndGetAnswer(myProject, affectedChanges)) { + int smartCheckoutDecision = GitWouldBeOverwrittenByCheckoutDialog.showAndGetAnswer(myProject, affectedChanges); + if (smartCheckoutDecision == GitWouldBeOverwrittenByCheckoutDialog.SMART_CHECKOUT) { boolean smartCheckedOutSuccessfully = smartCheckout(allConflictingRepositories, myStartPointReference, myNewBranch, getIndicator()); if (smartCheckedOutSuccessfully) { GitRepository[] otherRepositories = ArrayUtil.toObjectArray(otherProblematicRepositories, GitRepository.class); @@ -156,6 +157,9 @@ public class GitCheckoutOperation extends GitBranchOperation { return false; } } + else if (smartCheckoutDecision == GitWouldBeOverwrittenByCheckoutDialog.FORCE_CHECKOUT_EXIT_CODE) { + return checkoutOrNotify(allConflictingRepositories, myStartPointReference, myNewBranch, true); + } else { fatalLocalChangesError(); return false; @@ -248,7 +252,7 @@ public class GitCheckoutOperation extends GitBranchOperation { GitCompoundResult checkoutResult = new GitCompoundResult(myProject); GitCompoundResult deleteResult = new GitCompoundResult(myProject); for (GitRepository repository : getSuccessfulRepositories()) { - GitCommandResult result = Git.checkout(repository, myPreviousBranch, null); + GitCommandResult result = Git.checkout(repository, myPreviousBranch, null, true); checkoutResult.append(repository, result); if (result.success() && myNewBranch != null) { /* @@ -310,7 +314,7 @@ public class GitCheckoutOperation extends GitBranchOperation { } // stash - checkout - unstash - private boolean smartCheckout(@NotNull final Collection repositories, @NotNull final String reference, @Nullable final String newBranch, @NotNull ProgressIndicator indicator) { + private boolean smartCheckout(@NotNull final List repositories, @NotNull final String reference, @Nullable final String newBranch, @NotNull ProgressIndicator indicator) { final GitChangesSaver saver = configureSaver(reference, indicator); final AtomicBoolean result = new AtomicBoolean(); @@ -319,7 +323,7 @@ public class GitCheckoutOperation extends GitBranchOperation { boolean savedSuccessfully = save(repositories, saver); if (savedSuccessfully) { try { - result.set(checkoutOrNotify(repositories, reference, newBranch)); + result.set(checkoutOrNotify(repositories, reference, newBranch, false)); } finally { saver.restoreLocalChanges(context); } @@ -384,12 +388,11 @@ public class GitCheckoutOperation extends GitBranchOperation { /** * Checks out or shows an error message. */ - private boolean checkoutOrNotify(@NotNull Collection repositories, - @NotNull String reference, - @Nullable String newBranch) { + private boolean checkoutOrNotify(@NotNull List repositories, + @NotNull String reference, @Nullable String newBranch, boolean force) { GitCompoundResult compoundResult = new GitCompoundResult(myProject); for (GitRepository repository : repositories) { - compoundResult.append(repository, Git.checkout(repository, reference, newBranch)); + compoundResult.append(repository, Git.checkout(repository, reference, newBranch, force)); } if (compoundResult.totalSuccess()) { return true; diff --git a/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java b/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java index f281e4a1f718..ad60e17fcc44 100644 --- a/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java +++ b/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java @@ -26,8 +26,9 @@ import git4idea.DialogManager; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import java.awt.event.ActionEvent; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; /** * The dialog that is shown when the error "The following files would be overwritten by checkout" happens. @@ -38,23 +39,26 @@ import java.util.concurrent.atomic.AtomicBoolean; // TODO "don't ask again" option class GitWouldBeOverwrittenByCheckoutDialog extends DialogWrapper { + public static final int SMART_CHECKOUT = OK_EXIT_CODE; + public static final int FORCE_CHECKOUT_EXIT_CODE = NEXT_USER_EXIT_CODE; + private final Project myProject; private final List myChanges; /** * @return true if smart checkout has to be performed, false if user doesn't want to checkout. */ - static boolean showAndGetAnswer(@NotNull final Project project, @NotNull final List changes) { - final AtomicBoolean ok = new AtomicBoolean(); + static int showAndGetAnswer(@NotNull final Project project, @NotNull final List changes) { + final AtomicInteger exitCode = new AtomicInteger(); UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { GitWouldBeOverwrittenByCheckoutDialog dialog = new GitWouldBeOverwrittenByCheckoutDialog(project, changes); DialogManager.getInstance(project).showDialog(dialog); - ok.set(dialog.isOK()); + exitCode.set(dialog.getExitCode()); } }); - return ok.get(); + return exitCode.get(); } private GitWouldBeOverwrittenByCheckoutDialog(@NotNull Project project, @NotNull List changes) { @@ -68,8 +72,8 @@ class GitWouldBeOverwrittenByCheckoutDialog extends DialogWrapper { } @Override - protected Action getOKAction() { - return super.getOKAction(); + protected Action[] createLeftSideActions() { + return new Action[] {new ForceCheckoutAction() }; } @Override @@ -93,4 +97,17 @@ class GitWouldBeOverwrittenByCheckoutDialog extends DialogWrapper { return GitWouldBeOverwrittenByCheckoutDialog.class.getName(); } + + private class ForceCheckoutAction extends AbstractAction { + + ForceCheckoutAction() { + super("Force checkout"); + } + + @Override + public void actionPerformed(ActionEvent e) { + close(FORCE_CHECKOUT_EXIT_CODE); + } + } + } diff --git a/plugins/git4idea/src/git4idea/commands/Git.java b/plugins/git4idea/src/git4idea/commands/Git.java index 8f47061ad11c..ebe5b02a9f0e 100644 --- a/plugins/git4idea/src/git4idea/commands/Git.java +++ b/plugins/git4idea/src/git4idea/commands/Git.java @@ -138,12 +138,17 @@ public class Git { public static GitCommandResult checkout(@NotNull GitRepository repository, @NotNull String reference, @Nullable String newBranch, + boolean force, @NotNull GitLineHandlerListener... listeners) { final GitLineHandler h = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.CHECKOUT); h.setSilent(false); + if (force) { + h.addParameters("--force"); + } if (newBranch == null) { // simply checkout h.addParameters(reference); - } else { // checkout reference as new branch + } + else { // checkout reference as new branch h.addParameters("-b", newBranch, reference); } for (GitLineHandlerListener listener : listeners) { From d7c09d6ee2a02c5f5dd25510a5fa4441c08e73f6 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 30 Jan 2012 18:34:50 +0400 Subject: [PATCH 36/45] fix compilation --- .idea/libraries/Mocks.xml | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/.idea/libraries/Mocks.xml b/.idea/libraries/Mocks.xml index 5a52b9d16391..ba510628d742 100644 --- a/.idea/libraries/Mocks.xml +++ b/.idea/libraries/Mocks.xml @@ -5,14 +5,21 @@ - - - - - + + + + + + - - + + + + + + + + \ No newline at end of file From d5bb7b623b7c6148986384285e8b96fef096ed43 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 30 Jan 2012 16:46:23 +0400 Subject: [PATCH 37/45] Typo --- .../com/intellij/openapi/vfs/local/SymLinkHandlingTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymLinkHandlingTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymLinkHandlingTest.java index 38c562f69237..461375ebbd1f 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymLinkHandlingTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymLinkHandlingTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -57,7 +57,7 @@ public class SymLinkHandlingTest extends LightPlatformLangTestCase { assertNull(selfLinkVFile); } - public void testTargetIsWriteable() throws Exception { + public void testTargetIsWritable() throws Exception { if (!SystemInfo.areSymLinksSupported) return; final File targetFile = FileUtil.createTempFile("target", ""); From 784a25bdc32194ae845fb7a81855002cea7035d5 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 30 Jan 2012 17:29:02 +0400 Subject: [PATCH 38/45] More logging --- .../intellij/openapi/vfs/newvfs/persistent/FSRecords.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java index f8c6d21f2ce5..98d69abbf08c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -1040,9 +1040,9 @@ public class FSRecords implements Forceable { } private static void checkFileIsValid(int fileId) { - assert fileId > 0 : "assert fileId > 0 failed"; + assert fileId > 0 : fileId; // TODO: This assertion is a bit timey, will remove when bug is caught. - assert (getFlags(fileId) & FREE_RECORD_FLAG) == 0 : "Trying to find an attribute of deleted page"; + assert (getFlags(fileId) & FREE_RECORD_FLAG) == 0 : "Accessing attribute of a deleted page: " + fileId + ":" + getName(fileId); } public static int acquireFileContent(int fileId) { From 48b5a0e7eebb6817145bd1549987be877f19e677 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 30 Jan 2012 18:35:59 +0400 Subject: [PATCH 39/45] Font moved to a right place --- .../platform-resources}/src/fonts/Inconsolata.ttf | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename {resources => platform/platform-resources}/src/fonts/Inconsolata.ttf (100%) diff --git a/resources/src/fonts/Inconsolata.ttf b/platform/platform-resources/src/fonts/Inconsolata.ttf similarity index 100% rename from resources/src/fonts/Inconsolata.ttf rename to platform/platform-resources/src/fonts/Inconsolata.ttf From 82f1c26a00baaecf5e795583c8500060283f3184 Mon Sep 17 00:00:00 2001 From: "kirill.safonov" Date: Thu, 12 Jan 2012 16:27:17 +0400 Subject: [PATCH 40/45] SDK combobox - better API for 'New' and 'Edit' buttons --- .../roots/ui/configuration/JdkComboBox.java | 37 ++++++++----------- .../configuration/ModuleJdkConfigurable.java | 18 ++++++--- .../configuration/ProjectJdkConfigurable.java | 10 ++++- .../src/messages/ApplicationBundle.properties | 2 +- .../src/messages/ProjectBundle.properties | 2 +- 5 files changed, 37 insertions(+), 32 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java index e70b585dac5b..d06839e6df6c 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java @@ -18,7 +18,6 @@ package com.intellij.openapi.roots.ui.configuration; import com.intellij.ide.DataManager; import com.intellij.ide.util.projectWizard.ProjectJdkListRenderer; import com.intellij.openapi.actionSystem.DefaultActionGroup; -import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.Sdk; @@ -48,7 +47,6 @@ import java.util.Comparator; * @since May 18, 2005 */ class JdkComboBox extends ComboBoxWithWidePopup { - private final JButton myEditButton = new JButton(ApplicationBundle.message("button.edit")); public JdkComboBox(@NotNull final ProjectSdksModel jdkModel) { super(new JdkComboBoxModel(jdkModel)); @@ -101,17 +99,12 @@ class JdkComboBox extends ComboBoxWithWidePopup { return minSize; } - public JButton createSetupButton(final Project project, final ProjectSdksModel jdksModel, final JdkComboBoxItem firstItem) { - return createSetupButton(project, jdksModel, firstItem, null, false); - } - - - public JButton createSetupButton(final Project project, - final ProjectSdksModel jdksModel, - final JdkComboBoxItem firstItem, - @Nullable final Condition additionalSetup, - final boolean moduleJdkSetup) { - final JButton setUpButton = new JButton(ApplicationBundle.message("button.new")); + public void setSetupButton(final JButton setUpButton, + final Project project, + final ProjectSdksModel jdksModel, + final JdkComboBoxItem firstItem, + @Nullable final Condition additionalSetup, + final boolean moduleJdkSetup) { setUpButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { final JdkListConfigurable configurable = JdkListConfigurable.getInstance(project); @@ -130,15 +123,15 @@ class JdkComboBox extends ComboBoxWithWidePopup { }); JBPopupFactory.getInstance() .createActionGroupPopup(ProjectBundle.message("project.roots.set.up.jdk.title", moduleJdkSetup ? 1 : 2), group, - DataManager.getInstance().getDataContext(JdkComboBox.this), JBPopupFactory.ActionSelectionAid.MNEMONICS, false) + DataManager.getInstance().getDataContext(JdkComboBox.this), JBPopupFactory.ActionSelectionAid.MNEMONICS, + false) .showUnderneathOf(setUpButton); } }); - return setUpButton; } - public void appendEditButton(final Project project, final JPanel panel, GridBagConstraints gc, final Computable retrieveJDK){ - myEditButton.addActionListener(new ActionListener() { + public void setEditButton(final JButton editButton, final Project project, final Computable retrieveJDK){ + editButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { final Sdk projectJdk = retrieveJDK.compute(); if (projectJdk != null) { @@ -146,17 +139,17 @@ class JdkComboBox extends ComboBoxWithWidePopup { } } }); - addActionListener(new ActionListener(){ + addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { final JdkComboBoxItem selectedItem = getSelectedItem(); if (selectedItem instanceof ProjectJdkComboBoxItem) { - myEditButton.setEnabled(ProjectStructureConfigurable.getInstance(project).getProjectJdksModel().getProjectSdk() != null); - } else { - myEditButton.setEnabled(!(selectedItem instanceof InvalidJdkComboBoxItem) && selectedItem != null && selectedItem.getJdk() != null); + editButton.setEnabled(ProjectStructureConfigurable.getInstance(project).getProjectJdksModel().getProjectSdk() != null); + } + else { + editButton.setEnabled(!(selectedItem instanceof InvalidJdkComboBoxItem) && selectedItem != null && selectedItem.getJdk() != null); } } }); - panel.add(myEditButton, gc); } public JdkComboBoxItem getSelectedItem() { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java index 718f923efcea..3dd421d20568 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java @@ -17,6 +17,7 @@ package com.intellij.openapi.roots.ui.configuration; import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; @@ -119,17 +120,18 @@ public abstract class ModuleJdkConfigurable implements Disposable { GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(6, 6, 12, 0), 0, 0)); final Project project = getRootModel().getModule().getProject(); - final JButton setUpButton = myCbModuleJdk - .createSetupButton(project, myJdksModel, new JdkComboBox.ProjectJdkComboBoxItem(), new Condition(){ + final JButton setUpButton = new JButton(ApplicationBundle.message("button.new")); + myCbModuleJdk + .setSetupButton(setUpButton, project, myJdksModel, new JdkComboBox.ProjectJdkComboBoxItem(), new Condition() { public boolean value(Sdk jdk) { final Sdk projectJdk = myJdksModel.getProjectSdk(); - if (projectJdk == null){ + if (projectJdk == null) { final int res = Messages.showYesNoDialog(myJdkPanel, ProjectBundle.message("project.roots.no.jdk.on.project.message"), - ProjectBundle.message("project.roots.no.jdk.on.projecct.title"), + ProjectBundle.message("project.roots.no.jdk.on.project.title"), Messages.getInformationIcon()); - if (res == DialogWrapper.OK_EXIT_CODE){ + if (res == DialogWrapper.OK_EXIT_CODE) { myJdksModel.setProjectSdk(jdk); return true; } @@ -140,12 +142,16 @@ public abstract class ModuleJdkConfigurable implements Disposable { myJdkPanel.add(setUpButton, new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 4, 7, 0), 0, 0)); - myCbModuleJdk.appendEditButton(getRootModel().getModule().getProject(), myJdkPanel, new GridBagConstraints(GridBagConstraints.RELATIVE, 0, 1, 1, 1.0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 4, 7, 0), 0, 0) , new Computable() { + final JButton editButton = new JButton(ApplicationBundle.message("button.edit")); + myCbModuleJdk.setEditButton(editButton, getRootModel().getModule().getProject(), new Computable() { @Nullable public Sdk compute() { return getRootModel().getSdk(); } }); + myJdkPanel.add(editButton, + new GridBagConstraints(GridBagConstraints.RELATIVE, 0, 1, 1, 1.0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, + new Insets(0, 4, 7, 0), 0, 0)); } private void clearCaches() { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java index 54a36d3c569f..ade16cb422a5 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java @@ -16,6 +16,7 @@ package com.intellij.openapi.roots.ui.configuration; +import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.module.Module; import com.intellij.openapi.options.UnnamedConfigurable; import com.intellij.openapi.project.Project; @@ -90,14 +91,19 @@ public class ProjectJdkConfigurable implements UnnamedConfigurable { }); myJdkPanel.add(new JLabel(ProjectBundle.message("module.libraries.target.jdk.project.radio")), new GridBagConstraints(0, 0, 3, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 4, 0), 0, 0)); myJdkPanel.add(myCbProjectJdk, new GridBagConstraints(0, 1, 1, 1, 0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 4, 0, 0), 0, 0)); - final JButton setUpButton = myCbProjectJdk.createSetupButton(myProject, myJdksModel, new JdkComboBox.NoneJdkComboBoxItem()); + final JButton setUpButton = new JButton(ApplicationBundle.message("button.new")); + myCbProjectJdk.setSetupButton(setUpButton, myProject, myJdksModel, new JdkComboBox.NoneJdkComboBoxItem(), null, false); myJdkPanel.add(setUpButton, new GridBagConstraints(1, 1, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 4, 0, 0), 0, 0)); - myCbProjectJdk.appendEditButton(myProject, myJdkPanel, new GridBagConstraints(GridBagConstraints.RELATIVE, 1, 1, 1, 1.0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 4, 0, 0), 0, 0), new Computable() { + final JButton editButton = new JButton(ApplicationBundle.message("button.edit")); + myCbProjectJdk.setEditButton(editButton, myProject, new Computable() { @Nullable public Sdk compute() { return myJdksModel.getProjectSdk(); } }); + + myJdkPanel.add(editButton, new GridBagConstraints(GridBagConstraints.RELATIVE, 1, 1, 1, 1.0, 0, GridBagConstraints.NORTHWEST, + GridBagConstraints.NONE, new Insets(0, 4, 0, 0), 0, 0)); } return myJdkPanel; } diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index 8b853b5fa2d2..d6dd20356183 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -528,7 +528,7 @@ exclude.from.imports.no.exclusions=No exclude patterns inline.elements=Inline elements: don.t.break.if.inline.content=Don't break if inline content: edit.code.folding.options=Open code folding options -button.new=&New +button.new=&New... building.include.indices=Building include indices... loading.include.indices=Loading include indices... use.external.annotations=Use &external annotations diff --git a/platform/platform-resources-en/src/messages/ProjectBundle.properties b/platform/platform-resources-en/src/messages/ProjectBundle.properties index 694fc07924ea..c25a73143233 100644 --- a/platform/platform-resources-en/src/messages/ProjectBundle.properties +++ b/platform/platform-resources-en/src/messages/ProjectBundle.properties @@ -297,7 +297,7 @@ facet.banner.text=Facet ''{0}'' project.roots.project.banner.text=General Settings for Project ''{0}'' project.roots.set.up.jdk.title=Set up {0, choice, 1#module|2#project} SDK project.roots.no.jdk.on.project.message=Set up created sdk on project? -project.roots.no.jdk.on.projecct.title=No project sdk set up +project.roots.no.jdk.on.project.title=Create SDK project.roots.jdks.node.text=JDK stands for the Java Development Kit, a software development package that is required to write, test and debug Java applications. \ JDK also contains classes and runtime environment that are used to execute the target application.

    \ Mobile SDK contains emulator of mobile phone as well as embedded Java SDK to compile/pack/run/debug J2ME applications.

    \ From ae1b0f1a583cdc89e6ba07bb55684d7e42f3988f Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 30 Jan 2012 16:11:34 +0100 Subject: [PATCH 41/45] selection tests --- .../JavaAnonymousClassesNodeProvider.java | 3 +- .../fileStructure/selection/Constructor.java | 7 +++ .../fileStructure/selection/Constructor.tree | 6 ++ .../fileStructure/selection/Field.java | 7 +++ .../fileStructure/selection/Field.tree | 6 ++ .../fileStructure/selection/InsideClass.java | 7 +++ .../fileStructure/selection/InsideClass.tree | 6 ++ .../fileStructure/selection/Method.java | 7 +++ .../fileStructure/selection/Method.tree | 6 ++ .../JavaFileStructureSelectionTest.java | 31 ++++++++++ .../JavaFileStructureTestCase.java | 57 +++++++++++++++++++ .../intellij/ide/util/FileStructurePopup.java | 9 +-- .../ide/util/treeView/AbstractTreeUi.java | 2 +- .../filtered/FilteringTreeStructure.java | 2 +- .../testFramework/FileStructureTestBase.java | 5 +- 15 files changed, 152 insertions(+), 9 deletions(-) create mode 100644 java/java-tests/testData/fileStructure/selection/Constructor.java create mode 100644 java/java-tests/testData/fileStructure/selection/Constructor.tree create mode 100644 java/java-tests/testData/fileStructure/selection/Field.java create mode 100644 java/java-tests/testData/fileStructure/selection/Field.tree create mode 100644 java/java-tests/testData/fileStructure/selection/InsideClass.java create mode 100644 java/java-tests/testData/fileStructure/selection/InsideClass.tree create mode 100644 java/java-tests/testData/fileStructure/selection/Method.java create mode 100644 java/java-tests/testData/fileStructure/selection/Method.tree create mode 100644 java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureSelectionTest.java create mode 100644 java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureTestCase.java diff --git a/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaAnonymousClassesNodeProvider.java b/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaAnonymousClassesNodeProvider.java index 2f41b69c8368..65bc73d12b8a 100644 --- a/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaAnonymousClassesNodeProvider.java +++ b/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaAnonymousClassesNodeProvider.java @@ -43,6 +43,7 @@ import java.util.List; */ public class JavaAnonymousClassesNodeProvider implements FileStructureNodeProvider, PropertyOwner { public static final String ID = "SHOW_ANONYMOUS"; + public static final String JAVA_ANONYMOUS_PROPERTY_NAME = "java.anonymous.provider"; @Override public Collection provideNodes(TreeElement node) { @@ -87,6 +88,6 @@ public class JavaAnonymousClassesNodeProvider implements FileStructureNodeProvid @NotNull @Override public String getPropertyName() { - return "java.anonymous.provider"; + return JAVA_ANONYMOUS_PROPERTY_NAME; } } diff --git a/java/java-tests/testData/fileStructure/selection/Constructor.java b/java/java-tests/testData/fileStructure/selection/Constructor.java new file mode 100644 index 000000000000..55a5f021dedd --- /dev/null +++ b/java/java-tests/testData/fileStructure/selection/Constructor.java @@ -0,0 +1,7 @@ +class Constructor { + int num1; + int num2; + + Constructor() {} + void foo() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/selection/Constructor.tree b/java/java-tests/testData/fileStructure/selection/Constructor.tree new file mode 100644 index 000000000000..92a1b45db704 --- /dev/null +++ b/java/java-tests/testData/fileStructure/selection/Constructor.tree @@ -0,0 +1,6 @@ +-Constructor.java + -Constructor + [Constructor()] + foo():void + num1:int + num2:int \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/selection/Field.java b/java/java-tests/testData/fileStructure/selection/Field.java new file mode 100644 index 000000000000..35e5fea671f7 --- /dev/null +++ b/java/java-tests/testData/fileStructure/selection/Field.java @@ -0,0 +1,7 @@ +class Field { + int num1; + int num2; + + Field() {} + void foo() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/selection/Field.tree b/java/java-tests/testData/fileStructure/selection/Field.tree new file mode 100644 index 000000000000..1008b5f45802 --- /dev/null +++ b/java/java-tests/testData/fileStructure/selection/Field.tree @@ -0,0 +1,6 @@ +-Field.java + -Field + Field() + foo():void + num1:int + [num2:int] diff --git a/java/java-tests/testData/fileStructure/selection/InsideClass.java b/java/java-tests/testData/fileStructure/selection/InsideClass.java new file mode 100644 index 000000000000..5fc06c0e2be5 --- /dev/null +++ b/java/java-tests/testData/fileStructure/selection/InsideClass.java @@ -0,0 +1,7 @@ +class InsideClass { + int num1; + int num2; + + InsideClass() {} + void foo() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/selection/InsideClass.tree b/java/java-tests/testData/fileStructure/selection/InsideClass.tree new file mode 100644 index 000000000000..96d30ca6b340 --- /dev/null +++ b/java/java-tests/testData/fileStructure/selection/InsideClass.tree @@ -0,0 +1,6 @@ +-InsideClass.java + -[InsideClass] + InsideClass() + foo():void + num1:int + num2:int \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/selection/Method.java b/java/java-tests/testData/fileStructure/selection/Method.java new file mode 100644 index 000000000000..01e47e1aaabf --- /dev/null +++ b/java/java-tests/testData/fileStructure/selection/Method.java @@ -0,0 +1,7 @@ +class Method { + int num1; + int num2; + + Method() {} + void foo() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/selection/Method.tree b/java/java-tests/testData/fileStructure/selection/Method.tree new file mode 100644 index 000000000000..5e868f2f9765 --- /dev/null +++ b/java/java-tests/testData/fileStructure/selection/Method.tree @@ -0,0 +1,6 @@ +-Method.java + -Method + Method() + [foo():void] + num1:int + num2:int \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureSelectionTest.java b/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureSelectionTest.java new file mode 100644 index 000000000000..84e971463a84 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureSelectionTest.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2012 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.ide.fileStructure; + +/** + * @author Konstantin Bulenkov + */ +public class JavaFileStructureSelectionTest extends JavaFileStructureTestCase { + @Override + protected String getTestDataFolderName() { + return "selection"; + } + + public void testField() throws Exception {checkTree();} + public void testMethod() throws Exception {checkTree();} + public void testConstructor() throws Exception {checkTree();} + public void testInsideClass() throws Exception {checkTree();} +} diff --git a/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureTestCase.java b/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureTestCase.java new file mode 100644 index 000000000000..0753206117da --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureTestCase.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2012 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.ide.fileStructure; + +import com.intellij.JavaTestUtil; +import com.intellij.ide.structureView.impl.java.JavaAnonymousClassesNodeProvider; +import com.intellij.ide.util.FileStructurePopup; +import com.intellij.ide.util.PropertiesComponent; +import com.intellij.testFramework.FileStructureTestBase; + +/** + * @author Konstantin Bulenkov + */ +public abstract class JavaFileStructureTestCase extends FileStructureTestBase { + private boolean myShowAnonymousByDefault; + + protected abstract String getTestDataFolderName(); + + @Override + public void setUp() throws Exception { + super.setUp(); + myShowAnonymousByDefault = PropertiesComponent.getInstance().getBoolean(getAnonymousPropertyName(), false); + } + + @Override + protected String getFileExtension() { + return "java"; + } + + @Override + public void tearDown() throws Exception { + PropertiesComponent.getInstance().setValue(getAnonymousPropertyName(), Boolean.toString(myShowAnonymousByDefault)); + super.tearDown(); + } + + private static String getAnonymousPropertyName() { + return FileStructurePopup.getPropertyName(JavaAnonymousClassesNodeProvider.JAVA_ANONYMOUS_PROPERTY_NAME); + } + + @Override + protected String getBasePath() { + return JavaTestUtil.getRelativeJavaTestDataPath() + "/fileStructure/" + getTestDataFolderName(); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java index 9d885b1e49d8..39dbe47a25aa 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java @@ -424,7 +424,8 @@ public class FileStructurePopup implements Disposable { } } - public void selectPsiElement(PsiElement element) { + @Nullable + public FilteringTreeStructure.FilteringNode selectPsiElement(PsiElement element) { Set parents = getAllParents(element); FilteringTreeStructure.FilteringNode node = (FilteringTreeStructure.FilteringNode)myAbstractTreeBuilder.getRootElement(); @@ -443,11 +444,11 @@ public class FileStructurePopup implements Disposable { if (myAbstractTreeBuilder.getSelectedElements().isEmpty()) { TreeUtil.selectFirstNode(myTree); } - return; - + return node; } } TreeUtil.selectFirstNode(myTree); + return null; } private static Set getAllParents(PsiElement element) { @@ -721,7 +722,7 @@ public class FileStructurePopup implements Disposable { } } - private static String getPropertyName(String propertyName) { + public static String getPropertyName(String propertyName) { return propertyName + ".file.structure.state"; } diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java index 43423a359932..96560cad40a8 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java @@ -3688,7 +3688,7 @@ public class AbstractTreeUi { } public void userSelect(final Object[] elements, final Runnable onDone, final boolean addToSelection, boolean scroll) { - _select(elements, onDone, addToSelection, true, false, scroll, false, true, true); + _select(elements, onDone, addToSelection, true, false, scroll, false, true, !ApplicationManager.getApplication().isUnitTestMode()); } void _select(final Object[] elements, diff --git a/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeStructure.java b/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeStructure.java index 786ecdf73791..7a3fce1253bc 100644 --- a/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeStructure.java +++ b/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeStructure.java @@ -241,7 +241,7 @@ public class FilteringTreeStructure extends AbstractTreeStructure { } public Object[] getEqualityObjects() { - return NONE; + return new Object[]{myDelegate}; } @Override diff --git a/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java b/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java index 3f991b0cb683..5b9fe7a375cf 100644 --- a/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java +++ b/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java @@ -67,7 +67,7 @@ public abstract class FileStructureTestBase extends CodeInsightFixtureTestCase { protected void checkTree() throws Exception { final String expected = FileUtil.loadFile(new File(getTestDataPath() + "/" + getTreeFileName())); - Assert.assertEquals(expected, PlatformTestUtil.print(getTree(), true)); + Assert.assertEquals(expected.trim(), PlatformTestUtil.print(getTree(), true).trim()); } @@ -78,7 +78,8 @@ public abstract class FileStructureTestBase extends CodeInsightFixtureTestCase { getStructure().rebuild(); updateTree(); TreeUtil.expandAll(getTree()); - myPopup.selectPsiElement(getFile()); + final FilteringTreeStructure.FilteringNode node = myPopup.selectPsiElement(myPopup.getCurrentElement(getFile())); + getTree().getSelectionModel().setSelectionPath(getTree().getPath(node)); } }); } From 57515e1adacb21e81f04421e9ef635c8616948d0 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 30 Jan 2012 16:41:49 +0100 Subject: [PATCH 42/45] + line separators option --- .../com/intellij/openapi/util/io/FileUtil.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java index c48b53e30bdc..beca1196d72e 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java @@ -173,12 +173,23 @@ public class FileUtil { @NotNull public static String loadFile(@NotNull File file) throws IOException { - return loadFile(file, null); + return loadFile(file, null, false); + } + + @NotNull + public static String loadFile(@NotNull File file, boolean convertLineSeparators) throws IOException { + return loadFile(file, null, convertLineSeparators); } @NotNull public static String loadFile(@NotNull File file, String encoding) throws IOException { - return new String(loadFileText(file, encoding)); + return loadFile(file, encoding, false); + } + + @NotNull + public static String loadFile(@NotNull File file, String encoding, boolean convertLineSeparators) throws IOException { + final String s = new String(loadFileText(file, encoding)); + return convertLineSeparators ? StringUtil.convertLineSeparators(s) : s; } @NotNull From 30ec3a443478d3d48bc9bcb1a4833a6977426009 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 30 Jan 2012 16:43:54 +0100 Subject: [PATCH 43/45] fix line separators --- .../src/com/intellij/testFramework/FileStructureTestBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java b/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java index 5b9fe7a375cf..645d6ae0192e 100644 --- a/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java +++ b/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java @@ -66,7 +66,7 @@ public abstract class FileStructureTestBase extends CodeInsightFixtureTestCase { } protected void checkTree() throws Exception { - final String expected = FileUtil.loadFile(new File(getTestDataPath() + "/" + getTreeFileName())); + final String expected = FileUtil.loadFile(new File(getTestDataPath() + "/" + getTreeFileName()), true); Assert.assertEquals(expected.trim(), PlatformTestUtil.print(getTree(), true).trim()); } From ed4dd08df1f9f3f9258aaf41195f2cdfe7ff0f5d Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Mon, 30 Jan 2012 16:43:58 +0100 Subject: [PATCH 44/45] debugger event queue: more robust command cancellation when queue is closed --- .../engine/DebuggerManagerThreadImpl.java | 18 ++++++++---------- .../intellij/debugger/impl/EventQueue.java | 19 ++++++++++--------- .../impl/EventQueueClosedException.java | 4 ++++ .../debugger/impl/InvokeAndWaitThread.java | 8 ++++---- .../intellij/debugger/impl/InvokeThread.java | 8 ++++---- 5 files changed, 30 insertions(+), 27 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java index 027b82b25641..f5569d5bdb1f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java @@ -73,22 +73,20 @@ public class DebuggerManagerThreadImpl extends InvokeAndWaitThread { } } - public void pushBack(@NotNull E event, int priority) { + public boolean pushBack(@NotNull E event, int priority) { if(LOG.isDebugEnabled()) { LOG.debug("pushBack event " + event); } myLock.lock(); try { - assertOpen(); + if (isClosed()) { + return false; + } getEventsList(priority).addFirst(event); myEventsAvailable.signalAll(); } finally { myLock.unlock(); } + return true; } - public void put(@NotNull E event, int priority) { + public boolean put(@NotNull E event, int priority) { if(LOG.isDebugEnabled()) { LOG.debug("put event " + event); } myLock.lock(); try { - assertOpen(); + if (isClosed()) { + return false; + } getEventsList(priority).offer(event); myEventsAvailable.signalAll(); } finally { myLock.unlock(); } + return true; } private LinkedList getEventsList(final int priority) { @@ -84,7 +90,6 @@ public class EventQueue { public void close(){ myLock.lock(); try { - assertOpen(); myIsClosed = true; myEventsAvailable.signalAll(); } @@ -93,10 +98,6 @@ public class EventQueue { } } - private void assertOpen() { - if (myIsClosed) throw new AssertionError("Already closed"); - } - private E getEvent() throws EventQueueClosedException { myLock.lock(); try { diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/EventQueueClosedException.java b/java/debugger/impl/src/com/intellij/debugger/impl/EventQueueClosedException.java index be0cd485b30b..d58b663f522a 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/EventQueueClosedException.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/EventQueueClosedException.java @@ -19,4 +19,8 @@ package com.intellij.debugger.impl; * @author lex */ public class EventQueueClosedException extends Exception { + @Override + public Throwable fillInStackTrace() { + return this; + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/InvokeAndWaitThread.java b/java/debugger/impl/src/com/intellij/debugger/impl/InvokeAndWaitThread.java index 3278e59f1764..3576c86b4f65 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/InvokeAndWaitThread.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/InvokeAndWaitThread.java @@ -28,12 +28,12 @@ public abstract class InvokeAndWaitThread extends Invoke * !!! Do not remove this code !!! * Otherwise it will be impossible to override schedule method */ - public void schedule(E e) { - super.schedule(e); + public boolean schedule(E e) { + return super.schedule(e); } - public void pushBack(E e) { - super.pushBack(e); + public boolean pushBack(E e) { + return super.pushBack(e); } public void invokeAndWait(final E runnable) { diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/InvokeThread.java b/java/debugger/impl/src/com/intellij/debugger/impl/InvokeThread.java index b3ddf3a90ed2..e8835275f907 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/InvokeThread.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/InvokeThread.java @@ -172,18 +172,18 @@ public abstract class InvokeThread { return request != null? request.getOwner() : null; } - public void schedule(E r) { + public boolean schedule(E r) { if(LOG.isDebugEnabled()) { LOG.debug("schedule " + r + " in " + this); } - myEvents.put(r, r.getPriority().ordinal()); + return myEvents.put(r, r.getPriority().ordinal()); } - public void pushBack(E r) { + public boolean pushBack(E r) { if(LOG.isDebugEnabled()) { LOG.debug("pushBack " + r + " in " + this); } - myEvents.pushBack(r, r.getPriority().ordinal()); + return myEvents.pushBack(r, r.getPriority().ordinal()); } protected void switchToRequest(WorkerThreadRequest newWorkerThread) { From dc2e864253bf18427d2361406aa1b35ad5f26bee Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Mon, 30 Jan 2012 16:53:52 +0100 Subject: [PATCH 45/45] automake: notifications about successful compilations seem to be redundant --- .../intellij/compiler/CompileServerManager.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java index 6a6ef6bc66af..9e0e25ca9c94 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java @@ -695,13 +695,13 @@ public class CompileServerManager implements ApplicationComponent{ @Override public void sessionTerminated() { - String statusMessage = "Auto make completed"; + String statusMessage = null/*"Auto make completed"*/; switch (myBuildStatus) { case SUCCESS: - statusMessage = "Auto make completed successfully"; + //statusMessage = "Auto make completed successfully"; break; case UP_TO_DATE: - statusMessage = "All files are up-to-date"; + //statusMessage = "All files are up-to-date"; break; case ERRORS: statusMessage = "Auto make completed with errors"; @@ -710,9 +710,11 @@ public class CompileServerManager implements ApplicationComponent{ statusMessage = "Auto make has been canceled"; break; } - final Notification notification = CompilerManager.NOTIFICATION_GROUP.createNotification(statusMessage, MessageType.INFO); - if (!myProject.isDisposed()) { - notification.notify(myProject); + if (statusMessage != null) { + final Notification notification = CompilerManager.NOTIFICATION_GROUP.createNotification(statusMessage, MessageType.INFO); + if (!myProject.isDisposed()) { + notification.notify(myProject); + } } }