private static void installImpl(final @NotNull JComponent component, final @NotNull EditableModel model) {
    component.setTransferHandler(new TransferHandler(null));
    SmoothAutoScroller.installDropTargetAsNecessary(component);

    DnDSupport.createBuilder(component)
      .setBeanProvider(info -> {
        final Point p = info.getPoint();
        return new DnDDragStartBean(new RowDragInfo(component, getRow(component, p)));
      })
      .setTargetChecker(new DnDTargetChecker() {
        @Override
        public boolean update(DnDEvent event) {
          final Object o = event.getAttachedObject();
          if (! (o instanceof RowDragInfo) || ((RowDragInfo)o).component != component) {
            event.setDropPossible(false, "");
            return true;
          }
          event.setDropPossible(true);
          int oldIndex = ((RowDragInfo)o).row;
          int newIndex = getRow(component, event.getPoint());

          if (newIndex == -1) {
            event.setDropPossible(false, "");
            return true;
          }

          Rectangle cellBounds = getCellBounds(component, newIndex);
          if (model instanceof RefinedDropSupport) {
            RefinedDropSupport.Position position = ((RefinedDropSupport)model).isDropInto(component, oldIndex, newIndex)
                                                   ? INTO
                                                   : (event.getPoint().y < cellBounds.y + cellBounds.height / 2)
                                                     ? ABOVE
                                                     : BELOW;
            boolean canDrop = ((RefinedDropSupport)model).canDrop(oldIndex, newIndex, position);
            event.setDropPossible(canDrop);
            if (canDrop && oldIndex != newIndex) {
              switch (position) {
                case INTO:
                  event.setHighlighting(new RelativeRectangle(component, cellBounds), DnDEvent.DropTargetHighlightingType.RECTANGLE);
                  break;
                case BELOW:
                  cellBounds.y += cellBounds.height;
                case ABOVE:
                  cellBounds.y -= -1;
                  cellBounds.height = 2;
                  event.setHighlighting(new RelativeRectangle(component, cellBounds), DnDEvent.DropTargetHighlightingType.FILLED_RECTANGLE);
                  break;
              }
            }
            else {
              event.hideHighlighter();
            }
          }
          else if (oldIndex != newIndex) {
            // Drag&Drop always starts with new==old and we shouldn't display 'rejecting' cursor if they are equal
            boolean canExchange = model.canExchangeRows(oldIndex, newIndex);
            if (canExchange) {
              if (oldIndex < newIndex) {
                cellBounds.y += cellBounds.height - 2;
              }
              RelativeRectangle rectangle = new RelativeRectangle(component, cellBounds);
              rectangle.getDimension().height = 2;
              event.setDropPossible(true);
              event.setHighlighting(rectangle, DnDEvent.DropTargetHighlightingType.FILLED_RECTANGLE);
            }
            else {
              event.setDropPossible(false);
            }
          }
          return true;
        }
      })
      .setDropHandler(new DnDDropHandler() {
        @Override
        public void drop(DnDEvent event) {
          final Object o = event.getAttachedObject();
          final Point p = event.getPoint();
          if (o instanceof RowDragInfo && ((RowDragInfo)o).component == component) {
            int oldIndex = ((RowDragInfo)o).row;
            if (oldIndex == -1) return;
            int newIndex = getRow(component, p);
            if (newIndex == -1) {
              newIndex = getRowCount(component) - 1;
            }

            if (oldIndex != newIndex) {
              if (model instanceof RefinedDropSupport) {
                Rectangle cellBounds = getCellBounds(component, newIndex);
                RefinedDropSupport.Position position = ((RefinedDropSupport)model).isDropInto(component, oldIndex, newIndex)
                                                       ? INTO
                                                       : (event.getPoint().y < cellBounds.y + cellBounds.height / 2)
                                                         ? ABOVE
                                                         : BELOW;
                if (((RefinedDropSupport)model).canDrop(oldIndex, newIndex, position)) {
                  ((RefinedDropSupport)model).drop(oldIndex, newIndex, position);
                }
              }
              else {
                if (model.canExchangeRows(oldIndex, newIndex)) {
                  model.exchangeRows(oldIndex, newIndex);
                  setSelectedRow(component, newIndex);
                }
              }
            }
          }
          event.hideHighlighter();
        }
      })
      .install();
  }
private static void installImpl(final @NotNull JComponent component, final @NotNull EditableModel model)