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