From ae74a6133f78d909ce74d775e34de726eaba3244 Mon Sep 17 00:00:00 2001 From: donghualin Date: Wed, 2 Nov 2022 06:57:46 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=AE=9E=E7=8E=B0=E9=AB=98=E6=95=88?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E4=B8=8B=E6=89=98=E7=9B=98=E5=92=8C=E5=BF=AB?= =?UTF-8?q?=E6=8D=B7=E6=8F=92=E4=BB=B6=E6=8B=96=E5=8A=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 高效模式下和时尚模式下托盘区域共用一个TrayModel,在拖动图标的时候,时尚模式和高效模式保持相同的状态 Log: 实现高效模式下图标的拖动功能 Influence: 高效模式,从托盘或快捷面板拖动图标到任务栏 Task: https://pms.uniontech.com/task-view-112073.html Change-Id: I279b572231ea8efc9bd7f1ee0e628e9ee3eb064e --- CMakeLists.txt | 2 +- configs/com.deepin.dde.dock.dconfig.json | 22 +- debian/dde-dock.install | 2 +- frame/controller/quicksettingcontroller.cpp | 27 +- frame/controller/quicksettingcontroller.h | 6 +- frame/util/platformutils.cpp | 57 +++ frame/util/platformutils.h | 15 + frame/util/settingconfig.cpp | 57 +++ frame/util/settingconfig.h | 60 +++ frame/window/docktraywindow.cpp | 106 +++++- frame/window/docktraywindow.h | 3 + frame/window/quickpluginmodel.cpp | 202 ++++++++++ frame/window/quickpluginmodel.h | 69 ++++ frame/window/quickpluginwindow.cpp | 357 +++++++++--------- frame/window/quickpluginwindow.h | 17 +- frame/window/quicksettingcontainer.cpp | 95 +++-- frame/window/quicksettingcontainer.h | 11 +- frame/window/systempluginwindow.cpp | 10 + frame/window/systempluginwindow.h | 4 + frame/window/tray/tray_delegate.cpp | 28 +- frame/window/tray/tray_delegate.h | 3 +- frame/window/tray/tray_gridview.cpp | 24 +- frame/window/tray/tray_gridview.h | 9 +- frame/window/tray/tray_model.cpp | 311 ++++++++++++--- frame/window/tray/tray_model.h | 41 +- frame/window/tray/tray_monitor.cpp | 49 +++ frame/window/tray/tray_monitor.h | 13 + .../window/tray/widgets/expandiconwidget.cpp | 159 ++++---- frame/window/tray/widgets/expandiconwidget.h | 14 +- .../tray/widgets/xembedtrayitemwidget.cpp | 67 +--- .../tray/widgets/xembedtrayitemwidget.h | 3 - frame/window/traymainwindow.cpp | 1 + frame/window/traymanagerwindow.cpp | 74 ++-- frame/window/traymanagerwindow.h | 6 + 34 files changed, 1403 insertions(+), 521 deletions(-) create mode 100644 frame/util/platformutils.cpp create mode 100644 frame/util/platformutils.h create mode 100644 frame/util/settingconfig.cpp create mode 100644 frame/util/settingconfig.h create mode 100644 frame/window/quickpluginmodel.cpp create mode 100644 frame/window/quickpluginmodel.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c0a0ad527..7689c1b3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,7 +161,7 @@ install(FILES gschema/com.deepin.dde.dock.module.gschema.xml #dconfig file(GLOB DCONFIG_FILES "configs/*.json") -install(FILES ${DCONFIG_FILES} DESTINATION /usr/share/dsg/apps/dde-dock/configs/) +install(FILES ${DCONFIG_FILES} DESTINATION /usr/share/dsg/configs/dde-dock/) # Address Sanitizer 内存错误检测工具,打开下面的编译选项可以看到调试信息,正常运行时不需要这些信息 #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -fsanitize=address -O2") diff --git a/configs/com.deepin.dde.dock.dconfig.json b/configs/com.deepin.dde.dock.dconfig.json index 19c01ddcd..1d17aa4d5 100644 --- a/configs/com.deepin.dde.dock.dconfig.json +++ b/configs/com.deepin.dde.dock.dconfig.json @@ -15,6 +15,26 @@ "description":"0 Mouse over show;1 Always show; 2 Always hide", "permissions":"readwrite", "visibility":"public" - } + }, + "Dock_Quick_Plugin_Name": { + "value": ["network", "sound", "power"], + "serial": 0, + "flags": [], + "name": "显示在任务栏上的快捷插件", + "name[zh_CN]": "*****", + "description": "记录哪些插件的图标在任务栏启动的时候显示在任务栏上", + "permissions": "readwrite", + "visibility": "private" + }, + "Dock_Quick_Tray_Name": { + "value": ["fcitx"], + "serial": 0, + "flags": [], + "name": "显示在任务栏上的托盘图标", + "name[zh_CN]": "任务栏上固定的托盘图标", + "description": "记录哪些托盘的图标在任务栏启动的时候显示在任务栏上", + "permissions": "readwrite", + "visibility": "private" + } } } \ No newline at end of file diff --git a/debian/dde-dock.install b/debian/dde-dock.install index 24a6e6da9..4ea0c2294 100644 --- a/debian/dde-dock.install +++ b/debian/dde-dock.install @@ -8,4 +8,4 @@ usr/lib/dde-dock/plugins/quick-trays usr/lib/dde-dock/plugins/libmultitasking.so usr/lib/dde-dock/plugins/libshow-desktop.so usr/lib/dde-dock/plugins/libkeyboard-layout.so -usr/share/dsg/apps/dde-dock/configs/ +usr/share/dsg/configs/dde-dock/ diff --git a/frame/controller/quicksettingcontroller.cpp b/frame/controller/quicksettingcontroller.cpp index 7c72f6a42..4f05ec6c5 100644 --- a/frame/controller/quicksettingcontroller.cpp +++ b/frame/controller/quicksettingcontroller.cpp @@ -39,12 +39,19 @@ QuickSettingController::~QuickSettingController() void QuickSettingController::pluginItemAdded(PluginsItemInterface * const itemInter, const QString &itemKey) { // 根据读取到的metaData数据获取当前插件的类型,提供给外部 - PluginAttribute pluginClass = getPluginClass(itemInter); + PluginAttribute pluginAttr = pluginAttribute(itemInter); - m_quickPlugins[pluginClass] << itemInter; + m_quickPlugins[pluginAttr] << itemInter; m_quickPluginsMap[itemInter] = itemKey; - emit pluginInserted(itemInter, pluginClass); + emit pluginInserted(itemInter, pluginAttr); +} + +void QuickSettingController::pluginItemUpdate(PluginsItemInterface * const itemInter, const QString &) +{ + updateDockInfo(itemInter, DockPart::QuickPanel); + updateDockInfo(itemInter, DockPart::QuickShow); + updateDockInfo(itemInter, DockPart::SystemPanel); } void QuickSettingController::pluginItemRemoved(PluginsItemInterface * const itemInter, const QString &) @@ -72,18 +79,18 @@ void QuickSettingController::updateDockInfo(PluginsItemInterface * const itemInt Q_EMIT pluginUpdated(itemInter, part); } -QuickSettingController::PluginAttribute QuickSettingController::getPluginClass(PluginsItemInterface * const itemInter) const +QuickSettingController::PluginAttribute QuickSettingController::pluginAttribute(PluginsItemInterface * const itemInter) const { QPluginLoader *pluginLoader = ProxyPluginController::instance(PluginType::QuickPlugin)->pluginLoader(itemInter); if (!pluginLoader) return PluginAttribute::Quick; - if (pluginLoader->fileName().contains("/plugins/system-trays")) { + if (pluginLoader->fileName().contains(TRAY_PATH)) { // 如果是从系统目录下加载的插件,则认为它是系统插件,此时需要放入到托盘中 return PluginAttribute::Tray; } - QJsonObject meta = pluginLoader->metaData().value("MetaData").toObject(); + const QJsonObject &meta = pluginLoader->metaData().value("MetaData").toObject(); if (meta.contains("tool") && meta.value("tool").toBool()) { // 如果有tool标记,则认为它是工具插件,例如回收站和窗管提供的相关插件 return PluginAttribute::Tool; @@ -145,10 +152,10 @@ QList QuickSettingController::pluginInSettings() QMap> &plugins = ProxyPluginController::instance(PluginType::QuickPlugin)->pluginsMap(); QList allPlugins = plugins.keys(); for (PluginsItemInterface *plugin : allPlugins) { - PluginAttribute pluginClass = getPluginClass(plugin); - if (pluginClass == QuickSettingController::PluginAttribute::Quick - || pluginClass == QuickSettingController::PluginAttribute::System - || pluginClass == QuickSettingController::PluginAttribute::Tool) + PluginAttribute pluginAttr = pluginAttribute(plugin); + if (pluginAttr == QuickSettingController::PluginAttribute::Quick + || pluginAttr == QuickSettingController::PluginAttribute::System + || pluginAttr == QuickSettingController::PluginAttribute::Tool) settingPlugins << plugin; } diff --git a/frame/controller/quicksettingcontroller.h b/frame/controller/quicksettingcontroller.h index 63336d5e9..e129da755 100644 --- a/frame/controller/quicksettingcontroller.h +++ b/frame/controller/quicksettingcontroller.h @@ -46,6 +46,7 @@ public: QJsonObject metaData(PluginsItemInterface *pluginItem) const; PluginsItem *pluginItemWidget(PluginsItemInterface *pluginItem); QList pluginInSettings(); + PluginAttribute pluginAttribute(PluginsItemInterface * const itemInter) const; Q_SIGNALS: void pluginInserted(PluginsItemInterface *itemInter, const PluginAttribute &); @@ -58,7 +59,7 @@ protected: protected: void pluginItemAdded(PluginsItemInterface * const itemInter, const QString &itemKey) override; - void pluginItemUpdate(PluginsItemInterface * const itemInter, const QString &) override {} + void pluginItemUpdate(PluginsItemInterface * const itemInter, const QString &) override; void pluginItemRemoved(PluginsItemInterface * const itemInter, const QString &) override; void requestPluginWindowAutoHide(PluginsItemInterface * const, const QString &, const bool) override {} void requestRefreshPluginWindowVisible(PluginsItemInterface * const, const QString &) override {} @@ -66,9 +67,6 @@ protected: void updateDockInfo(PluginsItemInterface * const itemInter, const DockPart &part) override; -private: - PluginAttribute getPluginClass(PluginsItemInterface * const itemInter) const; - private: QMap> m_quickPlugins; QMap m_quickPluginsMap; diff --git a/frame/util/platformutils.cpp b/frame/util/platformutils.cpp new file mode 100644 index 000000000..17ba90efb --- /dev/null +++ b/frame/util/platformutils.cpp @@ -0,0 +1,57 @@ +#include "platformutils.h" +#include "utils.h" + +#include + +#include + +#define NORMAL_WINDOW_PROP_NAME "WM_CLASS" +#define WINE_WINDOW_PROP_NAME "__wine_prefix" +#define IS_WINE_WINDOW_BY_WM_CLASS "explorer.exe" + +QString PlatformUtils::getAppNameForWindow(quint32 winId) +{ + // is normal application + QString appName = getWindowProperty(winId, NORMAL_WINDOW_PROP_NAME); + if (!appName.isEmpty() && appName != IS_WINE_WINDOW_BY_WM_CLASS) + return appName; + + // is wine application + appName = getWindowProperty(winId, WINE_WINDOW_PROP_NAME).split("/").last(); + if (!appName.isEmpty()) + return appName; + + // fallback to window id + return QString::number(winId); +} + +QString PlatformUtils::getWindowProperty(quint32 winId, QString propName) +{ + const auto display = Utils::IS_WAYLAND_DISPLAY ? XOpenDisplay(nullptr) : QX11Info::display(); + if (!display) { + qWarning() << "QX11Info::display() is " << display; + return QString(); + } + + Atom atom_prop = XInternAtom(display, propName.toLocal8Bit(), true); + if (!atom_prop) { + qDebug() << "Error: get window property failed, invalid property atom"; + return QString(); + } + + Atom actual_type_return; + int actual_format_return; + unsigned long nitems_return; + unsigned long bytes_after_return; + unsigned char *prop_return; + + int r = XGetWindowProperty(display, winId, atom_prop, 0, 100, false, AnyPropertyType, + &actual_type_return, &actual_format_return, &nitems_return, + &bytes_after_return, &prop_return); + + Q_UNUSED(r); + if (Utils::IS_WAYLAND_DISPLAY) + XCloseDisplay(display); + + return QString::fromLocal8Bit((char*)prop_return); +} diff --git a/frame/util/platformutils.h b/frame/util/platformutils.h new file mode 100644 index 000000000..42ed3044a --- /dev/null +++ b/frame/util/platformutils.h @@ -0,0 +1,15 @@ +#ifndef PLATFORMUTILS_H +#define PLATFORMUTILS_H + +#include + +class PlatformUtils +{ +public: + static QString getAppNameForWindow(quint32 winId); + +private: + static QString getWindowProperty(quint32 winId, QString propName); +}; + +#endif // PLATFORMUTILS_H diff --git a/frame/util/settingconfig.cpp b/frame/util/settingconfig.cpp new file mode 100644 index 000000000..1c505ead8 --- /dev/null +++ b/frame/util/settingconfig.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd. + * + * Author: donghualin + * + * Maintainer: donghualin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "settingconfig.h" + +#include + +DCORE_USE_NAMESPACE + +SettingConfig *SettingConfig::instance() +{ + static SettingConfig instance; + return &instance; +} + +void SettingConfig::setValue(const QString &key, const QVariant &value) +{ + if (m_config->isValid() && m_config->keyList().contains(key)) + m_config->setValue(key, value); +} + +QVariant SettingConfig::value(const QString &key) const +{ + if (m_config->isValid() && m_config->keyList().contains(key)) + return m_config->value(key); + + return QVariant(); +} + +SettingConfig::SettingConfig(QObject *parent) + : QObject(parent) + , m_config(new DConfig(QString("com.deepin.dde.dock.dconfig"), QString())) +{ + connect(m_config, &DConfig::valueChanged, this, &SettingConfig::onValueChanged); +} + +void SettingConfig::onValueChanged(const QString &key) +{ + Q_EMIT valueChanged(key, m_config->value(key)); +} diff --git a/frame/util/settingconfig.h b/frame/util/settingconfig.h new file mode 100644 index 000000000..ceddb5994 --- /dev/null +++ b/frame/util/settingconfig.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd. + * + * Author: donghualin + * + * Maintainer: donghualin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include + +#include +#include + +DCORE_BEGIN_NAMESPACE +class DConfig; +DCORE_END_NAMESPACE + +DCORE_USE_NAMESPACE + +#define SETTINGCONFIG SettingConfig::instance() + +class SettingConfig : public QObject +{ + Q_OBJECT + +public: + static SettingConfig *instance(); + + void setValue(const QString &key, const QVariant &value); + QVariant value(const QString &key) const; + +Q_SIGNALS: + void valueChanged(const QString &key, const QVariant &value); + +protected: + explicit SettingConfig(QObject *parent = nullptr); + +private Q_SLOTS: + void onValueChanged(const QString &key); + +private: + DConfig *m_config; +}; + +#endif // SETTINGCONFIG_H diff --git a/frame/window/docktraywindow.cpp b/frame/window/docktraywindow.cpp index 34fa4f815..a784d19d8 100644 --- a/frame/window/docktraywindow.cpp +++ b/frame/window/docktraywindow.cpp @@ -27,6 +27,7 @@ #include "tray_delegate.h" #include "quicksettingcontroller.h" #include "pluginsitem.h" +#include "quicksettingcontainer.h" #include @@ -50,15 +51,12 @@ DockTrayWindow::DockTrayWindow(DockInter *dockInter, QWidget *parent) , m_systemPuginWidget(new SystemPluginWindow(this)) , m_quickIconWidget(new QuickPluginWindow(this)) , m_trayView(new TrayGridView(this)) - , m_model(new TrayModel(m_trayView, false, true, this)) + , m_model(TrayModel::getDockModel()) , m_delegate(new TrayDelegate(m_trayView, this)) { initUi(); initConnection(); - - m_trayView->setModel(m_model); - m_trayView->setItemDelegate(m_delegate); - m_trayView->openPersistentEditor(m_model->index(0, 0)); + initAttribute(); } void DockTrayWindow::setPositon(const Dock::Position &position) @@ -69,9 +67,11 @@ void DockTrayWindow::setPositon(const Dock::Position &position) m_quickIconWidget->setPositon(position); m_trayView->setPosition(position); m_delegate->setPositon(position); - QModelIndex index = m_model->index(0, 0); - m_trayView->closePersistentEditor(index); - m_trayView->openPersistentEditor(index); + if (m_model->hasExpand()) { + // 切换位置的时候,需要重新关闭编辑器,然后在model的flag函数中再打开,防止图标的方向没有切换过来 + QModelIndex index = m_model->index(0, 0); + m_trayView->closePersistentEditor(index); + } updateLayout(position); onResetLayout(); } @@ -153,6 +153,41 @@ void DockTrayWindow::paintEvent(QPaintEvent *event) painter.fillRect(m_toolLineLabel->geometry(), color); } +bool DockTrayWindow::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == this || watched == m_toolWidget || watched == m_dateTimeWidget + || watched == m_trayView) { + switch (event->type()) { + case QEvent::Drop: { + QDropEvent *dropEvent = static_cast(event); + onDropIcon(dropEvent); + break; + } + case QEvent::DragEnter: { + QDragEnterEvent *dragEnterEvent = static_cast(event); + dragEnterEvent->setDropAction(Qt::CopyAction); + dragEnterEvent->accept(); + return true; + } + case QEvent::DragMove: { + QDragMoveEvent *dragMoveEvent = static_cast(event); + dragMoveEvent->setDropAction(Qt::CopyAction); + dragMoveEvent->accept(); + return true; + } + case QEvent::DragLeave: { + QDragLeaveEvent *dragLeaveEvent = static_cast(event); + dragLeaveEvent->accept(); + break; + } + default: + break; + } + } + + return QWidget::eventFilter(watched, event); +} + /** 根据任务栏的位置来更新布局的方向 * @brief DockTrayWindow::updateLayout * @param position @@ -264,11 +299,6 @@ void DockTrayWindow::initUi() m_mainBoxLayout->addWidget(m_trayView); m_mainBoxLayout->setAlignment(m_toolLineLabel, Qt::AlignCenter); - WinInfo info; - info.type = TrayIconType::ExpandIcon; - m_model->addRow(info); - m_trayView->openPersistentEditor(m_model->index(0, 0)); - m_toolLineLabel->setFixedSize(0, 0); m_mainBoxLayout->addStretch(); @@ -279,8 +309,20 @@ void DockTrayWindow::initConnection() connect(m_systemPuginWidget, &SystemPluginWindow::itemChanged, this, &DockTrayWindow::onResetLayout); connect(m_dateTimeWidget, &DateTimeDisplayer::requestUpdate, this, &DockTrayWindow::onResetLayout); connect(m_quickIconWidget, &QuickPluginWindow::itemCountChanged, this, &DockTrayWindow::onResetLayout); + connect(m_quickIconWidget, &QuickPluginWindow::requestDrop, this, &DockTrayWindow::onDropIcon); + connect(m_systemPuginWidget, &SystemPluginWindow::requestDrop, this, &DockTrayWindow::onDropIcon); + connect(m_trayView, &TrayGridView::requestRemove, m_model, &TrayModel::removeRow); connect(m_trayView, &TrayGridView::requestRemove, this, &DockTrayWindow::onResetLayout); + connect(m_model, &TrayModel::rowCountChanged, this, &DockTrayWindow::onResetLayout); + connect(m_model, &TrayModel::rowCountChanged, m_trayView, &TrayGridView::onUpdateEditorView); + connect(m_model, &TrayModel::requestRefreshEditor, m_trayView, &TrayGridView::onUpdateEditorView); + connect(m_trayView, &TrayGridView::dragLeaved, m_delegate, [ this ]{ + Q_EMIT m_delegate->requestDrag(true); + }); + connect(m_trayView, &TrayGridView::dragEntered, m_delegate, [ this ]{ + Q_EMIT m_delegate->requestDrag(false); + }); connect(QuickSettingController::instance(), &QuickSettingController::pluginInserted, this, [ this ] (PluginsItemInterface *itemInter, const QuickSettingController::PluginAttribute &pluginAttr) { switch (pluginAttr) { case QuickSettingController::PluginAttribute::Tool: @@ -295,6 +337,24 @@ void DockTrayWindow::initConnection() connect(QuickSettingController::instance(), &QuickSettingController::pluginRemoved, this, &DockTrayWindow::onItemRemove); } +void DockTrayWindow::initAttribute() +{ + setAcceptDrops(true); + setMouseTracking(true); + + m_trayView->setModel(m_model); + m_trayView->setItemDelegate(m_delegate); + m_trayView->setDragDistance(2); + m_trayView->setDragEnabled(true); + + installEventFilter(this); + m_toolWidget->installEventFilter(this); + m_dateTimeWidget->installEventFilter(this); + m_systemPuginWidget->installEventFilter(this); + m_quickIconWidget->installEventFilter(this); + m_trayView->installEventFilter(this); +} + void DockTrayWindow::onResetLayout() { switch(m_position) { @@ -349,3 +409,23 @@ void DockTrayWindow::onItemRemove(PluginsItemInterface *itemInter) break; } } + +void DockTrayWindow::onDropIcon(QDropEvent *dropEvent) +{ + if (!dropEvent || !dropEvent->mimeData() || dropEvent->source() == this) + return; + + if (qobject_cast(dropEvent->source())) { + const QuickPluginMimeData *mimeData = qobject_cast(dropEvent->mimeData()); + if (!mimeData) + return; + + PluginsItemInterface *pluginItem = static_cast(mimeData->pluginItemInterface()); + if (pluginItem) + m_quickIconWidget->dragPlugin(pluginItem); + } else if (qobject_cast(dropEvent->source())) { + // 将trayView中的dropEvent扩大到整个区域(this),这样便于随意拖动到这个区域都可以捕获。 + // m_trayView中有e->accept不会导致事件重复处理。 + m_trayView->handleDropEvent(dropEvent); + } +} diff --git a/frame/window/docktraywindow.h b/frame/window/docktraywindow.h index fb1bffbbf..eb5f2def9 100644 --- a/frame/window/docktraywindow.h +++ b/frame/window/docktraywindow.h @@ -58,10 +58,12 @@ Q_SIGNALS: protected: void resizeEvent(QResizeEvent *event) override; void paintEvent(QPaintEvent *event) override; + bool eventFilter(QObject *watched, QEvent *event) override; private: void initUi(); void initConnection(); + void initAttribute(); void updateLayout(const Dock::Position &position); void resizeTool() const; bool pluginExists(PluginsItemInterface *itemInter) const; @@ -71,6 +73,7 @@ private Q_SLOTS: void onResetLayout(); void onItemAdded(PluginsItemInterface *itemInter); void onItemRemove(PluginsItemInterface *itemInter); + void onDropIcon(QDropEvent *dropEvent); private: DockInter *m_dockInter; diff --git a/frame/window/quickpluginmodel.cpp b/frame/window/quickpluginmodel.cpp new file mode 100644 index 000000000..5d2699ff7 --- /dev/null +++ b/frame/window/quickpluginmodel.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd. + * + * Author: donghualin + * + * Maintainer: donghualin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "quickpluginmodel.h" +#include "pluginsiteminterface.h" +#include "quicksettingcontroller.h" +#include "settingconfig.h" + +static QStringList fixedPluginNames { "network", "sound", "power" }; +#define PLUGINNAMEKEY "Dock_Quick_Plugin_Name" + +QuickPluginModel *QuickPluginModel::instance() +{ + static QuickPluginModel instance; + return &instance; +} + +void QuickPluginModel::addPlugin(PluginsItemInterface *itemInter, int index) +{ + // 这里只接受快捷面板的插件,因此,需要做一次判断 + if (QuickSettingController::instance()->pluginAttribute(itemInter) != QuickSettingController::PluginAttribute::Quick) + return; + + if (index < 0) { + // 如果索引值小于0,则认为它插在最后面 + index = m_dockedPluginIndex.size(); + } + + // 如果插入的插件在原来的插件列表中存在,并且位置相同,则不做任何的处理 + int oldIndex = m_dockedPluginIndex.contains(itemInter->pluginName()); + if (oldIndex == index && m_dockedPluginsItems.contains(itemInter)) + return; + + m_dockedPluginIndex[itemInter->pluginName()] = index; + if (!m_dockedPluginsItems.contains(itemInter)) { + m_dockedPluginsItems << itemInter; + // 保存配置到dConfig中 + saveConfig(); + } + // 向外发送更新列表的信号 + Q_EMIT requestUpdate(); +} + +void QuickPluginModel::removePlugin(PluginsItemInterface *itemInter) +{ + if (!m_dockedPluginsItems.contains(itemInter) && !m_dockedPluginIndex.contains(itemInter->pluginName())) + return; + + if (m_dockedPluginIndex.contains(itemInter->pluginName())) { + m_dockedPluginIndex.remove(itemInter->pluginName()); + // 保存配置到DConfig中 + saveConfig(); + } + + if (m_dockedPluginsItems.contains(itemInter)) { + m_dockedPluginsItems.removeOne(itemInter); + Q_EMIT requestUpdate(); + } +} + +QList QuickPluginModel::dockedPluginItems() const +{ + // 先查找出固定插件,始终排列在最前面 + QList dockedItems; + QList activedItems; + for (PluginsItemInterface *itemInter : m_dockedPluginsItems) { + if (fixedPluginNames.contains(itemInter->pluginName())) + dockedItems << itemInter; + else + activedItems << itemInter; + } + std::sort(dockedItems.begin(), dockedItems.end(), [ this ](PluginsItemInterface *item1, PluginsItemInterface *item2) { + return m_dockedPluginIndex.value(item1->pluginName()) < m_dockedPluginIndex.value(item2->pluginName()); + }); + std::sort(activedItems.begin(), activedItems.end(), [ this ](PluginsItemInterface *item1, PluginsItemInterface *item2) { + return m_dockedPluginIndex.value(item1->pluginName()) < m_dockedPluginIndex.value(item2->pluginName()); + }); + return (QList() << dockedItems << activedItems); +} + +bool QuickPluginModel::isDocked(PluginsItemInterface *itemInter) const +{ + return (m_dockedPluginsItems.contains(itemInter)); +} + +bool QuickPluginModel::isFixed(PluginsItemInterface *itemInter) const +{ + return fixedPluginNames.contains(itemInter->pluginName()); +} + +QuickPluginModel::QuickPluginModel(QObject *parent) + : QObject(parent) +{ + initConnection(); + initConfig(); +} + +void QuickPluginModel::onPluginRemoved(PluginsItemInterface *itemInter) +{ + // 如果插件移除,无需移除下方的排序设置,因为下次插件插入的时候还会插入到下方任务栏 + // 因此,此处只需要从列表中移除当前插件 + if (m_dockedPluginsItems.contains(itemInter)) + m_dockedPluginsItems.removeOne(itemInter); + // 向外发送更新列表的信号 + Q_EMIT requestUpdate(); +} + +void QuickPluginModel::onSettingChanged(const QString &key, const QVariant &value) +{ + if (key != PLUGINNAMEKEY) + return; + QStringList localOrder = m_dockedPluginIndex.keys(); + std::sort(localOrder.begin(), localOrder.end(), [ = ](const QString &key1, const QString &key2) { + return m_dockedPluginIndex.value(key1) < m_dockedPluginIndex.value(key2); + }); + if (localOrder == value.toStringList()) + return; + + // 当配置发生变化的时候,更新任务栏的插件显示 + // 1、将当前现有的插件列表中不在配置中的插件移除 + localOrder = value.toStringList(); + for (PluginsItemInterface *itemInter : m_dockedPluginsItems) { + if (localOrder.contains(itemInter->pluginName())) + continue; + + m_dockedPluginsItems.removeOne(itemInter); + m_dockedPluginIndex.remove(itemInter->pluginName()); + } + // 2、将配置中已有的但是插件列表中没有的插件移动到任务栏上 + QList plugins = QuickSettingController::instance()->pluginItems(QuickSettingController::PluginAttribute::Quick); + for (PluginsItemInterface *plugin : plugins) { + if (m_dockedPluginsItems.contains(plugin) || !localOrder.contains(plugin->pluginName())) + continue; + + m_dockedPluginsItems << plugin; + } + + m_dockedPluginIndex.clear(); + for (int i = 0; i < localOrder.size(); i++) + m_dockedPluginIndex[localOrder[i]] = i; + + Q_EMIT requestUpdate(); +} + +void QuickPluginModel::initConnection() +{ + QuickSettingController *quickController = QuickSettingController::instance(); + connect(quickController, &QuickSettingController::pluginInserted, this, [ this ](PluginsItemInterface *itemInter, const QuickSettingController::PluginAttribute &plugAttr) { + if (plugAttr != QuickSettingController::PluginAttribute::Quick) + return; + + // 用来读取已经固定在下方的插件 + if (!m_dockedPluginIndex.contains(itemInter->pluginName())) + return; + + m_dockedPluginsItems << itemInter; + + // 向外发送更新列表的信号 + Q_EMIT requestUpdate(); + }); + + connect(quickController, &QuickSettingController::pluginRemoved, this, &QuickPluginModel::onPluginRemoved); + connect(quickController, &QuickSettingController::pluginUpdated, this, &QuickPluginModel::requestUpdatePlugin); + connect(SETTINGCONFIG, &SettingConfig::valueChanged, this, &QuickPluginModel::onSettingChanged); +} + +void QuickPluginModel::initConfig() +{ + // 此处用于读取dConfig配置,记录哪些插件是固定在任务栏上面的 + QStringList dockPluginsName = SETTINGCONFIG->value(PLUGINNAMEKEY).toStringList(); + for (int i = 0; i < dockPluginsName.size(); i++) + m_dockedPluginIndex[dockPluginsName[i]] = i; +} + +void QuickPluginModel::saveConfig() +{ + QStringList plugins; + for (auto it = m_dockedPluginIndex.begin(); it != m_dockedPluginIndex.end(); it++) { + plugins << it.key(); + } + std::sort(plugins.begin(), plugins.end(), [ this ](const QString &p1, const QString &p2) { + return m_dockedPluginIndex.value(p1) < m_dockedPluginIndex.value(p2); + }); + SETTINGCONFIG->setValue(PLUGINNAMEKEY, plugins); +} diff --git a/frame/window/quickpluginmodel.h b/frame/window/quickpluginmodel.h new file mode 100644 index 000000000..f028ef7de --- /dev/null +++ b/frame/window/quickpluginmodel.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd. + * + * Author: donghualin + * + * Maintainer: donghualin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef QUICKPLUGINMODEL_H +#define QUICKPLUGINMODEL_H + +#include +#include + +class PluginsItemInterface; +enum class DockPart; +/** + * 这是一个独立的Model,用来记录显示在任务栏下方的快捷插件 + * @brief The QuickPluginModel class + */ + +class QuickPluginModel : public QObject +{ + Q_OBJECT + +public: + static QuickPluginModel *instance(); + + void addPlugin(PluginsItemInterface *itemInter, int index = -1); + void removePlugin(PluginsItemInterface *itemInter); + + QList dockedPluginItems() const; + bool isDocked(PluginsItemInterface *itemInter) const; + bool isFixed(PluginsItemInterface *itemInter) const; + +Q_SIGNALS: + void requestUpdate(); + void requestUpdatePlugin(PluginsItemInterface *, const DockPart &); + +protected: + explicit QuickPluginModel(QObject *parent = nullptr); + +private Q_SLOTS: + void onPluginRemoved(PluginsItemInterface *itemInter); + void onSettingChanged(const QString &key, const QVariant &value); + +private: + void initConnection(); + void initConfig(); + void saveConfig(); + +private: + QList m_dockedPluginsItems; + QMap m_dockedPluginIndex; +}; + +#endif // QUICKPLUGINMODEL_H diff --git a/frame/window/quickpluginwindow.cpp b/frame/window/quickpluginwindow.cpp index efe58c51a..ee3a12331 100644 --- a/frame/window/quickpluginwindow.cpp +++ b/frame/window/quickpluginwindow.cpp @@ -25,6 +25,7 @@ #include "quicksettingcontainer.h" #include "appdrag.h" #include "proxyplugincontroller.h" +#include "quickpluginmodel.h" #include #include @@ -43,25 +44,48 @@ #define ICONWIDTH 18 #define ICONHEIGHT 16 -static QStringList fixedPluginNames{ "network", "sound", "power" }; +typedef struct DragInfo{ + QPoint dragPoint; + QuickDockItem *dockItem = nullptr; -const int itemDataRole = Dtk::UserRole + 1; -const int itemSortRole = Dtk::UserRole + 2; + void reset() { + dockItem = nullptr; + dragPoint.setX(0); + dragPoint.setY(0); + } + + bool isNull() const { + return (!dockItem); + } + + bool canDrag(QPoint currentPoint) const { + if (dragPoint.isNull()) + return false; + + return (qAbs(currentPoint.x() - dragPoint.x()) >=5 || + qAbs(currentPoint.y() - dragPoint.y()) >= 5); + } +} DragInfo; + +static QStringList fixedPluginNames{ "network", "sound", "power" }; QuickPluginWindow::QuickPluginWindow(QWidget *parent) : QWidget(parent) , m_mainLayout(new QBoxLayout(QBoxLayout::RightToLeft, this)) , m_position(Dock::Position::Bottom) + , m_dragInfo(new DragInfo) { initUi(); initConnection(); + installEventFilter(this); setAcceptDrops(true); setMouseTracking(true); } QuickPluginWindow::~QuickPluginWindow() { + delete m_dragInfo; } void QuickPluginWindow::initUi() @@ -71,14 +95,6 @@ void QuickPluginWindow::initUi() m_mainLayout->setDirection(QBoxLayout::RightToLeft); m_mainLayout->setContentsMargins(ITEMSPACE, 0, ITEMSPACE, 0); m_mainLayout->setSpacing(ITEMSPACE); - QList items = QuickSettingController::instance()->pluginItems(QuickSettingController::PluginAttribute::Quick); - for (PluginsItemInterface *pluginItem : items) { - const QString pluginName = pluginItem->pluginName(); - if (!fixedPluginNames.contains(pluginName)) - continue; - - addPlugin(pluginItem); - } } void QuickPluginWindow::setPositon(Position position) @@ -97,40 +113,29 @@ void QuickPluginWindow::setPositon(Position position) } } -int QuickPluginWindow::findActiveTargetIndex(QuickDockItem *widget) -{ - for (int i = 0; i < m_activeSettingItems.size(); i++) { - PluginsItemInterface *settingItem = m_activeSettingItems[i]; - if (widget->pluginItem() == settingItem) - return i; - } - - return -1; -} - void QuickPluginWindow::dragPlugin(PluginsItemInterface *item) { - // 释放插件,一般是从快捷设置面板区域移动到这里的,固定插件不支持拖动 - if (fixedPluginNames.contains(item->pluginName())) - return; - + QuickPluginModel *quickModel = QuickPluginModel::instance(); QPoint itemPoint = mapFromGlobal(QCursor::pos()); // 查找移动后的位置,如果移动后的插件找不到,就直接放到最后 + int index = -1; QuickDockItem *targetWidget = qobject_cast(childAt(itemPoint)); - if (!targetWidget) { - m_activeSettingItems << item; - } else { + if (targetWidget) { // 如果是拖动到固定插件区域,也放到最后 - int targetIndex = findActiveTargetIndex(targetWidget); - if (targetIndex < 0) - m_activeSettingItems << item; - else - m_activeSettingItems.insert(targetIndex, item); + QList pluginItems = quickModel->dockedPluginItems(); + for (int i = 0; i < pluginItems.size(); i++) { + PluginsItemInterface *plugin = pluginItems[i]; + if (quickModel->isFixed(plugin)) + continue; + + if (targetWidget->pluginItem() == plugin) { + index = i; + break; + } + } } - //排序插入到当前窗体 - resetPluginDisplay(); - Q_EMIT itemCountChanged(); + quickModel->addPlugin(item, index); } QSize QuickPluginWindow::suitableSize() const @@ -138,41 +143,6 @@ QSize QuickPluginWindow::suitableSize() const return suitableSize(m_position); } -void QuickPluginWindow::addPlugin(PluginsItemInterface *pluginItem) -{ - if (!isQuickPlugin(pluginItem)) - return; - - for (int i = 0; i < m_mainLayout->count(); i++) { - QLayoutItem *layoutItem = m_mainLayout->itemAt(i); - if (!layoutItem) - continue; - - QuickDockItem *dockItem = qobject_cast(layoutItem->widget()); - if (!dockItem) - continue; - - if (pluginItem == dockItem->pluginItem()) { - resetPluginDisplay(); - return; - } - } - if (fixedPluginNames.contains(pluginItem->pluginName())) { - // 新插入的插件如果是固定插件,则将其插入到固定插件列表中,并对其进行排序 - m_fixedSettingItems << pluginItem; - qSort(m_fixedSettingItems.begin(), m_fixedSettingItems.end(), [](PluginsItemInterface *item1, PluginsItemInterface *item2) { - int index1 = fixedPluginNames.indexOf(item1->pluginName()); - int index2 = fixedPluginNames.indexOf(item2->pluginName()); - return index1 < index2; - }); - } else { - // 如果是非固定插件,则直接插入到末尾 - m_activeSettingItems << pluginItem; - } - resetPluginDisplay(); - Q_EMIT itemCountChanged(); -} - QSize QuickPluginWindow::suitableSize(const Dock::Position &position) const { if (position == Dock::Position::Top || position == Dock::Position::Bottom) @@ -190,19 +160,6 @@ QSize QuickPluginWindow::suitableSize(const Dock::Position &position) const return QSize(ITEMSIZE, height); } -void QuickPluginWindow::removePlugin(PluginsItemInterface *item) -{ - if (m_fixedSettingItems.contains(item)) - m_fixedSettingItems.removeOne(item); - else if (m_activeSettingItems.contains(item)) - m_activeSettingItems.removeOne(item); - else - return; - - resetPluginDisplay(); - Q_EMIT itemCountChanged(); -} - PluginsItemInterface *QuickPluginWindow::findQuickSettingItem(const QPoint &mousePoint, const QList &settingItems) { QuickDockItem *selectWidget = qobject_cast(childAt(mousePoint)); @@ -218,15 +175,105 @@ PluginsItemInterface *QuickPluginWindow::findQuickSettingItem(const QPoint &mous return nullptr; } -void QuickPluginWindow::mousePressEvent(QMouseEvent *event) +bool QuickPluginWindow::eventFilter(QObject *watched, QEvent *event) { - // 查找非固定的图标,然后执行拖动 - PluginsItemInterface *quickItem = findQuickSettingItem(event->pos(), m_activeSettingItems); - if (!quickItem) - return; + switch (event->type()) { + case QEvent::MouseButtonPress: { + QuickDockItem *dockItem = qobject_cast(watched); + if (!dockItem) + break; - // 如果不是固定图标,则让其拖动 - startDrag(quickItem); + QMouseEvent *mouseEvent = static_cast(event); + m_dragInfo->dockItem = dockItem; + m_dragInfo->dragPoint = mouseEvent->pos(); + break; + } + case QEvent::MouseButtonRelease: { + if (m_dragInfo->isNull()) + break; + + QMouseEvent *mouseEvent = static_cast(event); + if (!m_dragInfo->canDrag(mouseEvent->pos())) { + // 弹出快捷设置面板 + DockPopupWindow *popWindow = QuickSettingContainer::popWindow(); + popWindow->show(popupPoint()); + } + m_dragInfo->reset(); + break; + } + case QEvent::MouseMove: { + if (m_dragInfo->isNull()) + break; + + QMouseEvent *mouseEvent = static_cast(event); + if (m_dragInfo->canDrag(mouseEvent->pos())) { + startDrag(m_dragInfo->dockItem->pluginItem()); + m_dragInfo->reset(); + } + break; + } + case QEvent::Drop: { + Q_EMIT requestDrop(static_cast(event)); + break; + } + default: + break; + } + return QWidget::eventFilter(watched, event); +} + +void QuickPluginWindow::onRequestUpdate() +{ + bool countChanged = false; + QuickPluginModel *model = QuickPluginModel::instance(); + QList plugins = model->dockedPluginItems(); + // 先删除所有的widget + QMap pluginItems; + for (int i = m_mainLayout->count() - 1; i >= 0; i--) { + QLayoutItem *layoutItem = m_mainLayout->itemAt(i); + if (!layoutItem) + continue; + + QuickDockItem *dockItem = qobject_cast(layoutItem->widget()); + if (!dockItem) + continue; + + dockItem->setParent(nullptr); + m_mainLayout->removeItem(layoutItem); + if (plugins.contains(dockItem->pluginItem())) { + // 如果该插件在任务栏上,则先将其添加到临时列表中 + pluginItems[dockItem->pluginItem()] = dockItem; + } else { + // 如果该插件不在任务栏上,则先删除 + dockItem->deleteLater(); + countChanged = true; + } + } + + // 将列表中所有的控件按照顺序添加到布局上 + QuickSettingController *quickController = QuickSettingController::instance(); + for (PluginsItemInterface *item : plugins) { + QuickDockItem *itemWidget = nullptr; + if (pluginItems.contains(item)) { + itemWidget = pluginItems[item]; + } else { + QJsonObject metaData; + QPluginLoader *pluginLoader = ProxyPluginController::instance(PluginType::QuickPlugin)->pluginLoader(item); + if (pluginLoader) + metaData = pluginLoader->metaData().value("MetaData").toObject(); + + itemWidget = new QuickDockItem(item, metaData, quickController->itemKey(item), this); + itemWidget->setFixedSize(ICONWIDTH, ICONHEIGHT); + itemWidget->installEventFilter(this); + itemWidget->setMouseTracking(true); + countChanged = true; + } + itemWidget->setParent(this); + m_mainLayout->addWidget(itemWidget); + } + + if (countChanged) + Q_EMIT itemCountChanged(); } QPoint QuickPluginWindow::popupPoint() const @@ -259,18 +306,6 @@ QPoint QuickPluginWindow::popupPoint() const return pointCurrent; } -void QuickPluginWindow::onFixedClick() -{ - // 查找固定团图标,然后点击弹出快捷面板 - QuickDockItem *dockItem = qobject_cast(sender()); - if (!dockItem || !fixedPluginNames.contains(dockItem->pluginItem()->pluginName())) - return; - - // 弹出快捷设置面板 - DockPopupWindow *popWindow = QuickSettingContainer::popWindow(); - popWindow->show(popupPoint()); -} - void QuickPluginWindow::onUpdatePlugin(PluginsItemInterface *itemInter, const DockPart &dockPart) { //update plugin status @@ -293,7 +328,8 @@ void QuickPluginWindow::startDrag(PluginsItemInterface *moveItem) drag->setHotSpot(QPoint(0, 0)); connect(drag->appDragWidget(), &AppDragWidget::requestSplitWindow, this, [ this, moveItem ] { - removePlugin(moveItem); + QuickPluginModel::instance()->removePlugin(moveItem); + Q_EMIT itemCountChanged(); }); connect(static_cast(drag->appDragWidget()), &QuickDragWidget::requestDropItem, this, &QuickPluginWindow::onPluginDropItem); @@ -323,20 +359,34 @@ QuickDockItem *QuickPluginWindow::getDockItemByPlugin(PluginsItemInterface *item return nullptr; } -bool QuickPluginWindow::isQuickPlugin(PluginsItemInterface *pluginItem) +QuickDockItem *QuickPluginWindow::getActiveDockItem(QPoint point) const { - QJsonObject metaData = QuickSettingController::instance()->metaData(pluginItem); - if (metaData.contains("tool")) - return !metaData.value("tool").toBool(); + QuickDockItem *selectWidget = qobject_cast(childAt(point)); + if (!selectWidget) + return nullptr; - return true; + // 如果当前图标是固定插件,则不让插入 + if (QuickPluginModel::instance()->isFixed(selectWidget->pluginItem())) + return nullptr; + + return selectWidget; } int QuickPluginWindow::getDropIndex(QPoint point) { - QuickDockItem *targetItem = getDockItemByPlugin(findQuickSettingItem(point, m_activeSettingItems)); - if (targetItem) - return m_activeSettingItems.indexOf(targetItem->pluginItem()); + QuickDockItem *targetItem = getActiveDockItem(point); + if (targetItem) { + for (int i = 0; i < m_mainLayout->count(); i++) { + QLayoutItem *layoutItem = m_mainLayout->itemAt(i); + if (!layoutItem) + continue; + + if (layoutItem->widget() == targetItem) + return i; + } + + return -1; + } // 上下方向从右向左排列 if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) { @@ -384,14 +434,7 @@ void QuickPluginWindow::onPluginDropItem(QDropEvent *event) // 获取当前鼠标在任务栏快捷图标区域的位置 QPoint currentPoint = mapFromGlobal(QCursor::pos()); // 获取区域图标插入的位置 - int dropIndex = getDropIndex(currentPoint); - if (dropIndex >= 0) - m_activeSettingItems.insert(dropIndex, data->pluginItemInterface()); - else - m_activeSettingItems << data->pluginItemInterface(); - - resetPluginDisplay(); - Q_EMIT itemCountChanged(); + QuickPluginModel::instance()->addPlugin(data->pluginItemInterface(), getDropIndex(currentPoint)); } void QuickPluginWindow::onPluginDragMove(QDragMoveEvent *event) @@ -407,7 +450,7 @@ void QuickPluginWindow::onPluginDragMove(QDragMoveEvent *event) return; QuickDockItem *sourceMoveWidget = getDockItemByPlugin(sourceItem); - QuickDockItem *targetItem = getDockItemByPlugin(findQuickSettingItem(currentPoint, m_activeSettingItems)); + QuickDockItem *targetItem = getActiveDockItem(currentPoint); // 如果未找到要移动的目标位置,或者移动的目标位置是固定插件,或者原插件和目标插件是同一个插件,则不做任何操作 if (!sourceMoveWidget || !targetItem || sourceMoveWidget == targetItem) return; @@ -419,77 +462,21 @@ void QuickPluginWindow::onPluginDragMove(QDragMoveEvent *event) allItems[childWidget] = i; } // 调整列表中的位置 - int sourceIndex = m_activeSettingItems.indexOf(sourceItem); +/* int sourceIndex = m_activeSettingItems.indexOf(sourceItem); int targetIndex = m_activeSettingItems.indexOf(targetItem->pluginItem()); if (sourceIndex >= 0) m_activeSettingItems.move(sourceIndex, targetIndex); else m_activeSettingItems.insert(targetIndex, sourceItem); - +*/ event->accept(); } -void QuickPluginWindow::resetPluginDisplay() -{ - // 先删除所有的widget - QMap pluginItems; - for (int i = m_mainLayout->count() - 1; i >= 0; i--) { - QLayoutItem *layoutItem = m_mainLayout->itemAt(i); - if (!layoutItem) - continue; - - QuickDockItem *dockItem = qobject_cast(layoutItem->widget()); - if (!dockItem) - continue; - - dockItem->setParent(nullptr); - m_mainLayout->removeItem(layoutItem); - pluginItems[dockItem->pluginItem()] = dockItem; - } - // 将列表中所有的控件按照顺序添加到布局上 - auto addWidget = [ = ](const QList &items) { - QuickSettingController *quickController = QuickSettingController::instance(); - for (PluginsItemInterface *item : items) { - QuickDockItem *itemWidget = nullptr; - if (pluginItems.contains(item)) { - itemWidget = pluginItems[item]; - } else { - QJsonObject metaData; - QPluginLoader *pluginLoader = ProxyPluginController::instance(PluginType::QuickPlugin)->pluginLoader(item); - if (pluginLoader) - metaData = pluginLoader->metaData().value("MetaData").toObject(); - - itemWidget = new QuickDockItem(item, metaData, quickController->itemKey(item), this); - itemWidget->setFixedSize(ICONWIDTH, ICONHEIGHT); - } - connect(itemWidget, &QuickDockItem::clicked, this, &QuickPluginWindow::onFixedClick); - itemWidget->setParent(this); - m_mainLayout->addWidget(itemWidget); - } - }; - - addWidget(m_fixedSettingItems); - addWidget(m_activeSettingItems); -} - void QuickPluginWindow::initConnection() { - connect(QuickSettingController::instance(), &QuickSettingController::pluginInserted, this, [ this ](PluginsItemInterface *itemInter, const QuickSettingController::PluginAttribute &pluginClass) { - if (pluginClass != QuickSettingController::PluginAttribute::Quick) - return; - - const QString pluginName = itemInter->pluginName(); - if (!fixedPluginNames.contains(pluginName)) - return; - - addPlugin(itemInter); - }); - - connect(QuickSettingController::instance(), &QuickSettingController::pluginRemoved, this, [ this ] (PluginsItemInterface *itemInter){ - removePlugin(itemInter); - }); - - connect(QuickSettingController::instance(), &QuickSettingController::pluginUpdated, this, &QuickPluginWindow::onUpdatePlugin); + QuickPluginModel *model = QuickPluginModel::instance(); + connect(model, &QuickPluginModel::requestUpdate, this, &QuickPluginWindow::onRequestUpdate); + connect(model, &QuickPluginModel::requestUpdatePlugin, this, &QuickPluginWindow::onUpdatePlugin); } /** @@ -555,10 +542,6 @@ void QuickDockItem::paintEvent(QPaintEvent *event) void QuickDockItem::mousePressEvent(QMouseEvent *event) { switch (event->button()) { - case Qt::LeftButton: { - Q_EMIT clicked(); - break; - } case Qt::RightButton: { if (m_contextMenu->actions().isEmpty()) { const QString menuJson = m_pluginItem->itemContextMenu(m_itemKey); diff --git a/frame/window/quickpluginwindow.h b/frame/window/quickpluginwindow.h index 27bdd52c4..b8133cd3d 100644 --- a/frame/window/quickpluginwindow.h +++ b/frame/window/quickpluginwindow.h @@ -59,16 +59,15 @@ public: Q_SIGNALS: void itemCountChanged(); + void requestDrop(QDropEvent *dropEvent); protected: - void mousePressEvent(QMouseEvent *event) override; + bool eventFilter(QObject *watched, QEvent *event) override; private Q_SLOTS: - void addPlugin(PluginsItemInterface *pluginItem); - void removePlugin(PluginsItemInterface *item); + void onRequestUpdate(); void onPluginDropItem(QDropEvent *event); void onPluginDragMove(QDragMoveEvent *event); - void onFixedClick(); void onUpdatePlugin(PluginsItemInterface *itemInter, const DockPart &dockPart); private: @@ -76,18 +75,15 @@ private: void initConnection(); void startDrag(PluginsItemInterface *moveItem); PluginsItemInterface *findQuickSettingItem(const QPoint &mousePoint, const QList &settingItems); - int findActiveTargetIndex(QuickDockItem *widget); int getDropIndex(QPoint point); - void resetPluginDisplay(); QPoint popupPoint() const; QuickDockItem *getDockItemByPlugin(PluginsItemInterface *item); - bool isQuickPlugin(PluginsItemInterface *pluginItem); + QuickDockItem *getActiveDockItem(QPoint point) const; private: QBoxLayout *m_mainLayout; Dock::Position m_position; - QList m_activeSettingItems; - QList m_fixedSettingItems; + struct DragInfo *m_dragInfo; }; // 用于在任务栏上显示的插件 @@ -103,9 +99,6 @@ public: PluginsItemInterface *pluginItem(); bool isPrimary() const; -Q_SIGNALS: - void clicked(); - protected: void paintEvent(QPaintEvent *event) override; void mousePressEvent(QMouseEvent *event) override; diff --git a/frame/window/quicksettingcontainer.cpp b/frame/window/quicksettingcontainer.cpp index f241080d5..c7fa72423 100644 --- a/frame/window/quicksettingcontainer.cpp +++ b/frame/window/quicksettingcontainer.cpp @@ -41,10 +41,22 @@ #include #include #include +#include DWIDGET_USE_NAMESPACE -static const int QuickItemRole = Dtk::UserRole + 10; +struct QuickDragInfo { + QPoint dragPosition; + QuickSettingItem *dragItem = nullptr; + void reset() { + dragPosition.setX(0); + dragPosition.setY(0); + dragItem = nullptr; + } + bool isNull() { + return !dragItem; + } +} QuickDragInfo; #define ITEMWIDTH 70 #define ITEMHEIGHT 60 @@ -71,7 +83,7 @@ QuickSettingContainer::QuickSettingContainer(QWidget *parent) , m_volumeSettingWidget(new VolumeDevicesWidget(m_volumeModel, this)) , m_displaySettingWidget(new DisplaySettingWidget(this)) , m_childPage(new PluginChildPage(this)) - , m_dragPluginPosition(QPoint(0, 0)) + , m_dragInfo(new struct QuickDragInfo) { initUi(); initConnection(); @@ -81,6 +93,7 @@ QuickSettingContainer::QuickSettingContainer(QWidget *parent) QuickSettingContainer::~QuickSettingContainer() { + delete m_dragInfo; } void QuickSettingContainer::showHomePage() @@ -170,8 +183,29 @@ void QuickSettingContainer::onItemDetailClick(PluginsItemInterface *pluginInter) bool QuickSettingContainer::eventFilter(QObject *watched, QEvent *event) { - if (watched == m_childPage && event->type() == QEvent::Resize) - onResizeView(); + switch (event->type()) { + case QEvent::Resize: { + if (watched == m_childPage) + onResizeView(); + break; + } + case QEvent::MouseButtonPress: { + QuickSettingItem *item = qobject_cast(watched); + if (!item) + break; + + QMouseEvent *mouseEvent = static_cast(event); + m_dragInfo->dragPosition = mouseEvent->pos(); + m_dragInfo->dragItem = item; + break; + } + case QEvent::MouseButtonRelease: { + m_dragInfo->reset(); + break; + } + default: + break; + } return QWidget::eventFilter(watched, event); } @@ -183,6 +217,17 @@ void QuickSettingContainer::showWidget(QWidget *widget, const QString &title) m_switchLayout->setCurrentWidget(m_childPage); } +QPoint QuickSettingContainer::hotSpot(const QPixmap &pixmap) +{ + if (m_position == Dock::Position::Left) + return QPoint(0, pixmap.height()); + + if (m_position == Dock::Position::Top) + return QPoint(pixmap.width(), 0); + + return QPoint(pixmap.width(), pixmap.height()); +} + void QuickSettingContainer::onPluginInsert(PluginsItemInterface * itemInter) { initQuickItem(itemInter); @@ -216,51 +261,23 @@ void QuickSettingContainer::onPluginRemove(PluginsItemInterface * itemInter) onResizeView(); } -void QuickSettingContainer::mousePressEvent(QMouseEvent *event) -{ - if (event->button() != Qt::LeftButton) - return QWidget::mousePressEvent(event); - - QuickSettingItem *moveItem = qobject_cast(childAt(event->pos())); - if (!moveItem || moveItem->isPrimary()) - return QWidget::mousePressEvent(event); - - m_dragPluginPosition = event->pos(); -} - -void QuickSettingContainer::clearDragPoint() -{ - m_dragPluginPosition.setX(0); - m_dragPluginPosition.setY(0); -} - -void QuickSettingContainer::mouseReleaseEvent(QMouseEvent *event) -{ - Q_UNUSED(event); - clearDragPoint(); -} - void QuickSettingContainer::mouseMoveEvent(QMouseEvent *event) { - if (m_dragPluginPosition.isNull()) + if (m_dragInfo->isNull()) return; - QuickSettingItem *moveItem = qobject_cast(childAt(m_dragPluginPosition)); - if (!moveItem) { - clearDragPoint(); - return; - } - QPoint pointCurrent = event->pos(); - if (qAbs(m_dragPluginPosition.x() - pointCurrent.x()) > 5 - || qAbs(m_dragPluginPosition.y() - pointCurrent.y()) > 5) { - clearDragPoint(); + if (qAbs(m_dragInfo->dragPosition.x() - pointCurrent.x()) > 5 + || qAbs(m_dragInfo->dragPosition.y() - pointCurrent.y()) > 5) { + QuickSettingItem *moveItem = m_dragInfo->dragItem; + m_dragInfo->reset(); + QDrag *drag = new QDrag(this); QuickPluginMimeData *mimedata = new QuickPluginMimeData(moveItem->pluginItem()); drag->setMimeData(mimedata); QPixmap dragPixmap = moveItem->dragPixmap(); drag->setPixmap(dragPixmap); - drag->setHotSpot(QPoint(dragPixmap.width() / 2, dragPixmap.height() / 2)); + drag->setHotSpot(hotSpot(dragPixmap)); drag->exec(Qt::MoveAction | Qt::CopyAction); } diff --git a/frame/window/quicksettingcontainer.h b/frame/window/quicksettingcontainer.h index fec0ab53c..f2b714416 100644 --- a/frame/window/quicksettingcontainer.h +++ b/frame/window/quicksettingcontainer.h @@ -45,6 +45,7 @@ class QLabel; class PluginChildPage; class QGridLayout; class DisplaySettingWidget; +struct QuickDragInfo; DWIDGET_USE_NAMESPACE @@ -57,9 +58,8 @@ public: static void setPosition(Dock::Position position); protected: - void mousePressEvent(QMouseEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; + bool eventFilter(QObject *watched, QEvent *event) override; explicit QuickSettingContainer(QWidget *parent = nullptr); ~QuickSettingContainer() override; @@ -69,7 +69,6 @@ private Q_SLOTS: void onPluginInsert(PluginsItemInterface * itemInter); void onPluginRemove(PluginsItemInterface * itemInter); void onItemDetailClick(PluginsItemInterface *pluginInter); - bool eventFilter(QObject *watched, QEvent *event) override; void onResizeView(); private: @@ -83,8 +82,8 @@ private: void initQuickItem(PluginsItemInterface *plugin); // 显示具体的窗体 void showWidget(QWidget *widget, const QString &title); - // 清除移动轨迹 - void clearDragPoint(); + // 获取拖动图标的热点 + QPoint hotSpot(const QPixmap &pixmap); private: static DockPopupWindow *m_popWindow; @@ -105,7 +104,7 @@ private: VolumeDevicesWidget *m_volumeSettingWidget; DisplaySettingWidget *m_displaySettingWidget; PluginChildPage *m_childPage; - QPoint m_dragPluginPosition; + QuickDragInfo *m_dragInfo; QList m_quickSettings; }; diff --git a/frame/window/systempluginwindow.cpp b/frame/window/systempluginwindow.cpp index cd17498e7..0a408c85e 100644 --- a/frame/window/systempluginwindow.cpp +++ b/frame/window/systempluginwindow.cpp @@ -117,10 +117,19 @@ QSize SystemPluginWindow::suitableSize(const Position &position) const return QSize(QWIDGETSIZE_MAX, itemHeight); } +bool SystemPluginWindow::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == QEvent::Drop) + Q_EMIT requestDrop(static_cast(event)); + + return QWidget::eventFilter(watched, event); +} + void SystemPluginWindow::initUi() { m_mainLayout->setContentsMargins(0, 0, 0, 0); m_mainLayout->setSpacing(0); + installEventFilter(this); } void SystemPluginWindow::initConnection() @@ -161,6 +170,7 @@ void SystemPluginWindow::pluginAdded(PluginsItemInterface *plugin) StretchPluginsItem *item = new StretchPluginsItem(plugin, QuickSettingController::instance()->itemKey(plugin)); item->setDisplayMode(m_displayMode); item->setPosition(m_position); + item->installEventFilter(this); item->setParent(this); item->show(); m_mainLayout->addWidget(item); diff --git a/frame/window/systempluginwindow.h b/frame/window/systempluginwindow.h index 9a74aca1d..b7bda5dc3 100644 --- a/frame/window/systempluginwindow.h +++ b/frame/window/systempluginwindow.h @@ -48,6 +48,10 @@ public: Q_SIGNALS: void itemChanged(); + void requestDrop(QDropEvent *dropEvent); + +protected: + bool eventFilter(QObject *watched, QEvent *event) override; private: void initUi(); diff --git a/frame/window/tray/tray_delegate.cpp b/frame/window/tray/tray_delegate.cpp index a9bd34b5f..4e14e8243 100644 --- a/frame/window/tray/tray_delegate.cpp +++ b/frame/window/tray/tray_delegate.cpp @@ -48,6 +48,7 @@ TrayDelegate::TrayDelegate(QListView *view, QObject *parent) , m_position(Dock::Position::Bottom) , m_listView(view) { + connect(this, &TrayDelegate::requestDrag, this, &TrayDelegate::onUpdateExpand); } void TrayDelegate::setPositon(Dock::Position position) @@ -83,11 +84,11 @@ QWidget *TrayDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem trayWidget = new SNITrayItemWidget(servicePath, parent); } else if (type == TrayIconType::ExpandIcon) { ExpandIconWidget *expandWidget = new ExpandIconWidget(parent); - expandWidget->setPositonValue(m_position); - connect(expandWidget, &ExpandIconWidget::trayVisbleChanged, this, [ = ](bool visible) { - Q_EMIT visibleChanged(index, visible); - }); - connect(this, &TrayDelegate::requestDrag, this, &TrayDelegate::onRequestDrag); + expandWidget->setPositon(m_position); + bool openExpand = index.data(TrayModel::ExpandRole).toBool(); + if (openExpand) + expandWidget->setTrayPanelVisible(true); + trayWidget = expandWidget; } else if (type == TrayIconType::Incicator) { QString indicateName = key; @@ -119,18 +120,23 @@ QWidget *TrayDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem return trayWidget; } -void TrayDelegate::onRequestDrag(bool on) +void TrayDelegate::onUpdateExpand(bool on) { ExpandIconWidget *expandwidget = expandWidget(); - if (!expandwidget) - return; if (on) { - expandwidget->setTrayPanelVisible(true); - } else { + if (!expandwidget) { + // 如果三角按钮不存在,那么就设置三角按钮可见,此时它会自动创建一个三角按钮 + TrayModel *model = qobject_cast(m_listView->model()); + if (model) + model->setExpandVisible(true, true); + } else { + expandwidget->setTrayPanelVisible(true); + } + } else if (expandwidget) { // 如果释放鼠标,则判断当前鼠标的位置是否在托盘内部,如果在,则无需隐藏 QPoint currentPoint = QCursor::pos(); - QWidget *view = expandwidget->popupTrayView(); + TrayGridWidget *view = ExpandIconWidget::popupTrayView(); expandwidget->setTrayPanelVisible(view->geometry().contains(currentPoint)); } } diff --git a/frame/window/tray/tray_delegate.h b/frame/window/tray/tray_delegate.h index 5bd4e2175..26487f761 100644 --- a/frame/window/tray/tray_delegate.h +++ b/frame/window/tray/tray_delegate.h @@ -45,11 +45,10 @@ public: Q_SIGNALS: void removeRow(const QModelIndex &) const; - void visibleChanged(const QModelIndex &, bool) const; void requestDrag(bool) const; private Q_SLOTS: - void onRequestDrag(bool on); + void onUpdateExpand(bool on); protected: QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; diff --git a/frame/window/tray/tray_gridview.cpp b/frame/window/tray/tray_gridview.cpp index d190bd259..b62757f3c 100644 --- a/frame/window/tray/tray_gridview.cpp +++ b/frame/window/tray/tray_gridview.cpp @@ -19,6 +19,7 @@ * along with this program. If not, see . */ #include "tray_gridview.h" +#include "settingconfig.h" #include #include @@ -406,14 +407,22 @@ void TrayGridView::handleDropEvent(QDropEvent *e) info.key = static_cast(e->mimeData()->data("key")); info.winId = static_cast(e->mimeData()->data("winId").toInt()); info.servicePath = static_cast(e->mimeData()->data("servicePath")); + info.itemKey = static_cast(e->mimeData()->data("itemKey")); + info.isTypeWriting = (static_cast(e->mimeData()->data("isTypeWritting")) == "1"); + info.expand = (static_cast(e->mimeData()->data("expand")) == "1"); + info.pluginInter = (PluginsItemInterface *)(e->mimeData()->imageData().value()); QModelIndex targetIndex = getIndexFromPos(e->pos()); + int index = -1; if (targetIndex.isValid() && targetIndex.row() < dataModel->rowCount() - 1) { // 如果拖动的位置是合法的位置,则让其插入到当前的位置 - dataModel->insertRow(targetIndex.row(), info); + index = targetIndex.row(); + dataModel->insertRow(index, info); } else { // 在其他的情况下,让其插入到最后 dataModel->addRow(info); } + + dataModel->saveConfig(index, info); } } else { e->ignore(); @@ -421,6 +430,15 @@ void TrayGridView::handleDropEvent(QDropEvent *e) } } +void TrayGridView::onUpdateEditorView() +{ + for (int i = 0; i < model()->rowCount(); i++) { + QModelIndex index = model()->index(i, 0); + closePersistentEditor(index); + openPersistentEditor(index); + } +} + bool TrayGridView::beginDrag(Qt::DropActions supportedActions) { QModelIndex modelIndex = indexAt(m_dragPos); @@ -451,8 +469,6 @@ bool TrayGridView::beginDrag(Qt::DropActions supportedActions) QRect rectIcon(pixLabel->rect().topLeft(), pixLabel->size()); - listModel->setDragingIndex(modelIndex); - QDrag *drag = new QDrag(this); pixmap.scaled(pixmap.size() * ratio, Qt::KeepAspectRatio, Qt::SmoothTransformation); pixmap.setDevicePixelRatio(ratio); @@ -469,6 +485,7 @@ bool TrayGridView::beginDrag(Qt::DropActions supportedActions) setState(DraggingState); listModel->setDragKey(itemKey); + listModel->setDragingIndex(modelIndex); Qt::DropAction dropAct = drag->exec(supportedActions); @@ -484,6 +501,7 @@ bool TrayGridView::beginDrag(Qt::DropActions supportedActions) pixLabel->deleteLater(); listModel->setDragKey(QString()); clearDragModelIndex(); + listModel->setExpandVisible(!TrayModel::getIconModel()->isEmpty()); m_dropPos = QPoint(); m_dragPos = QPoint(); diff --git a/frame/window/tray/tray_gridview.h b/frame/window/tray/tray_gridview.h index 9a498453d..3a5e25b28 100644 --- a/frame/window/tray/tray_gridview.h +++ b/frame/window/tray/tray_gridview.h @@ -42,20 +42,23 @@ public: QSize suitableSize(const Dock::Position &position) const; void setDragDistance(int pixel); void setAnimationProperty(const QEasingCurve::Type easing, const int duringTime = 250); - void moveAnimation(); const QModelIndex modelIndex(const int index) const; const QRect indexRect(const QModelIndex &index) const; - void dropSwap(); void handleDropEvent(QDropEvent *e); +public Q_SLOTS: + void onUpdateEditorView(); + Q_SIGNALS: void requestRemove(const QString &); void dragLeaved(); void dragEntered(); -public Q_SLOTS: +private Q_SLOTS: void clearDragModelIndex(); + void dropSwap(); + void moveAnimation(); protected: void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE; diff --git a/frame/window/tray/tray_model.cpp b/frame/window/tray/tray_model.cpp index c0db86d71..7911adfb7 100644 --- a/frame/window/tray/tray_model.cpp +++ b/frame/window/tray/tray_model.cpp @@ -25,6 +25,8 @@ #include "indicatorplugin.h" #include "quicksettingcontroller.h" #include "pluginsiteminterface.h" +#include "settingconfig.h" +#include "platformutils.h" #include #include @@ -33,41 +35,54 @@ #include #define TRAY_DRAG_FALG "tray_drag" +#define DOCKQUICKTRAYNAME "Dock_Quick_Tray_Name" -TrayModel::TrayModel(QListView *view, bool isIconTray, bool hasInputMethod, QObject *parent) +TrayModel *TrayModel::getDockModel() +{ + static TrayModel *model = nullptr; + if (!model) { + model = new TrayModel(false); + TrayModel *iconModel = getIconModel(); + connect(iconModel, &TrayModel::rowsRemoved, model, [ = ] { + model->setExpandVisible(iconModel->rowCount() > 0); + }); + connect(iconModel, &TrayModel::rowsInserted, model, [ = ] { + model->setExpandVisible(iconModel->rowCount() > 0); + }); + } + + return model; +} + +TrayModel *TrayModel::getIconModel() +{ + static TrayModel model(true); + return &model; +} + +TrayModel::TrayModel(bool isIconTray, QObject *parent) : QAbstractListModel(parent) , m_dragModelIndex(QModelIndex()) , m_dropModelIndex(QModelIndex()) - , m_view(view) , m_monitor(new TrayMonitor(this)) , m_isTrayIcon(isIconTray) - , m_hasInputMethod(hasInputMethod) { - Q_ASSERT(m_view); - - if (isIconTray) { - connect(m_monitor, &TrayMonitor::xEmbedTrayAdded, this, &TrayModel::onXEmbedTrayAdded); - connect(m_monitor, &TrayMonitor::indicatorFounded, this, &TrayModel::onIndicatorFounded); - - QuickSettingController *quickController = QuickSettingController::instance(); - connect(quickController, &QuickSettingController::pluginInserted, this, [ = ](PluginsItemInterface *itemInter, const QuickSettingController::PluginAttribute &pluginAttr) { - if (pluginAttr != QuickSettingController::PluginAttribute::Tray) - return; - - systemItemAdded(itemInter); - }); - - connect(quickController, &QuickSettingController::pluginRemoved, this, &TrayModel::onSystemItemRemoved); - QMetaObject::invokeMethod(this, [ = ] { - QList trayPlugins = quickController->pluginItems(QuickSettingController::PluginAttribute::Tray); - for (PluginsItemInterface *plugin : trayPlugins) - systemItemAdded(plugin); - }, Qt::QueuedConnection); - } + connect(m_monitor, &TrayMonitor::xEmbedTrayAdded, this, &TrayModel::onXEmbedTrayAdded); connect(m_monitor, &TrayMonitor::xEmbedTrayRemoved, this, &TrayModel::onXEmbedTrayRemoved); - connect(m_monitor, &TrayMonitor::requestUpdateIcon, this, &TrayModel::requestUpdateIcon); + connect(m_monitor, &TrayMonitor::sniTrayAdded, this, &TrayModel::onSniTrayAdded); connect(m_monitor, &TrayMonitor::sniTrayRemoved, this, &TrayModel::onSniTrayRemoved); + + connect(m_monitor, &TrayMonitor::indicatorFounded, this, &TrayModel::onIndicatorFounded); + + connect(m_monitor, &TrayMonitor::systemTrayAdded, this, &TrayModel::onSystemTrayAdded); + connect(m_monitor, &TrayMonitor::systemTrayRemoved, this, &TrayModel::onSystemTrayRemoved); + + connect(m_monitor, &TrayMonitor::requestUpdateIcon, this, &TrayModel::requestUpdateIcon); + connect(SETTINGCONFIG, &SettingConfig::valueChanged, this, &TrayModel::onSettingChanged); + + m_fixedTrayNames = SETTINGCONFIG->value(DOCKQUICKTRAYNAME).toStringList(); + m_fixedTrayNames.removeDuplicates(); } void TrayModel::dropSwap(int newPos) @@ -97,6 +112,7 @@ void TrayModel::clearDragDropIndex() m_dragModelIndex = m_dropModelIndex = QModelIndex(); + Q_EMIT requestRefreshEditor(); emit QAbstractItemModel::dataChanged(startIndex, endIndex); emit QAbstractItemModel::dataChanged(endIndex, startIndex); } @@ -106,6 +122,7 @@ void TrayModel::setDragingIndex(const QModelIndex index) m_dragModelIndex = index; m_dropModelIndex = index; + Q_EMIT requestRefreshEditor(); emit QAbstractListModel::dataChanged(index, index); } @@ -120,6 +137,44 @@ void TrayModel::setDragDropIndex(const QModelIndex index) emit QAbstractListModel::dataChanged(index, m_dragModelIndex); } +void TrayModel::setExpandVisible(bool visible, bool openExpand) +{ + // 如果是托盘,不支持展开图标 + if (m_isTrayIcon) + return; + + if (visible) { + // 如果展开图标已经存在,则不添加, + for (const WinInfo &winInfo : m_winInfos) { + if (winInfo.type == TrayIconType::ExpandIcon) + return; + } + // 如果是任务栏图标,则添加托盘展开图标 + beginInsertRows(QModelIndex(), rowCount(), rowCount()); + WinInfo info; + info.type = TrayIconType::ExpandIcon; + info.expand = openExpand; + m_winInfos.insert(0, info); // 展开图标始终显示在第一个 + endInsertRows(); + + Q_EMIT requestRefreshEditor(); + Q_EMIT rowCountChanged(); + } else { + // 如果隐藏,则直接从列表中移除 + bool rowChanged = false; + beginResetModel(); + for (const WinInfo &winInfo : m_winInfos) { + if (winInfo.type == TrayIconType::ExpandIcon) { + m_winInfos.removeOne(winInfo); + rowChanged = true; + } + } + endResetModel(); + if (rowChanged) + Q_EMIT rowCountChanged(); + } +} + void TrayModel::setDragKey(const QString &key) { m_dragKey = key; @@ -165,8 +220,12 @@ QMimeData *TrayModel::mimeData(const QModelIndexList &indexes) const auto info = m_winInfos.at(itemIndex); mime->setData("type", QByteArray::number(static_cast(info.type))); mime->setData("key", info.key.toLatin1()); + mime->setData("itemKey", info.itemKey.toLatin1()); mime->setData("winId", QByteArray::number(info.winId)); mime->setData("servicePath", info.servicePath.toLatin1()); + mime->setData("isTypeWritting", info.isTypeWriting ? "1" : "0"); + mime->setData("expand", info.expand ? "1" : "0"); + mime->setImageData(QVariant::fromValue((qulonglong)(info.pluginInter))); //TODO 支持多个index的数据,待支持 } @@ -192,6 +251,10 @@ QVariant TrayModel::data(const QModelIndex &index, int role) const return info.servicePath; case Role::PluginInterfaceRole: return (qulonglong)(info.pluginInter); + case Role::ExpandRole: + return info.expand; + case Role::ItemKeyRole: + return info.itemKey; case Role::Blank: return indexDragging(index); default: @@ -211,6 +274,8 @@ bool TrayModel::removeRows(int row, int count, const QModelIndex &parent) m_dragInfo = m_winInfos.takeAt(row); endRemoveRows(); + Q_EMIT rowCountChanged(); + return true; } @@ -230,7 +295,7 @@ bool TrayModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, in Qt::ItemFlags TrayModel::flags(const QModelIndex &index) const { const Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index); - m_view->openPersistentEditor(index); + Q_EMIT requestOpenEditor(index); return defaultFlags | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } @@ -246,15 +311,40 @@ bool TrayModel::isIconTray() return m_isTrayIcon; } +bool TrayModel::hasExpand() const +{ + for (const WinInfo &winInfo : m_winInfos) { + if (winInfo.type == TrayIconType::ExpandIcon) + return true; + } + + return false; +} + +bool TrayModel::isEmpty() const +{ + for (const WinInfo &winInfo : m_winInfos) { + if (winInfo.type != TrayIconType::ExpandIcon) + return false; + } + + return true; +} + void TrayModel::clear() { beginResetModel(); m_winInfos.clear(); endResetModel(); + + Q_EMIT rowCountChanged(); } void TrayModel::onXEmbedTrayAdded(quint32 winId) { + if (!xembedCanExport(winId)) + return; + for (const WinInfo &info : m_winInfos) { if (info.winId == winId) return; @@ -264,9 +354,12 @@ void TrayModel::onXEmbedTrayAdded(quint32 winId) WinInfo info; info.type = XEmbed; info.key = "wininfo:" + QString::number(winId); + info.itemKey = xembedItemKey(winId); info.winId = winId; m_winInfos.append(info); endInsertRows(); + + Q_EMIT rowCountChanged(); } void TrayModel::onXEmbedTrayRemoved(quint32 winId) @@ -277,19 +370,21 @@ void TrayModel::onXEmbedTrayRemoved(quint32 winId) beginRemoveRows(QModelIndex(), index, index); m_winInfos.removeOne(info); endRemoveRows(); + + Q_EMIT rowCountChanged(); return; } } } -QString TrayModel::fileNameByServiceName(const QString &serviceName) +QString TrayModel::fileNameByServiceName(const QString &serviceName) const { QStringList serviceInfo = serviceName.split("/"); if (serviceInfo.size() <= 0) return QString(); QDBusInterface dbsInterface("org.freedesktop.DBus", "/org/freedesktop/DBus", - "org.freedesktop.DBus", QDBusConnection::sessionBus(), this); + "org.freedesktop.DBus", QDBusConnection::sessionBus()); QDBusMessage msg = dbsInterface.call("GetConnectionUnixProcessID", serviceInfo[0] ); QList arguments = msg.arguments(); if (arguments.size() == 0) @@ -308,35 +403,81 @@ QString TrayModel::fileNameByServiceName(const QString &serviceName) return QString(); } -bool TrayModel::isTypeWriting(const QString &servicePath) +bool TrayModel::isTypeWriting(const QString &servicePath) const { const QString appFilePath = fileNameByServiceName(servicePath); return (appFilePath.startsWith("/usr/bin/fcitx") || appFilePath.endsWith("chinime-qim")); } -void TrayModel::systemItemAdded(PluginsItemInterface *itemInter) +void TrayModel::saveConfig(int index, const WinInfo &winInfo) { - for (const WinInfo &info : m_winInfos) { - if (info.pluginInter == itemInter) - return; + if (m_fixedTrayNames.contains(winInfo.itemKey)) + return; + + if (index >= 0 && index < m_fixedTrayNames.size()) { + m_fixedTrayNames.insert(index, winInfo.itemKey); + } else { + m_fixedTrayNames << winInfo.itemKey; } + SETTINGCONFIG->setValue(DOCKQUICKTRAYNAME, m_fixedTrayNames); +} - beginInsertRows(QModelIndex(), rowCount(), rowCount()); +bool TrayModel::inTrayConfig(const QString itemKey) const +{ + if (m_isTrayIcon) { + // 如果是托盘区域,显示所有不在配置中的应用 + return !m_fixedTrayNames.contains(itemKey); + } + // 如果是任务栏区域,显示所有在配置中的应用 + return m_fixedTrayNames.contains(itemKey); +} - WinInfo info; - info.type = SystemItem; - info.pluginInter = itemInter; - m_winInfos.append(info); +QString TrayModel::xembedItemKey(quint32 winId) const +{ + return QString("embed:%1").arg(PlatformUtils::getAppNameForWindow(winId)); +} - endInsertRows(); +bool TrayModel::xembedCanExport(quint32 winId) const +{ + return inTrayConfig(xembedItemKey(winId)); +} + +QString TrayModel::sniItemKey(const QString &servicePath) const +{ + if (isTypeWriting(servicePath)) + return "fcitx"; + + QString fileName = fileNameByServiceName(servicePath); + return QString("sni:%1").arg(fileName.mid(fileName.lastIndexOf("/") + 1)); +} + +bool TrayModel::sniCanExport(const QString &servicePath) const +{ + return inTrayConfig(sniItemKey(servicePath)); +} + +bool TrayModel::indicatorCanExport(const QString &indicatorName) const +{ + return inTrayConfig(IndicatorTrayItem::toIndicatorKey(indicatorName)); +} + +QString TrayModel::systemItemKey(const QString &pluginName) const +{ + return QString("systemItem:%1").arg(pluginName); +} + +bool TrayModel::systemItemCanExport(const QString &pluginName) const +{ + return inTrayConfig(systemItemKey(pluginName)); } void TrayModel::onSniTrayAdded(const QString &servicePath) { - bool typeWriting = isTypeWriting(servicePath); - if ((m_hasInputMethod && !typeWriting) || (!m_hasInputMethod && typeWriting)) + if (!sniCanExport(servicePath)) return; + bool typeWriting = isTypeWriting(servicePath); + int citxIndex = -1; for (int i = 0; i < m_winInfos.size(); i++) { WinInfo info = m_winInfos[i]; @@ -351,6 +492,7 @@ void TrayModel::onSniTrayAdded(const QString &servicePath) WinInfo info; info.type = Sni; info.key = "sni:" + servicePath; + info.itemKey = sniItemKey(servicePath); info.servicePath = servicePath; info.isTypeWriting = typeWriting; // 是否为输入法 if (typeWriting) { @@ -366,6 +508,8 @@ void TrayModel::onSniTrayAdded(const QString &servicePath) } } else { m_winInfos.append(info); + + Q_EMIT rowCountChanged(); } endInsertRows(); } @@ -392,6 +536,8 @@ void TrayModel::onSniTrayRemoved(const QString &servicePath) beginRemoveRows(QModelIndex(), index, index); m_winInfos.removeOne(info); endRemoveRows(); + + Q_EMIT rowCountChanged(); } break; } @@ -423,6 +569,9 @@ void TrayModel::onIndicatorFounded(const QString &indicatorName) void TrayModel::onIndicatorAdded(const QString &indicatorName) { + if (!indicatorCanExport(indicatorName)) + return; + const QString &itemKey = IndicatorTrayItem::toIndicatorKey(indicatorName); for (const WinInfo &info : m_winInfos) { if (info.key == itemKey) @@ -433,8 +582,11 @@ void TrayModel::onIndicatorAdded(const QString &indicatorName) WinInfo info; info.type = Incicator; info.key = itemKey; + info.itemKey = IndicatorTrayItem::toIndicatorKey(indicatorName); m_winInfos.append(info); endInsertRows(); + + Q_EMIT rowCountChanged(); } void TrayModel::onIndicatorRemoved(const QString &indicatorName) @@ -443,19 +595,84 @@ void TrayModel::onIndicatorRemoved(const QString &indicatorName) removeRow(itemKey); } -void TrayModel::onSystemItemRemoved(PluginsItemInterface *itemInter) +void TrayModel::onSystemTrayAdded(PluginsItemInterface *itemInter) { + if (!systemItemCanExport(itemInter->pluginName())) + return; + + for (const WinInfo &info : m_winInfos) { + if (info.pluginInter == itemInter) + return; + } + beginInsertRows(QModelIndex(), rowCount(), rowCount()); + WinInfo info; + info.type = SystemItem; + info.pluginInter = itemInter; + info.itemKey = systemItemKey(itemInter->pluginName()); + m_winInfos.append(info); + + endInsertRows(); + + Q_EMIT rowCountChanged(); +} + +void TrayModel::onSystemTrayRemoved(PluginsItemInterface *itemInter) +{ for (const WinInfo &info : m_winInfos) { if (info.pluginInter != itemInter) continue; + beginInsertRows(QModelIndex(), rowCount(), rowCount()); m_winInfos.removeOne(info); + endInsertRows(); + + Q_EMIT rowCountChanged(); break; } +} - endInsertRows(); +void TrayModel::onSettingChanged(const QString &key, const QVariant &value) +{ + if (key != DOCKQUICKTRAYNAME) + return; + + // 先将其转换为任务栏上的图标列表 + m_fixedTrayNames = value.toStringList(); + // 依次获取所有的图盘图标,判断当前图标是否可以保持在当前的view中, + // 如果可以保留,则添加到view上显示,否则,移除显示 + QList trayWinIds = m_monitor->trayWinIds(); + for (quint32 trayId : trayWinIds) { + if (xembedCanExport(trayId)) + onXEmbedTrayAdded(trayId); + else + onXEmbedTrayRemoved(trayId); + } + + QStringList sniServices = m_monitor->sniServices(); + for (const QString &sniService : sniServices) { + if (sniCanExport(sniService)) + onSniTrayAdded(sniService); + else + onSniTrayRemoved(sniService); + } + + QStringList indicators = m_monitor->indicatorNames(); + for (const QString &indicatorName : indicators) { + if (indicatorCanExport(indicatorName)) + onIndicatorAdded(indicatorName); + else + onIndicatorRemoved(indicatorName); + } + + QList pluginItems = m_monitor->systemTrays(); + for (PluginsItemInterface *plugin : pluginItems) { + if (systemItemCanExport(plugin->pluginName())) + onSystemTrayAdded(plugin); + else + onSystemTrayRemoved(plugin); + } } void TrayModel::removeRow(const QString &itemKey) @@ -466,6 +683,8 @@ void TrayModel::removeRow(const QString &itemKey) beginRemoveRows(QModelIndex(), index, index); m_winInfos.removeOne(info); endRemoveRows(); + + Q_EMIT rowCountChanged(); break; } } @@ -481,6 +700,9 @@ void TrayModel::addRow(WinInfo info) beginInsertRows(QModelIndex(), rowCount(), rowCount()); m_winInfos.append(info); endInsertRows(); + + Q_EMIT requestRefreshEditor(); + Q_EMIT rowCountChanged(); } void TrayModel::insertRow(int index, WinInfo info) @@ -497,6 +719,9 @@ void TrayModel::insertRow(int index, WinInfo info) beginInsertRows(QModelIndex(), index, index); m_winInfos.insert(index, info); endInsertRows(); + + Q_EMIT requestRefreshEditor(); + Q_EMIT rowCountChanged(); } bool TrayModel::exist(const QString &itemKey) diff --git a/frame/window/tray/tray_model.h b/frame/window/tray/tray_model.h index df41c8bb4..0e5b9f95e 100644 --- a/frame/window/tray/tray_model.h +++ b/frame/window/tray/tray_model.h @@ -42,16 +42,20 @@ enum TrayIconType { struct WinInfo { TrayIconType type; QString key; + QString itemKey; quint32 winId; QString servicePath; bool isTypeWriting; + bool expand; PluginsItemInterface *pluginInter; WinInfo() : type(UnKnow) , key(QString()) + , itemKey(QString()) , winId(0) , servicePath(QString()) , isTypeWriting(false) + , expand(false) , pluginInter(nullptr) {} bool operator==(const WinInfo &other) { @@ -59,6 +63,7 @@ struct WinInfo { && this->key == other.key && this->winId == other.winId && this->servicePath == other.servicePath + && this->itemKey == other.itemKey && this->isTypeWriting == other.isTypeWriting && this->pluginInter == other.pluginInter; } @@ -75,12 +80,15 @@ public: WinIdRole, ServiceRole, PluginInterfaceRole, + ExpandRole, + ItemKeyRole, Blank }; typedef QList WinInfos; - TrayModel(QListView *view, bool isIconTray, bool hasInputMethod, QObject *parent = Q_NULLPTR); + static TrayModel *getDockModel(); + static TrayModel *getIconModel(); void dropSwap(int newPos); void dropInsert(int newPos); @@ -88,6 +96,7 @@ public: void clearDragDropIndex(); void setDragingIndex(const QModelIndex index); void setDragDropIndex(const QModelIndex index); + void setExpandVisible(bool visible, bool openExpand = false); void setDragKey(const QString &key); @@ -97,18 +106,27 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; bool isIconTray(); + bool hasExpand() const; + bool isEmpty() const; void clear(); + void saveConfig(int index, const WinInfo &winInfo); Q_SIGNALS: void requestUpdateIcon(quint32); void requestUpdateWidget(const QList &); + void requestOpenEditor(const QModelIndex &index, bool isOpen = true) const; + void rowCountChanged(); + void requestRefreshEditor(); public Q_SLOTS: void removeRow(const QString &itemKey); void addRow(WinInfo info); void insertRow(int index, WinInfo info); +protected: + TrayModel(bool isIconTray, QObject *parent = Q_NULLPTR); + private Q_SLOTS: void onXEmbedTrayAdded(quint32 winId); void onXEmbedTrayRemoved(quint32 winId); @@ -119,14 +137,24 @@ private Q_SLOTS: void onIndicatorAdded(const QString &indicatorName); void onIndicatorRemoved(const QString &indicatorName); - void onSystemItemRemoved(PluginsItemInterface *itemInter); + void onSystemTrayAdded(PluginsItemInterface *itemInter); + void onSystemTrayRemoved(PluginsItemInterface *itemInter); + + void onSettingChanged(const QString &key, const QVariant &value); private: bool exist(const QString &itemKey); - QString fileNameByServiceName(const QString &serviceName); - bool isTypeWriting(const QString &servicePath); + QString fileNameByServiceName(const QString &serviceName) const; + bool isTypeWriting(const QString &servicePath) const; - void systemItemAdded(PluginsItemInterface *itemInter); + bool inTrayConfig(const QString itemKey) const; + QString xembedItemKey(quint32 winId) const; + bool xembedCanExport(quint32 winId) const; + QString sniItemKey(const QString &servicePath) const; + bool sniCanExport(const QString &servicePath) const; + bool indicatorCanExport(const QString &indicatorName) const; + QString systemItemKey(const QString &pluginName) const; + bool systemItemCanExport(const QString &pluginName) const; protected: QMimeData *mimeData(const QModelIndexList &indexes) const Q_DECL_OVERRIDE; @@ -142,14 +170,13 @@ private: QModelIndex m_dragModelIndex; QModelIndex m_dropModelIndex; WinInfo m_dragInfo; - QListView *m_view; TrayMonitor *m_monitor; QString m_dragKey; QMap m_indicatorMap; + QStringList m_fixedTrayNames; bool m_isTrayIcon; - bool m_hasInputMethod; }; Q_DECLARE_METATYPE(TrayIconType); diff --git a/frame/window/tray/tray_monitor.cpp b/frame/window/tray/tray_monitor.cpp index bb92f9dbc..a925052c8 100644 --- a/frame/window/tray/tray_monitor.cpp +++ b/frame/window/tray/tray_monitor.cpp @@ -19,6 +19,8 @@ * along with this program. If not, see . */ #include "tray_monitor.h" +#include "quicksettingcontroller.h" +#include "pluginsiteminterface.h" TrayMonitor::TrayMonitor(QObject *parent) : QObject(parent) @@ -36,10 +38,56 @@ TrayMonitor::TrayMonitor(QObject *parent) connect(m_sniWatcher, &StatusNotifierWatcher::StatusNotifierItemUnregistered, this, &TrayMonitor::onSniItemsChanged, Qt::QueuedConnection); QMetaObject::invokeMethod(this, "onSniItemsChanged", Qt::QueuedConnection); + //-------------------------------System Tray------------------------------------------// + QuickSettingController *quickController = QuickSettingController::instance(); + connect(quickController, &QuickSettingController::pluginInserted, this, [ = ](PluginsItemInterface *itemInter, const QuickSettingController::PluginAttribute &pluginAttr) { + if (pluginAttr != QuickSettingController::PluginAttribute::Tray) + return; + + m_systemTrays << itemInter; + Q_EMIT systemTrayAdded(itemInter); + }); + + connect(quickController, &QuickSettingController::pluginRemoved, this, [ = ](PluginsItemInterface *itemInter) { + if (!m_systemTrays.contains(itemInter)) + return; + + m_systemTrays.removeOne(itemInter); + Q_EMIT systemTrayRemoved(itemInter); + }); + + QMetaObject::invokeMethod(this, [ = ] { + QList trayPlugins = quickController->pluginItems(QuickSettingController::PluginAttribute::Tray); + for (PluginsItemInterface *plugin : trayPlugins) { + m_systemTrays << plugin; + Q_EMIT systemTrayAdded(plugin); + } + }, Qt::QueuedConnection); + //-------------------------------Tray Indicator---------------------------------------------// QMetaObject::invokeMethod(this, "startLoadIndicators", Qt::QueuedConnection); } +QList TrayMonitor::trayWinIds() const +{ + return m_trayWids; +} + +QStringList TrayMonitor::sniServices() const +{ + return m_sniServices; +} + +QStringList TrayMonitor::indicatorNames() const +{ + return m_indicatorNames; +} + +QList TrayMonitor::systemTrays() const +{ + return m_systemTrays; +} + void TrayMonitor::onTrayIconsChanged() { QList wids = m_trayInter->trayIcons(); @@ -93,6 +141,7 @@ void TrayMonitor::startLoadIndicators() for (const QFileInfo &fileInfo : indicatorConfDir.entryInfoList({"*.json"}, QDir::Files | QDir::NoDotAndDotDot)) { const QString &indicatorName = fileInfo.baseName(); + m_indicatorNames << indicatorName; Q_EMIT indicatorFounded(indicatorName); } } diff --git a/frame/window/tray/tray_monitor.h b/frame/window/tray/tray_monitor.h index de2ee566d..9318a8a22 100644 --- a/frame/window/tray/tray_monitor.h +++ b/frame/window/tray/tray_monitor.h @@ -26,7 +26,10 @@ #include "dbustraymanager.h" #include "statusnotifierwatcher_interface.h" +class PluginsItemInterface; + using namespace org::kde; + class TrayMonitor : public QObject { Q_OBJECT @@ -34,6 +37,11 @@ class TrayMonitor : public QObject public: explicit TrayMonitor(QObject *parent = nullptr); + QList trayWinIds() const; + QStringList sniServices() const; + QStringList indicatorNames() const; + QList systemTrays() const; + Q_SIGNALS: void requestUpdateIcon(quint32); void xEmbedTrayAdded(quint32); @@ -42,6 +50,9 @@ Q_SIGNALS: void sniTrayAdded(const QString &); void sniTrayRemoved(const QString &); + void systemTrayAdded(PluginsItemInterface *); + void systemTrayRemoved(PluginsItemInterface *); + void indicatorFounded(const QString &); public Q_SLOTS: @@ -56,6 +67,8 @@ private: QList m_trayWids; QStringList m_sniServices; + QStringList m_indicatorNames; + QList m_systemTrays; }; #endif // TRAYMONITOR_H diff --git a/frame/window/tray/widgets/expandiconwidget.cpp b/frame/window/tray/widgets/expandiconwidget.cpp index 2c5b89fb8..9ffee3f9f 100644 --- a/frame/window/tray/widgets/expandiconwidget.cpp +++ b/frame/window/tray/widgets/expandiconwidget.cpp @@ -40,18 +40,43 @@ ExpandIconWidget::ExpandIconWidget(QWidget *parent, Qt::WindowFlags f) , m_regionInter(new DRegionMonitor(this)) , m_position(Dock::Position::Bottom) { + connect(m_regionInter, &DRegionMonitor::buttonPress, this, [ = ](const QPoint &mousePos, const int flag) { + TrayGridWidget *gridView = popupTrayView(); + // 如果当前是隐藏,那么在点击任何地方都隐藏 + if (!isVisible()) { + gridView->hide(); + return; + } + + if ((flag != DRegionMonitor::WatchedFlags::Button_Left) && (flag != DRegionMonitor::WatchedFlags::Button_Right)) + return; + + QPoint ptPos = parentWidget()->mapToGlobal(this->pos()); + const QRect rect = QRect(ptPos, size()); + if (rect.contains(mousePos)) + return; + + const QRect rctView(gridView->pos(), gridView->size()); + if (rctView.contains(mousePos)) + return; + + gridView->hide(); + }); } ExpandIconWidget::~ExpandIconWidget() { + TrayGridWidget *gridView = popupTrayView(); + gridView->setOwnerWidget(nullptr); + setTrayPanelVisible(false); } -void ExpandIconWidget::setPositonValue(Dock::Position position) +void ExpandIconWidget::setPositon(Dock::Position position) { - if (m_position == position) - return; + if (m_position != position) + m_position = position; - m_position = position; + TrayGridWidget::setPosition(position); } void ExpandIconWidget::sendClick(uint8_t mouseButton, int x, int y) @@ -59,6 +84,10 @@ void ExpandIconWidget::sendClick(uint8_t mouseButton, int x, int y) Q_UNUSED(x); Q_UNUSED(y); + // 如果当前图标不可见,则不让展开托盘列表 + if (popupTrayView()->trayView()->model()->rowCount() == 0) + return; + if (mouseButton != XCB_BUTTON_INDEX_1) return; @@ -68,9 +97,9 @@ void ExpandIconWidget::sendClick(uint8_t mouseButton, int x, int y) void ExpandIconWidget::setTrayPanelVisible(bool visible) { - QWidget *gridParentView = popupTrayView(); + TrayGridWidget *gridParentView = popupTrayView(); if (visible) { - resetPosition(); + gridParentView->resetPosition(); gridParentView->show(); m_regionInter->registerRegion(); } else { @@ -86,7 +115,8 @@ QPixmap ExpandIconWidget::icon() void ExpandIconWidget::paintEvent(QPaintEvent *event) { - if (popupTrayView()->trayView()->model()->rowCount() == 0) + TrayGridWidget *gridView = popupTrayView(); + if (gridView->trayView()->model()->rowCount() == 0) return BaseTrayWidget::paintEvent(event); QPainter painter(this); @@ -96,6 +126,8 @@ void ExpandIconWidget::paintEvent(QPaintEvent *event) ICON_SIZE, ICON_SIZE); painter.drawPixmap(rectOfPixmap, pixmap); + + gridView->setOwnerWidget(this); } const QString ExpandIconWidget::dropIconFile() const @@ -136,7 +168,7 @@ TrayGridWidget *ExpandIconWidget::popupTrayView() gridParentView = new TrayGridWidget(nullptr); TrayGridView *trayView = new TrayGridView(gridParentView); TrayDelegate *trayDelegate = new TrayDelegate(trayView, trayView); - TrayModel *trayModel = new TrayModel(trayView, true, false); + TrayModel *trayModel = TrayModel::getIconModel(); gridParentView->setTrayGridView(trayView); gridParentView->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool); @@ -152,102 +184,97 @@ TrayGridWidget *ExpandIconWidget::popupTrayView() auto rowCountChanged = [ = ] { int count = trayModel->rowCount(); - trayView->setFixedSize(trayView->suitableSize()); - gridParentView->setFixedSize(trayView->size() + QSize(ITEM_SPACING * 2, ITEM_SPACING * 2)); if (count > 0) - resetPosition(); + gridParentView->resetPosition(); else if (gridParentView->isVisible()) gridParentView->hide(); - - Q_EMIT trayVisbleChanged(count > 0); }; - connect(trayView, &TrayGridView::rowCountChanged, this, rowCountChanged); + connect(trayModel, &TrayModel::rowCountChanged, gridParentView, rowCountChanged); - connect(trayDelegate, &TrayDelegate::removeRow, this, [ = ](const QModelIndex &index) { + connect(trayDelegate, &TrayDelegate::removeRow, trayView, [ = ](const QModelIndex &index) { trayView->model()->removeRow(index.row(),index.parent()); }); connect(trayView, &TrayGridView::requestRemove, trayModel, &TrayModel::removeRow); - connect(m_regionInter, &DRegionMonitor::buttonPress, this, [ = ](const QPoint &mousePos, const int flag) { - // 如果当前是隐藏,那么在点击任何地方都隐藏 - if (!isVisible()) { - gridParentView->hide(); - return; - } - - if ((flag != DRegionMonitor::WatchedFlags::Button_Left) && (flag != DRegionMonitor::WatchedFlags::Button_Right)) - return; - - QPoint ptPos = parentWidget()->mapToGlobal(this->pos()); - const QRect rect = QRect(ptPos, size()); - if (rect.contains(mousePos)) - return; - - const QRect rctView(gridParentView->pos(), gridParentView->size()); - if (rctView.contains(mousePos)) - return; - - gridParentView->hide(); + connect(trayModel, &TrayModel::requestOpenEditor, trayView, [ trayView ](const QModelIndex &index) { + trayView->openPersistentEditor(index); }); - QMetaObject::invokeMethod(this, rowCountChanged, Qt::QueuedConnection); + QMetaObject::invokeMethod(gridParentView, rowCountChanged, Qt::QueuedConnection); return gridParentView; } -void ExpandIconWidget::resetPosition() -{ - if (!parentWidget()) - return; - - QWidget *gridParentView = popupTrayView(); - QPoint ptPos = parentWidget()->mapToGlobal(this->pos()); - switch (m_position) { - case Dock::Position::Bottom: { - ptPos.setY(ptPos.y() - gridParentView->height()); - ptPos.setX(ptPos.x() - gridParentView->width()); - break; - } - case Dock::Position::Top: { - ptPos.setY(ptPos.y() + gridParentView->height()); - ptPos.setX(ptPos.x() - gridParentView->width()); - break; - } - case Dock::Position::Left: { - ptPos.setX(ptPos.x() + gridParentView->width() / 2); - break; - } - case Dock::Position::Right: { - ptPos.setX(ptPos.x() - gridParentView->width() / 2); - break; - } - } - gridParentView->move(ptPos); -} - /** * @brief 圆角窗体的绘制 * @param parent */ +Dock::Position TrayGridWidget::m_position = Dock::Position::Bottom; + TrayGridWidget::TrayGridWidget(QWidget *parent) : QWidget (parent) , m_dockInter(new DockInter(dockServiceName(), dockServicePath(), QDBusConnection::sessionBus(), this)) , m_trayGridView(nullptr) + , m_ownerWidget(nullptr) { setAttribute(Qt::WA_TranslucentBackground); } +void TrayGridWidget::setPosition(const Dock::Position &position) +{ + m_position = position; +} + void TrayGridWidget::setTrayGridView(TrayGridView *trayView) { m_trayGridView = trayView; } +void TrayGridWidget::setOwnerWidget(QWidget *widget) +{ + // 设置所属的Widget,目的是为了计算当前窗体的具体位置 + m_ownerWidget = widget; +} + TrayGridView *TrayGridWidget::trayView() const { return m_trayGridView; } +void TrayGridWidget::resetPosition() +{ + // 如果没有设置所属窗体,则无法计算位置 + if (!m_ownerWidget || !m_ownerWidget->parentWidget()) + return; + + QWidget *topWidget = m_ownerWidget->topLevelWidget(); + QPoint ptPos = m_ownerWidget->parentWidget()->mapToGlobal(m_ownerWidget->pos()); + switch (m_position) { + case Dock::Position::Bottom: { + ptPos.setX(ptPos.x() - width()); + ptPos.setY(topWidget->y() - height()); + break; + } + case Dock::Position::Top: { + ptPos.setY(topWidget->y() + topWidget->height()); + ptPos.setX(ptPos.x() - width()); + break; + } + case Dock::Position::Left: { + ptPos.setX(topWidget->x() + topWidget->width()); + break; + } + case Dock::Position::Right: { + ptPos.setX(topWidget->x() - width()); + break; + } + } + m_trayGridView->setFixedSize(m_trayGridView->suitableSize()); + setFixedSize(m_trayGridView->size() + QSize(ITEM_SPACING * 2, ITEM_SPACING * 2)); + move(ptPos); +} + void TrayGridWidget::paintEvent(QPaintEvent *event) { Q_UNUSED(event); diff --git a/frame/window/tray/widgets/expandiconwidget.h b/frame/window/tray/widgets/expandiconwidget.h index 57747f01f..8a178492b 100644 --- a/frame/window/tray/widgets/expandiconwidget.h +++ b/frame/window/tray/widgets/expandiconwidget.h @@ -39,24 +39,19 @@ class ExpandIconWidget : public BaseTrayWidget public: explicit ExpandIconWidget(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()); ~ExpandIconWidget() override; - void setPositonValue(Dock::Position position); + void setPositon(Dock::Position position); void sendClick(uint8_t mouseButton, int x, int y) override; void setTrayPanelVisible(bool visible); QString itemKeyForConfig() override { return "Expand"; } void updateIcon() override {} QPixmap icon() override; - TrayGridWidget *popupTrayView(); - -Q_SIGNALS: - void trayVisbleChanged(bool); + static TrayGridWidget *popupTrayView(); protected: void paintEvent(QPaintEvent *event) override; const QString dropIconFile() const; - void resetPosition(); - private: Dtk::Gui::DRegionMonitor *m_regionInter; Dock::Position m_position; @@ -70,8 +65,11 @@ class TrayGridWidget : public QWidget public: explicit TrayGridWidget(QWidget *parent); + static void setPosition(const Dock::Position &position); void setTrayGridView(TrayGridView *trayView); + void setOwnerWidget(QWidget *widget); TrayGridView *trayView() const; + void resetPosition(); protected: void paintEvent(QPaintEvent *event) override; @@ -82,6 +80,8 @@ private: private: DockInter *m_dockInter; TrayGridView *m_trayGridView; + static Dock::Position m_position; + QWidget *m_ownerWidget; }; #endif // EXPANDICONWIDGET_H diff --git a/frame/window/tray/widgets/xembedtrayitemwidget.cpp b/frame/window/tray/widgets/xembedtrayitemwidget.cpp index eadb9745f..3a8c7ad74 100644 --- a/frame/window/tray/widgets/xembedtrayitemwidget.cpp +++ b/frame/window/tray/widgets/xembedtrayitemwidget.cpp @@ -21,6 +21,7 @@ #include "constants.h" #include "xembedtrayitemwidget.h" +#include "platformutils.h" //#include "utils.h" #include @@ -85,7 +86,7 @@ void sni_cleanup_xcb_image(void *data) XEmbedTrayItemWidget::XEmbedTrayItemWidget(quint32 winId, xcb_connection_t *cnn, Display *disp, QWidget *parent) : BaseTrayWidget(parent) , m_windowId(winId) - , m_appName(getAppNameForWindow(winId)) + , m_appName(PlatformUtils::getAppNameForWindow(winId)) , m_valid(true) , m_xcbCnn(cnn) , m_display(disp) @@ -116,7 +117,7 @@ XEmbedTrayItemWidget::~XEmbedTrayItemWidget() QString XEmbedTrayItemWidget::itemKeyForConfig() { - return QString("window:%1").arg(getAppNameForWindow(m_windowId)); + return QString("window:%1").arg(PlatformUtils::getAppNameForWindow(m_windowId)); } void XEmbedTrayItemWidget::showEvent(QShowEvent *e) @@ -375,45 +376,6 @@ void XEmbedTrayItemWidget::sendClick(uint8_t mouseButton, int x, int y) QTimer::singleShot(100, this, [=] { setX11PassMouseEvent(true); }); } -// NOTE: WM_NAME may can not obtain successfully -QString XEmbedTrayItemWidget::getWindowProperty(quint32 winId, QString propName) -{ - const auto display = IS_WAYLAND_DISPLAY ? XOpenDisplay(nullptr) : QX11Info::display(); - if (!display) { - qWarning() << "QX11Info::display() is " << display; - return QString(); - } - - Atom atom_prop = XInternAtom(display, propName.toLocal8Bit(), true); - if (!atom_prop) { - qDebug() << "Error: get window property failed, invalid property atom"; - return QString(); - } - - Atom actual_type_return; - int actual_format_return; - unsigned long nitems_return; - unsigned long bytes_after_return; - unsigned char *prop_return; - - int r = XGetWindowProperty(display, winId, atom_prop, 0, 100, false, AnyPropertyType, - &actual_type_return, &actual_format_return, &nitems_return, - &bytes_after_return, &prop_return); - - Q_UNUSED(r); - -// qDebug() << (r == Success) -// << actual_type_return -// << actual_format_return -// << nitems_return -// << bytes_after_return -// << QString::fromLocal8Bit((char*)prop_return); - if (IS_WAYLAND_DISPLAY) - XCloseDisplay(display); - - return QString::fromLocal8Bit((char*)prop_return); -} - QString XEmbedTrayItemWidget::toXEmbedKey(quint32 winId) { return QString("window:%1").arg(winId); @@ -477,29 +439,6 @@ void XEmbedTrayItemWidget::refershIconImage() } } -QString XEmbedTrayItemWidget::getAppNameForWindow(quint32 winId) -{ - QString appName; - do { - // is normal application - appName = getWindowProperty(winId, NORMAL_WINDOW_PROP_NAME); - if (!appName.isEmpty() && appName != IS_WINE_WINDOW_BY_WM_CLASS) { - break; - } - - // is wine application - appName = getWindowProperty(winId, WINE_WINDOW_PROP_NAME).split("/").last(); - if (!appName.isEmpty()) { - break; - } - - // fallback to window id - appName = QString::number(winId); - } while (false); - - return appName; -} - //int XEmbedTrayWidget::getTrayWidgetKeySuffix(const QString &appName, quint32 winId) //{ // int suffix = AppWinidSuffixMap.value(appName).value(winId, 0); diff --git a/frame/window/tray/widgets/xembedtrayitemwidget.h b/frame/window/tray/widgets/xembedtrayitemwidget.h index cf03ab10a..26c301e9e 100644 --- a/frame/window/tray/widgets/xembedtrayitemwidget.h +++ b/frame/window/tray/widgets/xembedtrayitemwidget.h @@ -43,7 +43,6 @@ public: void updateIcon() override; void sendClick(uint8_t mouseButton, int x, int y) override; - static QString getWindowProperty(quint32 winId, QString propName); static QString toXEmbedKey(quint32 winId); static uint getWindowPID(quint32 winId); static bool isXEmbedKey(const QString &itemKey); @@ -60,8 +59,6 @@ private: void sendHoverEvent(); void refershIconImage(); - static QString getAppNameForWindow(quint32 winId); - private slots: void setX11PassMouseEvent(const bool pass); void setWindowOnTop(const bool top); diff --git a/frame/window/traymainwindow.cpp b/frame/window/traymainwindow.cpp index 6f8f9d58e..d9356e12b 100644 --- a/frame/window/traymainwindow.cpp +++ b/frame/window/traymainwindow.cpp @@ -63,6 +63,7 @@ void TrayMainWindow::setDisplayMode(const Dock::DisplayMode &displayMode) // 只有在时尚模式下才显示 setVisible(displayMode == Dock::DisplayMode::Fashion); MainWindowBase::setDisplayMode(displayMode); + m_trayManager->setDisplayMode(displayMode); } MainWindowBase::DockWindowType TrayMainWindow::windowType() const diff --git a/frame/window/traymanagerwindow.cpp b/frame/window/traymanagerwindow.cpp index 0e4a9871c..a0b493246 100644 --- a/frame/window/traymanagerwindow.cpp +++ b/frame/window/traymanagerwindow.cpp @@ -59,9 +59,10 @@ TrayManagerWindow::TrayManagerWindow(QWidget *parent) , m_appPluginLayout(new QBoxLayout(QBoxLayout::Direction::LeftToRight, this)) , m_mainLayout(new QBoxLayout(QBoxLayout::Direction::LeftToRight, this)) , m_trayView(new TrayGridView(this)) - , m_model(new TrayModel(m_trayView, false, true)) + , m_model(TrayModel::getDockModel()) , m_delegate(new TrayDelegate(m_trayView, m_trayView)) , m_position(Dock::Position::Bottom) + , m_displayMode(Dock::DisplayMode::Fashion) , m_splitLine(new QLabel(m_appPluginDatetimeWidget)) , m_dockInter(new DockInter(dockServiceName(), dockServicePath(), QDBusConnection::sessionBus(), this)) , m_singleShow(false) @@ -120,20 +121,28 @@ void TrayManagerWindow::setPositon(Dock::Position position) else m_trayView->setOrientation(QListView::Flow::TopToBottom, false); - QModelIndex index = m_model->index(0, 0); - m_trayView->closePersistentEditor(index); TrayDelegate *delegate = static_cast(m_trayView->itemDelegate()); delegate->setPositon(position); - m_trayView->openPersistentEditor(index); m_trayView->setPosition(position); m_quickIconWidget->setPositon(position); m_dateTimeWidget->setPositon(position); m_systemPluginWidget->setPositon(position); + if (m_model->hasExpand()) { + // 切换位置的时候,需要先关闭编辑器,然后在model函数的flag方法中打开 + m_trayView->closePersistentEditor(m_model->index(0, 0)); + } updateLayout(); } +void TrayManagerWindow::setDisplayMode(Dock::DisplayMode displayMode) +{ + m_displayMode = displayMode; + // 从时尚模式切换到高效模式的时候,需要重新布局 + onTrayCountChanged(); +} + int TrayManagerWindow::appDatetimeSize(const Dock::Position &position) const { if (position == Dock::Position::Top || position == Dock::Position::Bottom) { @@ -208,6 +217,24 @@ QPainterPath TrayManagerWindow::roundedPaths() return path; } +void TrayManagerWindow::onTrayCountChanged() +{ + resetChildWidgetSize(); + Q_EMIT requestUpdate(); +} + +void TrayManagerWindow::onRequestUpdateWidget(const QList &idxs) +{ + for (int i = 0; i < idxs.size(); i++) { + int idx = idxs[i]; + if (idx < m_model->rowCount()) { + QModelIndex index = m_model->index(idx); + m_trayView->closePersistentEditor(index); + m_trayView->openPersistentEditor(index); + } + } +} + void TrayManagerWindow::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); @@ -230,11 +257,6 @@ void TrayManagerWindow::initUi() m_splitLine->setAutoFillBackground(true); m_splitLine->setPalette(pal); - WinInfo info; - info.type = TrayIconType::ExpandIcon; - m_model->addRow(info); - m_trayView->openPersistentEditor(m_model->index(0, 0)); - // 左侧的区域,包括应用托盘插件和下方的日期时间区域 m_appPluginLayout->setContentsMargins(0, 0, 0, 0); m_appPluginLayout->setSpacing(0); @@ -253,18 +275,9 @@ void TrayManagerWindow::initUi() void TrayManagerWindow::initConnection() { connect(m_trayView, &TrayGridView::requestRemove, m_model, &TrayModel::removeRow); - connect(m_trayView, &TrayGridView::rowCountChanged, this, [ this ] { - if (m_quickIconWidget->x() == 0) { - // 在加载界面的时候,会出现快捷设置区域的图标和左侧的托盘图标挤在一起(具体原因未知),此时需要延时50毫秒重新刷新界面来保证界面布局正常(临时解决方案) - QTimer::singleShot(50, this, [ this ] { - resetChildWidgetSize(); - Q_EMIT requestUpdate(); - }); - } else { - resetChildWidgetSize(); - Q_EMIT requestUpdate(); - } - }); + connect(m_model, &TrayModel::rowCountChanged, this, &TrayManagerWindow::onTrayCountChanged); + connect(m_model, &TrayModel::rowCountChanged, m_trayView, &TrayGridView::onUpdateEditorView); + connect(m_model, &TrayModel::requestRefreshEditor, m_trayView, &TrayGridView::onUpdateEditorView); connect(m_quickIconWidget, &QuickPluginWindow::itemCountChanged, this, [ this ] { // 当插件数量发生变化的时候,需要调整尺寸 m_quickIconWidget->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); @@ -287,28 +300,13 @@ void TrayManagerWindow::initConnection() Q_EMIT requestUpdate(); }); - connect(m_delegate, &TrayDelegate::visibleChanged, this, [ this ](const QModelIndex &index, bool visible) { - m_trayView->setRowHidden(index.row(), !visible); - resetChildWidgetSize(); - Q_EMIT requestUpdate(); - }); - connect(m_trayView, &TrayGridView::dragLeaved, m_delegate, [ this ]{ Q_EMIT m_delegate->requestDrag(true); }); connect(m_trayView, &TrayGridView::dragEntered, m_delegate, [ this ]{ Q_EMIT m_delegate->requestDrag(false); }); - connect(m_model, &TrayModel::requestUpdateWidget, this, [ this ](const QList &idxs) { - for (int i = 0; i < idxs.size(); i++) { - int idx = idxs[i]; - if (idx < m_model->rowCount()) { - QModelIndex index = m_model->index(idx); - m_trayView->closePersistentEditor(index); - m_trayView->openPersistentEditor(index); - } - } - }); + connect(m_model, &TrayModel::requestUpdateWidget, this, &TrayManagerWindow::onRequestUpdateWidget); connect(m_dateTimeWidget, &DateTimeDisplayer::requestUpdate, this, &TrayManagerWindow::requestUpdate); m_trayView->installEventFilter(this); @@ -475,7 +473,7 @@ void TrayManagerWindow::dropEvent(QDropEvent *e) if (!e || !e->mimeData() || e->source() == this) return; - if (qobject_cast(e->source())) { + if (qobject_cast(e->source())) { const QuickPluginMimeData *mimeData = qobject_cast(e->mimeData()); if (!mimeData) return; diff --git a/frame/window/traymanagerwindow.h b/frame/window/traymanagerwindow.h index 2e3580849..4068e9a45 100644 --- a/frame/window/traymanagerwindow.h +++ b/frame/window/traymanagerwindow.h @@ -57,6 +57,7 @@ public: void updateBorderRadius(int borderRadius); void updateLayout(); void setPositon(Dock::Position position); + void setDisplayMode(Dock::DisplayMode displayMode); QSize suitableSize() const; QSize suitableSize(const Dock::Position &position) const; @@ -83,6 +84,10 @@ private: int appDatetimeSize(const Dock::Position &position) const; QPainterPath roundedPaths(); +private Q_SLOTS: + void onTrayCountChanged(); + void onRequestUpdateWidget(const QList &idxs); + private: QWidget *m_appPluginDatetimeWidget; SystemPluginWindow *m_systemPluginWidget; @@ -95,6 +100,7 @@ private: TrayModel *m_model; TrayDelegate *m_delegate; Dock::Position m_position; + Dock::DisplayMode m_displayMode; QLabel *m_splitLine; DockInter *m_dockInter; bool m_singleShow; // 用于记录当前日期时间和插件区域是显示一行还是显示多行