private void setupPerFileTable() {
    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;
      }
    });
  }
private void setupPerFileTable()