7901b4205f0c497047eb6153a9280e7a96434704
[idea/community.git] / plugins / InspectionGadgets / src / com / siyeh / ig / ui / UiUtils.java
1 /*
2  * Copyright 2010-2016 Bas Leijdekkers
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.siyeh.ig.ui;
17
18 import com.intellij.codeInspection.ui.ListTable;
19 import com.intellij.codeInspection.ui.ListWrappingTableModel;
20 import com.intellij.ide.DataManager;
21 import com.intellij.ide.util.ClassFilter;
22 import com.intellij.ide.util.TreeClassChooser;
23 import com.intellij.ide.util.TreeClassChooserFactory;
24 import com.intellij.openapi.actionSystem.CommonDataKeys;
25 import com.intellij.openapi.actionSystem.DataContext;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.psi.PsiClass;
28 import com.intellij.psi.search.GlobalSearchScope;
29 import com.intellij.psi.util.InheritanceUtil;
30 import com.intellij.ui.*;
31 import com.intellij.ui.components.JBList;
32 import com.intellij.util.ui.JBUI;
33 import org.jetbrains.annotations.NonNls;
34
35 import javax.swing.*;
36 import javax.swing.table.TableCellEditor;
37 import java.awt.*;
38 import java.util.Collection;
39
40 public class UiUtils {
41
42   private UiUtils() {
43   }
44
45   public static void setComponentSize(Component component, int rows, int columns) {
46     final FontMetrics fontMetrics = component.getFontMetrics(component.getFont());
47     final int width = fontMetrics.charWidth('m') * columns;
48     component.setPreferredSize(new Dimension(width, fontMetrics.getHeight() * rows));
49   }
50
51   public static JPanel createAddRemovePanel(final ListTable table) {
52     final JPanel panel = ToolbarDecorator.createDecorator(table)
53       .setAddAction(new AnActionButtonRunnable() {
54         @Override
55         public void run(AnActionButton button) {
56           final ListWrappingTableModel tableModel = table.getModel();
57           tableModel.addRow();
58           EventQueue.invokeLater(() -> {
59             final int lastRowIndex = tableModel.getRowCount() - 1;
60             editTableCell(table, lastRowIndex, 0);
61           });
62         }
63       }).setRemoveAction(new RemoveAction(table))
64       .disableUpDownActions().createPanel();
65     panel.setPreferredSize(JBUI.size(150, 100));
66     return panel;
67   }
68
69   public static JPanel createAddRemoveTreeClassChooserPanel(final ListTable table, final String chooserTitle,
70                                                             @NonNls String... ancestorClasses) {
71     final ClassFilter filter;
72     if (ancestorClasses.length == 0) {
73       filter = ClassFilter.ALL;
74     }
75     else {
76       filter = new SubclassFilter(ancestorClasses);
77     }
78     final JPanel panel = ToolbarDecorator.createDecorator(table)
79       .setAddAction(new AnActionButtonRunnable() {
80         @Override
81         public void run(AnActionButton button) {
82           final DataContext dataContext = DataManager.getInstance().getDataContext(table);
83           final Project project = CommonDataKeys.PROJECT.getData(dataContext);
84           final int rowIndex;
85           final ListWrappingTableModel tableModel = table.getModel();
86           if (project == null) {
87             tableModel.addRow();
88             rowIndex = tableModel.getRowCount() - 1;
89           }
90           else {
91             final TreeClassChooserFactory chooserFactory = TreeClassChooserFactory.getInstance(project);
92             final TreeClassChooser classChooser =
93               chooserFactory.createWithInnerClassesScopeChooser(chooserTitle, GlobalSearchScope.allScope(project), filter, null);
94             classChooser.showDialog();
95             final PsiClass selectedClass = classChooser.getSelected();
96             if (selectedClass == null) {
97               return;
98             }
99             final String qualifiedName = selectedClass.getQualifiedName();
100             final int index = tableModel.indexOf(qualifiedName, 0);
101             if (index < 0) {
102               tableModel.addRow(qualifiedName);
103               rowIndex = tableModel.getRowCount() - 1;
104             }
105             else {
106               rowIndex = index;
107             }
108           }
109           editTableCell(table, rowIndex, table.getColumnCount() > 1 && project != null ? 1 : 0);
110         }
111       }).setRemoveAction(new RemoveAction(table))
112       .disableUpDownActions().createPanel();
113     panel.setPreferredSize(JBUI.size(150, 100));
114     return panel;
115   }
116
117   private static void editTableCell(final ListTable table, final int row, final int column) {
118     final ListSelectionModel selectionModel = table.getSelectionModel();
119     selectionModel.setSelectionInterval(row, row);
120     EventQueue.invokeLater(() -> {
121       final ListWrappingTableModel tableModel = table.getModel();
122       table.requestFocus();
123       final Rectangle rectangle = table.getCellRect(row, column, true);
124       table.scrollRectToVisible(rectangle);
125       table.editCellAt(row, column);
126       final TableCellEditor editor = table.getCellEditor();
127       final Component component = editor.getTableCellEditorComponent(table, tableModel.getValueAt(row, column), true, row, column);
128       component.requestFocus();
129     });
130   }
131
132   public static JPanel createTreeClassChooserList(final Collection<String> collection,
133                                                   String borderTitle,
134                                                   final String chooserTitle,
135                                                   String... ancestorClasses) {
136     final ClassFilter filter;
137     if (ancestorClasses.length == 0) {
138       filter = ClassFilter.ALL;
139     }
140     else {
141       filter = new SubclassFilter(ancestorClasses);
142     }
143     final JPanel optionsPanel = new JPanel(new BorderLayout());
144     final JBList list = new JBList(collection);
145
146     final JPanel panel = ToolbarDecorator.createDecorator(list)
147       .disableUpDownActions()
148       .setAddAction(new AnActionButtonRunnable() {
149         @Override
150         public void run(AnActionButton anActionButton) {
151           final DataContext dataContext = DataManager.getInstance().getDataContext(list);
152           final Project project = CommonDataKeys.PROJECT.getData(dataContext);
153           if (project == null) {
154             return;
155           }
156           final TreeClassChooser chooser = TreeClassChooserFactory.getInstance(project)
157             .createNoInnerClassesScopeChooser(chooserTitle, GlobalSearchScope.allScope(project), filter, null);
158           chooser.showDialog();
159           final PsiClass selected = chooser.getSelected();
160           if (selected == null) {
161             return;
162           }
163           final String qualifiedName = selected.getQualifiedName();
164           final DefaultListModel model = (DefaultListModel)list.getModel();
165           final int index = model.indexOf(qualifiedName);
166           if (index < 0) {
167             model.addElement(qualifiedName);
168             collection.add(qualifiedName);
169           }
170           else {
171             list.setSelectedIndex(index);
172           }
173         }
174       })
175       .setRemoveAction(new AnActionButtonRunnable() {
176         @Override
177         public void run(AnActionButton anActionButton) {
178           collection.remove(list.getSelectedValue());
179           ListUtil.removeSelectedItems(list);
180         }
181       }).createPanel();
182     panel.setPreferredSize(JBUI.size(150, 100));
183     optionsPanel.setBorder(IdeBorderFactory.createTitledBorder(borderTitle,
184                                                                false, JBUI.insetsTop(10)));
185     optionsPanel.add(panel);
186     return optionsPanel;
187   }
188
189   private static class RemoveAction implements AnActionButtonRunnable {
190
191     private final ListTable table;
192
193     public RemoveAction(ListTable table) {
194       this.table = table;
195     }
196
197     @Override
198     public void run(AnActionButton button) {
199       EventQueue.invokeLater(() -> {
200         final TableCellEditor editor = table.getCellEditor();
201         if (editor != null) {
202           editor.stopCellEditing();
203         }
204         final ListSelectionModel selectionModel = table.getSelectionModel();
205         final int minIndex = selectionModel.getMinSelectionIndex();
206         final int maxIndex = selectionModel.getMaxSelectionIndex();
207         if (minIndex == -1 || maxIndex == -1) {
208           return;
209         }
210         final ListWrappingTableModel tableModel = table.getModel();
211         for (int i = minIndex; i <= maxIndex; i++) {
212           tableModel.removeRow(minIndex);
213         }
214         final int count = tableModel.getRowCount();
215         if (count <= minIndex) {
216           selectionModel.setSelectionInterval(count - 1, count - 1);
217         }
218         else if (minIndex <= 0) {
219           if (count > 0) {
220             selectionModel.setSelectionInterval(0, 0);
221           }
222         }
223         else {
224           selectionModel.setSelectionInterval(minIndex - 1, minIndex - 1);
225         }
226       });
227     }
228   }
229
230   private static class SubclassFilter implements ClassFilter {
231
232     private final String[] ancestorClasses;
233
234     private SubclassFilter(String[] ancestorClasses) {
235       this.ancestorClasses = ancestorClasses;
236     }
237
238     @Override
239     public boolean isAccepted(PsiClass aClass) {
240       for (String ancestorClass : ancestorClasses) {
241         if (InheritanceUtil.isInheritor(aClass, ancestorClass)) {
242           return true;
243         }
244       }
245       return false;
246     }
247   }
248 }