From 09d2e7b454f2da21e53a18300f472eace824740f Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 6 Aug 2010 09:37:27 +0400 Subject: [PATCH] IDEA-25719: Add option to quickly create an application from a module in artifacts --- .../JarArtifactFromModulesDialog.form | 101 ++++++++++ .../JarArtifactFromModulesDialog.java | 141 ++++++++++++++ .../impl/artifacts/JarArtifactType.java | 14 ++ .../artifacts/JarFromModulesTemplate.java | 179 ++++++++++++++++++ .../impl/artifacts/PlainArtifactType.java | 3 +- .../ExtractedDirectoryElementType.java | 12 +- .../ExtractedDirectoryPackagingElement.java | 5 + .../impl/elements/ManifestFileUtil.java | 74 +++++++- .../elements/PackagingElementFactoryImpl.java | 12 ++ .../ElementWithManifestPropertiesPanel.java | 28 +-- .../elements/CompositePackagingElement.java | 20 +- .../elements/PackagingElementFactory.java | 6 +- 12 files changed, 547 insertions(+), 48 deletions(-) create mode 100644 java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.form create mode 100644 java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java create mode 100644 java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarFromModulesTemplate.java diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.form b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.form new file mode 100644 index 000000000000..d9347ab8d981 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.form @@ -0,0 +1,101 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java new file mode 100644 index 000000000000..22a9b83905f9 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java @@ -0,0 +1,141 @@ +/* + * Copyright 2000-2010 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.packaging.impl.artifacts; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.packaging.elements.PackagingElementResolvingContext; +import com.intellij.packaging.impl.elements.ManifestFileUtil; +import com.intellij.ui.DocumentAdapter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import java.awt.*; + +/** + * @author nik + */ +public class JarArtifactFromModulesDialog extends DialogWrapper { + private JPanel myMainPanel; + private TextFieldWithBrowseButton myMainClassField; + private JComboBox myModuleComboBox; + private JLabel myMainClassLabel; + private TextFieldWithBrowseButton myManifestDirField; + private JLabel myManifestDirLabel; + private JRadioButton myExtractJarsRadioButton; + private PackagingElementResolvingContext myContext; + + public JarArtifactFromModulesDialog(PackagingElementResolvingContext context) { + super(context.getProject()); + myContext = context; + setTitle("Create Jar from Modules"); + myMainClassLabel.setLabelFor(myMainClassField.getTextField()); + myManifestDirLabel.setLabelFor(myManifestDirField.getTextField()); + + final Project project = myContext.getProject(); + ManifestFileUtil.setupMainClassField(project, myMainClassField); + myMainClassField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + updateManifestDirField(); + } + }); + + updateManifestDirField(); + myManifestDirField.addBrowseFolderListener(null, null, project, ManifestFileUtil.createDescriptorForManifestDirectory()); + + final Module[] modules = context.getModulesProvider().getModules(); + if (modules.length > 1) { + myModuleComboBox.addItem(null); + } + for (Module module : modules) { + myModuleComboBox.addItem(module); + } + myModuleComboBox.setRenderer(new ModuleListRenderer()); + init(); + } + + private void updateManifestDirField() { + final boolean enable = !myMainClassField.getText().isEmpty() || !myExtractJarsRadioButton.isSelected(); + setManifestDirFieldEnabled(enable); + if (enable && myManifestDirField.getText().isEmpty()) { + final VirtualFile file = ManifestFileUtil.suggestManifestFileDirectory(myContext.getProject(), getSelectedModule()); + if (file != null) { + myManifestDirField.setText(FileUtil.toSystemDependentName(file.getPath())); + } + } + } + + @Nullable + private Module getSelectedModule() { + return (Module)myModuleComboBox.getSelectedItem(); + } + + @NotNull + public Module[] getSelectedModules() { + final Module module = getSelectedModule(); + if (module != null) { + return new Module[]{module}; + } + return myContext.getModulesProvider().getModules(); + } + + @NotNull + public String getDirectoryForManifest() { + return FileUtil.toSystemIndependentName(myManifestDirField.getText()); + } + + public boolean isExtractLibrariesToJar() { + return myExtractJarsRadioButton.isSelected(); + } + + public String getMainClassName() { + return myMainClassField.getText(); + } + + private void setManifestDirFieldEnabled(boolean enabled) { + myManifestDirLabel.setEnabled(enabled); + myManifestDirField.setEnabled(enabled); + } + + @Override + protected JComponent createCenterPanel() { + return myMainPanel; + } + + private static class ModuleListRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + final Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof Module) { + final Module module = (Module)value; + setIcon(module.getModuleType().getNodeIcon(false)); + setText(module.getName()); + } + else { + setText(""); + setIcon(null); + } + return component; + } + } +} diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactType.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactType.java index 01bcd7153c86..47d0033a6e09 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactType.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactType.java @@ -16,13 +16,17 @@ package com.intellij.packaging.impl.artifacts; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.packaging.artifacts.ArtifactTemplate; import com.intellij.packaging.artifacts.ArtifactType; import com.intellij.packaging.elements.CompositePackagingElement; import com.intellij.packaging.elements.PackagingElementOutputKind; +import com.intellij.packaging.elements.PackagingElementResolvingContext; import com.intellij.packaging.impl.elements.ArchivePackagingElement; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import java.util.Collections; +import java.util.List; /** * @author nik @@ -32,6 +36,10 @@ public class JarArtifactType extends ArtifactType { super("jar", "Jar"); } + public static JarArtifactType getInstance() { + return EP_NAME.findExtension(JarArtifactType.class); + } + @NotNull @Override public Icon getIcon() { @@ -48,4 +56,10 @@ public class JarArtifactType extends ArtifactType { public CompositePackagingElement createRootElement(@NotNull String artifactName) { return new ArchivePackagingElement(FileUtil.sanitizeFileName(artifactName) + ".jar"); } + + @NotNull + @Override + public List getNewArtifactTemplates(@NotNull PackagingElementResolvingContext context) { + return Collections.singletonList(new JarFromModulesTemplate(context)); + } } diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarFromModulesTemplate.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarFromModulesTemplate.java new file mode 100644 index 000000000000..976533aaa8de --- /dev/null +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarFromModulesTemplate.java @@ -0,0 +1,179 @@ +/* + * Copyright 2000-2010 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.packaging.impl.artifacts; + +import com.intellij.CommonBundle; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.packaging.artifacts.ArtifactTemplate; +import com.intellij.packaging.elements.*; +import com.intellij.packaging.impl.elements.LibraryPackagingElement; +import com.intellij.packaging.impl.elements.ManifestFileUtil; +import com.intellij.util.PathUtil; +import com.intellij.util.Processor; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashSet; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.*; + +/** + * @author nik + */ +public class JarFromModulesTemplate extends ArtifactTemplate { + private static final Logger LOG = Logger.getInstance("#com.intellij.packaging.impl.artifacts.JarFromModulesTemplate"); + + private PackagingElementResolvingContext myContext; + + public JarFromModulesTemplate(PackagingElementResolvingContext context) { + myContext = context; + } + + @Override + public NewArtifactConfiguration createArtifact() { + JarArtifactFromModulesDialog dialog = new JarArtifactFromModulesDialog(myContext); + dialog.show(); + if (!dialog.isOK()) { + return null; + } + + return doCreateArtifact(dialog.getSelectedModules(), dialog.getMainClassName(), dialog.getDirectoryForManifest(), + dialog.isExtractLibrariesToJar()); + } + + @Nullable + public NewArtifactConfiguration doCreateArtifact(final Module[] modules, final String mainClassName, + final String directoryForManifest, final boolean extractLibrariesToJar) { + VirtualFile manifestFile = null; + final Project project = myContext.getProject(); + if (mainClassName != null && !mainClassName.isEmpty() || !extractLibrariesToJar) { + final VirtualFile directory; + try { + directory = VfsUtil.createDirectoryIfMissing(directoryForManifest); + } + catch (IOException e) { + LOG.info(e); + Messages.showErrorDialog(project, "Cannot create directory '" + directoryForManifest + "': " + e.getMessage(), + CommonBundle.getErrorTitle()); + return null; + } + if (directory == null) return null; + + manifestFile = ManifestFileUtil.createManifestFile(directory, project); + if (manifestFile == null) { + return null; + } + ManifestFileUtil.updateManifest(manifestFile, mainClassName, null, true); + } + + String name = modules.length == 1 ? modules[0].getName() : project.getName(); + + final PackagingElementFactory factory = PackagingElementFactory.getInstance(); + final CompositePackagingElement archive = factory.createArchive(FileUtil.sanitizeFileName(name) + ".jar"); + + final OrderEnumerator orderEnumerator = ProjectRootManager.getInstance(project).orderEntries(Arrays.asList(modules)); + + final Set libraries = new THashSet(); + orderEnumerator.using(myContext.getModulesProvider()).withoutSdk().productionOnly().runtimeOnly().recursively().forEach(new Processor() { + @Override + public boolean process(OrderEntry orderEntry) { + if (orderEntry instanceof ModuleSourceOrderEntry) { + archive.addOrFindChild(factory.createModuleOutput(orderEntry.getOwnerModule())); + } + else if (orderEntry instanceof LibraryOrderEntry) { + ContainerUtil.addIfNotNull(((LibraryOrderEntry)orderEntry).getLibrary(), libraries); + } + return true; + } + }); + + final JarArtifactType jarArtifactType = JarArtifactType.getInstance(); + if (manifestFile != null && !manifestFile.equals(ManifestFileUtil.findManifestFile(archive, myContext, jarArtifactType))) { + archive.addFirstChild(factory.createFileCopyWithParentDirectories(manifestFile.getPath(), ManifestFileUtil.MANIFEST_DIR_NAME)); + } + + final String artifactName = name + ":jar"; + if (extractLibrariesToJar) { + addExtractedLibrariesToJar(archive, factory, libraries); + return new NewArtifactConfiguration(archive, artifactName, jarArtifactType); + } + else { + final ArtifactRootElement root = factory.createArtifactRootElement(); + List classpath = new ArrayList(); + root.addOrFindChild(archive); + addLibraries(libraries, root, archive, classpath); + ManifestFileUtil.updateManifest(manifestFile, mainClassName, classpath, true); + return new NewArtifactConfiguration(root, artifactName, PlainArtifactType.getInstance()); + } + } + + private void addLibraries(Set libraries, ArtifactRootElement root, CompositePackagingElement archive, + List classpath) { + PackagingElementFactory factory = PackagingElementFactory.getInstance(); + for (Library library : libraries) { + if (LibraryPackagingElement.getKindForLibrary(library).containsDirectoriesWithClasses()) { + for (VirtualFile classesRoot : library.getFiles(OrderRootType.CLASSES)) { + if (classesRoot.isInLocalFileSystem()) { + archive.addOrFindChild(factory.createDirectoryCopyWithParentDirectories(classesRoot.getPath(), "/")); + } + else { + final PackagingElement child = factory.createFileCopyWithParentDirectories(PathUtil.getLocalFile(classesRoot).getPath(), "/"); + root.addOrFindChild(child); + classpath.addAll(ManifestFileUtil.getClasspathForElements(Collections.singletonList(child), myContext, PlainArtifactType.getInstance())); + } + } + + } + else { + final List> children = factory.createLibraryElements(library); + classpath.addAll(ManifestFileUtil.getClasspathForElements(children, myContext, PlainArtifactType.getInstance())); + root.addOrFindChildren(children); + } + } + } + + private static void addExtractedLibrariesToJar(CompositePackagingElement archive, PackagingElementFactory factory, Set libraries) { + for (Library library : libraries) { + if (LibraryPackagingElement.getKindForLibrary(library).containsJarFiles()) { + for (VirtualFile classesRoot : library.getFiles(OrderRootType.CLASSES)) { + if (classesRoot.isInLocalFileSystem()) { + archive.addOrFindChild(factory.createDirectoryCopyWithParentDirectories(classesRoot.getPath(), "/")); + } + else { + archive.addOrFindChild(factory.createExtractedDirectory(classesRoot)); + } + } + + } + else { + archive.addOrFindChildren(factory.createLibraryElements(library)); + } + } + } + + @Override + public String getPresentableName() { + return "Jar from Modules..."; + } +} diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/PlainArtifactType.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/PlainArtifactType.java index 4cd6ab503037..b720824c04f3 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/PlainArtifactType.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/PlainArtifactType.java @@ -21,7 +21,6 @@ import com.intellij.packaging.artifacts.ArtifactType; import com.intellij.packaging.elements.CompositePackagingElement; import com.intellij.packaging.elements.PackagingElementOutputKind; import com.intellij.packaging.impl.elements.ArtifactRootElementImpl; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -35,7 +34,7 @@ public class PlainArtifactType extends ArtifactType { @NonNls public static final String ID = "plain"; public static PlainArtifactType getInstance() { - return ContainerUtil.findInstance(getAllTypes(), PlainArtifactType.class); + return EP_NAME.findExtension(PlainArtifactType.class); } public PlainArtifactType() { diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ExtractedDirectoryElementType.java b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ExtractedDirectoryElementType.java index 34be7a6e00bf..ab4c1e9efe34 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ExtractedDirectoryElementType.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ExtractedDirectoryElementType.java @@ -20,10 +20,11 @@ import com.intellij.openapi.fileChooser.FileChooserDialog; import com.intellij.openapi.fileChooser.FileChooserFactory; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.IconLoader; -import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.packaging.artifacts.Artifact; import com.intellij.packaging.elements.CompositePackagingElement; +import com.intellij.packaging.elements.PackagingElement; +import com.intellij.packaging.elements.PackagingElementFactory; import com.intellij.packaging.elements.PackagingElementType; import com.intellij.packaging.ui.ArtifactEditorContext; import org.jetbrains.annotations.NotNull; @@ -53,7 +54,7 @@ public class ExtractedDirectoryElementType extends PackagingElementType chooseAndCreate(@NotNull ArtifactEditorContext context, @NotNull Artifact artifact, + public List> chooseAndCreate(@NotNull ArtifactEditorContext context, @NotNull Artifact artifact, @NotNull CompositePackagingElement parent) { final FileChooserDescriptor descriptor = new FileChooserDescriptor(false, true, true, false, true, true) { @Override @@ -64,11 +65,10 @@ public class ExtractedDirectoryElementType extends PackagingElementType list = new ArrayList(); + final List> list = new ArrayList>(); + final PackagingElementFactory factory = PackagingElementFactory.getInstance(); for (VirtualFile file : files) { - final String fullPath = file.getPath(); - final int jarEnd = fullPath.indexOf(JarFileSystem.JAR_SEPARATOR); - list.add(new ExtractedDirectoryPackagingElement(fullPath.substring(0, jarEnd), fullPath.substring(jarEnd + 1))); + list.add(factory.createExtractedDirectory(file)); } return list; } diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ExtractedDirectoryPackagingElement.java b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ExtractedDirectoryPackagingElement.java index 112f8c4cf95c..a0b4ddabe537 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ExtractedDirectoryPackagingElement.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ExtractedDirectoryPackagingElement.java @@ -63,6 +63,11 @@ public class ExtractedDirectoryPackagingElement extends FileOrDirectoryCopyPacka return new ExtractedDirectoryPresentation(this); } + @Override + public String toString() { + return "extracted:" + myFilePath + "!" + myPathInJar; + } + @Override public VirtualFile findFile() { final VirtualFile jarFile = super.findFile(); diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ManifestFileUtil.java b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ManifestFileUtil.java index 21433a5e74e3..392d58aa7e8d 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ManifestFileUtil.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ManifestFileUtil.java @@ -16,6 +16,9 @@ package com.intellij.packaging.impl.elements; import com.intellij.CommonBundle; +import com.intellij.ide.util.TreeClassChooser; +import com.intellij.ide.util.TreeClassChooserFactory; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.compiler.make.ManifestBuilder; @@ -24,9 +27,12 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; +import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.OrderEnumerator; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -42,10 +48,16 @@ import com.intellij.packaging.impl.artifacts.PackagingElementPath; import com.intellij.packaging.impl.artifacts.PackagingElementProcessor; import com.intellij.packaging.ui.ArtifactEditorContext; import com.intellij.packaging.ui.ManifestFileConfiguration; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClass; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.PsiMethodUtil; import com.intellij.util.PathUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -111,7 +123,18 @@ public class ManifestFileUtil { } @Nullable - private static VirtualFile suggestBaseDir(Project project, final @Nullable VirtualFile file) { + public static VirtualFile suggestManifestFileDirectory(@NotNull Project project, @Nullable Module module) { + OrderEnumerator enumerator = module != null ? OrderEnumerator.orderEntries(module) : OrderEnumerator.orderEntries(project); + final VirtualFile[] files = enumerator.withoutDepModules().withoutLibraries().withoutSdk().productionOnly().sources().getRoots(); + if (files.length > 0) { + return files[0]; + } + return suggestBaseDir(project, null); + } + + + @Nullable + private static VirtualFile suggestBaseDir(@NotNull Project project, final @Nullable VirtualFile file) { final VirtualFile[] contentRoots = ProjectRootManager.getInstance(project).getContentRoots(); if (file == null && contentRoots.length > 0) { return contentRoots[0]; @@ -145,7 +168,7 @@ public class ManifestFileUtil { } } - public static void updateManifest(VirtualFile file, final String mainClass, final List classpath, final boolean replaceValues) { + public static void updateManifest(@NotNull VirtualFile file, final @Nullable String mainClass, final @Nullable List classpath, final boolean replaceValues) { final Manifest manifest = readManifest(file); final Attributes mainAttributes = manifest.getMainAttributes(); @@ -235,18 +258,23 @@ public class ManifestFileUtil { @Nullable public static VirtualFile showDialogAndCreateManifest(final ArtifactEditorContext context, final CompositePackagingElement element) { - FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); - descriptor.setTitle("Select Directory for META-INF/MANIFEST.MF file"); + FileChooserDescriptor descriptor = createDescriptorForManifestDirectory(); final VirtualFile directory = suggestManifestFileDirectory(element, context, context.getArtifactType()); final VirtualFile[] files = FileChooser.chooseFiles(context.getProject(), descriptor, directory); if (files.length != 1) { return null; } + return createManifestFile(files[0], context.getProject()); + } + + @Nullable + public static VirtualFile createManifestFile(final @NotNull VirtualFile directory, final @NotNull Project project) { + ApplicationManager.getApplication().assertIsDispatchThread(); final Ref exc = Ref.create(null); final VirtualFile file = new WriteAction() { protected void run(final Result result) { - VirtualFile dir = files[0]; + VirtualFile dir = directory; try { if (!dir.getName().equals(MANIFEST_DIR_NAME)) { dir = VfsUtil.createDirectoryIfMissing(dir, MANIFEST_DIR_NAME); @@ -272,12 +300,18 @@ public class ManifestFileUtil { final IOException exception = exc.get(); if (exception != null) { LOG.info(exception); - Messages.showErrorDialog(context.getProject(), exception.getMessage(), CommonBundle.getErrorTitle()); + Messages.showErrorDialog(project, exception.getMessage(), CommonBundle.getErrorTitle()); return null; } return file; } + public static FileChooserDescriptor createDescriptorForManifestDirectory() { + FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); + descriptor.setTitle("Select Directory for META-INF/MANIFEST.MF file"); + return descriptor; + } + public static void addManifestFileToLayout(final @NotNull String path, final @NotNull ArtifactEditorContext context, final @NotNull CompositePackagingElement element) { context.editLayout(context.getArtifact(), new Runnable() { @@ -289,4 +323,32 @@ public class ManifestFileUtil { } }); } + + @Nullable + public static PsiClass selectMainClass(Project project, final @Nullable String initialClassName) { + final TreeClassChooserFactory chooserFactory = TreeClassChooserFactory.getInstance(project); + final GlobalSearchScope searchScope = GlobalSearchScope.allScope(project); + final PsiClass aClass = initialClassName != null ? JavaPsiFacade.getInstance(project).findClass(initialClassName, searchScope) : null; + final TreeClassChooser chooser = + chooserFactory.createWithInnerClassesScopeChooser("Select Main Class", searchScope, new MainClassFilter(), aClass); + chooser.showDialog(); + return chooser.getSelectedClass(); + } + + public static void setupMainClassField(final Project project, final TextFieldWithBrowseButton field) { + field.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + final PsiClass selected = selectMainClass(project, field.getText()); + if (selected != null) { + field.setText(selected.getQualifiedName()); + } + } + }); + } + + private static class MainClassFilter implements TreeClassChooser.ClassFilter { + public boolean isAccepted(PsiClass aClass) { + return PsiMethodUtil.MAIN_CLASS.value(aClass) && PsiMethodUtil.hasMainMethod(aClass); + } + } } diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/PackagingElementFactoryImpl.java b/java/compiler/impl/src/com/intellij/packaging/impl/elements/PackagingElementFactoryImpl.java index be6c0b32993f..7ec062a7101a 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/elements/PackagingElementFactoryImpl.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/elements/PackagingElementFactoryImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.packaging.impl.elements; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModulePointer; @@ -27,6 +28,7 @@ import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; 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.VirtualFile; import com.intellij.packaging.artifacts.Artifact; import com.intellij.packaging.artifacts.ArtifactPointer; @@ -47,6 +49,7 @@ import java.util.List; * @author nik */ public class PackagingElementFactoryImpl extends PackagingElementFactory { + private static final Logger LOG = Logger.getInstance("#com.intellij.packaging.impl.elements.PackagingElementFactoryImpl"); public static final PackagingElementType DIRECTORY_ELEMENT_TYPE = new DirectoryElementType(); public static final PackagingElementType ARCHIVE_ELEMENT_TYPE = new ArchiveElementType(); public static final PackagingElementType FILE_COPY_ELEMENT_TYPE = new FileCopyElementType(); @@ -261,6 +264,15 @@ public class PackagingElementFactoryImpl extends PackagingElementFactory { return createParentDirectories(relativeOutputPath, new ExtractedDirectoryPackagingElement(jarPath, pathInJar)); } + @NotNull + @Override + public PackagingElement createExtractedDirectory(@NotNull VirtualFile jarEntry) { + LOG.assertTrue(jarEntry.getFileSystem() instanceof JarFileSystem, "Expected file from jar but file from " + jarEntry.getFileSystem() + " found"); + final String fullPath = jarEntry.getPath(); + final int jarEnd = fullPath.indexOf(JarFileSystem.JAR_SEPARATOR); + return new ExtractedDirectoryPackagingElement(fullPath.substring(0, jarEnd), fullPath.substring(jarEnd + 1)); + } + @NotNull @Override public PackagingElement createFileCopyWithParentDirectories(@NotNull String filePath, @NotNull String relativeOutputPath) { diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/ui/properties/ElementWithManifestPropertiesPanel.java b/java/compiler/impl/src/com/intellij/packaging/impl/ui/properties/ElementWithManifestPropertiesPanel.java index 0d8cc91fbd75..9aad9c69c6da 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/ui/properties/ElementWithManifestPropertiesPanel.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/ui/properties/ElementWithManifestPropertiesPanel.java @@ -15,11 +15,8 @@ */ package com.intellij.packaging.impl.ui.properties; -import com.intellij.ide.util.TreeClassChooser; -import com.intellij.ide.util.TreeClassChooserFactory; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; -import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Comparing; @@ -31,10 +28,6 @@ import com.intellij.packaging.impl.elements.ManifestFileUtil; import com.intellij.packaging.ui.ArtifactEditorContext; import com.intellij.packaging.ui.ManifestFileConfiguration; import com.intellij.packaging.ui.PackagingElementPropertiesPanel; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiClass; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.PsiMethodUtil; import com.intellij.ui.DocumentAdapter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -67,21 +60,7 @@ public abstract class ElementWithManifestPropertiesPanel extends PackagingElement i } } myChildren.add(child); - myUnmodifiableChildren = null; return child; } + public void addFirstChild(@NotNull PackagingElement child) { + myChildren.add(0, child); + for (int i = 1; i < myChildren.size(); i++) { + PackagingElement element = myChildren.get(i); + if (element.isEqualTo(child)) { + if (element instanceof CompositePackagingElement) { + ((CompositePackagingElement)child).addOrFindChildren(((CompositePackagingElement)element).getChildren()); + } + myChildren.remove(i); + break; + } + } + } + public List> addOrFindChildren(Collection> children) { List> added = new ArrayList>(); for (PackagingElement child : children) { added.add(addOrFindChild(child)); } - myUnmodifiableChildren = null; return added; } @@ -69,7 +81,6 @@ public abstract class CompositePackagingElement extends PackagingElement i final PackagingElement element2 = myChildren.get(target); myChildren.set(index, element2); myChildren.set(target, element1); - myUnmodifiableChildren = null; return element1; } return null; @@ -77,12 +88,10 @@ public abstract class CompositePackagingElement extends PackagingElement i public void removeChild(@NotNull PackagingElement child) { myChildren.remove(child); - myUnmodifiableChildren = null; } public void removeChildren(@NotNull Collection> children) { myChildren.removeAll(children); - myUnmodifiableChildren = null; } @NotNull @@ -117,6 +126,5 @@ public abstract class CompositePackagingElement extends PackagingElement i public void removeAllChildren() { myChildren.clear(); - myUnmodifiableChildren = null; } } diff --git a/java/compiler/openapi/src/com/intellij/packaging/elements/PackagingElementFactory.java b/java/compiler/openapi/src/com/intellij/packaging/elements/PackagingElementFactory.java index 2cbad503ce6a..eaf0c6f2554e 100644 --- a/java/compiler/openapi/src/com/intellij/packaging/elements/PackagingElementFactory.java +++ b/java/compiler/openapi/src/com/intellij/packaging/elements/PackagingElementFactory.java @@ -17,8 +17,9 @@ package com.intellij.packaging.elements; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.module.Module; -import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.packaging.artifacts.Artifact; import com.intellij.packaging.artifacts.ArtifactPointer; import org.jetbrains.annotations.NonNls; @@ -71,6 +72,9 @@ public abstract class PackagingElementFactory { public abstract PackagingElement createExtractedDirectoryWithParentDirectories(@NotNull String jarPath, @NotNull String pathInJar, @NotNull String relativeOutputPath); + @NotNull + public abstract PackagingElement createExtractedDirectory(@NotNull VirtualFile jarEntry); + @NotNull public abstract PackagingElement createFileCopyWithParentDirectories(@NotNull String filePath, @NotNull String relativeOutputPath, @Nullable String outputFileName);