diff --git a/panels/dock/OverflowContainer.qml b/panels/dock/OverflowContainer.qml index 142af682d..74ca96677 100644 --- a/panels/dock/OverflowContainer.qml +++ b/panels/dock/OverflowContainer.qml @@ -12,6 +12,9 @@ Item { property alias delegate: listView.delegate property alias spacing: listView.spacing property alias count: listView.count + property alias add: listView.add + property alias remove: listView.remove + property alias move: listView.move property alias displaced: listView.displaced ListView { id: listView diff --git a/panels/dock/taskmanager/appitem.cpp b/panels/dock/taskmanager/appitem.cpp index 54daa78a1..f8d7ba769 100644 --- a/panels/dock/taskmanager/appitem.cpp +++ b/panels/dock/taskmanager/appitem.cpp @@ -52,8 +52,8 @@ QString AppItem::type() const QString AppItem::icon() const { - if (m_currentActiveWindow.isNull() || m_desktopfileParser->isValied().first) - return m_desktopfileParser->desktopIcon(); + if (m_currentActiveWindow.isNull() || (m_desktopfileParser && m_desktopfileParser->isValied().first)) + return m_desktopfileParser ? m_desktopfileParser->desktopIcon() : "application-default-icon"; else { return m_currentActiveWindow->icon(); } diff --git a/panels/dock/taskmanager/itemmodel.cpp b/panels/dock/taskmanager/itemmodel.cpp index 60b898502..7c9dbd8e8 100644 --- a/panels/dock/taskmanager/itemmodel.cpp +++ b/panels/dock/taskmanager/itemmodel.cpp @@ -82,12 +82,7 @@ void ItemModel::moveTo(const QString &id, int dIndex) if (sIndex == dIndex) { return; } - if (sIndex + 1 == dIndex) { - // Do not move from sIndex to sIndex + 1, as endMoveRows is not trivial, this operation equals do nothing. - // FIXME: maybe this is a bug of Qt? but swap these two is a compatible fix - std::swap(sIndex, dIndex); - } - beginMoveRows(QModelIndex(), sIndex, sIndex, QModelIndex(), dIndex); + beginMoveRows(QModelIndex(), sIndex, sIndex, QModelIndex(), dIndex > sIndex ? (dIndex + 1) : dIndex); m_items.move(sIndex, dIndex); endMoveRows(); @@ -138,7 +133,6 @@ void ItemModel::addItem(QPointer item) beginInsertRows(QModelIndex(), rowCount(), rowCount()); m_items.append(item); endInsertRows(); - Q_EMIT itemAdded(); } void ItemModel::onItemDestroyed() @@ -152,7 +146,6 @@ void ItemModel::onItemDestroyed() beginRemoveRows(QModelIndex(), beginIndex, lastIndex); m_items.removeAll(item); endRemoveRows(); - Q_EMIT itemRemoved(); } void ItemModel::onItemChanged() diff --git a/panels/dock/taskmanager/itemmodel.h b/panels/dock/taskmanager/itemmodel.h index 7fb9fdb6d..f9ec6dbc0 100644 --- a/panels/dock/taskmanager/itemmodel.h +++ b/panels/dock/taskmanager/itemmodel.h @@ -41,10 +41,6 @@ class ItemModel : public QAbstractListModel void addItem(QPointer item); QJsonArray dumpDockedItems() const; -Q_SIGNALS: - void itemAdded(); - void itemRemoved(); - private Q_SLOTS: void onItemDestroyed(); void onItemChanged(); diff --git a/panels/dock/taskmanager/package/TaskManager.qml b/panels/dock/taskmanager/package/TaskManager.qml index 336a828b7..b8dd3febd 100644 --- a/panels/dock/taskmanager/package/TaskManager.qml +++ b/panels/dock/taskmanager/package/TaskManager.qml @@ -22,12 +22,29 @@ ContainmentItem { anchors.centerIn: parent useColumnLayout: taskmanager.useColumnLayout spacing: Panel.rootObject.itemSpacing + add: Transition { + NumberAnimation { + properties: "scale,opacity" + from: 0 + to: 1 + duration: 200 + } + } + remove: Transition { + NumberAnimation { + properties: "scale,opacity" + from: 1 + to: 0 + duration: 200 + } + } displaced: Transition { NumberAnimation { properties: "x,y" easing.type: Easing.OutQuad } } + move: displaced model: DelegateModel { id: visualModel model: taskmanager.Applet.dataModel @@ -40,8 +57,25 @@ ContainmentItem { required property string iconName required property string menus required property list windows - keys: ["text/x-dde-dock-dnd-appid", "text/x-dde-launcher-dnd-desktopId"] + keys: ["text/x-dde-dock-dnd-appid"] z: attention ? -1 : 0 + visible: itemId !== launcherDndDropArea.launcherDndDesktopId + + states: [ + State { + name: "item-visible" + when: delegateRoot.visible + PropertyChanges { target: delegateRoot; opacity: 1.0; scale: 1.0; } + }, + State { + name: "item-invisible" + when: !delegateRoot.visible + PropertyChanges { target: delegateRoot; opacity: 0.0; scale: 0.0; } + } + ] + + Behavior on opacity { NumberAnimation { duration: 200 } } + Behavior on scale { NumberAnimation { duration: 200 } } // TODO: 临时溢出逻辑,待后面修改 // 1:4 the distance between app : dock height; get width/height≈0.8 @@ -49,22 +83,9 @@ ContainmentItem { implicitHeight: useColumnLayout ? Panel.rootObject.dockItemMaxSize * 0.8 : Panel.rootObject.dockItemMaxSize onEntered: function(drag) { - if (drag.keys.includes("text/x-dde-launcher-dnd-desktopId")) { - // accepted but don't need to do anything here. - return; - } visualModel.items.move((drag.source as AppItem).visualIndex, app.visualIndex) } - onDropped: function(drop) { - if (drop.keys.includes("text/x-dde-launcher-dnd-desktopId")) { - let desktopId = drop.getDataAsString("text/x-dde-launcher-dnd-desktopId") - taskmanager.Applet.requestDockByDesktopId(desktopId) - drop.accepted = false - return; - } - } - property int visualIndex: DelegateModel.itemsIndex AppItem { @@ -86,14 +107,50 @@ ContainmentItem { onDragFinished: function() { // 就算在非法区域松开也更新 Model taskmanager.Applet.dataModel.moveTo(itemId, visualIndex) - - // 更新 visualModel 的 model 数据 - visualModel.model = taskmanager.Applet.dataModel } anchors.fill: parent // This is mandatory for draggable item center in drop area } } } + + DropArea { + id: launcherDndDropArea + anchors.fill: parent + keys: ["text/x-dde-launcher-dnd-desktopId"] + property string launcherDndDesktopId: "" + onEntered: function(drag) { + let desktopId = drag.getDataAsString("text/x-dde-launcher-dnd-desktopId") + launcherDndDesktopId = taskmanager.Applet.desktopIdToAppId(desktopId) + if (taskmanager.Applet.requestDockByDesktopId(desktopId) === false) { + launcherDndDesktopId = "" + } + } + + onPositionChanged: function(drag) { + if (launcherDndDesktopId === "") return + let curX = taskmanager.useColumnLayout ? drag.y : drag.x + curX *= Screen.devicePixelRatio + let cellWidth = Panel.rootObject.dockItemMaxSize + let curCell = curX / cellWidth + let left = (curX % cellWidth) < (cellWidth / 2) + taskmanager.Applet.dataModel.moveTo(launcherDndDesktopId, curCell) + } + + onDropped: function(drop) { + if (launcherDndDesktopId === "") return + let curX = taskmanager.useColumnLayout ? drop.y : drop.x + curX *= Screen.devicePixelRatio + let cellWidth = Panel.rootObject.dockItemMaxSize + let curCell = curX / cellWidth + let left = (curX % cellWidth) < (cellWidth / 2) + taskmanager.Applet.dataModel.moveTo(launcherDndDesktopId, curCell) + launcherDndDesktopId = "" + } + + onExited: function() { + launcherDndDesktopId = "" + } + } } Component.onCompleted: { diff --git a/panels/dock/taskmanager/taskmanager.cpp b/panels/dock/taskmanager/taskmanager.cpp index 0866f2b71..41c1cd2ce 100644 --- a/panels/dock/taskmanager/taskmanager.cpp +++ b/panels/dock/taskmanager/taskmanager.cpp @@ -47,9 +47,6 @@ TaskManager::TaskManager(QObject* parent) qDBusRegisterMetaType(); qDBusRegisterMetaType(); - connect(ItemModel::instance(), &ItemModel::itemAdded, this, &TaskManager::itemsChanged); - connect(ItemModel::instance(), &ItemModel::itemRemoved, this, &TaskManager::itemsChanged); - connect(Settings, &TaskManagerSettings::allowedForceQuitChanged, this, &TaskManager::allowedForceQuitChanged); connect(Settings, &TaskManagerSettings::windowSplitChanged, this, &TaskManager::windowSplitChanged); } @@ -182,11 +179,15 @@ bool TaskManager::allowForceQuit() return Settings->isAllowedForceQuit(); } +QString TaskManager::desktopIdToAppId(const QString& desktopId) +{ + return Q_LIKELY(desktopId.endsWith(".desktop")) ? desktopId.chopped(8) : desktopId; +} + bool TaskManager::requestDockByDesktopId(const QString& appID) { if (appID.startsWith("internal/")) return false; - QString dockAppId(Q_LIKELY(appID.endsWith(".desktop")) ? appID.chopped(8) : appID); - return RequestDock(dockAppId); + return RequestDock(desktopIdToAppId(appID)); } bool TaskManager::RequestDock(QString appID) diff --git a/panels/dock/taskmanager/taskmanager.h b/panels/dock/taskmanager/taskmanager.h index 22b5ef51f..0d10223f9 100644 --- a/panels/dock/taskmanager/taskmanager.h +++ b/panels/dock/taskmanager/taskmanager.h @@ -17,7 +17,7 @@ class AppItem; class TaskManager : public DS_NAMESPACE::DContainment { Q_OBJECT - Q_PROPERTY(ItemModel* dataModel READ dataModel NOTIFY itemsChanged) + Q_PROPERTY(ItemModel* dataModel READ dataModel NOTIFY dataModelChanged) Q_PROPERTY(bool windowSplit READ windowSplit NOTIFY windowSplitChanged) Q_PROPERTY(bool allowForceQuit READ allowForceQuit NOTIFY allowedForceQuitChanged) @@ -33,6 +33,7 @@ class TaskManager : public DS_NAMESPACE::DContainment bool windowSplit(); bool allowForceQuit(); + Q_INVOKABLE QString desktopIdToAppId(const QString& desktopId); Q_INVOKABLE bool requestDockByDesktopId(const QString& appID); Q_INVOKABLE bool RequestDock(QString appID); Q_INVOKABLE bool IsDocked(QString appID); @@ -45,7 +46,7 @@ class TaskManager : public DS_NAMESPACE::DContainment Q_INVOKABLE void setAppItemWindowIconGeometry(const QString& appid, QObject* relativePositionItem, const int& x1, const int& y1, const int& x2, const int& y2); Q_SIGNALS: - void itemsChanged(); + void dataModelChanged(); void windowSplitChanged(); void allowedForceQuitChanged();