• Jens Bache-Wiig's avatar
    Enable TableView multi-row selection · 72072899
    Jens Bache-Wiig authored
    
    This adds a new read-only property selection
    and selectionMode to TableView with the following features:
    
      selection.selectAll()
      selection.select(from, to)
      selection.deselect(from, to)
      selection.forEach(callback)
      selection.contains(index)
      selection.selectionChanged()
      selection.count
    
    Change-Id: I3cbd433851354bb68a6075f0b31f46dab8c83fd4
    Reviewed-by: default avatarGabriel de Dietrich <gabriel.dedietrich@digia.com>
    72072899
TableViewSelection.qml 6.90 KiB
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Quick Controls module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
**     of its contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
****************************************************************************/
import QtQuick 2.1
QtObject {
    property int count: 0
    signal selectionChanged
    property bool __dirty: false
    property var __ranges: new Array()
    function forEach (callback) {
        if (!(callback instanceof Function)) {
            console.warn("TableViewSelection.forEach: argument is not a function")
            return;
        __forEach(callback, -1)
    function contains(index) {
        for (var i = 0 ; i < __ranges.length ; ++i) {
            if (__ranges[i][0] <= index && index <= __ranges[i][1])
                return true;
            else if (__ranges[i][0] > index)
                return false;
        return false;
    function clear() {
        __ranges = new Array()
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
__dirty = true count = 0 selectionChanged() } function selectAll() { select(0, rowCount - 1) } function select(first, last) { __select(true, first, last) } function deselect(first, last) { __select(false, first, last) } // --- private section --- function __printRanges() { var out = "" for (var i = 0 ; i < __ranges.length ; ++ i) out += ("{" + __ranges[i][0] + "," + __ranges[i][1] + "} ") print(out) } function __count() { var sum = 0 for (var i = 0 ; i < __ranges.length ; ++i) { sum += (1 + __ranges[i][1] - __ranges[i][0]) } return sum } function __forEach (callback, startIndex) { __dirty = false var i, j for (i = 0 ; i < __ranges.length && !__dirty ; ++i) { for (j = __ranges[i][0] ; !__dirty && j <= __ranges[i][1] ; ++j) { if (j >= startIndex) callback.call(this, j) } } // Restart iteration at last index if selection changed if (__dirty) return __forEach(callback, j) } function __selectOne(index) { __ranges = [[index, index]] __dirty = true count = 1 selectionChanged(); } function __select(select, first, last) { var i, range var start = first var stop = first var startRangeIndex = -1 var stopRangeIndex = -1 var newRangePos = 0 if (first < 0 || last < 0 || first >= rowCount || last >=rowCount) { console.warn("TableViewSelection: index out of range") return } if (last !== undefined) { start = first <= last ? first : last stop = first <= last ? last : first } if (select) {
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
// Find beginning and end ranges for (i = 0 ; i < __ranges.length; ++ i) { range = __ranges[i] if (range[0] > stop + 1) continue; // above range if (range[1] < start - 1) { // below range newRangePos = i + 1 continue; } if (startRangeIndex == -1) startRangeIndex = i stopRangeIndex = i } if (startRangeIndex !== -1) start = Math.min(__ranges[startRangeIndex][0], start) if (stopRangeIndex !== -1) stop = Math.max(__ranges[stopRangeIndex][1], stop) if (startRangeIndex == -1) startRangeIndex = newRangePos __ranges.splice(Math.max(0, startRangeIndex), 1 + stopRangeIndex - startRangeIndex, [start, stop]) } else { // Find beginning and end ranges for (i = 0 ; i < __ranges.length; ++ i) { range = __ranges[i] if (range[1] < start) continue; // below range if (range[0] > stop) continue; // above range if (startRangeIndex == -1) startRangeIndex = i stopRangeIndex = i } // Slice ranges accordingly if (startRangeIndex >= 0 && stopRangeIndex >= 0) { var startRange = __ranges[startRangeIndex] var stopRange = __ranges[stopRangeIndex] var length = 1 + stopRangeIndex - startRangeIndex if (start <= startRange[0] && stop >= stopRange[1]) { //remove __ranges.splice(startRangeIndex, length) } else if (start - 1 < startRange[0] && stop <= stopRange[1]) { //cut front __ranges.splice(startRangeIndex, length, [stop + 1, stopRange[1]]) } else if (start - 1 < startRange[1] && stop >= stopRange[1]) { // cut back __ranges.splice(startRangeIndex, length, [startRange[0], start - 1]) } else { //split __ranges.splice(startRangeIndex, length, [startRange[0], start - 1], [stop + 1, stopRange[1]]) } } } __dirty = true count = __count() // forces a re-evaluation of indexes in the delegates selectionChanged() } }