001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.util;
003
004import javax.swing.ListSelectionModel;
005import javax.swing.table.TableModel;
006
007import org.openstreetmap.josm.data.ReorderableModel;
008
009/**
010 * Defines a table model that can be reordered.
011 * @param <T> item type
012 * @since 15226
013 */
014public interface ReorderableTableModel<T> extends TableModel, ReorderableModel<T> {
015
016    /**
017     * Returns the selection model.
018     * @return the selection model (never null)
019     */
020    ListSelectionModel getSelectionModel();
021
022    /**
023     * Returns an array of all of the selected indices in the selection model, in increasing order.
024     * @return an array of all of the selected indices in the selection model, in increasing order
025     */
026    default int[] getSelectedIndices() {
027        return TableHelper.getSelectedIndices(getSelectionModel());
028    }
029
030    /**
031     * Checks that the currently selected range of rows can be moved by a number of positions.
032     * @param delta negative or positive delta
033     * @return {@code true} if rows can be moved
034     */
035    default boolean canMove(int delta) {
036        return canMove(delta, this::getRowCount, getSelectedIndices());
037    }
038
039    /**
040     * Checks that the currently selected range of rows can be moved up.
041     * @return {@code true} if rows can be moved up
042     */
043    default boolean canMoveUp() {
044        return canMoveUp(getSelectedIndices());
045    }
046
047    /**
048     * Checks that a range of rows can be moved up.
049     * @param rows indexes of rows to move up
050     * @return {@code true} if rows can be moved up
051     */
052    default boolean canMoveUp(int... rows) {
053        return canMoveUp(this::getRowCount, rows);
054    }
055
056    /**
057     * Checks that the currently selected range of rows can be moved down.
058     * @return {@code true} if rows can be moved down
059     */
060    default boolean canMoveDown() {
061        return canMoveDown(getSelectedIndices());
062    }
063
064    /**
065     * Checks that a range of rows can be moved down.
066     * @param rows indexes of rows to move down
067     * @return {@code true} if rows can be moved down
068     */
069    default boolean canMoveDown(int... rows) {
070        return canMoveDown(this::getRowCount, rows);
071    }
072
073    /**
074     * Move up selected rows, if possible.
075     * @return {@code true} if the move was performed
076     * @see #canMoveUp
077     */
078    default boolean moveUp() {
079        return moveUp(getSelectedIndices());
080    }
081
082    /**
083     * Move up selected rows, if possible.
084     * @param selectedRows rows to move up
085     * @return {@code true} if the move was performed
086     * @see #canMoveUp
087     */
088    default boolean moveUp(int... selectedRows) {
089        return move(-1, selectedRows);
090    }
091
092    /**
093     * Move down selected rows, if possible.
094     * @return {@code true} if the move was performed
095     * @see #canMoveDown
096     */
097    default boolean moveDown() {
098        return moveDown(getSelectedIndices());
099    }
100
101    /**
102     * Move down selected rows by 1 position, if possible.
103     * @param selectedRows rows to move down
104     * @return {@code true} if the move was performed
105     * @see #canMoveDown
106     */
107    default boolean moveDown(int... selectedRows) {
108        return move(1, selectedRows);
109    }
110
111    /**
112     * Move selected rows by any number of positions, if possible.
113     * @param delta negative or positive delta
114     * @param selectedRows rows to move
115     * @return {@code true} if the move was performed
116     * @see #canMove
117     */
118    default boolean move(int delta, int... selectedRows) {
119        if (!canMove(delta, this::getRowCount, selectedRows))
120            return false;
121        if (!doMove(delta, selectedRows))
122            return false;
123        final ListSelectionModel selectionModel = getSelectionModel();
124        selectionModel.setValueIsAdjusting(true);
125        selectionModel.clearSelection();
126        for (int row: selectedRows) {
127            selectionModel.addSelectionInterval(row + delta, row + delta);
128        }
129        selectionModel.setValueIsAdjusting(false);
130        return true;
131    }
132}