source roots editors refactored: root type specific UI moved to extension

This commit is contained in:
nik
2013-08-26 15:55:27 +04:00
parent 70d526d597
commit e60a55bdfb
22 changed files with 521 additions and 231 deletions
@@ -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<ContentEntry> addContentEntries(VirtualFile[] files) {
List<ContentEntry> contentEntries = super.addContentEntries(files);
@@ -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<ModuleSourceRootEditHandler<?>> 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);
}
};
}
@@ -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;
}
}
@@ -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 <P extends JpsElement> SourceFolder addSourceFolder(@NotNull VirtualFile file,
@NotNull JpsModuleSourceRootType<P> type,
@NotNull P properties) {
return myDelegate.addSourceFolder(file, type, properties);
}
@Override
public SourceFolder addSourceFolder(@NotNull String url, boolean isTestSource) {
return myDelegate.addSourceFolder(url, isTestSource);
@@ -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)};
}
}
@@ -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<ModuleSourceRootEditHandler<?>> myEditHandlers = new ArrayList<ModuleSourceRootEditHandler<?>>();
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<ModuleSourceRootEditHandler<?>> 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();
@@ -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<ContentEntryEditorListener> myEventDispatcher;
private final String myContentEntryUrl;
protected final boolean myCanMarkSources;
protected final boolean myCanMarkTestSources;
private final List<ModuleSourceRootEditHandler<?>> 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<ModuleSourceRootEditHandler<?>> editHandlers) {
myContentEntryUrl = url;
myEditHandlers = editHandlers;
}
protected final List<ModuleSourceRootEditHandler<?>> 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 <P extends JpsElement> SourceFolder addSourceFolder(@NotNull final VirtualFile file, final JpsModuleSourceRootType<P> 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) {
@@ -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) {
}
}
@@ -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<ModuleSourceRootEditHandler<?>> 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<ModuleSourceRootEditHandler<?>> 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);
@@ -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<ModuleSourceRootEditHandler<?>> myModuleSourceRootEditHandlers;
private JComponent myHeader;
private JComponent myBottom;
private final Map<JComponent, Color> myComponentToForegroundMap = new HashMap<JComponent, Color>();
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<ModuleSourceRootEditHandler<?>> 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<ContentFolder> sources = new ArrayList<ContentFolder>();
final List<ContentFolder> testSources = new ArrayList<ContentFolder>();
final List<ContentFolder> excluded = new ArrayList<ContentFolder>();
final SourceFolder[] sourceFolders = getContentEntry().getSourceFolders();
MultiMap<JpsModuleSourceRootType<?>, SourceFolder> folderByType = new MultiMap<JpsModuleSourceRootType<?>, 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<SourceFolder> 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 <P extends JpsElement> JComponent createFolderComponent(final ContentFolder folder, Color foreground, ModuleSourceRootEditHandler<P> 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);
@@ -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");
}
}
@@ -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<JpsSimpleElement<JavaSourceRootProperties>> {
public JavaSourceRootEditHandlerBase(JpsModuleSourceRootType<JpsSimpleElement<JavaSourceRootProperties>> rootType) {
super(rootType);
}
@NotNull
@Override
public JpsSimpleElement<JavaSourceRootProperties> createDefaultProperties() {
return JpsElementFactory.getInstance().createSimpleElement(new JavaSourceRootProperties());
}
@Nullable
@Override
public String getPropertiesString(@NotNull JpsSimpleElement<JavaSourceRootProperties> 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;
}
}
@@ -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");
}
}
@@ -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<P extends JpsElement> {
public static final ExtensionPointName<ModuleSourceRootEditHandler> EP_NAME = ExtensionPointName.create("com.intellij.projectStructure.sourceRootEditHandler");
private final JpsModuleSourceRootType<P> myRootType;
protected ModuleSourceRootEditHandler(JpsModuleSourceRootType<P> rootType) {
myRootType = rootType;
}
public final JpsModuleSourceRootType<P> 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;
}
}
@@ -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<ContentEntry> addContentEntries(VirtualFile[] files) {
List<ContentEntry> entries = super.addContentEntries(files);
@@ -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<P extends JpsElement> extends ContentEntryEditingAction {
private final ContentEntryTreeEditor myEntryTreeEditor;
private final boolean myEditTestSources;
private final ModuleSourceRootEditHandler<P> myEditHandler;
public ToggleSourcesStateAction(JTree tree, ContentEntryTreeEditor entryEditor, boolean editTestSources) {
public ToggleSourcesStateAction(JTree tree, ContentEntryTreeEditor entryEditor, ModuleSourceRootEditHandler<P> 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());
}
}
@@ -780,6 +780,9 @@
<extensionPoint name="moduleRendererFactory" interface="com.intellij.ide.util.ModuleRendererFactory"/>
<extensionPoint name="projectStructure.sourceRootEditHandler"
interface="com.intellij.openapi.roots.ui.configuration.ModuleSourceRootEditHandler"/>
<extensionPoint name="toolsProvider" interface="com.intellij.tools.ToolsProvider"/>
<extensionPoint name="defaultHighlightingSettingProvider"
@@ -848,6 +848,9 @@
<applicationService serviceInterface="com.intellij.ide.util.treeView.TreeAnchorizer"
serviceImplementation="com.intellij.ide.projectView.impl.nodes.PsiTreeAnchorizer"/>
<projectStructure.sourceRootEditHandler implementation="com.intellij.openapi.roots.ui.configuration.JavaModuleSourceRootEditHandler"/>
<projectStructure.sourceRootEditHandler implementation="com.intellij.openapi.roots.ui.configuration.JavaTestSourceRootEditHandler"/>
<elementPreviewProvider implementation="com.intellij.codeInsight.preview.ElementPreviewHintProvider"/>
</extensions>
</idea-plugin>
@@ -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
<P extends JpsElement>
SourceFolder addSourceFolder(@NotNull VirtualFile file, @NotNull JpsModuleSourceRootType<P> type, @NotNull P properties);
/**
* Adds a source or test source root under the content root.
*
@@ -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<JavaSourceRootProperties> properties = JpsElementFactory.getInstance().createSimpleElement(new JavaSourceRootProperties(""));
return addSourceFolder(file, type, properties);
}
@Override
@NotNull
public <P extends JpsElement> SourceFolder addSourceFolder(@NotNull VirtualFile file, @NotNull JpsModuleSourceRootType<P> type,
@NotNull P properties) {
assertCanAddFolder(file);
return addSourceFolder(new SourceFolderImpl(file, JpsElementFactory.getInstance().createModuleSourceRoot(file.getUrl(), type, properties), this));
}
@@ -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 <P extends JpsElement> SourceFolder addSourceFolder(@NotNull VirtualFile file,
@NotNull JpsModuleSourceRootType<P> 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<JavaSourceRootProperties> 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;
@@ -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=<empty library>