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 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); + } } } 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) { 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 additionalSetup, + final boolean moduleJdkSetup) { + setSetupButton(setUpButton, project, jdksModel, firstItem, additionalSetup, + ProjectBundle.message("project.roots.set.up.jdk.title", moduleJdkSetup ? 1 : 2)); } - - 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 String actionGroupTitle) { setUpButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { final JdkListConfigurable configurable = JdkListConfigurable.getInstance(project); @@ -129,16 +132,16 @@ 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) + .createActionGroupPopup(actionGroupTitle, group, + 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 +149,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() { @@ -260,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(); } @@ -286,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/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/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(); } 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() { 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-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 { 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); 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(); 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); } 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/lib/dev/hamcrest-api-1.0.jar b/lib/dev/hamcrest-api-1.0.jar deleted file mode 100644 index 5df3f19d924f..000000000000 Binary files a/lib/dev/hamcrest-api-1.0.jar and /dev/null differ diff --git a/lib/dev/hamcrest-core-1.1.jar b/lib/dev/hamcrest-core-1.1.jar new file mode 100644 index 000000000000..5f1d5ce0c3d6 Binary files /dev/null and b/lib/dev/hamcrest-core-1.1.jar differ diff --git a/lib/dev/hamcrest-library-1.0.jar b/lib/dev/hamcrest-library-1.0.jar deleted file mode 100644 index e0b275f049fd..000000000000 Binary files a/lib/dev/hamcrest-library-1.0.jar and /dev/null differ diff --git a/lib/dev/hamcrest-library-1.1.jar b/lib/dev/hamcrest-library-1.1.jar new file mode 100644 index 000000000000..40610c9b4a23 Binary files /dev/null and b/lib/dev/hamcrest-library-1.1.jar differ 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 77aef4b19156..4415dfbc94f8 100644 Binary files a/lib/dev/jmock-2.3.0-RC2.jar and b/lib/dev/jmock-2.5.1.jar differ 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 cfb2fbdebf68..000000000000 Binary files a/lib/dev/jmock-junit4-2.3.0-RC2.jar and /dev/null differ 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 000000000000..fb3697af4bfa Binary files /dev/null and b/lib/dev/jmock-junit4-2.5.1.jar differ 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 000000000000..c26cc0d25483 Binary files /dev/null and b/lib/dev/jmock-legacy-2.5.1.jar differ diff --git a/platform/lang-impl/src/com/intellij/execution/util/ProgramParametersUtil.java b/platform/lang-impl/src/com/intellij/execution/util/ProgramParametersUtil.java index d5057096f40f..2f7adf63a796 100644 --- a/platform/lang-impl/src/com/intellij/execution/util/ProgramParametersUtil.java +++ b/platform/lang-impl/src/com/intellij/execution/util/ProgramParametersUtil.java @@ -17,6 +17,7 @@ package com.intellij.execution.util; import com.intellij.execution.CommonProgramRunConfigurationParameters; import com.intellij.execution.configurations.ModuleBasedConfiguration; +import com.intellij.execution.configurations.RuntimeConfigurationWarning; import com.intellij.execution.configurations.SimpleProgramParameters; import com.intellij.openapi.components.PathMacroManager; import com.intellij.openapi.module.Module; @@ -26,6 +27,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.PathUtil; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.util.HashMap; import java.util.Map; @@ -36,6 +38,19 @@ public class ProgramParametersUtil { parameters.getProgramParametersList().addParametersString(configuration.getProgramParameters()); + parameters.setWorkingDirectory(getWorkingDir(configuration, project, module)); + + 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 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/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..39dbe47a25aa 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,38 @@ 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) { + @Nullable + public FilteringTreeStructure.FilteringNode selectPsiElement(PsiElement element) { Set parents = getAllParents(element); FilteringTreeStructure.FilteringNode node = (FilteringTreeStructure.FilteringNode)myAbstractTreeBuilder.getRootElement(); @@ -432,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) { @@ -478,7 +490,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(); @@ -710,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"; } @@ -718,6 +730,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/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/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; 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..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 @@ -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(); @@ -3680,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/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/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/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) { 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..466de59f09d3 100644 --- a/platform/platform-resources-en/src/messages/ProjectBundle.properties +++ b/platform/platform-resources-en/src/messages/ProjectBundle.properties @@ -295,9 +295,9 @@ 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.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.

\ diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index cca38e9c553b..044b1b5cac10 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -313,6 +313,8 @@ + + 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 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 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/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); } 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)); 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(); 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/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/branch/GitCheckoutNewBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java index fb6b50305e38..f7bfa21ecd7c 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."; } @@ -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 966e26487b5d..06f93d1c9233 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; @@ -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; @@ -203,7 +207,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 +242,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."; } @@ -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); } @@ -376,7 +380,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; } } @@ -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/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."; } 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) { 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(); 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/GitBranchPopup.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java index 2e6309a2ed9b..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; /** *

@@ -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); @@ -157,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/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; } 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; diff --git a/plugins/gradle/resources/icons/gradle.png b/plugins/gradle/resources/icons/gradle.png index b76b4ba5b8a8..af8da119630b 100644 Binary files a/plugins/gradle/resources/icons/gradle.png and b/plugins/gradle/resources/icons/gradle.png differ 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/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); 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 + } +} 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
    - + - - + - - + @@ -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 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); }