[vlc-commits] [Git][videolan/vlc][master] qml: refactor DnD data resolution
Steve Lhomme (@robUx4)
gitlab at videolan.org
Tue Jul 11 06:16:57 UTC 2023
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
9af46e0a by Pierre Lamot at 2023-07-11T05:57:14+00:00
qml: refactor DnD data resolution
* this unify how data and input items are resolved
* request id is no longer passed to the implementation (local capture)
* an FSM is used to track resolution sequence
* retrieval of the input item from the drop handler is made using a Promise
- - - - -
7 changed files:
- modules/gui/qt/medialibrary/qml/MusicArtistDelegate.qml
- modules/gui/qt/medialibrary/qml/PlaylistMedia.qml
- modules/gui/qt/medialibrary/qml/VideoDisplayRecentVideos.qml
- modules/gui/qt/network/qml/BrowseTreeDisplay.qml
- modules/gui/qt/playlist/qml/PlaylistListView.qml
- modules/gui/qt/widgets/qml/DragItem.qml
- modules/gui/qt/widgets/qml/MLDragItem.qml
Changes:
=====================================
modules/gui/qt/medialibrary/qml/MusicArtistDelegate.qml
=====================================
@@ -86,11 +86,13 @@ T.ItemDelegate {
titleRole: "name"
onRequestData: {
- setData(identifier, [model])
+ console.assert(indexes[0] === index)
+ resolve([model])
}
- function getSelectedInputItem(cb) {
- return MediaLib.mlInputItem([model.id], cb)
+ onRequestInputItems: {
+ const idList = data.map((o) => o.id)
+ MediaLib.mlInputItem(idList, resolve)
}
}
=====================================
modules/gui/qt/medialibrary/qml/PlaylistMedia.qml
=====================================
@@ -161,13 +161,10 @@ MainInterface.MainTableView {
// NOTE: Dropping medialibrary content into the playlist.
} else if (Helpers.isValidInstanceOf(item, Widgets.DragItem)) {
- if (item.inputItems) {
- model.insert(item.inputItems, destinationIndex)
- } else {
- item.getSelectedInputItem(function(inputItems) {
+ item.getSelectedInputItem()
+ .then(inputItems => {
model.insert(inputItems, destinationIndex)
})
- }
}
root.forceActiveFocus()
=====================================
modules/gui/qt/medialibrary/qml/VideoDisplayRecentVideos.qml
=====================================
@@ -142,11 +142,12 @@ FocusScope {
indexes: [index]
onRequestData: {
- setData(identifier, [model])
+ resolve([model])
}
- function getSelectedInputItem(cb) {
- return MediaLib.mlInputItem([model.id], cb)
+ onRequestInputItems: {
+ const idList = data.map((o) => o.id)
+ MediaLib.mlInputItem(idList, resolve)
}
}
=====================================
modules/gui/qt/network/qml/BrowseTreeDisplay.qml
=====================================
@@ -112,14 +112,15 @@ MainInterface.MainViewLoader {
}
onRequestData: {
- setData(identifier, selectionModel.selectedIndexes.map(function (x){
- return filterModel.getDataAt(x.row)
- }))
+ resolve(
+ indexes.map(x => filterModel.getDataAt(x.row))
+ )
}
- function getSelectedInputItem(cb) {
- //directly call the callback
- cb(providerModel.getItemsForIndexes(filterModel.mapIndexesToSource(selectionModel.selectedIndexes)))
+ onRequestInputItems: {
+ resolve(
+ providerModel.getItemsForIndexes(filterModel.mapIndexesToSource(indexes))
+ )
}
Component {
=====================================
modules/gui/qt/playlist/qml/PlaylistListView.qml
=====================================
@@ -75,22 +75,20 @@ Control {
const item = drop.source;
// NOTE: Move implementation.
- if (dragItem == item) {
+ if (dragItem === item) {
model.moveItemsPre(model.getSelection(), index);
// NOTE: Dropping medialibrary content into the queue.
} else if (Helpers.isValidInstanceOf(item, Widgets.DragItem)) {
- if (item.inputItems) {
- mainPlaylistController.insert(index, item.inputItems, false)
- } else {
- item.getSelectedInputItem(function(inputItems) {
+
+ item.getSelectedInputItem()
+ .then((inputItems) => {
if (!Array.isArray(inputItems) || inputItems.length === 0) {
console.warn("can't convert items to input items");
return
}
mainPlaylistController.insert(index, inputItems, false)
})
- }
// NOTE: Dropping an external item (i.e. filesystem) into the queue.
} else if (drop.hasUrls) {
@@ -142,7 +140,7 @@ Control {
parent: (typeof g_mainDisplay !== 'undefined') ? g_mainDisplay : root
onRequestData: {
- setData(identifier, indexes.map(function (index) {
+ resolve(indexes.map((index) => {
const item = root.model.itemAt(index)
return {
"title": item.title,
@@ -151,8 +149,8 @@ Control {
}))
}
- function getSelectedInputItem(cb) {
- cb(root.model.getItemsForIndexes(root.model.getSelection()))
+ onRequestInputItems: {
+ resolve(root.model.getItemsForIndexes(indexes))
}
}
=====================================
modules/gui/qt/widgets/qml/DragItem.qml
=====================================
@@ -29,6 +29,7 @@ import org.videolan.vlc 0.1
import "qrc:///style/"
import "qrc:///playlist/" as Playlist
import "qrc:///util/Helpers.js" as Helpers
+import "qrc:///util/" as Util
Item {
id: dragItem
@@ -41,9 +42,6 @@ Item {
property var indexes: []
- // data from last setData
- readonly property alias indexesData: dragItem._data
-
property string defaultCover: VLCStyle.noArtAlbumCover
property string defaultText: I18n.qtr("Unknown")
@@ -60,31 +58,75 @@ Item {
// string => role
property string titleRole: "title"
- readonly property var inputItems: _inputItems
+ readonly property ColorContext colorContext: ColorContext {
+ id: theme
+ colorSet: ColorContext.Window
+ }
+
+ signal requestData(var indexes, var resolve, var reject)
+ signal requestInputItems(var indexes, var data, var resolve, var reject)
function coversXPos(index) {
return VLCStyle.margin_small + (coverSize / 3) * index;
}
- signal requestData(var identifier)
+ /**
+ * @return {Promise} Promise object of the input items
+ */
+ function getSelectedInputItem() {
+ if (_inputItems)
+ return Promise.resolve(dragItem._inputItems)
+ else if (dragItem._dropPromise)
+ return dragItem._dropPromise
+ else
+ dragItem._dropPromise = new Promise((resolve, reject) => {
+ dragItem._dropCallback = resolve
+ dragItem._dropFailedCallback = reject
+ })
+ return dragItem._dropPromise
+ }
- function getSelectedInputItem(cb) {
- console.assert(false, "getSelectedInputItem is not implemented.")
+ //---------------------------------------------------------------------------------------------
+ // Private
- return undefined
- }
+ readonly property int _maxCovers: 3
- function setData(id, data) {
- if (id !== dragItem._currentRequest)
- return
+ readonly property int _indexesSize: !!indexes ? indexes.length : 0
- console.assert(data.length === indexes.length)
- _data = data
+ readonly property int _displayedCoversCount: Math.min(_indexesSize, _maxCovers + 1)
- if (!dragItem.Drag.active)
- return
+ property var _inputItems: []
+
+ property var _data: []
+
+ property var _covers: []
+
+ property string _title: ""
+
+ property int _currentRequest: 0
+
+ property var _dropPromise: null
+ property var _dropCallback: null
+ property var _dropFailedCallback: null
+
+ //---------------------------------------------------------------------------------------------
+ // Implementation
+ //---------------------------------------------------------------------------------------------
+
+ parent: g_mainDisplay
+
+ width: VLCStyle.colWidth(2)
+
+ height: coverSize + VLCStyle.margin_small * 2
- Qt.callLater(dragItem.getSelectedInputItem, dragItem.setInputItems)
+ opacity: visible ? 0.90 : 0
+
+ visible: Drag.active
+ enabled: visible
+
+ function _setData(data) {
+ console.assert(data.length === indexes.length)
+ _data = data
const covers = []
const titleList = []
@@ -95,7 +137,8 @@ Item {
const cover = _getCover(indexes[i], data[i])
const itemTitle = _getTitle(indexes[i], data[i])
- if (!cover || !itemTitle) continue
+ if (!cover || !itemTitle)
+ continue
covers.push(cover)
titleList.push(itemTitle)
@@ -111,7 +154,7 @@ Item {
_title = titleList.join(",") + (indexes.length > _maxCovers ? "..." : "")
}
- function setInputItems(inputItems) {
+ function _setInputItems(inputItems) {
if (!Array.isArray(inputItems) || inputItems.length === 0) {
console.warn("can't convert items to input items");
dragItem._inputItems = null
@@ -121,40 +164,6 @@ Item {
dragItem._inputItems = inputItems
}
- //---------------------------------------------------------------------------------------------
- // Private
-
- readonly property int _maxCovers: 3
-
- readonly property int _indexesSize: !!indexes ? indexes.length : 0
-
- readonly property int _displayedCoversCount: Math.min(_indexesSize, _maxCovers + 1)
-
- property var _inputItems
-
- property var _data: []
-
- property var _covers: []
-
- property string _title: ""
-
- property int _currentRequest: 0
-
- //---------------------------------------------------------------------------------------------
- // Implementation
- //---------------------------------------------------------------------------------------------
-
- parent: g_mainDisplay
-
- width: VLCStyle.colWidth(2)
-
- height: coverSize + VLCStyle.margin_small * 2
-
- opacity: visible ? 0.90 : 0
-
- visible: Drag.active
- enabled: visible
-
function _getCover(index, data) {
console.assert(dragItem.coverRole)
if (!!dragItem.coverProvider)
@@ -178,20 +187,9 @@ Item {
Drag.onActiveChanged: {
if (Drag.active) {
- // reset any data from previous drags before requesting new data,
- // so that we don't show invalid data while data is being requested
- _title = ""
- _covers = []
- _data = []
-
- dragItem._currentRequest += 1
- dragItem.requestData(dragItem._currentRequest)
-
- MainCtx.setCursor(Qt.DragMoveCursor)
+ fsm.startDrag()
} else {
- MainCtx.restoreCursor()
-
- dragItem._inputItems = undefined
+ fsm.stopDrag()
}
}
@@ -202,15 +200,141 @@ Item {
}
}
- readonly property ColorContext colorContext: ColorContext {
- id: theme
- colorSet: ColorContext.Window
+ Util.FSM {
+ id: fsm
+
+ signal startDrag()
+ signal stopDrag()
+
+ //internal signals
+ signal resolveData(var requestId, var indexes)
+ signal resolveInputItems(var requestId, var indexes)
+ signal resolveFailed()
+
+ signalMap: ({
+ startDrag: startDrag,
+ stopDrag: stopDrag,
+ resolveData: resolveData,
+ resolveInputItems: resolveInputItems,
+ resolveFailed: resolveFailed
+ })
+
+ initialState: fsmDragInactive
+
+ Util.FSMState {
+ id: fsmDragInactive
+
+ function enter() {
+ _title = ""
+ _covers = []
+ _data = []
+ }
+
+ transitions: ({
+ startDrag: fsmDragActive
+ })
+ }
+
+ Util.FSMState {
+ id: fsmDragActive
+
+ initialState: fsmRequestData
+
+ function enter() {
+ MainCtx.setCursor(Qt.DragMoveCursor)
+ }
+
+ function exit() {
+ MainCtx.restoreCursor()
+ if (dragItem._dropFailedCallback) {
+ dragItem._dropFailedCallback()
+ }
+ dragItem._dropPromise = null
+ dragItem._dropFailedCallback = null
+ dragItem._dropCallback = null
+ }
+
+ transitions: ({
+ stopDrag: fsmDragInactive
+ })
+
+ Util.FSMState {
+ id: fsmRequestData
+
+ function enter() {
+ const requestId = ++dragItem._currentRequest
+ dragItem.requestData(
+ dragItem.indexes,
+ (data) => fsm.resolveData(requestId, data),
+ fsm.resolveFailed)
+ }
+
+ transitions: ({
+ resolveData: {
+ guard: (requestId, data) => requestId === dragItem._currentRequest,
+ action: (requestId, data) => {
+ dragItem._setData(data)
+ },
+ target: fsmRequestInputItem
+ },
+ resolveFailed: fsmLoadingFailed
+ })
+ }
+
+ Util.FSMState {
+ id: fsmRequestInputItem
+
+ function enter() {
+ const requestId = ++dragItem._currentRequest
+ dragItem.requestInputItems(
+ dragItem.indexes, _data,
+ (items) => { fsm.resolveInputItems(requestId, items) },
+ fsm.resolveFailed)
+ }
+
+ transitions: ({
+ resolveInputItems: {
+ guard: (requestId, items) => requestId === dragItem._currentRequest,
+ action: (requestId, items) => {
+ dragItem._setInputItems(items)
+ },
+ target: fsmLoadingDone,
+ },
+ resolveFailed: fsmLoadingFailed
+ })
+ }
+
+ Util.FSMState {
+ id: fsmLoadingDone
+
+ function enter() {
+ if (dragItem._dropCallback) {
+ dragItem._dropCallback(dragItem._inputItems)
+ }
+ dragItem._dropPromise = null
+ dragItem._dropCallback = null
+ dragItem._dropFailedCallback = null
+ }
+ }
+
+ Util.FSMState {
+ id: fsmLoadingFailed
+ function enter() {
+ if (dragItem._dropFailedCallback) {
+ dragItem._dropFailedCallback()
+ }
+ dragItem._dropPromise = null
+ dragItem._dropCallback = null
+ dragItem._dropFailedCallback = null
+ }
+ }
+ }
}
Rectangle {
/* background */
anchors.fill: parent
- color: theme.bg.primary
+ color: fsmLoadingFailed.active ? theme.bg.negative : theme.bg.primary
border.color: theme.border
border.width: VLCStyle.dp(1, VLCStyle.scale)
radius: VLCStyle.dp(6, VLCStyle.scale)
=====================================
modules/gui/qt/widgets/qml/MLDragItem.qml
=====================================
@@ -31,17 +31,13 @@ DragItem {
// string => role for medialib id, data[id] will be pass to Medialib::mlInputItem for SharedInputItem
property string mlIDRole: "id"
- function getSelectedInputItem(cb) {
- console.assert(mlIDRole)
- const inputIdList = root.indexesData.map(function(obj){
- return obj[root.mlIDRole]
- })
- MediaLib.mlInputItem(inputIdList, cb)
+ onRequestData: {
+ mlModel.getData(indexes, resolve)
}
- onRequestData: {
- mlModel.getData(indexes, function (data) {
- root.setData(identifier, data)
- })
+ onRequestInputItems: {
+ console.assert(mlIDRole)
+ const inputIdList = data.map(o => o[root.mlIDRole])
+ MediaLib.mlInputItem(inputIdList, resolve)
}
}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/9af46e0abda02682e1d96b1a170d232331aef357
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/9af46e0abda02682e1d96b1a170d232331aef357
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list