001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data; 003 004import java.util.Arrays; 005import java.util.function.IntSupplier; 006 007import org.openstreetmap.josm.tools.Utils; 008 009/** 010 * Defines a model that can be reordered. 011 * @param <T> item type 012 * @since 15226 013 */ 014public interface ReorderableModel<T> { 015 016 /** 017 * Get object value at given index. 018 * @param index index 019 * @return object value at given index 020 */ 021 T getValue(int index); 022 023 /** 024 * Set object value at given index. 025 * @param index index 026 * @param value new value 027 * @return the value previously at the specified position 028 */ 029 T setValue(int index, T value); 030 031 /** 032 * Checks that a range of rows can be moved by a given number of positions. 033 * @param delta negative or positive delta 034 * @param rowCount row count supplier 035 * @param rows indexes of rows to move 036 * @return {@code true} if rows can be moved 037 */ 038 default boolean canMove(int delta, IntSupplier rowCount, int... rows) { 039 if (rows == null || rows.length == 0) 040 return false; 041 int[] sortedRows = Utils.copyArray(rows); 042 Arrays.sort(sortedRows); 043 if (delta < 0) 044 return sortedRows[0] >= -delta; 045 else if (delta > 0) 046 return sortedRows[sortedRows.length-1] <= rowCount.getAsInt()-1 - delta; 047 else 048 return true; 049 } 050 051 /** 052 * Checks that a range of rows can be moved up (by 1 position). 053 * @param rowCount row count supplier 054 * @param rows indexes of rows to move up 055 * @return {@code true} if rows can be moved up 056 */ 057 default boolean canMoveUp(IntSupplier rowCount, int... rows) { 058 return canMove(-1, rowCount, rows); 059 } 060 061 /** 062 * Checks that a range of rows can be moved down (by 1 position). 063 * @param rowCount row count supplier 064 * @param rows indexes of rows to move down 065 * @return {@code true} if rows can be moved down 066 */ 067 default boolean canMoveDown(IntSupplier rowCount, int... rows) { 068 return canMove(1, rowCount, rows); 069 } 070 071 /** 072 * Performs the move operation, without any check nor selection handling. 073 * @param delta negative or positive delta 074 * @param selectedRows rows to move 075 * @return {@code true} if rows have been moved 076 */ 077 default boolean doMove(int delta, int... selectedRows) { 078 if (delta != 0) { 079 if (delta < 0) { 080 for (int row: selectedRows) { 081 setValue(row + delta, setValue(row, getValue(row + delta))); 082 } 083 } else { 084 for (int i = selectedRows.length - 1; i >= 0; i--) { 085 int row = selectedRows[i]; 086 setValue(row + delta, setValue(row, getValue(row + delta))); 087 } 088 } 089 } 090 return delta != 0 && selectedRows.length > 0; 091 } 092}