diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorEx.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorEx.java index 3b6ca1e4c661..a9a3f4fac5f6 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorEx.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorEx.java @@ -40,6 +40,8 @@ public interface ArtifactEditorEx extends ArtifactEditor, Disposable { void removePackagingElement(@NotNull String pathToParent, @NotNull PackagingElement element); + void replacePackagingElement(@NotNull String pathToParent, @NotNull PackagingElement element, @NotNull PackagingElement replacement); + LayoutTreeComponent getLayoutTreeComponent(); Artifact getArtifact(); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java index 6ef0f76ce44b..f3959c21ff8a 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java @@ -365,6 +365,17 @@ public class ArtifactEditorImpl implements ArtifactEditorEx { @Override public void removePackagingElement(@NotNull final String pathToParent, @NotNull final PackagingElement element) { + doReplaceElement(pathToParent, element, null); + } + + @Override + public void replacePackagingElement(@NotNull final String pathToParent, + @NotNull final PackagingElement element, + @NotNull final PackagingElement replacement) { + doReplaceElement(pathToParent, element, replacement); + } + + private void doReplaceElement(final @NotNull String pathToParent, final @NotNull PackagingElement element, final @Nullable PackagingElement replacement) { myLayoutTreeComponent.editLayout(new Runnable() { @Override public void run() { @@ -373,6 +384,9 @@ public class ArtifactEditorImpl implements ArtifactEditorEx { for (PackagingElement child : parent.getChildren()) { if (child.isEqualTo(element)) { parent.removeChild(child); + if (replacement != null) { + parent.addOrFindChild(replacement); + } break; } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/UsageInArtifact.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/UsageInArtifact.java index 11f6715e1f16..087298d522ce 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/UsageInArtifact.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/UsageInArtifact.java @@ -52,10 +52,17 @@ public class UsageInArtifact extends ProjectStructureElementUsage { } public void removeElement() { - final ArtifactEditorEx editor = (ArtifactEditorEx)myContext.getOrCreateEditor(myOriginalArtifact); - editor.removePackagingElement(myParentPath, myPackagingElement); + getOrCreateEditor().removePackagingElement(myParentPath, myPackagingElement); } - + + private ArtifactEditorEx getOrCreateEditor() { + return (ArtifactEditorEx)myContext.getOrCreateEditor(myOriginalArtifact); + } + + public void replaceElement(PackagingElement replacement) { + getOrCreateEditor().replacePackagingElement(myParentPath, myPackagingElement, replacement); + } + @Override public String getPresentableName() { return myOriginalArtifact.getName(); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelActionBase.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelActionBase.java index ba3a92b78e5b..684e175f392e 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelActionBase.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelActionBase.java @@ -57,27 +57,27 @@ public abstract class ChangeLibraryLevelActionBase extends AnAction { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.ui.configuration.classpath.ChangeLibraryLevelActionBase"); protected final Project myProject; protected final String myTargetTableLevel; + protected final boolean myCopy; - public ChangeLibraryLevelActionBase(@NotNull Project project, @NotNull String targetTableName, @NotNull String targetTableLevel) { + public ChangeLibraryLevelActionBase(@NotNull Project project, @NotNull String targetTableName, @NotNull String targetTableLevel, boolean copy) { myProject = project; myTargetTableLevel = targetTableLevel; + myCopy = copy; getTemplatePresentation().setText(getActionName() + " to " + targetTableName + "..."); } - protected abstract boolean isCopy(); - protected abstract LibraryTableModifiableModelProvider getModifiableTableModelProvider(); protected abstract JComponent getParentComponent(); @Nullable - protected Library doAction(LibraryEx library) { + protected Library doCopy(LibraryEx library) { final VirtualFile baseDir = getBaseDir(); final String libPath = baseDir != null ? baseDir.getPath() + "/lib" : ""; boolean allowEmptyName = isConvertingToModuleLibrary() && library.getFiles(OrderRootType.CLASSES).length == 1; final String libraryName = allowEmptyName ? "" : StringUtil.notNullize(library.getName(), "Unnamed"); final LibraryTableModifiableModelProvider provider = getModifiableTableModelProvider(); - final ChangeLibraryLevelDialog dialog = new ChangeLibraryLevelDialog(getParentComponent(), myProject, isCopy(), + final ChangeLibraryLevelDialog dialog = new ChangeLibraryLevelDialog(getParentComponent(), myProject, myCopy, libraryName, libPath, allowEmptyName, provider); dialog.show(); if (!dialog.isOK()) { @@ -115,9 +115,8 @@ public abstract class ChangeLibraryLevelActionBase extends AnAction { private boolean copyOrMoveFiles(final Set filesToProcess, @NotNull final String targetDirPath, final Map copiedFiles) { - final boolean copy = isCopy(); final Ref finished = Ref.create(false); - new Task.Modal(myProject, (copy ? "Copying" : "Moving") + " Library Files", true) { + new Task.Modal(myProject, (myCopy ? "Copying" : "Moving") + " Library Files", true) { @Override public void run(@NotNull ProgressIndicator indicator) { final File targetDir = new File(FileUtil.toSystemDependentName(targetDirPath)); @@ -127,7 +126,7 @@ public abstract class ChangeLibraryLevelActionBase extends AnAction { FileUtil.getExtension(from.getName())); try { if (from.isDirectory()) { - if (copy) { + if (myCopy) { FileUtil.copyDir(from, to); } else { @@ -135,7 +134,7 @@ public abstract class ChangeLibraryLevelActionBase extends AnAction { } } else { - if (copy) { + if (myCopy) { FileUtil.copy(from, to); } else { @@ -158,7 +157,7 @@ public abstract class ChangeLibraryLevelActionBase extends AnAction { if (virtualTo != null) { copiedFiles.put(FileUtil.toSystemIndependentName(from.getAbsolutePath()), virtualTo.getPath()); } - if (!copy) { + if (!myCopy) { final VirtualFile parent = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(from.getParentFile()); if (parent != null) { parent.refresh(false, false); @@ -185,7 +184,7 @@ public abstract class ChangeLibraryLevelActionBase extends AnAction { } private String getActionName() { - return isCopy() ? "Copy" : "Move"; + return myCopy ? "Copy" : "Move"; } @Nullable diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelInClasspathAction.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelInClasspathAction.java index 9a4af426ebc9..2b42fd3158e4 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelInClasspathAction.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ChangeLibraryLevelInClasspathAction.java @@ -19,6 +19,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.roots.LibraryOrderEntry; import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.roots.impl.libraries.LibraryEx; +import com.intellij.openapi.roots.impl.libraries.LibraryTableImplUtil; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.ui.configuration.LibraryTableModifiableModelProvider; import com.intellij.openapi.vfs.VirtualFile; @@ -34,7 +35,7 @@ class ChangeLibraryLevelInClasspathAction extends ChangeLibraryLevelActionBase { private final ClasspathPanel myPanel; public ChangeLibraryLevelInClasspathAction(@NotNull ClasspathPanel panel, final @NotNull String targetTableName, @NotNull String targetTableLevel) { - super(panel.getProject(), targetTableName, targetTableLevel); + super(panel.getProject(), targetTableName, targetTableLevel, targetTableLevel.equals(LibraryTableImplUtil.MODULE_LEVEL)); myPanel = panel; } @@ -45,7 +46,7 @@ class ChangeLibraryLevelInClasspathAction extends ChangeLibraryLevelActionBase { final LibraryEx library = (LibraryEx)((LibraryOrderEntry)entry).getLibrary(); if (library == null) return; - final Library copied = doAction(library); + final Library copied = doCopy(library); if (copied == null) return; myPanel.getRootModel().removeOrderEntry(entry); @@ -79,11 +80,6 @@ class ChangeLibraryLevelInClasspathAction extends ChangeLibraryLevelActionBase { return myPanel.getComponent(); } - @Override - protected boolean isCopy() { - return isConvertingToModuleLibrary(); - } - @Override @Nullable protected VirtualFile getBaseDir() { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseLibrariesConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseLibrariesConfigurable.java index f4e00aa31a66..06153b62ad84 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseLibrariesConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseLibrariesConfigurable.java @@ -30,10 +30,7 @@ import com.intellij.openapi.roots.ui.configuration.artifacts.UsageInArtifact; import com.intellij.openapi.roots.ui.configuration.libraries.LibraryEditingUtil; import com.intellij.openapi.roots.ui.configuration.libraryEditor.CreateNewLibraryAction; import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.*; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.ui.NamedConfigurable; -import com.intellij.openapi.ui.NonEmptyInputValidator; +import com.intellij.openapi.ui.*; import com.intellij.openapi.util.Comparing; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NonNls; @@ -208,6 +205,13 @@ public abstract class BaseLibrariesConfigurable extends BaseStructureConfigurabl } } + public void removeLibraryNode(@NotNull Library library) { + final MyNode node = findNodeByObject(myRoot, library); + if (node != null) { + removePaths(TreeUtil.getPathFromRoot(node)); + } + } + protected boolean removeLibrary(final Library library) { final LibraryTable table = library.getTable(); if (table != null) { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ChangeLibraryLevelAction.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ChangeLibraryLevelAction.java index 3f2ecbceec0a..1d6e9f2f95e5 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ChangeLibraryLevelAction.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ChangeLibraryLevelAction.java @@ -17,13 +17,25 @@ package com.intellij.openapi.roots.ui.configuration.projectRoot; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModifiableRootModel; +import com.intellij.openapi.roots.impl.OrderEntryUtil; import com.intellij.openapi.roots.impl.libraries.LibraryEx; +import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.ui.configuration.LibraryTableModifiableModelProvider; +import com.intellij.openapi.roots.ui.configuration.ModuleEditor; +import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator; +import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable; +import com.intellij.openapi.roots.ui.configuration.artifacts.UsageInArtifact; import com.intellij.openapi.roots.ui.configuration.classpath.ChangeLibraryLevelActionBase; +import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.*; +import com.intellij.packaging.elements.PackagingElement; +import com.intellij.packaging.elements.PackagingElementFactory; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import java.util.Collection; /** * @author nik @@ -37,7 +49,8 @@ public class ChangeLibraryLevelAction extends ChangeLibraryLevelActionBase { public ChangeLibraryLevelAction(@NotNull Project project, @NotNull JComponent parentComponent, @NotNull BaseLibrariesConfigurable sourceConfigurable, @NotNull BaseLibrariesConfigurable targetConfigurable) { - super(project, targetConfigurable.getLibraryTablePresentation().getDisplayName(true), targetConfigurable.getLevel()); + super(project, targetConfigurable.getLibraryTablePresentation().getDisplayName(true), targetConfigurable.getLevel(), + sourceConfigurable instanceof GlobalLibrariesConfigurable); myParentComponent = parentComponent; mySourceConfigurable = sourceConfigurable; myTargetConfigurable = targetConfigurable; @@ -45,22 +58,45 @@ public class ChangeLibraryLevelAction extends ChangeLibraryLevelActionBase { @Override public void actionPerformed(AnActionEvent e) { - final Object selected = mySourceConfigurable.getSelectedObject(); - if (!(selected instanceof LibraryEx)) return; - final LibraryEx library = (LibraryEx)selected; - final LibraryEx actualLibrary = (LibraryEx)mySourceConfigurable.myContext.getLibrary(library.getName(), mySourceConfigurable.getLevel()); - LOG.assertTrue(actualLibrary != null); - doAction(library); + final ProjectStructureElement selectedElement = mySourceConfigurable.getSelectedElement(); + if (!(selectedElement instanceof LibraryProjectStructureElement)) return; + final StructureConfigurableContext context = mySourceConfigurable.myContext; + final Library originalLibrary = ((LibraryProjectStructureElement)selectedElement).getLibrary(); + final LibraryEx oldLibrary = (LibraryEx)context.getLibrary(originalLibrary.getName(), mySourceConfigurable.getLevel()); + LOG.assertTrue(oldLibrary != null); + final Library newLibrary = doCopy(oldLibrary); + if (newLibrary == null) return; + + final ModulesConfigurator configurator = context.getModulesConfigurator(); + final Collection usages = context.getDaemonAnalyzer().getUsages(selectedElement); + for (ProjectStructureElementUsage usage : usages) { + if (usage instanceof UsageInModuleClasspath) { + final Module module = ((UsageInModuleClasspath)usage).getModule(); + final ModuleEditor editor = configurator.getModuleEditor(module); + if (editor != null) { + final ModifiableRootModel rootModel = editor.getModifiableRootModelProxy(); + OrderEntryUtil.replaceLibrary(rootModel, oldLibrary, newLibrary); + context.getDaemonAnalyzer().queueUpdate(new ModuleProjectStructureElement(context, module)); + } + } + else if (usage instanceof UsageInArtifact) { + final PackagingElement libraryElement = PackagingElementFactory.getInstance().createLibraryFiles(newLibrary.getName(), + newLibrary.getTable().getTableLevel(), null); + ((UsageInArtifact)usage).replaceElement(libraryElement); + } + } + + if (!myCopy) { + mySourceConfigurable.getModelProvider().getModifiableModel().removeLibrary(originalLibrary); + context.getDaemonAnalyzer().removeElement(selectedElement); + mySourceConfigurable.removeLibraryNode(originalLibrary); + } + ProjectStructureConfigurable.getInstance(myProject).selectProjectOrGlobalLibrary(newLibrary, true); } @Override protected boolean isEnabled() { - return mySourceConfigurable.getSelectedObject() instanceof LibraryEx; - } - - @Override - protected boolean isCopy() { - return true; + return mySourceConfigurable.getSelectedElement() instanceof LibraryProjectStructureElement; } @Override diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/UsageInModuleClasspath.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/UsageInModuleClasspath.java index 30351e7b0215..7ad2ec53aef6 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/UsageInModuleClasspath.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/UsageInModuleClasspath.java @@ -34,10 +34,14 @@ public class UsageInModuleClasspath extends ProjectStructureElementUsage { } @Override - public ProjectStructureElement getContainingElement() { + public ModuleProjectStructureElement getContainingElement() { return myContainingElement; } + public Module getModule() { + return myModule; + } + @Override public String getPresentableName() { return myModule.getName(); diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEntryUtil.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEntryUtil.java index 61ab227795af..3f07119311dd 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEntryUtil.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEntryUtil.java @@ -150,4 +150,21 @@ public class OrderEntryUtil { } rootModel.commit(); } + + public static void replaceLibrary(@NotNull ModifiableRootModel model, @NotNull Library oldLibrary, @NotNull Library newLibrary) { + OrderEntry[] entries = model.getOrderEntries(); + for (int i = 0; i < entries.length; i++) { + OrderEntry orderEntry = entries[i]; + if (orderEntry instanceof LibraryOrderEntry && oldLibrary.equals(((LibraryOrderEntry)orderEntry).getLibrary())) { + model.removeOrderEntry(orderEntry); + final LibraryOrderEntry newEntry = model.addLibraryEntry(newLibrary); + final OrderEntry[] newEntries = new OrderEntry[entries.length]; + System.arraycopy(entries, 0, newEntries, 0, i); + newEntries[i] = newEntry; + System.arraycopy(entries, i, newEntries, i+1, entries.length - i - 1); + model.rearrangeOrderEntries(newEntries); + return; + } + } + } }