EditorConfig documentation test
[idea/community.git] / java / java-impl / src / com / intellij / application / options / editor / ExcludeTable.java
1 // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.application.options.editor;
3
4 import com.intellij.codeInsight.CodeInsightSettings;
5 import com.intellij.codeInsight.JavaProjectCodeInsightSettings;
6 import com.intellij.execution.util.ListTableWithButtons;
7 import com.intellij.icons.AllIcons;
8 import com.intellij.ide.ui.laf.darcula.DarculaUIUtil;
9 import com.intellij.openapi.Disposable;
10 import com.intellij.openapi.application.ApplicationBundle;
11 import com.intellij.openapi.project.Project;
12 import com.intellij.openapi.ui.ComboBoxTableRenderer;
13 import com.intellij.openapi.ui.ComponentValidator;
14 import com.intellij.openapi.ui.ValidationInfo;
15 import com.intellij.openapi.ui.cellvalidators.CellComponentProvider;
16 import com.intellij.openapi.ui.cellvalidators.CellTooltipManager;
17 import com.intellij.openapi.ui.cellvalidators.ValidatingTableCellRendererWrapper;
18 import com.intellij.openapi.ui.cellvalidators.ValidationUtils;
19 import com.intellij.openapi.util.Disposer;
20 import com.intellij.openapi.util.text.StringUtil;
21 import com.intellij.openapi.wm.IdeFocusManager;
22 import com.intellij.ui.ScrollingUtil;
23 import com.intellij.ui.components.fields.ExtendableTextField;
24 import com.intellij.ui.scale.JBUIScale;
25 import com.intellij.ui.table.JBTable;
26 import com.intellij.util.ArrayUtilRt;
27 import com.intellij.util.ui.ColumnInfo;
28 import com.intellij.util.ui.ListTableModel;
29 import org.jetbrains.annotations.NotNull;
30 import org.jetbrains.annotations.Nullable;
31
32 import javax.swing.*;
33 import javax.swing.table.DefaultTableCellRenderer;
34 import javax.swing.table.TableCellEditor;
35 import javax.swing.table.TableCellRenderer;
36 import java.util.*;
37 import java.util.function.BiFunction;
38 import java.util.regex.Pattern;
39
40 class ExcludeTable extends ListTableWithButtons<ExcludeTable.Item> {
41   private static final Pattern ourPackagePattern = Pattern.compile("([\\w*]+\\.)*[\\w*]+");
42
43   private static final BiFunction<Object, JComponent, ValidationInfo> validationInfoProducer = (value, component) ->
44     (value == null || StringUtil.isEmpty(value.toString()) || ourPackagePattern.matcher(value.toString()).matches()) ?
45       null : new ValidationInfo("Illegal name: " + value.toString(), component);
46
47   private static final Disposable validatorsDisposable = Disposer.newDisposable();
48   private static final ColumnInfo<Item, String> NAME_COLUMN = new ColumnInfo<Item, String>("Class/package/member qualified name mask") {
49
50     @Nullable
51     @Override
52     public String valueOf(Item pair) {
53       return pair.exclude;
54     }
55
56     @Override
57     public TableCellEditor getEditor(Item pair) {
58       ExtendableTextField cellEditor = new ExtendableTextField();
59       cellEditor.putClientProperty(DarculaUIUtil.COMPACT_PROPERTY, Boolean.TRUE);
60
61       new ComponentValidator(validatorsDisposable).withValidator(() -> {
62         String text = cellEditor.getText();
63         boolean hasError = !StringUtil.isEmpty(text) && !ourPackagePattern.matcher(text).matches();
64         ValidationUtils.setExtension(cellEditor, ValidationUtils.ERROR_EXTENSION, hasError);
65
66         return validationInfoProducer.apply(text, cellEditor);
67       }).andRegisterOnDocumentListener(cellEditor).installOn(cellEditor);
68
69       return new DefaultCellEditor(cellEditor);
70     }
71
72     @Override
73     public TableCellRenderer getRenderer(Item pair) {
74       JTextField cellEditor = new JTextField();
75       cellEditor.putClientProperty(DarculaUIUtil.COMPACT_PROPERTY, Boolean.TRUE);
76
77       return new ValidatingTableCellRendererWrapper(new DefaultTableCellRenderer()).
78         withCellValidator((value, row, column) -> validationInfoProducer.apply(value, null)).
79         bindToEditorSize(cellEditor::getPreferredSize);
80     }
81
82     @Override
83     public boolean isCellEditable(Item pair) {
84       return true;
85     }
86
87     @Override
88     public void setValue(Item item, String value) {
89       item.exclude = value;
90     }
91   };
92
93   private static final ColumnInfo<Item, ExclusionScope> SCOPE_COLUMN = new ColumnInfo<Item, ExclusionScope>("Scope") {
94     @Nullable
95     @Override
96     public ExclusionScope valueOf(Item pair) {
97       return pair.scope;
98     }
99
100     @Override
101     public TableCellRenderer getRenderer(Item pair) {
102       return new ComboBoxTableRenderer<>(ExclusionScope.values());
103     }
104
105     @Override
106     public TableCellEditor getEditor(Item pair) {
107       return new ComboBoxTableRenderer<>(ExclusionScope.values());
108     }
109
110     @Override
111     public boolean isCellEditable(Item pair) {
112       return true;
113     }
114
115     @Override
116     public void setValue(Item pair, ExclusionScope value) {
117       pair.scope = value;
118     }
119
120     @Override
121     public String getMaxStringValue() {
122       return "Project";
123     }
124
125     @Override
126     public int getAdditionalWidth() {
127       return JBUIScale.scale(12) + AllIcons.General.ArrowDown.getIconWidth();
128     }
129   };
130   private final Project myProject;
131
132   ExcludeTable(@NotNull Project project) {
133     myProject = project;
134
135     JBTable table = getTableView();
136     table.getEmptyText().setText(ApplicationBundle.message("exclude.from.imports.no.exclusions"));
137     table.setStriped(false);
138     new CellTooltipManager(myProject).withCellComponentProvider(CellComponentProvider.forTable(table)).installOn(table);
139
140     Disposer.register(project, validatorsDisposable);
141   }
142
143   @Override
144   protected ListTableModel createListModel() {
145     return new ListTableModel<Item>(NAME_COLUMN, SCOPE_COLUMN);
146   }
147
148   @Override
149   protected Item createElement() {
150     return new Item("", ExclusionScope.IDE);
151   }
152
153   @Override
154   protected boolean isEmpty(Item element) {
155     return element.exclude.isEmpty();
156   }
157
158   @Override
159   protected Item cloneElement(Item variable) {
160     return new Item(variable.exclude, variable.scope);
161   }
162
163   @Override
164   protected boolean canDeleteElement(Item selection) {
165     return true;
166   }
167
168   void addExcludePackage(@NotNull String packageName) {
169     int index = 0;
170     while (index < getTableView().getListTableModel().getRowCount()) {
171       if (getTableView().getListTableModel().getItem(index).exclude.compareTo(packageName) > 0) {
172         break;
173       }
174       index++;
175     }
176
177     getTableView().getListTableModel().insertRow(index, new Item(packageName, ExclusionScope.IDE));
178     getTableView().clearSelection();
179     getTableView().addRowSelectionInterval(index, index);
180     ScrollingUtil.ensureIndexIsVisible(getTableView(), index, 0);
181     IdeFocusManager.getGlobalInstance().requestFocus(getTableView(), false);
182   }
183
184   void reset() {
185     List<Item> rows = new ArrayList<>();
186     for (String s : CodeInsightSettings.getInstance().EXCLUDED_PACKAGES) {
187       rows.add(new Item(s, ExclusionScope.IDE));
188     }
189     for (String s : JavaProjectCodeInsightSettings.getSettings(myProject).excludedNames) {
190       rows.add(new Item(s, ExclusionScope.Project));
191     }
192     Collections.sort(rows, Comparator.comparing(o -> o.exclude));
193
194     setValues(rows);
195   }
196
197   void apply() {
198     CodeInsightSettings.getInstance().EXCLUDED_PACKAGES = ArrayUtilRt.toStringArray(getExcludedPackages(ExclusionScope.IDE));
199     JavaProjectCodeInsightSettings.getSettings(myProject).excludedNames = getExcludedPackages(ExclusionScope.Project);
200   }
201
202   private List<String> getExcludedPackages(ExclusionScope scope) {
203     List<String> result = new ArrayList<>();
204     for (Item pair : getTableView().getListTableModel().getItems()) {
205       if (scope == pair.scope) {
206         result.add(pair.exclude);
207       }
208     }
209     Collections.sort(result);
210     return result;
211   }
212
213   boolean isModified() {
214     return !getExcludedPackages(ExclusionScope.IDE).equals(Arrays.asList(CodeInsightSettings.getInstance().EXCLUDED_PACKAGES))
215            ||
216            !getExcludedPackages(ExclusionScope.Project).equals(JavaProjectCodeInsightSettings.getSettings(myProject).excludedNames);
217
218   }
219
220   private enum ExclusionScope {Project, IDE}
221
222   static class Item {
223     String exclude;
224     ExclusionScope scope;
225
226     Item(@NotNull String exclude, ExclusionScope scope) {
227       this.exclude = exclude;
228       this.scope = scope;
229     }
230   }
231 }