diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelImpl.java index eb7f0ea68c12..8ece843b5972 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelImpl.java @@ -350,6 +350,12 @@ public class RootModelImpl extends RootModelBase implements ModifiableRootModel getSourceModel().setOrderEntriesFrom(this); } + for (ModuleExtension extension : myExtensions) { + if (extension.isChanged()) { + extension.commit(); + } + } + if (areContentEntriesChanged()) { getSourceModel().removeAllContentEntries(); for (ContentEntry contentEntry : myContent) { @@ -357,12 +363,6 @@ public class RootModelImpl extends RootModelBase implements ModifiableRootModel getSourceModel().myContent.add(cloned); } } - - for (ModuleExtension extension : myExtensions) { - if (extension.isChanged()) { - extension.commit(); - } - } } @Override diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenFoldersImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenFoldersImporter.java index f3ad1ff78c29..1b40dfadccee 100755 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenFoldersImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenFoldersImporter.java @@ -107,7 +107,6 @@ public class MavenFoldersImporter { configOutputFolders(); } configGeneratedAndExcludedFolders(); - myModel.sortSourceFolders(); } private void configSourceFolders() { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenRootModelAdapter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenRootModelAdapter.java index 63ebdd3fa56a..08d534e2c630 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenRootModelAdapter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenRootModelAdapter.java @@ -25,7 +25,6 @@ import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; 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.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFileManager; @@ -41,15 +40,12 @@ import org.jetbrains.idea.maven.project.MavenProjectsManager; import org.jetbrains.idea.maven.utils.Path; import org.jetbrains.idea.maven.utils.Url; import org.jetbrains.jps.model.JpsElement; -import org.jetbrains.jps.model.java.JavaSourceRootProperties; import org.jetbrains.jps.model.java.JavaSourceRootType; import org.jetbrains.jps.model.java.JpsJavaExtensionService; import org.jetbrains.jps.model.module.JpsModuleSourceRootType; import java.io.File; -import java.util.Comparator; import java.util.Set; -import java.util.TreeSet; public class MavenRootModelAdapter { @@ -57,12 +53,17 @@ public class MavenRootModelAdapter { private final ModifiableModuleModel myModuleModel; private final ModifiableRootModel myRootModel; + private final MavenSourceFoldersModuleExtension myRootModelModuleExtension; + private final Set myOrderEntriesBeforeJdk = new THashSet(); public MavenRootModelAdapter(@NotNull MavenProject p, @NotNull Module module, final MavenModifiableModelsProvider rootModelsProvider) { myMavenProject = p; myModuleModel = rootModelsProvider.getModuleModel(); myRootModel = rootModelsProvider.getRootModel(module); + + myRootModelModuleExtension = myRootModel.getModuleExtension(MavenSourceFoldersModuleExtension.class); + myRootModelModuleExtension.init(module, myRootModel); } public void init(boolean isNewlyCreatedModule) { @@ -132,9 +133,7 @@ public class MavenRootModelAdapter { } public void clearSourceFolders() { - for (ContentEntry each : myRootModel.getContentEntries()) { - each.clearSourceFolders(); - } + myRootModelModuleExtension.clearSourceFolders(); } public

void addSourceFolder(String path, final JpsModuleSourceRootType

rootType) { @@ -156,34 +155,18 @@ public class MavenRootModelAdapter { } Url url = toUrl(path); - ContentEntry e = getContentRootFor(url); - if (e == null) return; - unregisterAll(path, true, true); - unregisterAll(path, false, true); - e.addSourceFolder(url.getUrl(), rootType, properties); + myRootModelModuleExtension.addSourceFolder(url, rootType, properties); } - public boolean hasRegisteredSourceSubfolder(File f) { + public boolean hasRegisteredSourceSubfolder(@NotNull File f) { String url = toUrl(f.getPath()).getUrl(); - for (ContentEntry eachEntry : myRootModel.getContentEntries()) { - for (SourceFolder eachFolder : eachEntry.getSourceFolders()) { - if (VfsUtilCore.isEqualOrAncestor(url, eachFolder.getUrl())) return true; - } - } - return false; + return myRootModelModuleExtension.hasRegisteredSourceSubfolder(url); } @Nullable public SourceFolder getSourceFolder(File folder) { String url = toUrl(folder.getPath()).getUrl(); - for (ContentEntry entry : myRootModel.getContentEntries()) { - for (SourceFolder sourceFolder : entry.getSourceFolders()) { - if (sourceFolder.getUrl().equals(url)) { - return sourceFolder; - } - } - } - return null; + return myRootModelModuleExtension.getSourceFolder(url); } public boolean isAlreadyExcluded(File f) { @@ -212,13 +195,7 @@ public class MavenRootModelAdapter { for (ContentEntry eachEntry : myRootModel.getContentEntries()) { if (unregisterSources) { - for (SourceFolder eachFolder : eachEntry.getSourceFolders()) { - String ancestor = under ? url.getUrl() : eachFolder.getUrl(); - String child = under ? eachFolder.getUrl() : url.getUrl(); - if (VfsUtilCore.isEqualOrAncestor(ancestor, child)) { - eachEntry.removeSourceFolder(eachFolder); - } - } + myRootModelModuleExtension.unregisterAll(url, under); } for (String excludedUrl : eachEntry.getExcludeFolderUrls()) { @@ -505,68 +482,4 @@ public class MavenRootModelAdapter { //bad value was stored } } - - public void sortSourceFolders() { - for (ContentEntry eachEntry : myRootModel.getContentEntries()) { - final Set sourceFolders = new TreeSet(SourceFolderDataComparator.INSTANCE); - for (SourceFolder eachFolder : eachEntry.getSourceFolders()) { - final JpsElement properties = eachFolder.getJpsElement().getProperties(); - //noinspection unchecked - JpsModuleSourceRootType sourceRootType = (JpsModuleSourceRootType)eachFolder.getRootType(); - if (properties instanceof JavaSourceRootProperties) { - sourceFolders.add( - new SourceFolderData(eachFolder.getUrl(), sourceRootType, ((JavaSourceRootProperties)properties).createCopy()) - ); - } - else { - sourceFolders.add(new SourceFolderData(eachFolder.getUrl(), sourceRootType, null)); - } - eachEntry.removeSourceFolder(eachFolder); - } - for (SourceFolderData data : sourceFolders) { - if (data.getProperties() == null) { - eachEntry.addSourceFolder(data.getUrl(), data.getType()); - } - else { - eachEntry.addSourceFolder(data.getUrl(), data.getType(), data.getProperties()); - } - } - } - } - - private static final class SourceFolderData

{ - @NotNull private final String url; - @NotNull private final JpsModuleSourceRootType

type; - @Nullable private final P properties; - - private SourceFolderData(@NotNull String url, @NotNull JpsModuleSourceRootType

type, @Nullable P properties) { - this.url = url; - this.type = type; - this.properties = properties; - } - - @NotNull - public String getUrl() { - return url; - } - - @NotNull - public JpsModuleSourceRootType

getType() { - return type; - } - - @Nullable - public P getProperties() { - return properties; - } - } - - private static final class SourceFolderDataComparator implements Comparator { - public static final SourceFolderDataComparator INSTANCE = new SourceFolderDataComparator(); - - @Override - public int compare(@NotNull SourceFolderData o1, @NotNull SourceFolderData o2) { - return StringUtil.naturalCompare(o1.getUrl(), o2.getUrl()); - } - } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenSourceFoldersModuleExtension.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenSourceFoldersModuleExtension.java new file mode 100644 index 000000000000..e45a1d5f143e --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenSourceFoldersModuleExtension.java @@ -0,0 +1,206 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.idea.maven.importing; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VfsUtilCore; +import com.intellij.project.model.impl.module.JpsRootModel; +import com.intellij.project.model.impl.module.content.JpsContentEntry; +import com.intellij.project.model.impl.module.content.JpsSourceFolder; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.maven.utils.Url; +import org.jetbrains.jps.model.JpsElement; +import org.jetbrains.jps.model.JpsElementFactory; +import org.jetbrains.jps.model.ex.JpsElementBase; +import org.jetbrains.jps.model.java.JpsJavaModuleType; +import org.jetbrains.jps.model.module.JpsModule; +import org.jetbrains.jps.model.module.JpsModuleSourceRoot; +import org.jetbrains.jps.model.module.JpsModuleSourceRootType; + +import java.util.Comparator; +import java.util.Iterator; +import java.util.Set; +import java.util.TreeSet; + +/** + * @author Vladislav.Soroka + * @since 4/30/2014 + */ +public class MavenSourceFoldersModuleExtension extends ModuleExtension { + + private ModifiableRootModel myRootModel; + private JpsModule myDummyJpsModule; + private JpsRootModel myDummyJpsRootModel; + private final Set myJpsSourceFolders = new TreeSet(ContentFolderComparator.INSTANCE); + private boolean isJpsSourceFoldersChanged; + + public void init(@NotNull Module module, @NotNull ModifiableRootModel modifiableRootModel) { + myRootModel = modifiableRootModel; + + myDummyJpsModule = JpsElementFactory.getInstance() + .createModule(module.getName(), JpsJavaModuleType.INSTANCE, JpsElementFactory.getInstance().createDummyElement()); + myDummyJpsRootModel = new JpsRootModel(module, myDummyJpsModule); + myJpsSourceFolders.clear(); + + for (ContentEntry eachEntry : modifiableRootModel.getContentEntries()) { + for (SourceFolder eachFolder : eachEntry.getSourceFolders()) { + //noinspection unchecked + final JpsModuleSourceRoot jpsModuleSourceRoot = + JpsElementFactory.getInstance().createModuleSourceRoot( + eachFolder.getUrl(), + (JpsModuleSourceRootType)eachFolder.getRootType(), + eachFolder.getJpsElement().getProperties().getBulkModificationSupport().createCopy()); + + final JpsContentEntry dummyJpsContentEntry = new JpsContentEntry(myDummyJpsModule, myDummyJpsRootModel, eachFolder.getUrl()); + myJpsSourceFolders.add(new JpsSourceFolder(jpsModuleSourceRoot, dummyJpsContentEntry)); + } + } + } + + @Override + public ModuleExtension getModifiableModel(boolean writable) { + return new MavenSourceFoldersModuleExtension(); + } + + @Override + public void commit() { + if (!isJpsSourceFoldersChanged) return; + + for (ContentEntry eachEntry : myRootModel.getContentEntries()) { + for (SourceFolder eachFolder : eachEntry.getSourceFolders()) { + boolean found = false; + for (JpsSourceFolder jpsSourceFolder : myJpsSourceFolders) { + if (StringUtil.equals(jpsSourceFolder.getUrl(), eachFolder.getUrl()) + && eachFolder.getRootType().equals(jpsSourceFolder.getRootType())) { + found = true; + eachFolder.setPackagePrefix(jpsSourceFolder.getPackagePrefix()); + myJpsSourceFolders.remove(jpsSourceFolder); + break; + } + } + if (!found) { + eachEntry.removeSourceFolder(eachFolder); + } + } + } + + for (JpsSourceFolder jpsSourceFolder : myJpsSourceFolders) { + Url url = new Url(jpsSourceFolder.getUrl()); + ContentEntry e = getContentRootFor(url); + if (e == null) continue; + //noinspection unchecked + JpsModuleSourceRootType sourceRootType = (JpsModuleSourceRootType)jpsSourceFolder.getRootType(); + final JpsElementBase properties = (JpsElementBase)jpsSourceFolder.getSourceRoot().getProperties(); + //noinspection unchecked + properties.setParent(null); + e.addSourceFolder(url.getUrl(), sourceRootType, properties); + } + + isJpsSourceFoldersChanged = false; + } + + @Override + public boolean isChanged() { + return isJpsSourceFoldersChanged; + } + + @Override + public void dispose() { + myJpsSourceFolders.clear(); + } + + @Override + public void readExternal(Element element) throws InvalidDataException { + } + + @Override + public void writeExternal(Element element) throws WriteExternalException { + } + + public void clearSourceFolders() { + myJpsSourceFolders.clear(); + isJpsSourceFoldersChanged = true; + } + + public

void addSourceFolder(final @NotNull Url url, + final @NotNull JpsModuleSourceRootType

rootType, + final @NotNull P properties) { + for (Iterator iterator = myJpsSourceFolders.iterator(); iterator.hasNext(); ) { + SourceFolder eachFolder = iterator.next(); + if (VfsUtilCore.isEqualOrAncestor(url.getUrl(), eachFolder.getUrl()) || + VfsUtilCore.isEqualOrAncestor(eachFolder.getUrl(), url.getUrl())) { + iterator.remove(); + } + } + + final JpsModuleSourceRoot jpsModuleSourceRoot = + JpsElementFactory.getInstance().createModuleSourceRoot(url.getUrl(), rootType, properties); + final JpsContentEntry dummyJpsContentEntry = new JpsContentEntry(myDummyJpsModule, myDummyJpsRootModel, url.getUrl()); + myJpsSourceFolders.add(new JpsSourceFolder(jpsModuleSourceRoot, dummyJpsContentEntry)); + + isJpsSourceFoldersChanged = true; + } + + public boolean hasRegisteredSourceSubfolder(@NotNull String url) { + for (JpsSourceFolder eachFolder : myJpsSourceFolders) { + if (VfsUtilCore.isEqualOrAncestor(url, eachFolder.getUrl())) return true; + } + return false; + } + + @Nullable + public SourceFolder getSourceFolder(@NotNull String url) { + for (JpsSourceFolder eachFolder : myJpsSourceFolders) { + if (eachFolder.getUrl().equals(url)) return eachFolder; + } + return null; + } + + + @Nullable + private ContentEntry getContentRootFor(@NotNull Url url) { + for (ContentEntry e : myRootModel.getContentEntries()) { + if (VfsUtilCore.isEqualOrAncestor(e.getUrl(), url.getUrl())) return e; + } + return null; + } + + public void unregisterAll(@NotNull Url url, boolean under) { + for (Iterator iterator = myJpsSourceFolders.iterator(); iterator.hasNext(); ) { + JpsSourceFolder eachFolder = iterator.next(); + String ancestor = under ? url.getUrl() : eachFolder.getUrl(); + String child = under ? eachFolder.getUrl() : url.getUrl(); + if (VfsUtilCore.isEqualOrAncestor(ancestor, child)) { + iterator.remove(); + } + } + } + + private static final class ContentFolderComparator implements Comparator { + public static final ContentFolderComparator INSTANCE = new ContentFolderComparator(); + + @Override + public int compare(@NotNull ContentFolder o1, @NotNull ContentFolder o2) { + return StringUtil.naturalCompare(o1.getUrl(), o2.getUrl()); + } + } +} diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml index 608de2a8d966..303c92f1b56c 100644 --- a/plugins/maven/src/main/resources/META-INF/plugin.xml +++ b/plugins/maven/src/main/resources/META-INF/plugin.xml @@ -39,6 +39,7 @@ + diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/FoldersImportingTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/FoldersImportingTest.java index 309d43add7e3..fa81ab8d1cdd 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/FoldersImportingTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/FoldersImportingTest.java @@ -16,7 +16,6 @@ package org.jetbrains.idea.maven.importing; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.idea.maven.MavenCustomRepositoryHelper; import org.jetbrains.idea.maven.MavenImportingTestCase; @@ -173,8 +172,7 @@ public class FoldersImportingTest extends MavenImportingTestCase { " src1" + ""); - assertSources("project", "src1", "src2"); - + assertSources("project", "src2", "src1"); } public void testCustomSourceFolders() throws Exception {