Skip to content

Commit 79201d3

Browse files
authored
Improve selection table in python UI dialog (#2182)
* Add simple python table * Continue with dialog window * New table in python dialog window * Remove unused code * Support file selection * Fix TestSourceDirectoryChooser
1 parent 3580196 commit 79201d3

File tree

11 files changed

+758
-257
lines changed

11 files changed

+758
-257
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.utbot.intellij.plugin.language.python.table;
2+
3+
import com.intellij.icons.AllIcons;
4+
import com.jetbrains.python.psi.PyClass;
5+
import com.jetbrains.python.psi.PyElement;
6+
7+
import javax.swing.*;
8+
9+
public class UtPyClassItem implements UtPyTableItem {
10+
private final PyClass pyClass;
11+
private boolean isChecked;
12+
13+
public UtPyClassItem(PyClass clazz) {
14+
pyClass = clazz;
15+
isChecked = false;
16+
}
17+
18+
@Override
19+
public PyElement getContent() {
20+
return pyClass;
21+
}
22+
23+
@Override
24+
public String getIdName() {
25+
return pyClass.getQualifiedName();
26+
}
27+
28+
@Override
29+
public Icon getIcon() {
30+
return AllIcons.Nodes.Class;
31+
}
32+
33+
@Override
34+
public boolean isChecked() {
35+
return isChecked;
36+
}
37+
38+
@Override
39+
public void setChecked(boolean valueToBeSet) {
40+
isChecked = valueToBeSet;
41+
}
42+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.utbot.intellij.plugin.language.python.table;
2+
3+
import com.intellij.icons.AllIcons;
4+
import com.jetbrains.python.psi.PyElement;
5+
import com.jetbrains.python.psi.PyFunction;
6+
7+
import javax.swing.*;
8+
9+
public class UtPyFunctionItem implements UtPyTableItem {
10+
private final PyFunction pyFunction;
11+
private boolean isChecked;
12+
13+
public UtPyFunctionItem(PyFunction function) {
14+
pyFunction = function;
15+
isChecked = false;
16+
}
17+
18+
@Override
19+
public PyElement getContent() {
20+
return pyFunction;
21+
}
22+
23+
@Override
24+
public String getIdName() {
25+
return pyFunction.getQualifiedName();
26+
}
27+
28+
@Override
29+
public Icon getIcon() {
30+
return AllIcons.Nodes.Function;
31+
}
32+
33+
@Override
34+
public boolean isChecked() {
35+
return isChecked;
36+
}
37+
38+
@Override
39+
public void setChecked(boolean valueToBeSet) {
40+
isChecked = valueToBeSet;
41+
}
42+
}
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
package org.utbot.intellij.plugin.language.python.table;
2+
3+
import com.intellij.openapi.actionSystem.CommonDataKeys;
4+
import com.intellij.openapi.actionSystem.DataProvider;
5+
import com.intellij.refactoring.ui.EnableDisableAction;
6+
import com.intellij.ui.*;
7+
import com.intellij.ui.icons.RowIcon;
8+
import com.intellij.ui.table.JBTable;
9+
import com.intellij.util.containers.ContainerUtil;
10+
import com.intellij.util.ui.JBUI;
11+
import org.jetbrains.annotations.NonNls;
12+
import org.jetbrains.annotations.NotNull;
13+
import org.jetbrains.annotations.Nullable;
14+
15+
import javax.swing.*;
16+
import javax.swing.table.AbstractTableModel;
17+
import javax.swing.table.TableColumn;
18+
import javax.swing.table.TableColumnModel;
19+
import java.awt.*;
20+
import java.util.ArrayList;
21+
import java.util.Collection;
22+
import java.util.List;
23+
24+
public class UtPyMemberSelectionTable<T extends UtPyTableItem> extends JBTable implements DataProvider {
25+
protected static final int CHECKED_COLUMN = 0;
26+
protected static final int DISPLAY_NAME_COLUMN = 1;
27+
protected static final int ICON_POSITION = 0;
28+
29+
protected List<T> myItems;
30+
protected MyTableModel<T> myTableModel;
31+
32+
public UtPyMemberSelectionTable(Collection<T> items) {
33+
myItems = new ArrayList<>(items);
34+
myTableModel = new MyTableModel<>(this);
35+
setModel(myTableModel);
36+
37+
TableColumnModel model = getColumnModel();
38+
model.getColumn(DISPLAY_NAME_COLUMN).setCellRenderer(new MyTableRenderer<>(this));
39+
TableColumn checkBoxColumn = model.getColumn(CHECKED_COLUMN);
40+
TableUtil.setupCheckboxColumn(checkBoxColumn);
41+
checkBoxColumn.setCellRenderer(new MyBooleanRenderer<>(this));
42+
setPreferredScrollableViewportSize(JBUI.size(400, -1));
43+
setVisibleRowCount(12);
44+
getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
45+
setShowGrid(false);
46+
setIntercellSpacing(new Dimension(0, 0));
47+
new MyEnableDisableAction().register();
48+
}
49+
50+
public void setItems(Collection<T> items) {
51+
myItems = new ArrayList<>(items);
52+
}
53+
54+
@Override
55+
public @Nullable Object getData(@NotNull @NonNls String dataId) {
56+
if (CommonDataKeys.PSI_ELEMENT.is(dataId)) {
57+
return ContainerUtil.getFirstItem(getSelectedMemberInfos());
58+
}
59+
return null;
60+
}
61+
62+
public Collection<T> getSelectedMemberInfos() {
63+
ArrayList<T> list = new ArrayList<>(myItems.size());
64+
for (T info : myItems) {
65+
if (info.isChecked()) {
66+
list.add(info);
67+
}
68+
}
69+
return list;
70+
}
71+
72+
private class MyEnableDisableAction extends EnableDisableAction {
73+
74+
@Override
75+
protected JTable getTable() {
76+
return UtPyMemberSelectionTable.this;
77+
}
78+
79+
@Override
80+
protected void applyValue(int[] rows, boolean valueToBeSet) {
81+
for (int row : rows) {
82+
final T memberInfo = myItems.get(row);
83+
memberInfo.setChecked(valueToBeSet);
84+
}
85+
final int[] selectedRows = getSelectedRows();
86+
final ListSelectionModel selectionModel = getSelectionModel();
87+
for (int selectedRow : selectedRows) {
88+
selectionModel.addSelectionInterval(selectedRow, selectedRow);
89+
}
90+
}
91+
92+
@Override
93+
protected boolean isRowChecked(final int row) {
94+
return myItems.get(row).isChecked();
95+
}
96+
}
97+
98+
private static class MyBooleanRenderer<T extends UtPyTableItem> extends BooleanTableCellRenderer {
99+
private final UtPyMemberSelectionTable<T> myTable;
100+
101+
MyBooleanRenderer(UtPyMemberSelectionTable<T> table) {
102+
myTable = table;
103+
}
104+
105+
@Override
106+
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
107+
Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
108+
if (component instanceof JCheckBox) {
109+
int modelColumn = myTable.convertColumnIndexToModel(column);
110+
T itemInfo = myTable.myItems.get(row);
111+
component.setEnabled(modelColumn == CHECKED_COLUMN || itemInfo.isChecked());
112+
}
113+
return component;
114+
}
115+
}
116+
117+
private static class MyTableRenderer<T extends UtPyTableItem> extends ColoredTableCellRenderer {
118+
private final UtPyMemberSelectionTable<T> myTable;
119+
120+
MyTableRenderer(UtPyMemberSelectionTable<T> table) {
121+
myTable = table;
122+
}
123+
124+
@Override
125+
public void customizeCellRenderer(@NotNull JTable table, final Object value,
126+
boolean isSelected, boolean hasFocus, final int row, final int column) {
127+
128+
final int modelColumn = myTable.convertColumnIndexToModel(column);
129+
final T item = myTable.myItems.get(row);
130+
if (modelColumn == DISPLAY_NAME_COLUMN) {
131+
Icon itemIcon = item.getIcon();
132+
RowIcon icon = IconManager.getInstance().createRowIcon(3);
133+
icon.setIcon(itemIcon, ICON_POSITION);
134+
setIcon(icon);
135+
}
136+
else {
137+
setIcon(null);
138+
}
139+
setIconOpaque(false);
140+
setOpaque(false);
141+
142+
if (value == null) return;
143+
append((String)value);
144+
}
145+
146+
}
147+
148+
protected static class MyTableModel<T extends UtPyTableItem> extends AbstractTableModel {
149+
private final UtPyMemberSelectionTable<T> myTable;
150+
private Boolean removePrefix;
151+
152+
public MyTableModel(UtPyMemberSelectionTable<T> table) {
153+
myTable = table;
154+
}
155+
156+
private void initRemovePrefix() {
157+
List<String> names = new ArrayList<>();
158+
for (UtPyTableItem item: myTable.myItems) {
159+
names.add(item.getIdName());
160+
}
161+
removePrefix = Utils.haveCommonPrefix(names);
162+
}
163+
164+
@Override
165+
public int getColumnCount() {
166+
return 2;
167+
}
168+
169+
@Override
170+
public int getRowCount() {
171+
return myTable.myItems.size();
172+
}
173+
174+
@Override
175+
public Class getColumnClass(int columnIndex) {
176+
if (columnIndex == CHECKED_COLUMN) {
177+
return Boolean.class;
178+
}
179+
return super.getColumnClass(columnIndex);
180+
}
181+
182+
@Override
183+
public Object getValueAt(int rowIndex, int columnIndex) {
184+
if (removePrefix == null) {
185+
initRemovePrefix();
186+
}
187+
final T itemInfo = myTable.myItems.get(rowIndex);
188+
if (columnIndex == CHECKED_COLUMN) {
189+
return itemInfo.isChecked();
190+
} else if (columnIndex == DISPLAY_NAME_COLUMN) {
191+
if (removePrefix) {
192+
return Utils.getSuffix(itemInfo.getIdName());
193+
}
194+
return itemInfo.getIdName();
195+
} else {
196+
throw new RuntimeException("Incorrect column index");
197+
}
198+
}
199+
200+
@Override
201+
public String getColumnName(int column) {
202+
if (column == CHECKED_COLUMN) {
203+
return " ";
204+
} else if (column == DISPLAY_NAME_COLUMN) {
205+
return "Members";
206+
} else {
207+
throw new RuntimeException("Incorrect column index");
208+
}
209+
}
210+
211+
@Override
212+
public boolean isCellEditable(int rowIndex, int columnIndex) {
213+
return columnIndex == CHECKED_COLUMN;
214+
}
215+
216+
217+
@Override
218+
public void setValueAt(final Object aValue, final int rowIndex, final int columnIndex) {
219+
if (columnIndex == CHECKED_COLUMN) {
220+
myTable.myItems.get(rowIndex).setChecked((Boolean) aValue);
221+
}
222+
}
223+
}
224+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.utbot.intellij.plugin.language.python.table;
2+
3+
import com.jetbrains.python.psi.PyElement;
4+
5+
import javax.swing.*;
6+
7+
public interface UtPyTableItem {
8+
9+
public PyElement getContent();
10+
11+
public String getIdName();
12+
13+
public Icon getIcon();
14+
15+
boolean isChecked();
16+
17+
void setChecked(boolean valueToBeSet);
18+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.utbot.intellij.plugin.language.python.table;
2+
3+
import java.util.HashSet;
4+
import java.util.List;
5+
import java.util.Set;
6+
7+
public class Utils {
8+
public static Boolean haveCommonPrefix(List<String> strings) {
9+
Set<String> prefixes = new HashSet<>();
10+
for (String str: strings) {
11+
prefixes.add(getPrefix(str));
12+
}
13+
return prefixes.size() <= 1;
14+
}
15+
16+
public static String getPrefix(String str) {
17+
String suffix = getSuffix(str);
18+
int len = str.length();
19+
return str.substring(0, len-suffix.length()-1);
20+
}
21+
22+
public static String getSuffix(String str) {
23+
String[] parts = str.split("\\.");
24+
int len = parts.length;
25+
return parts[len-1];
26+
}
27+
}

0 commit comments

Comments
 (0)