diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentEntriesEditor.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentEntriesEditor.java index 2ed1ac7db662..2c6d8d8fb7ff 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentEntriesEditor.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentEntriesEditor.java @@ -30,6 +30,7 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.concurrency.SwingWorker; +import org.jetbrains.jps.model.java.JavaSourceRootType; import javax.swing.*; import java.awt.*; @@ -41,12 +42,12 @@ import java.util.Map; public class JavaContentEntriesEditor extends CommonContentEntriesEditor { public JavaContentEntriesEditor(String moduleName, ModuleConfigurationState state) { - super(moduleName, state, true, true); + super(moduleName, state, JavaSourceRootType.SOURCE, JavaSourceRootType.TEST_SOURCE); } @Override protected ContentEntryEditor createContentEntryEditor(final String contentEntryUrl) { - return new JavaContentEntryEditor(contentEntryUrl) { + return new JavaContentEntryEditor(contentEntryUrl, getEditHandlers()) { @Override protected ModifiableRootModel getModel() { return JavaContentEntriesEditor.this.getModel(); @@ -54,11 +55,6 @@ public class JavaContentEntriesEditor extends CommonContentEntriesEditor { }; } - @Override - protected ContentEntryTreeEditor createContentEntryTreeEditor(Project project) { - return new ContentEntryTreeEditor(project, true, true); - } - @Override protected List addContentEntries(VirtualFile[] files) { List contentEntries = super.addContentEntries(files); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentEntryEditor.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentEntryEditor.java index 41b8c8d057ec..7d3c535fcd9b 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentEntryEditor.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentEntryEditor.java @@ -18,28 +18,38 @@ package com.intellij.openapi.roots.ui.configuration; import com.intellij.openapi.roots.CompilerModuleExtension; import com.intellij.openapi.roots.ContentEntry; import com.intellij.openapi.roots.ExcludeFolder; +import com.intellij.openapi.roots.SourceFolder; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; +import java.util.List; + public abstract class JavaContentEntryEditor extends ContentEntryEditor { private final CompilerModuleExtension myCompilerExtension; - public JavaContentEntryEditor(final String contentEntryUrl) { - super(contentEntryUrl, true, true); + public JavaContentEntryEditor(final String contentEntryUrl, List> moduleSourceRootEditHandlers) { + super(contentEntryUrl, moduleSourceRootEditHandlers); myCompilerExtension = getModel().getModuleExtension(CompilerModuleExtension.class); } @Override protected ContentRootPanel createContentRootPane() { - return new JavaContentRootPanel(this) { + return new ContentRootPanel(this, getEditHandlers()) { @Nullable @Override protected ContentEntry getContentEntry() { return JavaContentEntryEditor.this.getContentEntry(); } + + @Nullable + @Override + protected JComponent createRootPropertiesEditor(ModuleSourceRootEditHandler editor, SourceFolder folder) { + return editor.createPropertiesEditor(folder, this, myCallback); + } }; } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentRootPanel.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentRootPanel.java deleted file mode 100644 index d0af3a1c4694..000000000000 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentRootPanel.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2000-2009 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.openapi.roots.ui.configuration; - -import com.intellij.icons.AllIcons; -import com.intellij.openapi.project.ProjectBundle; -import com.intellij.openapi.roots.ContentFolder; -import com.intellij.openapi.roots.SourceFolder; -import com.intellij.openapi.ui.Messages; -import com.intellij.ui.roots.IconActionComponent; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; - -public abstract class JavaContentRootPanel extends ContentRootPanel { - - public JavaContentRootPanel(ActionCallback callback) { - super(callback, true, true); - } - - @Override - @Nullable - protected JComponent createAdditionalComponent(ContentFolder folder) { - if (folder instanceof SourceFolder) { - return createAddPrefixComponent((SourceFolder)folder); - } - return null; - } - - private JComponent createAddPrefixComponent(final SourceFolder folder) { - final IconActionComponent iconComponent = new IconActionComponent(AllIcons.Modules.SetPackagePrefix, - AllIcons.Modules.SetPackagePrefixRollover, - ProjectBundle.message("module.paths.package.prefix.tooltip"), new Runnable() { - @Override - public void run() { - final String message = ProjectBundle.message("module.paths.package.prefix.prompt", - toRelativeDisplayPath(folder.getUrl(), getContentEntry().getUrl() + ":")); - final String prefix = Messages.showInputDialog(JavaContentRootPanel.this, message, - ProjectBundle.message("module.paths.package.prefix.title"), Messages.getQuestionIcon(), folder.getPackagePrefix(), null); - if (prefix != null) { - myCallback.setPackagePrefix(folder, prefix); - } - } - }); - final JPanel panel = new JPanel(new BorderLayout()); - panel.setOpaque(false); - panel.add(iconComponent, BorderLayout.CENTER); - panel.add(Box.createHorizontalStrut(3), BorderLayout.EAST); - return panel; - } -} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/ModuleAwareContentRoot.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/ModuleAwareContentRoot.java index 789203e75839..8479bfc259c2 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/ModuleAwareContentRoot.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/ModuleAwareContentRoot.java @@ -6,6 +6,8 @@ import com.intellij.openapi.roots.ExcludeFolder; import com.intellij.openapi.roots.SourceFolder; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.model.JpsElement; +import org.jetbrains.jps.model.module.JpsModuleSourceRootType; /** * @author Denis Zhdanov @@ -77,6 +79,14 @@ public class ModuleAwareContentRoot implements ContentEntry { return myDelegate.addSourceFolder(file, isTestSource, packagePrefix); } + @NotNull + @Override + public

SourceFolder addSourceFolder(@NotNull VirtualFile file, + @NotNull JpsModuleSourceRootType

type, + @NotNull P properties) { + return myDelegate.addSourceFolder(file, type, properties); + } + @Override public SourceFolder addSourceFolder(@NotNull String url, boolean isTestSource) { return myDelegate.addSourceFolder(url, isTestSource); diff --git a/platform/lang-impl/src/com/intellij/openapi/module/WebModuleConfigurationEditorProvider.java b/platform/lang-impl/src/com/intellij/openapi/module/WebModuleConfigurationEditorProvider.java index a65052d6c18a..fd1b91d740de 100644 --- a/platform/lang-impl/src/com/intellij/openapi/module/WebModuleConfigurationEditorProvider.java +++ b/platform/lang-impl/src/com/intellij/openapi/module/WebModuleConfigurationEditorProvider.java @@ -26,6 +26,6 @@ public class WebModuleConfigurationEditorProvider implements ModuleConfiguration if (!WebModuleTypeBase.isWebModule(module)) { return ModuleConfigurationEditor.EMPTY; } - return new ModuleConfigurationEditor[]{new CommonContentEntriesEditor(module.getName(), state, false, false)}; + return new ModuleConfigurationEditor[]{new CommonContentEntriesEditor(module.getName(), state)}; } } diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java index af1c3384f5e7..684284552231 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java @@ -43,9 +43,11 @@ import com.intellij.openapi.vfs.ex.VirtualFileManagerAdapter; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.roots.ToolbarPanel; import com.intellij.util.Consumer; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.module.JpsModuleSourceRootType; import javax.swing.*; import javax.swing.border.Border; @@ -77,16 +79,16 @@ public class CommonContentEntriesEditor extends ModuleElementsEditor { private final String myModuleName; private final ModulesProvider myModulesProvider; private final ModuleConfigurationState myState; - private final boolean myCanMarkSources; - private final boolean myCanMarkTestSources; + private final List> myEditHandlers = new ArrayList>(); - public CommonContentEntriesEditor(String moduleName, final ModuleConfigurationState state, boolean canMarkSources, boolean canMarkTestSources) { + public CommonContentEntriesEditor(String moduleName, final ModuleConfigurationState state, JpsModuleSourceRootType... rootTypes) { super(state); myState = state; myModuleName = moduleName; - myCanMarkSources = canMarkSources; - myCanMarkTestSources = canMarkTestSources; myModulesProvider = state.getModulesProvider(); + for (JpsModuleSourceRootType type : rootTypes) { + ContainerUtil.addIfNotNull(myEditHandlers, findEditHandler(type)); + } final VirtualFileManagerAdapter fileManagerListener = new VirtualFileManagerAdapter() { @Override public void afterRefreshFinish(boolean asynchronous) { @@ -110,6 +112,16 @@ public class CommonContentEntriesEditor extends ModuleElementsEditor { }); } + @Nullable + private static ModuleSourceRootEditHandler findEditHandler(JpsModuleSourceRootType type) { + for (ModuleSourceRootEditHandler editor : ModuleSourceRootEditHandler.EP_NAME.getExtensions()) { + if (editor.getRootType().equals(type)) { + return editor; + } + } + return null; + } + @Override protected ModifiableRootModel getModel() { return myState.getRootModel(); @@ -125,6 +137,10 @@ public class CommonContentEntriesEditor extends ModuleElementsEditor { return NAME; } + protected final List> getEditHandlers() { + return myEditHandlers; + } + @Override public void disposeUIResources() { if (myRootTreeEditor != null) { @@ -197,7 +213,7 @@ public class CommonContentEntriesEditor extends ModuleElementsEditor { } protected ContentEntryTreeEditor createContentEntryTreeEditor(Project project) { - return new ContentEntryTreeEditor(project, myCanMarkSources, myCanMarkTestSources); + return new ContentEntryTreeEditor(project, myEditHandlers); } protected void addAdditionalSettingsToPanel(final JPanel mainPanel) { @@ -229,7 +245,7 @@ public class CommonContentEntriesEditor extends ModuleElementsEditor { } protected ContentEntryEditor createContentEntryEditor(String contentEntryUrl) { - return new ContentEntryEditor(contentEntryUrl, myCanMarkSources, myCanMarkTestSources) { + return new ContentEntryEditor(contentEntryUrl, myEditHandlers) { @Override protected ModifiableRootModel getModel() { return CommonContentEntriesEditor.this.getModel(); diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java index f6adae4fe9e9..705df244f7eb 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java @@ -25,12 +25,18 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.EventDispatcher; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.JpsElement; +import org.jetbrains.jps.model.JpsElementFactory; +import org.jetbrains.jps.model.java.JavaSourceRootProperties; +import org.jetbrains.jps.model.java.JavaSourceRootType; +import org.jetbrains.jps.model.module.JpsModuleSourceRootType; import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.EventListener; +import java.util.*; +import java.util.List; /** * @author Eugene Zhuravlev @@ -43,24 +49,27 @@ public abstract class ContentEntryEditor implements ContentRootPanel.ActionCallb private JPanel myMainPanel; protected EventDispatcher myEventDispatcher; private final String myContentEntryUrl; - protected final boolean myCanMarkSources; - protected final boolean myCanMarkTestSources; + private final List> myEditHandlers; public interface ContentEntryEditorListener extends EventListener{ + void editingStarted(@NotNull ContentEntryEditor editor); void beforeEntryDeleted(@NotNull ContentEntryEditor editor); void sourceFolderAdded(@NotNull ContentEntryEditor editor, SourceFolder folder); - void sourceFolderRemoved(@NotNull ContentEntryEditor editor, VirtualFile file, boolean isTestSource); + void sourceFolderRemoved(@NotNull ContentEntryEditor editor, VirtualFile file); void folderExcluded(@NotNull ContentEntryEditor editor, VirtualFile file); void folderIncluded(@NotNull ContentEntryEditor editor, VirtualFile file); void navigationRequested(@NotNull ContentEntryEditor editor, VirtualFile file); - void packagePrefixSet(@NotNull ContentEntryEditor editor, @NotNull SourceFolder folder); + void sourceRootPropertiesChanged(@NotNull ContentEntryEditor editor, @NotNull SourceFolder folder); } - public ContentEntryEditor(final String contentEntryUrl, boolean canMarkSources, boolean canMarkTestSources) { - myContentEntryUrl = contentEntryUrl; - myCanMarkSources = canMarkSources; - myCanMarkTestSources = canMarkTestSources; + public ContentEntryEditor(String url, List> editHandlers) { + myContentEntryUrl = url; + myEditHandlers = editHandlers; + } + + protected final List> getEditHandlers() { + return myEditHandlers; } public String getContentEntryUrl() { @@ -145,10 +154,9 @@ public abstract class ContentEntryEditor implements ContentRootPanel.ActionCallb } @Override - public void setPackagePrefix(@NotNull SourceFolder folder, @NotNull String prefix) { - folder.setPackagePrefix(prefix); + public void onSourceRootPropertiesChanged(@NotNull SourceFolder folder) { update(); - myEventDispatcher.getMulticaster().packagePrefixSet(this, folder); + myEventDispatcher.getMulticaster().sourceRootPropertiesChanged(this, folder); } public void addContentEntryEditorListener(ContentEntryEditorListener listener) { @@ -188,7 +196,7 @@ public abstract class ContentEntryEditor implements ContentRootPanel.ActionCallb } protected ContentRootPanel createContentRootPane() { - return new ContentRootPanel(this, myCanMarkSources, myCanMarkTestSources) { + return new ContentRootPanel(this, myEditHandlers) { @Override protected ContentEntry getContentEntry() { return ContentEntryEditor.this.getContentEntry(); @@ -198,16 +206,19 @@ public abstract class ContentEntryEditor implements ContentRootPanel.ActionCallb @Nullable public SourceFolder addSourceFolder(@NotNull final VirtualFile file, boolean isTestSource, String packagePrefix) { + return addSourceFolder(file, isTestSource ? JavaSourceRootType.TEST_SOURCE : JavaSourceRootType.SOURCE, + JpsElementFactory.getInstance().createSimpleElement(new JavaSourceRootProperties(packagePrefix))); + } + + @Nullable + public

SourceFolder addSourceFolder(@NotNull final VirtualFile file, final JpsModuleSourceRootType

rootType, + final P properties) { final ContentEntry contentEntry = getContentEntry(); if (contentEntry != null) { - final SourceFolder sourceFolder = contentEntry.addSourceFolder(file, isTestSource, packagePrefix); - try { - return sourceFolder; - } - finally { - myEventDispatcher.getMulticaster().sourceFolderAdded(this, sourceFolder); - update(); - } + final SourceFolder sourceFolder = contentEntry.addSourceFolder(file, rootType, properties); + myEventDispatcher.getMulticaster().sourceFolderAdded(this, sourceFolder); + update(); + return sourceFolder; } return null; @@ -224,7 +235,7 @@ public abstract class ContentEntryEditor implements ContentRootPanel.ActionCallb doRemoveSourceFolder(sourceFolder); } finally { - myEventDispatcher.getMulticaster().sourceFolderRemoved(this, sourceFolder.getFile(), sourceFolder.isTestSource()); + myEventDispatcher.getMulticaster().sourceFolderRemoved(this, sourceFolder.getFile()); update(); } } @@ -268,14 +279,10 @@ public abstract class ContentEntryEditor implements ContentRootPanel.ActionCallb } } - public boolean isSource(@NotNull final VirtualFile file) { - final SourceFolder sourceFolder = getSourceFolder(file); - return sourceFolder != null && !sourceFolder.isTestSource(); - } - - public boolean isTestSource(@NotNull final VirtualFile file) { - final SourceFolder sourceFolder = getSourceFolder(file); - return sourceFolder != null && sourceFolder.isTestSource(); + @Nullable + public JpsModuleSourceRootType getRootType(@NotNull VirtualFile file) { + SourceFolder folder = getSourceFolder(file); + return folder != null ? folder.getRootType() : null; } public boolean isExcluded(@NotNull final VirtualFile file) { diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditorListenerAdapter.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditorListenerAdapter.java index e21475f49eec..2b4b9b98c0d2 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditorListenerAdapter.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditorListenerAdapter.java @@ -39,7 +39,7 @@ public class ContentEntryEditorListenerAdapter implements ContentEntryEditor.Con } @Override - public void sourceFolderRemoved(@NotNull ContentEntryEditor editor, VirtualFile file, boolean isTestSource) { + public void sourceFolderRemoved(@NotNull ContentEntryEditor editor, VirtualFile file) { } @Override @@ -55,6 +55,6 @@ public class ContentEntryEditorListenerAdapter implements ContentEntryEditor.Con } @Override - public void packagePrefixSet(@NotNull ContentEntryEditor editor, @NotNull SourceFolder folder) { + public void sourceRootPropertiesChanged(@NotNull ContentEntryEditor editor, @NotNull SourceFolder folder) { } } diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryTreeEditor.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryTreeEditor.java index b41404608f5c..72d8971b87f5 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryTreeEditor.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryTreeEditor.java @@ -41,7 +41,6 @@ import com.intellij.openapi.roots.ui.configuration.actions.ToggleExcludedStateAc import com.intellij.openapi.roots.ui.configuration.actions.ToggleSourcesStateAction; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.ScrollPaneFactory; @@ -59,6 +58,7 @@ import java.awt.*; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.Comparator; +import java.util.List; /** * @author Eugene Zhuravlev @@ -67,21 +67,19 @@ import java.util.Comparator; */ public class ContentEntryTreeEditor { private final Project myProject; - private final boolean myCanMarkSources; - private final boolean myCanMarkTestSources; - protected Tree myTree; + private final List> myEditHandlers; + protected final Tree myTree; private FileSystemTreeImpl myFileSystemTree; private final JPanel myTreePanel; private final DefaultMutableTreeNode EMPTY_TREE_ROOT = new DefaultMutableTreeNode(ProjectBundle.message("module.paths.empty.node")); - protected DefaultActionGroup myEditingActionsGroup; + protected final DefaultActionGroup myEditingActionsGroup; private ContentEntryEditor myContentEntryEditor; private final MyContentEntryEditorListener myContentEntryEditorListener = new MyContentEntryEditorListener(); private final FileChooserDescriptor myDescriptor; - public ContentEntryTreeEditor(Project project, boolean canMarkSources, boolean canMarkTestSources) { + public ContentEntryTreeEditor(Project project, List> editHandlers) { myProject = project; - myCanMarkSources = canMarkSources; - myCanMarkTestSources = canMarkTestSources; + myEditHandlers = editHandlers; myTree = new Tree(); myTree.setRootVisible(true); myTree.setShowsRootHandles(true); @@ -101,14 +99,13 @@ public class ContentEntryTreeEditor { } protected void createEditingActions() { - if (myCanMarkSources) { - ToggleSourcesStateAction markSourcesAction = new ToggleSourcesStateAction(myTree, this, false); - markSourcesAction.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.ALT_MASK)), myTree); - myEditingActionsGroup.add(markSourcesAction); - } - - if (myCanMarkTestSources) { - setupTestsAction(); + for (ModuleSourceRootEditHandler editor : myEditHandlers) { + ToggleSourcesStateAction action = new ToggleSourcesStateAction(myTree, this, editor); + CustomShortcutSet shortcutSet = editor.getMarkRootShortcutSet(); + if (shortcutSet != null) { + action.registerCustomShortcutSet(shortcutSet, myTree); + } + myEditingActionsGroup.add(action); } setupExcludedAction(); @@ -225,7 +222,7 @@ public class ContentEntryTreeEditor { } @Override - public void sourceFolderRemoved(@NotNull ContentEntryEditor editor, VirtualFile file, boolean isTestSource) { + public void sourceFolderRemoved(@NotNull ContentEntryEditor editor, VirtualFile file) { update(); } @@ -240,7 +237,7 @@ public class ContentEntryTreeEditor { } @Override - public void packagePrefixSet(@NotNull ContentEntryEditor editor, @NotNull SourceFolder folder) { + public void sourceRootPropertiesChanged(@NotNull ContentEntryEditor editor, @NotNull SourceFolder folder) { update(); } } @@ -289,12 +286,6 @@ public class ContentEntryTreeEditor { } } - protected void setupTestsAction() { - ToggleSourcesStateAction markTestsAction = new ToggleSourcesStateAction(myTree, this, true); - markTestsAction.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.ALT_MASK)), myTree); - myEditingActionsGroup.add(markTestsAction); - } - protected void setupExcludedAction() { ToggleExcludedStateAction toggleExcludedAction = new ToggleExcludedStateAction(myTree, this); myEditingActionsGroup.add(toggleExcludedAction); diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentRootPanel.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentRootPanel.java index be14b1e28bb9..68150812d3bd 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentRootPanel.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentRootPanel.java @@ -22,6 +22,7 @@ import com.intellij.openapi.roots.ContentEntry; import com.intellij.openapi.roots.ContentFolder; import com.intellij.openapi.roots.ExcludeFolder; import com.intellij.openapi.roots.SourceFolder; +import com.intellij.openapi.roots.impl.SourceFolderImpl; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtilCore; @@ -36,27 +37,28 @@ import com.intellij.ui.roots.IconActionComponent; import com.intellij.ui.roots.ResizingWrapper; import com.intellij.uiDesigner.core.GridConstraints; import com.intellij.uiDesigner.core.GridLayoutManager; +import com.intellij.util.containers.MultiMap; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.JpsElement; +import org.jetbrains.jps.model.module.JpsModuleSourceRootType; import javax.swing.*; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import java.awt.*; import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; +import java.util.*; import java.util.List; -import java.util.Map; /** * @author Eugene Zhuravlev * Date: Jan 19, 2004 */ public abstract class ContentRootPanel extends JPanel { - protected static final Color SOURCES_COLOR = new JBColor(new Color(0x0A50A1), DarculaColors.BLUE); - protected static final Color TESTS_COLOR = new Color(0x008C2E); + public static final Color SOURCES_COLOR = new JBColor(new Color(0x0A50A1), DarculaColors.BLUE); + public static final Color TESTS_COLOR = new Color(0x008C2E); protected static final Color EXCLUDED_COLOR = new JBColor(new Color(0x992E00), DarculaColors.RED); private static final Color SELECTED_HEADER_COLOR = new JBColor(new Color(0xDEF2FF), UIUtil.getPanelBackground().darker()); private static final Color HEADER_COLOR = new JBColor(new Color(0xF5F5F5), Gray._82); @@ -65,24 +67,22 @@ public abstract class ContentRootPanel extends JPanel { private static final Color UNSELECTED_TEXT_COLOR = Gray._51; protected final ActionCallback myCallback; + private final List> myModuleSourceRootEditHandlers; private JComponent myHeader; private JComponent myBottom; private final Map myComponentToForegroundMap = new HashMap(); - private final boolean myCanMarkSources; - private final boolean myCanMarkTestSources; public interface ActionCallback { void deleteContentEntry(); void deleteContentFolder(ContentEntry contentEntry, ContentFolder contentFolder); void navigateFolder(ContentEntry contentEntry, ContentFolder contentFolder); - void setPackagePrefix(@NotNull SourceFolder folder, @NotNull String prefix); + void onSourceRootPropertiesChanged(@NotNull SourceFolder folder); } - public ContentRootPanel(ActionCallback callback, boolean canMarkSources, boolean canMarkTestSources) { + public ContentRootPanel(ActionCallback callback, List> moduleSourceRootEditHandlers) { super(new GridBagLayout()); myCallback = callback; - myCanMarkSources = canMarkSources; - myCanMarkTestSources = canMarkTestSources; + myModuleSourceRootEditHandlers = moduleSourceRootEditHandlers; } @Nullable @@ -102,10 +102,9 @@ public abstract class ContentRootPanel extends JPanel { } protected void addFolderGroupComponents() { - final List sources = new ArrayList(); - final List testSources = new ArrayList(); final List excluded = new ArrayList(); final SourceFolder[] sourceFolders = getContentEntry().getSourceFolders(); + MultiMap, SourceFolder> folderByType = new MultiMap, SourceFolder>(); for (SourceFolder folder : sourceFolders) { if (folder.isSynthetic()) { continue; @@ -114,12 +113,7 @@ public abstract class ContentRootPanel extends JPanel { if (folderFile != null && (isExcluded(folderFile) || isUnderExcludedDirectory(folderFile))) { continue; } - if (folder.isTestSource()) { - testSources.add(folder); - } - else { - sources.add(folder); - } + folderByType.putValue(folder.getRootType(), folder); } final ExcludeFolder[] excludeFolders = getContentEntry().getExcludeFolders(); @@ -129,18 +123,21 @@ public abstract class ContentRootPanel extends JPanel { } } - if (!sources.isEmpty() && myCanMarkSources) { - final JComponent sourcesComponent = createFolderGroupComponent(ProjectBundle.message("module.paths.sources.group"), sources.toArray(new ContentFolder[sources.size()]), - SOURCES_COLOR); - this.add(sourcesComponent, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 10, 0), 0, 0)); - } - if (!testSources.isEmpty() && myCanMarkTestSources) { - final JComponent testSourcesComponent = createFolderGroupComponent(ProjectBundle.message("module.paths.test.sources.group"), testSources.toArray(new ContentFolder[testSources.size()]), TESTS_COLOR); - this.add(testSourcesComponent, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 10, 0), 0, 0)); + Insets insets = new Insets(0, 0, 10, 0); + GridBagConstraints constraints = new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, insets, 0, 0); + for (ModuleSourceRootEditHandler editor : myModuleSourceRootEditHandlers) { + Collection folders = folderByType.get(editor.getRootType()); + if (folders.isEmpty()) continue; + + ContentFolder[] foldersArray = folders.toArray(new ContentFolder[folders.size()]); + final JComponent sourcesComponent = createFolderGroupComponent(editor.getRootsGroupTitle(), foldersArray, editor.getRootsGroupColor(), editor); + add(sourcesComponent, constraints); } + if (!excluded.isEmpty()) { - final JComponent excludedComponent = createFolderGroupComponent(ProjectBundle.message("module.paths.excluded.group"), excluded.toArray(new ContentFolder[excluded.size()]), EXCLUDED_COLOR); - this.add(excludedComponent, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 10, 0), 0, 0)); + final JComponent excludedComponent = createFolderGroupComponent(ProjectBundle.message("module.paths.excluded.group"), excluded.toArray(new ContentFolder[excluded.size()]), EXCLUDED_COLOR, + null); + this.add(excludedComponent, constraints); } } @@ -167,23 +164,28 @@ public abstract class ContentRootPanel extends JPanel { return panel; } - protected JComponent createFolderGroupComponent(String title, ContentFolder[] folders, Color foregroundColor) { + protected JComponent createFolderGroupComponent(String title, + ContentFolder[] folders, + Color foregroundColor, + @Nullable ModuleSourceRootEditHandler editor) { final JPanel panel = new JPanel(new GridLayoutManager(folders.length, 3, new Insets(1, 17, 0, 2), 0, 1)); panel.setOpaque(false); for (int idx = 0; idx < folders.length; idx++) { final ContentFolder folder = folders[idx]; final int verticalPolicy = idx == folders.length - 1? GridConstraints.SIZEPOLICY_CAN_GROW : GridConstraints.SIZEPOLICY_FIXED; - panel.add(createFolderComponent(folder, foregroundColor), new GridConstraints(idx, 0, 1, 1, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW | GridConstraints.SIZEPOLICY_CAN_SHRINK, verticalPolicy, null, null, null)); + panel.add(createFolderComponent(folder, foregroundColor, editor), new GridConstraints(idx, 0, 1, 1, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW | GridConstraints.SIZEPOLICY_CAN_SHRINK, verticalPolicy, null, null, null)); int column = 1; int colspan = 2; - JComponent additionalComponent = createAdditionalComponent(folder); - if (additionalComponent != null) { - panel.add(additionalComponent, new GridConstraints(idx, column++, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, verticalPolicy, null, null, null)); - colspan = 1; + if (editor != null) { + JComponent additionalComponent = createRootPropertiesEditor(editor, (SourceFolder)folder); + if (additionalComponent != null) { + panel.add(additionalComponent, new GridConstraints(idx, column++, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, verticalPolicy, null, null, null)); + colspan = 1; + } } - panel.add(createFolderDeleteComponent(folder), new GridConstraints(idx, column, 1, colspan, GridConstraints.ANCHOR_EAST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, verticalPolicy, null, null, null)); + panel.add(createFolderDeleteComponent(folder, editor), new GridConstraints(idx, column, 1, colspan, GridConstraints.ANCHOR_EAST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, verticalPolicy, null, null, null)); } final JLabel titleLabel = new JLabel(title); @@ -202,7 +204,7 @@ public abstract class ContentRootPanel extends JPanel { } @Nullable - protected JComponent createAdditionalComponent(ContentFolder folder) { + protected JComponent createRootPropertiesEditor(ModuleSourceRootEditHandler editor, SourceFolder folder) { return null; } @@ -211,16 +213,14 @@ public abstract class ContentRootPanel extends JPanel { myComponentToForegroundMap.put(component, foreground); } - private JComponent createFolderComponent(final ContentFolder folder, Color foreground) { + private

JComponent createFolderComponent(final ContentFolder folder, Color foreground, ModuleSourceRootEditHandler

editor) { final VirtualFile folderFile = folder.getFile(); final VirtualFile contentEntryFile = getContentEntry().getFile(); - final String packagePrefix = folder instanceof SourceFolder? ((SourceFolder)folder).getPackagePrefix() : ""; + final String properties = folder instanceof SourceFolderImpl? StringUtil.notNullize( + editor.getPropertiesString((P)((SourceFolderImpl)folder).getJpsElement().getProperties())) : ""; if (folderFile != null && contentEntryFile != null) { String path = folderFile.equals(contentEntryFile)? "." : VfsUtilCore.getRelativePath(folderFile, contentEntryFile, File.separatorChar); - if (!packagePrefix.isEmpty()) { - path = path + " (" + packagePrefix + ")"; - } - HoverHyperlinkLabel hyperlinkLabel = new HoverHyperlinkLabel(path, foreground); + HoverHyperlinkLabel hyperlinkLabel = new HoverHyperlinkLabel(path + properties, foreground); hyperlinkLabel.setMinimumSize(new Dimension(0, 0)); hyperlinkLabel.addHyperlinkListener(new HyperlinkListener() { @Override @@ -233,10 +233,7 @@ public abstract class ContentRootPanel extends JPanel { } else { String path = toRelativeDisplayPath(folder.getUrl(), getContentEntry().getUrl()); - if (!packagePrefix.isEmpty()) { - path = path + " (" + packagePrefix + ")"; - } - final JLabel pathLabel = new JLabel(path); + final JLabel pathLabel = new JLabel(path + properties); pathLabel.setOpaque(false); pathLabel.setForeground(Color.RED); @@ -244,13 +241,11 @@ public abstract class ContentRootPanel extends JPanel { } } - private JComponent createFolderDeleteComponent(final ContentFolder folder) { + private JComponent createFolderDeleteComponent(final ContentFolder folder, @Nullable ModuleSourceRootEditHandler editor) { final String tooltipText; if (folder.getFile() != null && getContentEntry().getFile() != null) { - if (folder instanceof SourceFolder) { - tooltipText = ((SourceFolder)folder).isTestSource() - ? ProjectBundle.message("module.paths.unmark.tests.tooltip") - : ProjectBundle.message("module.paths.unmark.source.tooltip"); + if (editor != null) { + tooltipText = editor.getUnmarkRootActionName(); } else if (folder instanceof ExcludeFolder) { tooltipText = ProjectBundle.message("module.paths.include.excluded.tooltip"); @@ -313,7 +308,7 @@ public abstract class ContentRootPanel extends JPanel { protected static String toRelativeDisplayPath(String url, String ancestorUrl) { if (!StringUtil.endsWithChar(ancestorUrl, '/')) { - ancestorUrl = ancestorUrl + "/"; + ancestorUrl += "/"; } if (url.startsWith(ancestorUrl)) { return url.substring(ancestorUrl.length()).replace('/', File.separatorChar); diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/JavaModuleSourceRootEditHandler.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/JavaModuleSourceRootEditHandler.java new file mode 100644 index 000000000000..c72a2b2defde --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/JavaModuleSourceRootEditHandler.java @@ -0,0 +1,71 @@ +/* + * Copyright 2000-2013 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.openapi.roots.ui.configuration; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.CustomShortcutSet; +import com.intellij.openapi.project.ProjectBundle; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.model.java.JavaSourceRootType; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +/** + * @author nik + */ +public class JavaModuleSourceRootEditHandler extends JavaSourceRootEditHandlerBase { + public JavaModuleSourceRootEditHandler() { + super(JavaSourceRootType.SOURCE); + } + + @NotNull + @Override + public String getRootTypeName() { + return ProjectBundle.message("module.toggle.sources.action"); + } + + @NotNull + @Override + public String getRootsGroupTitle() { + return ProjectBundle.message("module.paths.sources.group"); + } + + @NotNull + @Override + public Icon getRootIcon() { + return AllIcons.Modules.SourceRoot; + } + + @Override + public CustomShortcutSet getMarkRootShortcutSet() { + return new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.ALT_MASK)); + } + + @NotNull + @Override + public Color getRootsGroupColor() { + return ContentRootPanel.SOURCES_COLOR; + } + + @NotNull + @Override + public String getUnmarkRootActionName() { + return ProjectBundle.message("module.paths.unmark.source.tooltip"); + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/JavaSourceRootEditHandlerBase.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/JavaSourceRootEditHandlerBase.java new file mode 100644 index 000000000000..a2aa899824ca --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/JavaSourceRootEditHandlerBase.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2013 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.openapi.roots.ui.configuration; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.project.ProjectBundle; +import com.intellij.openapi.roots.SourceFolder; +import com.intellij.openapi.ui.Messages; +import com.intellij.ui.roots.IconActionComponent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.JpsElementFactory; +import org.jetbrains.jps.model.JpsSimpleElement; +import org.jetbrains.jps.model.java.JavaSourceRootProperties; +import org.jetbrains.jps.model.module.JpsModuleSourceRootType; + +import javax.swing.*; +import java.awt.*; + +/** + * @author nik + */ +public abstract class JavaSourceRootEditHandlerBase extends ModuleSourceRootEditHandler> { + public JavaSourceRootEditHandlerBase(JpsModuleSourceRootType> rootType) { + super(rootType); + } + + @NotNull + @Override + public JpsSimpleElement createDefaultProperties() { + return JpsElementFactory.getInstance().createSimpleElement(new JavaSourceRootProperties()); + } + + @Nullable + @Override + public String getPropertiesString(@NotNull JpsSimpleElement properties) { + String packagePrefix = properties.getData().getPackagePrefix(); + return packagePrefix.isEmpty() ? null : " (" + packagePrefix + ")"; + } + + @Nullable + @Override + public JComponent createPropertiesEditor(@NotNull final SourceFolder folder, + @NotNull final JComponent parentComponent, + @NotNull final ContentRootPanel.ActionCallback callback) { + final IconActionComponent iconComponent = new IconActionComponent(AllIcons.Modules.SetPackagePrefix, + AllIcons.Modules.SetPackagePrefixRollover, + ProjectBundle.message("module.paths.package.prefix.tooltip"), new Runnable() { + @Override + public void run() { + final String message = ProjectBundle.message("module.paths.package.prefix.prompt", + ContentRootPanel.toRelativeDisplayPath(folder.getUrl(), folder.getContentEntry().getUrl() + ":")); + final String prefix = Messages.showInputDialog(parentComponent, message, + ProjectBundle.message("module.paths.package.prefix.title"), + Messages.getQuestionIcon(), folder.getPackagePrefix(), null); + if (prefix != null) { + folder.setPackagePrefix(prefix); + callback.onSourceRootPropertiesChanged(folder); + } + } + }); + final JPanel panel = new JPanel(new BorderLayout()); + panel.setOpaque(false); + panel.add(iconComponent, BorderLayout.CENTER); + panel.add(Box.createHorizontalStrut(3), BorderLayout.EAST); + return panel; + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/JavaTestSourceRootEditHandler.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/JavaTestSourceRootEditHandler.java new file mode 100644 index 000000000000..4d172cf75c57 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/JavaTestSourceRootEditHandler.java @@ -0,0 +1,72 @@ +/* + * Copyright 2000-2013 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.openapi.roots.ui.configuration; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.CustomShortcutSet; +import com.intellij.openapi.project.ProjectBundle; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.model.java.JavaSourceRootType; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +/** + * @author nik + */ +public class JavaTestSourceRootEditHandler extends JavaSourceRootEditHandlerBase { + public JavaTestSourceRootEditHandler() { + super(JavaSourceRootType.TEST_SOURCE); + } + + + @NotNull + @Override + public String getRootTypeName() { + return ProjectBundle.message("module.toggle.test.sources.action"); + } + + @NotNull + @Override + public String getRootsGroupTitle() { + return ProjectBundle.message("module.paths.test.sources.group"); + } + + @NotNull + @Override + public Icon getRootIcon() { + return AllIcons.Modules.TestRoot; + } + + @Override + public CustomShortcutSet getMarkRootShortcutSet() { + return new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.ALT_MASK)); + } + + @NotNull + @Override + public Color getRootsGroupColor() { + return ContentRootPanel.TESTS_COLOR; + } + + @NotNull + @Override + public String getUnmarkRootActionName() { + return ProjectBundle.message("module.paths.unmark.tests.tooltip"); + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ModuleSourceRootEditHandler.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ModuleSourceRootEditHandler.java new file mode 100644 index 000000000000..6742bc12a802 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ModuleSourceRootEditHandler.java @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2013 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.openapi.roots.ui.configuration; + +import com.intellij.openapi.actionSystem.CustomShortcutSet; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.roots.SourceFolder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.JpsElement; +import org.jetbrains.jps.model.module.JpsModuleSourceRootType; + +import javax.swing.*; +import java.awt.*; + +/** + * @author nik + */ +public abstract class ModuleSourceRootEditHandler

{ + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.projectStructure.sourceRootEditHandler"); + private final JpsModuleSourceRootType

myRootType; + + protected ModuleSourceRootEditHandler(JpsModuleSourceRootType

rootType) { + myRootType = rootType; + } + + public final JpsModuleSourceRootType

getRootType() { + return myRootType; + } + + @NotNull + public abstract String getRootTypeName(); + + @NotNull + public abstract Icon getRootIcon(); + + @Nullable + public abstract CustomShortcutSet getMarkRootShortcutSet(); + + @NotNull + public abstract String getRootsGroupTitle(); + + @NotNull + public abstract Color getRootsGroupColor(); + + @NotNull + public abstract String getUnmarkRootActionName(); + + + @NotNull + public abstract P createDefaultProperties(); + + @Nullable + public String getPropertiesString(@NotNull P properties) { + return null; + } + + @Nullable + public JComponent createPropertiesEditor(@NotNull SourceFolder folder, @NotNull JComponent parentComponent, + @NotNull ContentRootPanel.ActionCallback callback) { + return null; + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/PlatformContentEntriesConfigurable.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/PlatformContentEntriesConfigurable.java index 998310bceda1..a818b4b94956 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/PlatformContentEntriesConfigurable.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/PlatformContentEntriesConfigurable.java @@ -11,6 +11,7 @@ import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.jps.model.module.JpsModuleSourceRootType; import javax.swing.*; import java.awt.*; @@ -21,16 +22,14 @@ import java.util.List; */ public class PlatformContentEntriesConfigurable implements Configurable { private final Module myModule; - private final boolean myCanMarkSources; - private final boolean myCanMarkTestSources; + private final JpsModuleSourceRootType[] myRootTypes; private final JPanel myTopPanel = new JPanel(new BorderLayout()); private ModifiableRootModel myModifiableModel; private CommonContentEntriesEditor myEditor; - public PlatformContentEntriesConfigurable(final Module module, boolean canMarkSources, boolean canMarkTestSources) { + public PlatformContentEntriesConfigurable(final Module module, JpsModuleSourceRootType... rootTypes) { myModule = module; - myCanMarkSources = canMarkSources; - myCanMarkTestSources = canMarkTestSources; + myRootTypes = rootTypes; } @Override @@ -69,7 +68,7 @@ public class PlatformContentEntriesConfigurable implements Configurable { return DefaultFacetsProvider.INSTANCE; } }; - myEditor = new CommonContentEntriesEditor(myModule.getName(), moduleConfigurationState, myCanMarkSources, myCanMarkTestSources) { + myEditor = new CommonContentEntriesEditor(myModule.getName(), moduleConfigurationState, myRootTypes) { @Override protected List addContentEntries(VirtualFile[] files) { List entries = super.addContentEntries(files); diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/actions/ToggleSourcesStateAction.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/actions/ToggleSourcesStateAction.java index 6a3daf44f978..3fae3c64eae4 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/actions/ToggleSourcesStateAction.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/actions/ToggleSourcesStateAction.java @@ -16,14 +16,16 @@ package com.intellij.openapi.roots.ui.configuration.actions; -import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.roots.SourceFolder; +import com.intellij.openapi.roots.impl.SourceFolderImpl; import com.intellij.openapi.roots.ui.configuration.ContentEntryEditor; import com.intellij.openapi.roots.ui.configuration.ContentEntryTreeEditor; +import com.intellij.openapi.roots.ui.configuration.ModuleSourceRootEditHandler; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.jps.model.JpsElement; import javax.swing.*; @@ -31,25 +33,18 @@ import javax.swing.*; * @author Eugene Zhuravlev * @since Oct 14, 2003 */ -public class ToggleSourcesStateAction extends ContentEntryEditingAction { +public class ToggleSourcesStateAction

extends ContentEntryEditingAction { private final ContentEntryTreeEditor myEntryTreeEditor; - private final boolean myEditTestSources; + private final ModuleSourceRootEditHandler

myEditHandler; - public ToggleSourcesStateAction(JTree tree, ContentEntryTreeEditor entryEditor, boolean editTestSources) { + public ToggleSourcesStateAction(JTree tree, ContentEntryTreeEditor entryEditor, ModuleSourceRootEditHandler

editHandler) { super(tree); myEntryTreeEditor = entryEditor; - myEditTestSources = editTestSources; + myEditHandler = editHandler; final Presentation templatePresentation = getTemplatePresentation(); - if (editTestSources) { - templatePresentation.setText(ProjectBundle.message("module.toggle.test.sources.action")); - templatePresentation.setDescription(ProjectBundle.message("module.toggle.test.sources.action.description")); - templatePresentation.setIcon(AllIcons.Modules.TestRoot); - } - else { - templatePresentation.setText(ProjectBundle.message("module.toggle.sources.action")); - templatePresentation.setDescription(ProjectBundle.message("module.toggle.sources.action.description")); - templatePresentation.setIcon(AllIcons.Modules.SourceRoot); - } + templatePresentation.setText(editHandler.getRootTypeName()); + templatePresentation.setDescription(ProjectBundle.message("module.toggle.sources.action.description", editHandler.getRootType())); + templatePresentation.setIcon(editHandler.getRootIcon()); } @Override @@ -58,7 +53,7 @@ public class ToggleSourcesStateAction extends ContentEntryEditingAction { if (selectedFiles.length == 0) return false; final ContentEntryEditor editor = myEntryTreeEditor.getContentEntryEditor(); - return myEditTestSources ? editor.isTestSource(selectedFiles[0]) : editor.isSource(selectedFiles[0]); + return myEditHandler.getRootType().equals(editor.getRootType(selectedFiles[0])); } @Override @@ -71,20 +66,23 @@ public class ToggleSourcesStateAction extends ContentEntryEditingAction { final SourceFolder sourceFolder = contentEntryEditor.getSourceFolder(selectedFile); if (isSelected) { if (sourceFolder == null) { // not marked yet - contentEntryEditor.addSourceFolder(selectedFile, myEditTestSources, ""); + P properties = myEditHandler.createDefaultProperties(); + contentEntryEditor.addSourceFolder(selectedFile, myEditHandler.getRootType(), properties); } - else { - if (myEditTestSources != sourceFolder.isTestSource()) { - final String packagePrefix = sourceFolder.getPackagePrefix(); - contentEntryEditor.removeSourceFolder(sourceFolder); - contentEntryEditor.addSourceFolder(selectedFile, myEditTestSources, packagePrefix); + else if (!myEditHandler.getRootType().equals(sourceFolder.getRootType())) { + P properties; + if (myEditHandler.getRootType().getClass().equals(sourceFolder.getRootType().getClass())) { + properties = (P)((SourceFolderImpl)sourceFolder).getJpsElement().getProperties().getBulkModificationSupport().createCopy(); } + else { + properties = myEditHandler.createDefaultProperties(); + } + contentEntryEditor.removeSourceFolder(sourceFolder); + contentEntryEditor.addSourceFolder(selectedFile, myEditHandler.getRootType(), properties); } } - else { - if (sourceFolder != null) { // already marked - contentEntryEditor.removeSourceFolder(sourceFolder); - } + else if (sourceFolder != null) { // already marked + contentEntryEditor.removeSourceFolder(sourceFolder); } } } @@ -92,7 +90,6 @@ public class ToggleSourcesStateAction extends ContentEntryEditingAction { @Override public void update(final AnActionEvent e) { super.update(e); - final Presentation presentation = e.getPresentation(); - presentation.setText(ProjectBundle.message(myEditTestSources ? "module.toggle.test.sources.action" : "module.toggle.sources.action")); + e.getPresentation().setText(myEditHandler.getRootTypeName()); } } diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 0d6e267109e8..b9a857d5a815 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -780,6 +780,9 @@ + + + + + diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/ContentEntry.java b/platform/projectModel-api/src/com/intellij/openapi/roots/ContentEntry.java index d2e22de30447..c44cd90be1f6 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/roots/ContentEntry.java +++ b/platform/projectModel-api/src/com/intellij/openapi/roots/ContentEntry.java @@ -18,6 +18,8 @@ package com.intellij.openapi.roots; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.JpsElement; +import org.jetbrains.jps.model.module.JpsModuleSourceRootType; /** * Represents a module content root. @@ -95,6 +97,10 @@ public interface ContentEntry extends Synthetic { */ SourceFolder addSourceFolder(@NotNull VirtualFile file, boolean isTestSource, @NotNull String packagePrefix); + @NotNull +

+ SourceFolder addSourceFolder(@NotNull VirtualFile file, @NotNull JpsModuleSourceRootType

type, @NotNull P properties); + /** * Adds a source or test source root under the content root. * diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ContentEntryImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ContentEntryImpl.java index 9bf2d02fd299..64d379a8fdd9 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ContentEntryImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ContentEntryImpl.java @@ -36,10 +36,12 @@ import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.JpsElement; import org.jetbrains.jps.model.JpsElementFactory; import org.jetbrains.jps.model.JpsSimpleElement; import org.jetbrains.jps.model.java.JavaSourceRootProperties; import org.jetbrains.jps.model.java.JavaSourceRootType; +import org.jetbrains.jps.model.module.JpsModuleSourceRootType; import org.jetbrains.jps.model.serialization.module.JpsModuleRootModelSerializer; import java.util.*; @@ -168,9 +170,16 @@ public class ContentEntryImpl extends RootModelComponentBase implements ContentE @Override public SourceFolder addSourceFolder(@NotNull VirtualFile file, boolean isTestSource, @NotNull String packagePrefix) { - assertCanAddFolder(file); JavaSourceRootType type = isTestSource ? JavaSourceRootType.TEST_SOURCE : JavaSourceRootType.SOURCE; JpsSimpleElement properties = JpsElementFactory.getInstance().createSimpleElement(new JavaSourceRootProperties("")); + return addSourceFolder(file, type, properties); + } + + @Override + @NotNull + public

SourceFolder addSourceFolder(@NotNull VirtualFile file, @NotNull JpsModuleSourceRootType

type, + @NotNull P properties) { + assertCanAddFolder(file); return addSourceFolder(new SourceFolderImpl(file, JpsElementFactory.getInstance().createModuleSourceRoot(file.getUrl(), type, properties), this)); } diff --git a/platform/projectModel-impl/src/com/intellij/project/model/impl/module/content/JpsContentEntry.java b/platform/projectModel-impl/src/com/intellij/project/model/impl/module/content/JpsContentEntry.java index b5b79c9ce205..f2d76a301e71 100644 --- a/platform/projectModel-impl/src/com/intellij/project/model/impl/module/content/JpsContentEntry.java +++ b/platform/projectModel-impl/src/com/intellij/project/model/impl/module/content/JpsContentEntry.java @@ -31,11 +31,14 @@ import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager; import com.intellij.project.model.impl.module.JpsRootModel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.JpsElement; import org.jetbrains.jps.model.JpsElementFactory; +import org.jetbrains.jps.model.JpsSimpleElement; import org.jetbrains.jps.model.java.JavaSourceRootProperties; import org.jetbrains.jps.model.java.JavaSourceRootType; import org.jetbrains.jps.model.module.JpsModule; import org.jetbrains.jps.model.module.JpsModuleSourceRoot; +import org.jetbrains.jps.model.module.JpsModuleSourceRootType; import java.util.ArrayList; import java.util.List; @@ -141,10 +144,21 @@ public class JpsContentEntry implements ContentEntry, Disposable { return addSourceFolder(file.getUrl(), isTestSource, packagePrefix); } + @NotNull + @Override + public

SourceFolder addSourceFolder(@NotNull VirtualFile file, + @NotNull JpsModuleSourceRootType

type, + @NotNull P properties) { + final JpsModuleSourceRoot sourceRoot = myModule.addSourceRoot(file.getUrl(), type, properties); + final JpsSourceFolder sourceFolder = new JpsSourceFolder(sourceRoot, this); + mySourceFolders.add(sourceFolder); + return sourceFolder; + } + private SourceFolder addSourceFolder(final String url, boolean isTestSource, String packagePrefix) { final JavaSourceRootType rootType = isTestSource ? JavaSourceRootType.TEST_SOURCE : JavaSourceRootType.SOURCE; - final JpsModuleSourceRoot sourceRoot = myModule.addSourceRoot(url, rootType, JpsElementFactory.getInstance() - .createSimpleElement(new JavaSourceRootProperties(packagePrefix))); + JpsSimpleElement properties = JpsElementFactory.getInstance().createSimpleElement(new JavaSourceRootProperties(packagePrefix)); + final JpsModuleSourceRoot sourceRoot = myModule.addSourceRoot(url, rootType, properties); final JpsSourceFolder sourceFolder = new JpsSourceFolder(sourceRoot, this); mySourceFolders.add(sourceFolder); return sourceFolder; diff --git a/platform/projectModel-impl/src/messages/ProjectBundle.properties b/platform/projectModel-impl/src/messages/ProjectBundle.properties index 370b8f0aa768..a8eefc9d46ef 100644 --- a/platform/projectModel-impl/src/messages/ProjectBundle.properties +++ b/platform/projectModel-impl/src/messages/ProjectBundle.properties @@ -173,9 +173,8 @@ module.new.action.description=Add new module to the project module.toggle.excluded.action=Excluded module.toggle.excluded.action.description=Include/Exclude directory from module module.toggle.test.sources.action=Test Sources -module.toggle.test.sources.action.description=Mark directory as a Test Sources root module.toggle.sources.action=Sources -module.toggle.sources.action.description=Mark directory as a Sources root +module.toggle.sources.action.description=Mark directory as a {0} root library.classes.node=Classes library.javadocs.node=JavaDocs library.empty.item=