WEB-17977 Feature: Configure Patterns for Automatic Nesting of Transpiled Files

This commit is contained in:
Alexander Doroshko
2017-05-30 22:48:01 +03:00
parent 10cb4a767f
commit 40f14e07f9
7 changed files with 461 additions and 69 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -20,4 +20,6 @@ package com.intellij.ide.projectView;
*/
public interface ProjectViewSettings extends ViewSettings {
boolean isShowExcludedFiles();
default boolean isUseFileNestingRules() {return true;}
}
@@ -0,0 +1,202 @@
/*
* Copyright 2000-2017 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.ide.projectView.impl;
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.projectView.impl.ProjectViewFileNestingService.NestingRule;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.ui.DumbAwareActionButton;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.table.TableView;
import com.intellij.util.Consumer;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.ElementProducer;
import com.intellij.util.ui.ListTableModel;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
public class FileNestingInProjectViewDialog extends DialogWrapper {
private final JBCheckBox myUseNestingRulesCheckBox;
private final JPanel myRulesPanel;
private final TableView<NestingRule> myTable;
protected FileNestingInProjectViewDialog(@NotNull final Project project) {
super(project);
setTitle(IdeBundle.message("file.nesting.dialog.title"));
myUseNestingRulesCheckBox = new JBCheckBox(IdeBundle.message("use.file.nesting.rules.checkbox"));
myUseNestingRulesCheckBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
UIUtil.setEnabled(myRulesPanel, myUseNestingRulesCheckBox.isSelected(), true);
}
});
myTable = createTable();
myRulesPanel = createRulesPanel(myTable);
init();
}
@Override
protected String getHelpId() {
return "project.view.file.nesting.dialog";
}
@Override
protected JComponent createCenterPanel() {
final JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(myUseNestingRulesCheckBox, BorderLayout.NORTH);
mainPanel.add(myRulesPanel, BorderLayout.CENTER);
return mainPanel;
}
private static JPanel createRulesPanel(@NotNull final TableView<NestingRule> table) {
final ToolbarDecorator toolbarDecorator =
ToolbarDecorator.createDecorator(table,
new ElementProducer<NestingRule>() {
@Override
public boolean canCreateElement() {
return true;
}
@Override
public NestingRule createElement() {
return new NestingRule();
}
})
.disableUpDownActions()
.addExtraAction(
new DumbAwareActionButton(IdeBundle.message("file.nesting.use.default.ruleset"), AllIcons.Actions.Reset_to_default) {
@Override
public void actionPerformed(AnActionEvent e) {
final List<NestingRule> rules = new ArrayList<>();
for (NestingRule rule : ProjectViewFileNestingService.DEFAULT_NESTING_RULES) {
rules.add(new NestingRule(rule.getParentFileSuffix(), rule.getChildFileSuffix()));
}
table.getListTableModel().setItems(rules);
}
});
return toolbarDecorator.createPanel();
}
private static TableView<NestingRule> createTable() {
ListTableModel<NestingRule> model = new ListTableModel<>(
new ColumnInfo<NestingRule, String>("Parent file suffix") {
@Override
public boolean isCellEditable(NestingRule rule) {
return true;
}
@Override
public String valueOf(NestingRule rule) {
return rule.getParentFileSuffix();
}
@Override
public void setValue(NestingRule rule, String value) {
rule.setParentFileSuffix(value.trim());
}
},
new ColumnInfo<NestingRule, String>("Child file suffix") {
@Override
public boolean isCellEditable(NestingRule rule) {
return true;
}
@Override
public String valueOf(NestingRule rule) {
return rule.getChildFileSuffix();
}
@Override
public void setValue(NestingRule rule, String value) {
rule.setChildFileSuffix(value);
}
}
);
return new TableView<>(model);
}
@Nullable
@Override
protected ValidationInfo doValidate() {
if (!myUseNestingRulesCheckBox.isSelected()) return null;
List<NestingRule> items = myTable.getListTableModel().getItems();
for (int i = 0; i < items.size(); i++) {
final NestingRule rule = items.get(i);
final int row = i + 1;
if (rule.getParentFileSuffix().isEmpty()) {
return new ValidationInfo("Parent file suffix must not be empty (see row " + row + ")", null);
}
if (rule.getChildFileSuffix().isEmpty()) {
return new ValidationInfo("Child file suffix must not be empty (see row " + row + ")", null);
}
if (rule.getChildFileSuffix().equals(rule.getParentFileSuffix())) {
return new ValidationInfo(
"Parent and child file suffixes must not be equal ('" + rule.getParentFileSuffix() + "', see row " + row + ")", null);
}
}
return null;
}
@Override
protected void doOKAction() {
myTable.stopEditing();
super.doOKAction();
}
public void reset(boolean useFileNestingRules) {
myUseNestingRulesCheckBox.setSelected(useFileNestingRules);
UIUtil.setEnabled(myRulesPanel, myUseNestingRulesCheckBox.isSelected(), true);
final List<NestingRule> rules = new ArrayList<>();
for (NestingRule rule : ProjectViewFileNestingService.getInstance().getRules()) {
rules.add(new NestingRule(rule.getParentFileSuffix(), rule.getChildFileSuffix()));
}
myTable.getListTableModel().setItems(rules);
}
public void apply(@NotNull final Consumer<Boolean> useNestingRulesOptionConsumer) {
useNestingRulesOptionConsumer.consume(myUseNestingRulesCheckBox.isSelected());
if (myUseNestingRulesCheckBox.isSelected()) {
final List<NestingRule> result = new ArrayList<>();
for (NestingRule rule : myTable.getListTableModel().getItems()) {
result.add(new NestingRule(rule.getParentFileSuffix(), rule.getChildFileSuffix()));
}
ProjectViewFileNestingService.getInstance().setRules(result);
}
}
}
@@ -15,15 +15,13 @@
*/
package com.intellij.ide.projectView.impl;
import com.intellij.ide.projectView.ProjectViewNestingRulesProvider;
import com.intellij.ide.projectView.TreeStructureProvider;
import com.intellij.ide.projectView.ViewSettings;
import com.intellij.ide.projectView.*;
import com.intellij.ide.projectView.impl.ProjectViewFileNestingService.NestingRule;
import com.intellij.ide.projectView.impl.nodes.NestingTreeNode;
import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode;
import com.intellij.ide.projectView.impl.nodes.PsiFileNode;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
@@ -48,50 +46,49 @@ import java.util.*;
* {@code com.intellij.projectViewNestingRulesProvider} extensions.
*
* @see ProjectViewNestingRulesProvider
* @see ProjectViewFileNestingService
* @see FileNestingInProjectViewDialog
*/
public class NestingTreeStructureProvider implements TreeStructureProvider, DumbAware {
private static ExtensionPointName<ProjectViewNestingRulesProvider> EP_NAME =
ExtensionPointName.create("com.intellij.projectViewNestingRulesProvider");
private static final Logger LOG = Logger.getInstance(NestingTreeStructureProvider.class);
private int myBaseListHashCode = 0;
private Set<NestingRule> myNestingRules;
@NotNull
private Collection<NestingRule> getNestingRules() {
if (myNestingRules == null) {
final List<NestingRule> baseRules = ProjectViewFileNestingService.getInstance().getRules();
final int baseRulesHashCode = baseRules.hashCode();
if (myNestingRules == null || myBaseListHashCode != baseRulesHashCode) {
myNestingRules = new THashSet<>();
myBaseListHashCode = baseRulesHashCode;
final MultiMap<String, String> childToParentSuffix = new MultiMap<>();
final MultiMap<String, String> parentToChildSuffix = new MultiMap<>();
final ProjectViewNestingRulesProvider.Consumer consumer = new ProjectViewNestingRulesProvider.Consumer() {
@Override
public void addNestingRule(@NotNull final String parentFileSuffix, @NotNull final String childFileSuffix) {
LOG.assertTrue(!parentFileSuffix.isEmpty() && !childFileSuffix.isEmpty(), "file suffix must not be empty");
LOG.assertTrue(!parentFileSuffix.equals(childFileSuffix), "parent and child suffixes must be different: " + parentFileSuffix);
for (NestingRule rule : baseRules) {
final String parentFileSuffix = rule.getParentFileSuffix();
final String childFileSuffix = rule.getChildFileSuffix();
if (parentFileSuffix.isEmpty() || childFileSuffix.isEmpty()) continue; // shouldn't happen, checked on component loading and in UI
if (parentFileSuffix.equals(childFileSuffix)) continue; // shouldn't happen, checked on component loading and in UI
myNestingRules.add(new NestingRule(parentFileSuffix, childFileSuffix));
childToParentSuffix.putValue(childFileSuffix, parentFileSuffix);
parentToChildSuffix.putValue(parentFileSuffix, childFileSuffix);
myNestingRules.add(rule);
childToParentSuffix.putValue(childFileSuffix, parentFileSuffix);
parentToChildSuffix.putValue(parentFileSuffix, childFileSuffix);
// for all cases like A -> B -> C we also add a rule A -> C
for (String s : parentToChildSuffix.get(childFileSuffix)) {
myNestingRules.add(new NestingRule(parentFileSuffix, s));
parentToChildSuffix.putValue(parentFileSuffix, s);
childToParentSuffix.putValue(s, parentFileSuffix);
}
for (String s : childToParentSuffix.get(parentFileSuffix)) {
myNestingRules.add(new NestingRule(s, childFileSuffix));
parentToChildSuffix.putValue(s, childFileSuffix);
childToParentSuffix.putValue(childFileSuffix, s);
}
// for all cases like A -> B -> C we also add a rule A -> C
for (String s : parentToChildSuffix.get(childFileSuffix)) {
myNestingRules.add(new NestingRule(parentFileSuffix, s));
parentToChildSuffix.putValue(parentFileSuffix, s);
childToParentSuffix.putValue(s, parentFileSuffix);
}
};
for (ProjectViewNestingRulesProvider provider : EP_NAME.getExtensions()) {
provider.addFileNestingRules(consumer);
for (String s : childToParentSuffix.get(parentFileSuffix)) {
myNestingRules.add(new NestingRule(s, childFileSuffix));
parentToChildSuffix.putValue(s, childFileSuffix);
childToParentSuffix.putValue(childFileSuffix, s);
}
}
}
@@ -113,6 +110,7 @@ public class NestingTreeStructureProvider implements TreeStructureProvider, Dumb
public Collection<AbstractTreeNode> modify(@NotNull final AbstractTreeNode parent,
@NotNull final Collection<AbstractTreeNode> children,
final ViewSettings settings) {
if (!(settings instanceof ProjectViewSettings) || !((ProjectViewSettings)settings).isUseFileNestingRules()) return children;
if (!(parent instanceof PsiDirectoryNode)) return children;
final Collection<NestingRule> rules = getNestingRules();
@@ -153,6 +151,11 @@ public class NestingTreeStructureProvider implements TreeStructureProvider, Dumb
@NotNull final VirtualFile parentFile) {
LOG.assertTrue(!parentFile.isDirectory());
final AbstractProjectViewPane pane = ProjectView.getInstance(project).getProjectViewPaneById(ProjectViewPane.ID);
if (pane instanceof ProjectViewPane) {
if (!((ProjectViewPane)pane).isUseFileNestingRules()) return Collections.emptyList();
}
final VirtualFile dir = parentFile.getParent();
if (dir == null) return Collections.emptyList();
@@ -181,8 +184,8 @@ public class NestingTreeStructureProvider implements TreeStructureProvider, Dumb
final boolean matchesParent = c.first;
if (matchesParent) {
final String baseName = childName.substring(0, childName.length() - rule.myParentFileSuffix.length());
if (parentFile.getName().equals(baseName + rule.myChildFileSuffix)) {
final String baseName = childName.substring(0, childName.length() - rule.getParentFileSuffix().length());
if (parentFile.getName().equals(baseName + rule.getChildFileSuffix())) {
return Collections.emptyList(); // parentFile itself appears to be a child of childFile
}
}
@@ -195,8 +198,8 @@ public class NestingTreeStructureProvider implements TreeStructureProvider, Dumb
final boolean matchesChild = c.second;
if (matchesChild) {
final String baseName = childName.substring(0, childName.length() - rule.myChildFileSuffix.length());
if (parentFile.getName().equals(baseName + rule.myParentFileSuffix)) {
final String baseName = childName.substring(0, childName.length() - rule.getChildFileSuffix().length());
if (parentFile.getName().equals(baseName + rule.getParentFileSuffix())) {
result.add(new ChildFileInfo(child, baseName));
}
}
@@ -274,14 +277,14 @@ public class NestingTreeStructureProvider implements TreeStructureProvider, Dumb
}
if (matchesParent) {
final String baseName = fileName.substring(0, fileName.length() - rule.myParentFileSuffix.length());
final String baseName = fileName.substring(0, fileName.length() - rule.getParentFileSuffix().length());
final Edge<PsiFileNode> edge = getOrCreateEdge(baseNameAndRuleToEdge, baseName, rule);
edge.from = (PsiFileNode)node;
updateInfoIfEdgeComplete(parentToChildren, allChildNodes, edge);
}
if (matchesChild) {
final String baseName = fileName.substring(0, fileName.length() - rule.myChildFileSuffix.length());
final String baseName = fileName.substring(0, fileName.length() - rule.getChildFileSuffix().length());
final Edge<PsiFileNode> edge = getOrCreateEdge(baseNameAndRuleToEdge, baseName, rule);
edge.to = (PsiFileNode)node;
updateInfoIfEdgeComplete(parentToChildren, allChildNodes, edge);
@@ -293,11 +296,11 @@ public class NestingTreeStructureProvider implements TreeStructureProvider, Dumb
}
private static Couple<Boolean> checkMatchingAsParentOrChild(@NotNull final NestingRule rule, @NotNull final String fileName) {
boolean matchesParent = !fileName.equals(rule.myParentFileSuffix) && fileName.endsWith(rule.myParentFileSuffix);
boolean matchesChild = !fileName.equals(rule.myChildFileSuffix) && fileName.endsWith(rule.myChildFileSuffix);
boolean matchesParent = !fileName.equals(rule.getParentFileSuffix()) && fileName.endsWith(rule.getParentFileSuffix());
boolean matchesChild = !fileName.equals(rule.getChildFileSuffix()) && fileName.endsWith(rule.getChildFileSuffix());
if (matchesParent && matchesChild) {
if (rule.myParentFileSuffix.length() > rule.myChildFileSuffix.length()) {
if (rule.getParentFileSuffix().length() > rule.getChildFileSuffix().length()) {
matchesChild = false;
}
else {
@@ -334,32 +337,6 @@ public class NestingTreeStructureProvider implements TreeStructureProvider, Dumb
}
}
private static class NestingRule {
@NotNull private final String myParentFileSuffix;
@NotNull private final String myChildFileSuffix;
public NestingRule(@NotNull String parentFileSuffix, @NotNull String childFileSuffix) {
myParentFileSuffix = parentFileSuffix;
myChildFileSuffix = childFileSuffix;
}
@Override
public String toString() {
return myParentFileSuffix + "->" + myChildFileSuffix;
}
@Override
public boolean equals(Object o) {
return o instanceof NestingRule &&
myParentFileSuffix.equals(((NestingRule)o).myParentFileSuffix) &&
myChildFileSuffix.equals(((NestingRule)o).myChildFileSuffix);
}
@Override
public int hashCode() {
return myParentFileSuffix.hashCode() + 239 * myChildFileSuffix.hashCode();
}
}
private static class Edge<T> {
@Nullable private T from;
@@ -0,0 +1,163 @@
/*
* Copyright 2000-2017 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.ide.projectView.impl;
import com.intellij.ide.projectView.ProjectViewNestingRulesProvider;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.util.containers.SortedList;
import com.intellij.util.xmlb.annotations.AbstractCollection;
import com.intellij.util.xmlb.annotations.Attribute;
import com.intellij.util.xmlb.annotations.Tag;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
/**
* Holds data used by {@link NestingTreeStructureProvider} and {@link FileNestingInProjectViewDialog}.
*/
@State(
name = "ProjectViewFileNesting",
storages = @Storage("ui.lnf.xml")
)
public class ProjectViewFileNestingService implements PersistentStateComponent<ProjectViewFileNestingService.MyState> {
private static final Logger LOG = Logger.getInstance(ProjectViewFileNestingService.class);
private static final ExtensionPointName<ProjectViewNestingRulesProvider> EP_NAME =
ExtensionPointName.create("com.intellij.projectViewNestingRulesProvider");
public static final NestingRule[] DEFAULT_NESTING_RULES = loadDefaultNestingRules();
private MyState myState = new MyState();
@NotNull
public static ProjectViewFileNestingService getInstance() {
return ServiceManager.getService(ProjectViewFileNestingService.class);
}
@NotNull
private static NestingRule[] loadDefaultNestingRules() {
final List<NestingRule> result = new SortedList<>(Comparator.comparing(o -> o.getParentFileSuffix()));
final ProjectViewNestingRulesProvider.Consumer consumer = new ProjectViewNestingRulesProvider.Consumer() {
@Override
public void addNestingRule(@NotNull final String parentFileSuffix, @NotNull final String childFileSuffix) {
LOG.assertTrue(!parentFileSuffix.isEmpty() && !childFileSuffix.isEmpty(), "file suffix must not be empty");
LOG.assertTrue(!parentFileSuffix.equals(childFileSuffix), "parent and child suffixes must be different: " + parentFileSuffix);
result.add(new NestingRule(parentFileSuffix, childFileSuffix));
}
};
for (ProjectViewNestingRulesProvider provider : EP_NAME.getExtensions()) {
provider.addFileNestingRules(consumer);
}
return result.toArray(new NestingRule[0]);
}
@Override
public MyState getState() {
return myState;
}
@Override
public void loadState(@NotNull final MyState state) {
myState = state;
}
/**
* This list of rules is used for serialization and for UI.
* See also {@link NestingTreeStructureProvider}, it adjusts this list of rules to match its needs
*/
@NotNull
public List<NestingRule> getRules() {
return myState.myRules;
}
public void setRules(@NotNull final List<NestingRule> rules) {
myState.myRules.clear();
myState.myRules.addAll(rules);
}
public static class MyState {
@Tag("nesting-rules")
@AbstractCollection(surroundWithTag = false)
public List<NestingRule> myRules = new SortedList<>(Comparator.comparing(o -> o.getParentFileSuffix()));
public MyState() {
myRules.addAll(Arrays.asList(DEFAULT_NESTING_RULES));
}
}
public static class NestingRule {
@NotNull private String myParentFileSuffix;
@NotNull private String myChildFileSuffix;
@SuppressWarnings("unused") // used by serializer
public NestingRule() {
this("", "");
}
public NestingRule(@NotNull String parentFileSuffix, @NotNull String childFileSuffix) {
myParentFileSuffix = parentFileSuffix;
myChildFileSuffix = childFileSuffix;
}
@NotNull
@Attribute("parent-file-suffix")
public String getParentFileSuffix() {
return myParentFileSuffix;
}
public void setParentFileSuffix(@NotNull final String parentFileSuffix) {
myParentFileSuffix = parentFileSuffix;
}
@NotNull
@Attribute("child-file-suffix")
public String getChildFileSuffix() {
return myChildFileSuffix;
}
public void setChildFileSuffix(@NotNull final String childFileSuffix) {
myChildFileSuffix = childFileSuffix;
}
@Override
public String toString() {
return myParentFileSuffix + "->" + myChildFileSuffix;
}
@Override
public boolean equals(Object o) {
return o instanceof NestingRule &&
myParentFileSuffix.equals(((NestingRule)o).myParentFileSuffix) &&
myChildFileSuffix.equals(((NestingRule)o).myChildFileSuffix);
}
@Override
public int hashCode() {
return myParentFileSuffix.hashCode() + 239 * myChildFileSuffix.hashCode();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -33,6 +33,7 @@ import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
@@ -51,7 +52,10 @@ import java.awt.*;
public class ProjectViewPane extends AbstractProjectViewPSIPane {
@NonNls public static final String ID = "ProjectPane";
public static final String SHOW_EXCLUDED_FILES_OPTION = "show-excluded-files";
private static final String USE_FILE_NESTING_RULES = "use-file-nesting-rules";
private boolean myShowExcludedFiles = true;
private boolean myUseFileNestingRules = true;
public ProjectViewPane(Project project) {
super(project);
@@ -116,6 +120,8 @@ public class ProjectViewPane extends AbstractProjectViewPSIPane {
super.readExternal(element);
String showExcludedOption = JDOMExternalizerUtil.readField(element, SHOW_EXCLUDED_FILES_OPTION);
myShowExcludedFiles = showExcludedOption == null || Boolean.parseBoolean(showExcludedOption);
String useFileNestingRules = JDOMExternalizerUtil.readField(element, USE_FILE_NESTING_RULES);
myUseFileNestingRules = useFileNestingRules == null || Boolean.parseBoolean(useFileNestingRules);
}
@Override
@@ -124,11 +130,19 @@ public class ProjectViewPane extends AbstractProjectViewPSIPane {
if (!myShowExcludedFiles) {
JDOMExternalizerUtil.writeField(element, SHOW_EXCLUDED_FILES_OPTION, String.valueOf(false));
}
if (!myUseFileNestingRules) {
JDOMExternalizerUtil.writeField(element, USE_FILE_NESTING_RULES, String.valueOf(false));
}
}
@Override
public void addToolbarActions(DefaultActionGroup actionGroup) {
actionGroup.addAction(new ShowExcludedFilesAction()).setAsSecondary(true);
actionGroup.addAction(new ConfigureFilesNestingAction()).setAsSecondary(true);
}
public boolean isUseFileNestingRules() {
return myUseFileNestingRules;
}
// should be first
@@ -186,6 +200,11 @@ public class ProjectViewPane extends AbstractProjectViewPSIPane {
return myShowExcludedFiles;
}
@Override
public boolean isUseFileNestingRules() {
return myUseFileNestingRules;
}
@Override
public boolean isToBuildChildrenInBackground(Object element) {
return Registry.is("ide.projectView.ProjectViewPaneTreeStructure.BuildChildrenInBackground");
@@ -218,4 +237,27 @@ public class ProjectViewPane extends AbstractProjectViewPSIPane {
presentation.setEnabledAndVisible(projectView.getCurrentProjectViewPane() == ProjectViewPane.this);
}
}
private class ConfigureFilesNestingAction extends DumbAwareAction {
private ConfigureFilesNestingAction() {
super(IdeBundle.message("action.file.nesting.in.project.view"));
}
@Override
public void update(@NotNull final AnActionEvent e) {
final ProjectView projectView = ProjectView.getInstance(myProject);
e.getPresentation().setEnabledAndVisible(projectView.getCurrentProjectViewPane() == ProjectViewPane.this);
}
@Override
public void actionPerformed(@NotNull final AnActionEvent e) {
final FileNestingInProjectViewDialog dialog = new FileNestingInProjectViewDialog(myProject);
dialog.reset(myUseFileNestingRules);
dialog.show();
if (dialog.isOK()) {
dialog.apply(useFileNestingRules -> myUseFileNestingRules = useFileNestingRules);
updateFromRoot(true);
}
}
}
}
@@ -583,6 +583,10 @@ action.show.libraries.contents=Show Libraries Contents
action.show.hide.library.contents=Show/Hide Library Contents
action.show.excluded.files=Show Excluded Files
action.show.hide.excluded.files=Show/Hide Excluded Files
action.file.nesting.in.project.view=File Nesting...
file.nesting.dialog.title=File Nesting
use.file.nesting.rules.checkbox=&Show files with the same names as nested according to the rules below
file.nesting.use.default.ruleset=Use the default ruleset
action.manual.order=Manual Order
action.sort.by.type=Sort by Type
action.show.structure=Show Structure
@@ -1028,6 +1028,8 @@
order="last"/>
<stripTrailingSpacesFilterFactory implementation="com.intellij.psi.codeStyle.KeepTrailingSpacesOnEmptyLinesFilterFactory"/>
<applicationService serviceInterface="com.intellij.ide.projectView.impl.ProjectViewFileNestingService"
serviceImplementation="com.intellij.ide.projectView.impl.ProjectViewFileNestingService"/>
<treeStructureProvider implementation="com.intellij.ide.projectView.impl.NestingTreeStructureProvider" order="last"/>
<refactoring.safeDeleteProcessor implementation="com.intellij.refactoring.safeDelete.RelatedFilesSafeDeleteProcessorDelegate"/>
<automaticRenamerFactory implementation="com.intellij.refactoring.rename.RelatedFilesRenamerFactory"/>