void () { myTable.setEnableAntialiasing(true); myTable.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); myTable.setRowSelectionAllowed(true); myTable.setShowGrid(false); myTable.getColumnModel().setColumnMargin(0); myTable.getTableHeader().setReorderingAllowed(false); TableRowSorter<MyModel<T>> sorter = new TableRowSorter<>(myModel); sorter.setStringConverter(new TableStringConverter() { final SimpleColoredText text = new SimpleColoredText(); @Override public String toString(TableModel model, int row, int column) { text.clear(); Pair<Object, T> pair = myModel.data.get(row); if (column == 0) renderTarget(pair.first, text); else if (pair.second != null) renderValue(pair.first, pair.second, text); else renderDefaultValue(pair.first, text); return StringUtil.toLowerCase(text.toString()); } }); sorter.setSortable(0, true); sorter.setSortable(1, true); sorter.setSortsOnUpdates(true); myTable.setRowSorter(sorter); myTable.getRowSorter().setSortKeys(Collections.singletonList(new RowSorter.SortKey(0, SortOrder.ASCENDING))); TableSpeedSearch.installOn(myTable, o -> keyToString(o)); FontMetrics metrics = myTable.getFontMetrics(myTable.getFont()); int maxValueWidth = 2 * metrics.stringWidth(myTable.getModel().getColumnName(1)); SimpleColoredText text = new SimpleColoredText(); for (T t : getValueVariants(null)) { text.clear(); renderValue(null, t, text); maxValueWidth = Math.max(metrics.stringWidth(text.toString()), maxValueWidth); } if (maxValueWidth < 300) { myTable.getColumnModel().getColumn(1).setMinWidth(maxValueWidth); } myTable.getColumnModel().getColumn(0).setMinWidth(metrics.stringWidth(myTable.getModel().getColumnName(0)) * 2); myTable.getColumnModel().getColumn(0).setCellRenderer(new ColoredTableCellRenderer() { @Override public void acquireState(JTable table, boolean isSelected, boolean hasFocus, int row, int column) { super.acquireState(table, isSelected, false, row, column); } @Override protected void customizeCellRenderer(@NotNull JTable table, @Nullable Object value, boolean selected, boolean hasFocus, int row, int column) { renderTarget(value, this); SpeedSearchUtil.applySpeedSearchHighlighting(table, this, false, selected); } }); myTable.getColumnModel().getColumn(1).setCellRenderer(new ColoredTableCellRenderer() { @Override public void acquireState(JTable table, boolean isSelected, boolean hasFocus, int row, int column) { super.acquireState(table, isSelected, false, row, column); } @Override protected void customizeCellRenderer(@NotNull JTable table, @Nullable Object value, boolean selected, boolean hasFocus, int row, int column) { Pair<Object, T> p = myModel.data.get(myTable.convertRowIndexToModel(row)); if (p.second != null) { setTransparentIconBackground(true); renderValue(p.first, p.second, this); } else { renderDefaultValue(p.first, this); } } }); myTable.getColumnModel().getColumn(0).setCellEditor(new AbstractTableCellEditor() { VirtualFile startValue; String newPath; @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { int modelRow = myTable.convertRowIndexToModel(row); Pair<Object, T> pair = myModel.data.get(modelRow); Object target = pair.first; if (!(target instanceof VirtualFile)) return null; startValue = (VirtualFile)target; newPath = null; TextFieldWithBrowseButton panel = new TextFieldWithBrowseButton(); panel.setText(startValue.getPath()); panel.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { @Override protected void textChanged(@NotNull DocumentEvent e) { newPath = panel.getTextField().getText(); } }); panel.addBrowseFolderListener(new TextBrowseFolderListener(FileChooserDescriptorFactory.createSingleLocalFileDescriptor())); return panel; } @Override public Object getCellEditorValue() { if (newPath == null || newPath.equals(startValue.getPath())) return startValue; VirtualFile newFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(this.newPath); return ObjectUtils.notNull(newFile, startValue); } }); myTable.getColumnModel().getColumn(1).setCellEditor(new AbstractTableCellEditor() { T editorValue; @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { int modelRow = myTable.convertRowIndexToModel(row); Pair<Object, T> pair = myModel.data.get(modelRow); Object target = pair.first; editorValue = pair.second; // (T)value if (!canEditTarget(target, editorValue)) return null; JPanel panel = createActionPanel(target, new Value<>() { @Override public T get() { return editorValue; } @Override public void set(T value) { editorValue = adjustChosenValue(target, value); } @Override public void commit() { TableUtil.stopEditing(myTable); selectRows(new int[]{modelRow}, true); if (Comparing.equal(editorValue, pair.second)) { // do nothing } else { int ret = clearSubdirectoriesOnDemandOrCancel(false, target); if (ret == Messages.CANCEL) { myModel.setValueAt(value, modelRow, column); } selectRows(new int[]{modelRow}, true); } } }, true); return panel; } @Override public Object getCellEditorValue() { return editorValue; } }); }