feat(qt): Library Explorer columns select a run with Shift
A facet column already took Ctrl as "add or remove one" and a plain click as "only this". Shift now picks the run from the last clicked value and Ctrl+Shift adds that run, the file-list rule (SelectionModel.nextExclusive), each column over its values as listed. A column whose values are rebuilt by a change upstream starts without an anchor. cc
This commit is contained in:
3 files changed
+84
-14
No files matched your search
@@ -118,4 +118,39 @@ QtObject {
|
||||
root.anchorId = key
|
||||
return out
|
||||
}
|
||||
|
||||
/// The spreadsheet / file-manager rule, for lists where a plain click
|
||||
/// REPLACES the selection (the Library Explorer facets):
|
||||
///
|
||||
/// plain click only this row; it becomes the anchor
|
||||
/// Ctrl / Cmd toggle this row, keep the rest; it becomes the anchor
|
||||
/// Shift only the range anchor..row; the anchor stays
|
||||
/// Ctrl+Shift add the range anchor..row to the selection
|
||||
///
|
||||
/// Without a visible anchor Shift behaves like the same click without it.
|
||||
function nextExclusive(current, id, rows, modifiers) {
|
||||
var mods = modifiers || 0
|
||||
var shift = (mods & Qt.ShiftModifier) !== 0
|
||||
var additive = (mods & (Qt.ControlModifier | Qt.MetaModifier)) !== 0
|
||||
var key = String(id)
|
||||
var anchorAt = root.anchorId !== "" ? root._indexOf(rows, root.anchorId) : -1
|
||||
|
||||
if (shift && anchorAt >= 0) {
|
||||
var here = root._indexOf(rows, id)
|
||||
if (here >= 0)
|
||||
return root._fillRange(additive ? Object.assign({}, current) : {},
|
||||
rows, anchorAt, here)
|
||||
}
|
||||
|
||||
root.anchorId = key
|
||||
if (!additive) {
|
||||
var only = {}
|
||||
only[key] = true
|
||||
return only
|
||||
}
|
||||
var out = Object.assign({}, current)
|
||||
if (out[key] === true) delete out[key]
|
||||
else out[key] = true
|
||||
return out
|
||||
}
|
||||
}
|
||||
@@ -1187,23 +1187,42 @@ Rectangle {
|
||||
return sortRows(rows, genresSort)
|
||||
}
|
||||
|
||||
// The Explorer facets follow the spreadsheet rule — a plain click picks
|
||||
// one value, Ctrl adds or removes one, Shift picks the run from the last
|
||||
// click, Ctrl+Shift adds that run (SelectionModel.nextExclusive) — each
|
||||
// column over its values AS LISTED (sorted, and filtered by its own
|
||||
// search box). One anchor per column; a column whose values are rebuilt
|
||||
// by a change upstream starts without one.
|
||||
SelectionModel { id: genreFacetSel; idKey: "key" }
|
||||
SelectionModel { id: yearFacetSel; idKey: "key" }
|
||||
SelectionModel { id: artistFacetSel; idKey: "key" }
|
||||
SelectionModel { id: albumFacetSel; idKey: "key" }
|
||||
function toggleGenre(key, modifiers) {
|
||||
selectedGenres = nextFacetSelection(selectedGenres, key, modifiers)
|
||||
selectedGenres = nextFacetSelection(genreFacetSel, selectedGenres, key, modifiers, genreNames)
|
||||
selectedGenreYears = ({})
|
||||
selectedGenreArtists = ({})
|
||||
selectedGenreAlbums = ({})
|
||||
yearFacetSel.anchorId = ""
|
||||
artistFacetSel.anchorId = ""
|
||||
albumFacetSel.anchorId = ""
|
||||
}
|
||||
function toggleGenreYear(key, modifiers) {
|
||||
selectedGenreYears = nextFacetSelection(selectedGenreYears, key, modifiers)
|
||||
selectedGenreYears = nextFacetSelection(yearFacetSel, selectedGenreYears, key, modifiers,
|
||||
genreYearOptions)
|
||||
selectedGenreArtists = ({})
|
||||
selectedGenreAlbums = ({})
|
||||
artistFacetSel.anchorId = ""
|
||||
albumFacetSel.anchorId = ""
|
||||
}
|
||||
function toggleGenreArtist(key, modifiers) {
|
||||
selectedGenreArtists = nextFacetSelection(selectedGenreArtists, key, modifiers)
|
||||
selectedGenreArtists = nextFacetSelection(artistFacetSel, selectedGenreArtists, key,
|
||||
modifiers, genreArtistOptions)
|
||||
selectedGenreAlbums = ({})
|
||||
albumFacetSel.anchorId = ""
|
||||
}
|
||||
function toggleGenreAlbum(key, modifiers) {
|
||||
selectedGenreAlbums = nextFacetSelection(selectedGenreAlbums, key, modifiers)
|
||||
selectedGenreAlbums = nextFacetSelection(albumFacetSel, selectedGenreAlbums, key, modifiers,
|
||||
genreAlbumOptions)
|
||||
}
|
||||
function setExplorerColumns(mode) {
|
||||
if (["genre", "year", "both"].indexOf(mode) < 0 || mode === explorerColumns)
|
||||
@@ -1219,17 +1238,14 @@ Rectangle {
|
||||
readonly property int explorerFacetCount: explorerColumns === "both" ? 4 : 3
|
||||
readonly property int explorerLeadingCount: explorerColumns === "year"
|
||||
? genreYearOptions.length : genreNames.length
|
||||
function nextFacetSelection(current, key, modifiers) {
|
||||
if (key === "") return ({})
|
||||
var additive = (modifiers & Qt.ControlModifier) !== 0
|
||||
|| (modifiers & Qt.MetaModifier) !== 0
|
||||
if (!additive) {
|
||||
var only = {}; only[key] = true; return only
|
||||
/// `key` "" is the column's "All" row: it clears the column.
|
||||
function nextFacetSelection(rule, current, key, modifiers, options) {
|
||||
if (key === "") {
|
||||
rule.anchorId = ""
|
||||
return ({})
|
||||
}
|
||||
var out = Object.assign({}, current)
|
||||
if (out[key]) delete out[key]
|
||||
else out[key] = true
|
||||
return out
|
||||
return rule.nextExclusive(current, key, options || [],
|
||||
modifiers === undefined ? Qt.NoModifier : modifiers)
|
||||
}
|
||||
|
||||
// The selected artist's albums.
|
||||
|
||||
@@ -432,5 +432,24 @@ Item {
|
||||
m = keyedRule.next(m, 7, rows, Qt.ShiftModifier)
|
||||
compare(Object.keys(m).sort().join(","), "7,8,9")
|
||||
}
|
||||
|
||||
function test_exclusive_rule() {
|
||||
var rows = [{ "id": "g1" }, { "id": "g2" }, { "id": "g3" }, { "id": "g4" }, { "id": "g5" }]
|
||||
var m = rule.nextExclusive({}, "g2", rows, Qt.NoModifier)
|
||||
compare(Object.keys(m).sort().join(","), "g2", "a plain click selects only that row")
|
||||
m = rule.nextExclusive(m, "g4", rows, Qt.ShiftModifier)
|
||||
compare(Object.keys(m).sort().join(","), "g2,g3,g4", "Shift selects the range")
|
||||
m = rule.nextExclusive(m, "g1", rows, Qt.ShiftModifier)
|
||||
compare(Object.keys(m).sort().join(","), "g1,g2", "the anchor stays, Shift replaces the range")
|
||||
m = rule.nextExclusive(m, "g5", rows, Qt.ControlModifier)
|
||||
compare(Object.keys(m).sort().join(","), "g1,g2,g5", "Ctrl adds one")
|
||||
m = rule.nextExclusive(m, "g5", rows, Qt.ControlModifier)
|
||||
compare(Object.keys(m).sort().join(","), "g1,g2", "Ctrl on a selected row removes it")
|
||||
m = rule.nextExclusive(m, "g3", rows, Qt.ControlModifier)
|
||||
m = rule.nextExclusive(m, "g5", rows, Qt.ControlModifier | Qt.ShiftModifier)
|
||||
compare(Object.keys(m).sort().join(","), "g1,g2,g3,g4,g5", "Ctrl+Shift adds a range")
|
||||
m = rule.nextExclusive(m, "g4", rows, Qt.NoModifier)
|
||||
compare(Object.keys(m).sort().join(","), "g4", "a plain click starts over")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user