[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