feat: 加载插件流程移动到插件里单独加载

将加载插件的流程和快捷面板的功能移动到单独的插件中,精简任务栏的代码

Log:
Influence: 加载插件
Task: https://pms.uniontech.com/task-view-222353.html
Change-Id: I9b2fbe4f32c852f6a3535daab87c63741bd8914a
This commit is contained in:
donghualin 2023-01-12 13:09:17 +08:00
parent 978d7fe738
commit 4a2847f03f
29 changed files with 3661 additions and 2 deletions

View File

@ -1,6 +1,7 @@
usr/share
usr/bin
etc/dde-dock
usr/lib/dde-dock/plugins/loader/libpluginmanager.so
usr/lib/dde-dock/plugins/libshutdown.so
usr/lib/dde-dock/plugins/libtrash.so
usr/lib/dde-dock/plugins/liboverlay-warning.so

View File

@ -12,7 +12,7 @@ endif()
generation_dbus_interface(${CMAKE_CURRENT_SOURCE_DIR}/dbusinterface/xml ${CMAKE_CURRENT_SOURCE_DIR}/dbusinterface/generation_dbus_interface)
# Sources files
file(GLOB_RECURSE SRCS "*.h" "*.cpp" "../widgets/*.h" "../widgets/*.cpp")
file(GLOB_RECURSE SRCS "*.h" "*.cpp" "../widgets/*.h" "../widgets/*.cpp" "../interfaces/*.h")
# Find the library
find_package(PkgConfig REQUIRED)

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2023 ~ 2023 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PLUGINMANAGERINTERFACE_H
#define PLUGINMANAGERINTERFACE_H
#include <QObject>
#include <QJsonObject>
class PluginsItemInterface;
class PluginManagerInterface : public QObject
{
Q_OBJECT
public:
virtual QList<PluginsItemInterface *> plugins() const = 0;
virtual QList<PluginsItemInterface *> pluginsInSetting() const = 0;
virtual QList<PluginsItemInterface *> currentPlugins() const = 0;
virtual QString itemKey(PluginsItemInterface *itemInter) const = 0;
virtual QJsonObject metaData(PluginsItemInterface *itemInter) const = 0;
Q_SIGNALS:
void pluginLoadFinished();
};
#endif // PLUGINMANAGERINTERFACE_H

View File

@ -4,7 +4,7 @@ add_subdirectory("power")
add_subdirectory("sound")
add_subdirectory("display")
add_subdirectory("media")
#add_subdirectory("tray")
add_subdirectory("pluginmanager")
add_subdirectory("trash")
add_subdirectory("keyboard-layout")
add_subdirectory("onboard")

View File

@ -0,0 +1,45 @@
set(PLUGIN_NAME "pluginmanager")
project(${PLUGIN_NAME})
# Sources files
file(GLOB_RECURSE SRCS "*.h" "*.cpp" "*.qrc" "../../frame/drag/quickdragcore.h" "../../frame/drag/quickdragcore.cpp"
"../../frame/util/settingconfig.h" "../../frame/util/settingconfig.cpp"
"../../frame/util/pluginloader.h" "../../frame/util/pluginloader.cpp"
"../../frame/dbus/dockinterface.h" "../../frame/dbus/dockinterface.cpp"
"../../frame/dbusinterface/generation_dbus_interface/org_deepin_dde_daemon_dock1.h"
"../../frame/dbusinterface/generation_dbus_interface/org_deepin_dde_daemon_dock1.cpp"
"../../frame/dbusinterface/types/dockrect.h"
"../../frame/dbusinterface/types/dockrect.cpp"
"../../interfaces/pluginmanagerinterface.h"
)
find_package(PkgConfig REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Svg REQUIRED)
find_package(Qt5DBus REQUIRED)
find_package(DtkWidget REQUIRED)
pkg_check_modules(QGSettings REQUIRED gsettings-qt)
add_library(${PLUGIN_NAME} SHARED ${SRCS})
set_target_properties(${PLUGIN_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../loader/)
target_include_directories(${PLUGIN_NAME} PUBLIC ${DtkWidget_INCLUDE_DIRS}
${Qt5DBus_INCLUDE_DIRS}
${QGSettings_INCLUDE_DIRS}
./pluginadapter
../../frame/drag
../../frame/dbusinterface
../../frame/dbusinterface/generation_dbus_interface/
../../interfaces
)
target_link_libraries(${PLUGIN_NAME} PRIVATE
${DtkWidget_LIBRARIES}
${Qt5Widgets_LIBRARIES}
${Qt5Svg_LIBRARIES}
${Qt5DBus_LIBRARIES}
${QGSettings_LIBRARIES}
)
install(TARGETS ${PLUGIN_NAME} LIBRARY DESTINATION lib/dde-dock/plugins/loader)

View File

@ -0,0 +1,704 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "dockplugincontroller.h"
#include "pluginsiteminterface.h"
#include "pluginsiteminterface_v20.h"
#include "pluginadapter.h"
#include "utils.h"
#include "settingconfig.h"
#include <DNotifySender>
#include <DSysInfo>
#include <QDebug>
#include <QDir>
#include <QMapIterator>
#include <QPluginLoader>
#define PLUGININFO "pluginInfo"
#define DOCK_QUICK_PLUGINS "Dock_Quick_Plugins"
static const QStringList CompatiblePluginApiList {
"1.1.1",
"1.2",
"1.2.1",
"1.2.2",
DOCK_PLUGIN_API_VERSION
};
class PluginInfo : public QObject
{
public:
PluginInfo() : QObject(nullptr), m_loaded(false), m_visible(false) {}
bool m_loaded;
bool m_visible;
QString m_itemKey;
};
DockPluginController::DockPluginController(PluginProxyInterface *proxyInter, QObject *parent)
: QObject(parent)
, m_dbusDaemonInterface(QDBusConnection::sessionBus().interface())
, m_dockDaemonInter(new DockInter(dockServiceName(), dockServicePath(), QDBusConnection::sessionBus(), this))
, m_proxyInter(proxyInter)
{
qApp->installEventFilter(this);
refreshPluginSettings();
connect(SETTINGCONFIG, &SettingConfig::valueChanged, this, &DockPluginController::onConfigChanged);
connect(m_dockDaemonInter, &DockInter::PluginSettingsSynced, this, &DockPluginController::refreshPluginSettings, Qt::QueuedConnection);
}
DockPluginController::~DockPluginController()
{
for (auto inter : m_pluginsMap.keys()) {
delete m_pluginsMap.value(inter).value("pluginloader");
m_pluginsMap[inter]["pluginloader"] = nullptr;
if (m_pluginsMap[inter].contains(PLUGININFO))
m_pluginsMap[inter][PLUGININFO]->deleteLater();
m_pluginsMap.remove(inter);
delete inter;
inter = nullptr;
}
}
QList<PluginsItemInterface *> DockPluginController::plugins() const
{
return m_pluginsMap.keys();
}
QList<PluginsItemInterface *> DockPluginController::pluginsInSetting() const
{
// 插件有三种状态
// 1、所有的插件不管这个插件是否调用itemAdded方法只要是通过dock加载的插件换句话说也就是在/lib/dde-dock/plugins目录下的插件
// 2、在1的基础上插件自身调用了itemAdded方法的插件例如机器上没有蓝牙设备那么蓝牙插件就不会调用itemAdded方法这时候就不算
// 3、在2的基础上由控制中心来决定那些插件是否在任务栏显示的插件
// 此处返回的是第二种插件
QList<PluginsItemInterface *> settingPlugins;
QMap<PluginsItemInterface *, int> pluginSort;
for (auto it = m_pluginsMap.begin(); it != m_pluginsMap.end(); it++) {
PluginsItemInterface *plugin = it.key();
qInfo() << plugin->pluginName();
if (plugin->pluginDisplayName().isEmpty())
continue;
QMap<QString, QObject *> pluginMap = it.value();
// 如果不包含PLUGININFO这个key值肯定是未加载
if (!pluginMap.contains(PLUGININFO))
continue;
PluginInfo *pluginInfo = static_cast<PluginInfo *>(pluginMap[PLUGININFO]);
if (!pluginInfo->m_loaded)
continue;
// 这里只需要返回插件为可以在控制中心设置的插件
if (!(plugin->flags() & PluginFlag::Attribute_CanSetting))
continue;
settingPlugins << plugin;
pluginSort[plugin] = plugin->itemSortKey(pluginInfo->m_itemKey);
}
std::sort(settingPlugins.begin(), settingPlugins.end(), [ pluginSort ](PluginsItemInterface *plugin1, PluginsItemInterface *plugin2) {
return pluginSort[plugin1] < pluginSort[plugin2];
});
return settingPlugins;
}
QList<PluginsItemInterface *> DockPluginController::currentPlugins() const
{
QList<PluginsItemInterface *> loadedPlugins;
QMap<PluginsItemInterface *, int> pluginSortMap;
for (auto it = m_pluginsMap.begin(); it != m_pluginsMap.end(); it++) {
QMap<QString, QObject *> objectMap = it.value();
if (!objectMap.contains(PLUGININFO))
continue;
PluginInfo *pluginInfo = static_cast<PluginInfo *>(objectMap[PLUGININFO]);
if (!pluginInfo->m_loaded)
continue;
PluginsItemInterface *plugin = it.key();
loadedPlugins << plugin;
pluginSortMap[plugin] = plugin->itemSortKey(pluginInfo->m_itemKey);
}
std::sort(loadedPlugins.begin(), loadedPlugins.end(), [ pluginSortMap ](PluginsItemInterface *pluginItem1, PluginsItemInterface *pluginItem2) {
return pluginSortMap.value(pluginItem1) < pluginSortMap.value(pluginItem2);
});
return loadedPlugins;
}
void DockPluginController::saveValue(PluginsItemInterface *const itemInter, const QString &key, const QVariant &value)
{
savePluginValue(getPluginInterface(itemInter), key, value);
}
const QVariant DockPluginController::getValue(PluginsItemInterface *const itemInter, const QString &key, const QVariant &fallback)
{
return getPluginValue(getPluginInterface(itemInter), key, fallback);
}
void DockPluginController::removeValue(PluginsItemInterface *const itemInter, const QStringList &keyList)
{
removePluginValue(getPluginInterface(itemInter), keyList);
}
void DockPluginController::itemAdded(PluginsItemInterface * const itemInter, const QString &itemKey)
{
PluginsItemInterface *pluginItem = getPluginInterface(itemInter);
PluginAdapter *pluginAdapter = dynamic_cast<PluginAdapter *>(pluginItem);
if (pluginAdapter) {
// 如果该插件可以正常转换为PluginAdapter插件表示当前插件是v20插件为了兼容v20插件
// 中获取ICON因此使用调用插件的itemWidget来截图的方式返回QIcon所以此处传入itemKey
pluginAdapter->setItemKey(itemKey);
}
// 如果是通过插件来调用m_proxyInter的
PluginInfo *pluginInfo = nullptr;
QMap<QString, QObject *> &interfaceData = m_pluginsMap[pluginItem];
if (interfaceData.contains(PLUGININFO)) {
pluginInfo = static_cast<PluginInfo *>(interfaceData[PLUGININFO]);
// 如果插件已经加载则无需再次加载此处保证插件出现重复调用itemAdded的情况
if (pluginInfo->m_loaded)
return;
} else {
pluginInfo = new PluginInfo;
interfaceData[PLUGININFO] = pluginInfo;
}
pluginInfo->m_itemKey = itemKey;
pluginInfo->m_loaded = true;
if (pluginCanDock(pluginItem))
addPluginItem(pluginItem, itemKey);
Q_EMIT pluginInserted(pluginItem, itemKey);
}
void DockPluginController::itemUpdate(PluginsItemInterface * const itemInter, const QString &itemKey)
{
m_proxyInter->itemUpdate(getPluginInterface(itemInter), itemKey);
}
void DockPluginController::itemRemoved(PluginsItemInterface * const itemInter, const QString &itemKey)
{
PluginsItemInterface *pluginInter = getPluginInterface(itemInter);
// 更新字段中的isLoaded字段表示当前没有加载
QMap<QString, QObject *> &interfaceData = m_pluginsMap[pluginInter];
if (interfaceData.contains(PLUGININFO)) {
PluginInfo *pluginInfo = static_cast<PluginInfo *>(interfaceData[PLUGININFO]);
// 将是否加载的标记修改为未加载
pluginInfo->m_loaded = false;
}
removePluginItem(pluginInter, itemKey);
Q_EMIT pluginRemoved(pluginInter);
}
void DockPluginController::requestWindowAutoHide(PluginsItemInterface * const itemInter, const QString &itemKey, const bool autoHide)
{
m_proxyInter->requestWindowAutoHide(getPluginInterface(itemInter), itemKey, autoHide);
}
void DockPluginController::requestRefreshWindowVisible(PluginsItemInterface * const itemInter, const QString &itemKey)
{
m_proxyInter->requestRefreshWindowVisible(getPluginInterface(itemInter), itemKey);
}
// 请求页面显示或者隐藏,由插件内部来调用,例如在移除蓝牙插件后,如果已经弹出了蓝牙插件的面板,则隐藏面板
void DockPluginController::requestSetAppletVisible(PluginsItemInterface * const itemInter, const QString &itemKey, const bool visible)
{
PluginsItemInterface *pluginInter = getPluginInterface(itemInter);
Q_EMIT requestAppletVisible(pluginInter, itemKey, visible);
m_proxyInter->requestSetAppletVisible(pluginInter, itemKey, visible);
}
PluginsItemInterface *DockPluginController::getPluginInterface(PluginsItemInterface * const itemInter)
{
// 先从事先定义好的map中查找如果没有找到就是v23插件直接返回当前插件的指针
qulonglong pluginAddr = (qulonglong)itemInter;
if (m_pluginAdapterMap.contains(pluginAddr))
return m_pluginAdapterMap[pluginAddr];
return itemInter;
}
void DockPluginController::addPluginItem(PluginsItemInterface * const itemInter, const QString &itemKey)
{
// 如果这个插件都没有加载,那么此处肯定是无需新增
if (!m_pluginsMap.contains(itemInter))
return;
PluginInfo *pluginInfo = nullptr;
QMap<QString, QObject *> &interfaceData = m_pluginsMap[itemInter];
// 此处的PLUGININFO的数据已经在前面调用的地方给填充了数据如果没有获取到这个数据则无需新增
if (!interfaceData.contains(PLUGININFO))
return;
pluginInfo = static_cast<PluginInfo *>(interfaceData[PLUGININFO]);
pluginInfo->m_visible = true;
m_proxyInter->itemAdded(itemInter, itemKey);
}
void DockPluginController::removePluginItem(PluginsItemInterface * const itemInter, const QString &itemKey)
{
if (!m_pluginsMap.contains(itemInter))
return;
// 更新字段中的isLoaded字段表示当前没有加载
QMap<QString, QObject *> &interfaceData = m_pluginsMap[itemInter];
if (!interfaceData.contains(PLUGININFO))
return;
PluginInfo *pluginInfo = static_cast<PluginInfo *>(interfaceData[PLUGININFO]);
// 将是否在任务栏显示的标记改为不显示
pluginInfo->m_visible = false;
m_proxyInter->itemRemoved(itemInter, itemKey);
}
QString DockPluginController::itemKey(PluginsItemInterface *itemInter) const
{
if (!m_pluginsMap.contains(itemInter))
return QString();
QMap<QString, QObject *> interfaceData = m_pluginsMap[itemInter];
if (!interfaceData.contains(PLUGININFO))
return QString();
PluginInfo *pluginInfo = static_cast<PluginInfo *>(interfaceData[PLUGININFO]);
return pluginInfo->m_itemKey;
}
QJsonObject DockPluginController::metaData(PluginsItemInterface *pluginItem)
{
if (!m_pluginsMap.contains(pluginItem))
return QJsonObject();
QPluginLoader *pluginLoader = qobject_cast<QPluginLoader *>(m_pluginsMap[pluginItem].value("pluginloader"));
if (!pluginLoader)
return QJsonObject();
return pluginLoader->metaData().value("MetaData").toObject();
}
void DockPluginController::savePluginValue(PluginsItemInterface * const itemInter, const QString &key, const QVariant &value)
{
// is it necessary?
// refreshPluginSettings();
// save to local cache
QJsonObject localObject = m_pluginSettingsObject.value(itemInter->pluginName()).toObject();
localObject.insert(key, QJsonValue::fromVariant(value)); //Note: QVariant::toJsonValue() not work in Qt 5.7
// save to daemon
QJsonObject remoteObject, remoteObjectInter;
remoteObjectInter.insert(key, QJsonValue::fromVariant(value)); //Note: QVariant::toJsonValue() not work in Qt 5.7
remoteObject.insert(itemInter->pluginName(), remoteObjectInter);
if (itemInter->type() == PluginsItemInterface::Fixed && key == "enable" && !value.toBool()) {
int fixedPluginCount = 0;
// 遍历FixPlugin插件个数
for (auto it(m_pluginsMap.begin()); it != m_pluginsMap.end();) {
if (it.key()->type() == PluginsItemInterface::Fixed) {
fixedPluginCount++;
}
++it;
}
// 修改插件的order值位置为队尾
QString name = localObject.keys().last();
// 此次做一下判断有可能初始数据不存在pos_*字段会导致enable字段被修改。或者此处可以循环所有字段是否存在pos_开头的字段
if (name != key) {
localObject.insert(name, QJsonValue::fromVariant(fixedPluginCount)); //Note: QVariant::toJsonValue() not work in Qt 5.7
// daemon中同样修改
remoteObjectInter.insert(name, QJsonValue::fromVariant(fixedPluginCount)); //Note: QVariant::toJsonValue() not work in Qt 5.7
remoteObject.insert(itemInter->pluginName(), remoteObjectInter);
}
}
m_pluginSettingsObject.insert(itemInter->pluginName(), localObject);
m_dockDaemonInter->MergePluginSettings(QJsonDocument(remoteObject).toJson(QJsonDocument::JsonFormat::Compact));
}
const QVariant DockPluginController::getPluginValue(PluginsItemInterface * const itemInter, const QString &key, const QVariant &fallback)
{
// load from local cache
QVariant v = m_pluginSettingsObject.value(itemInter->pluginName()).toObject().value(key).toVariant();
if (v.isNull() || !v.isValid()) {
v = fallback;
}
return v;
}
void DockPluginController::removePluginValue(PluginsItemInterface * const itemInter, const QStringList &keyList)
{
if (keyList.isEmpty()) {
m_pluginSettingsObject.remove(itemInter->pluginName());
} else {
QJsonObject localObject = m_pluginSettingsObject.value(itemInter->pluginName()).toObject();
for (auto key : keyList) {
localObject.remove(key);
}
m_pluginSettingsObject.insert(itemInter->pluginName(), localObject);
}
m_dockDaemonInter->RemovePluginSettings(itemInter->pluginName(), keyList);
}
void DockPluginController::startLoadPlugin(const QStringList &dirs)
{
QDir dir;
for (const QString &path : dirs) {
if (!dir.exists(path))
continue;
startLoader(new PluginLoader(path, this));
}
}
bool DockPluginController::isPluginLoaded(PluginsItemInterface *itemInter)
{
if (!m_pluginsMap.contains(itemInter))
return false;
QMap<QString, QObject *> pluginObject = m_pluginsMap.value(itemInter);
if (!pluginObject.contains(PLUGININFO))
return false;
PluginInfo *pluginInfo = static_cast<PluginInfo *>(pluginObject.value(PLUGININFO));
return pluginInfo->m_visible;
}
QObject *DockPluginController::pluginItemAt(PluginsItemInterface *const itemInter, const QString &itemKey) const
{
if (!m_pluginsMap.contains(itemInter))
return nullptr;
return m_pluginsMap[itemInter][itemKey];
}
PluginsItemInterface *DockPluginController::pluginInterAt(const QString &itemKey)
{
QMapIterator<PluginsItemInterface *, QMap<QString, QObject *>> it(m_pluginsMap);
while (it.hasNext()) {
it.next();
if (it.value().keys().contains(itemKey)) {
return it.key();
}
}
return nullptr;
}
PluginsItemInterface *DockPluginController::pluginInterAt(QObject *destItem)
{
QMapIterator<PluginsItemInterface *, QMap<QString, QObject *>> it(m_pluginsMap);
while (it.hasNext()) {
it.next();
if (it.value().values().contains(destItem)) {
return it.key();
}
}
return nullptr;
}
void DockPluginController::startLoader(PluginLoader *loader)
{
connect(loader, &PluginLoader::finished, loader, &PluginLoader::deleteLater, Qt::QueuedConnection);
connect(loader, &PluginLoader::pluginFounded, this, [ = ](const QString &pluginFile) {
QPair<QString, PluginsItemInterface *> pair;
pair.first = pluginFile;
pair.second = nullptr;
m_pluginLoadMap.insert(pair, false);
});
connect(loader, &PluginLoader::pluginFounded, this, &DockPluginController::loadPlugin, Qt::QueuedConnection);
int delay = Utils::SettingValue("com.deepin.dde.dock", "/com/deepin/dde/dock/", "delay-plugins-time", 0).toInt();
QTimer::singleShot(delay, loader, [ = ] { loader->start(QThread::LowestPriority); });
}
void DockPluginController::displayModeChanged()
{
const Dock::DisplayMode displayMode = qApp->property(PROP_DISPLAY_MODE).value<Dock::DisplayMode>();
const auto inters = m_pluginsMap.keys();
for (auto inter : inters)
inter->displayModeChanged(displayMode);
}
void DockPluginController::positionChanged()
{
const Dock::Position position = qApp->property(PROP_POSITION).value<Dock::Position>();
const auto inters = m_pluginsMap.keys();
for (auto inter : inters)
inter->positionChanged(position);
}
void DockPluginController::loadPlugin(const QString &pluginFile)
{
QPluginLoader *pluginLoader = new QPluginLoader(pluginFile, this);
const QJsonObject &meta = pluginLoader->metaData().value("MetaData").toObject();
const QString &pluginApi = meta.value("api").toString();
bool pluginIsValid = true;
if (pluginApi.isEmpty() || !CompatiblePluginApiList.contains(pluginApi)) {
qDebug() << objectName()
<< "plugin api version not matched! expect versions:" << CompatiblePluginApiList
<< ", got version:" << pluginApi
<< ", the plugin file is:" << pluginFile;
pluginIsValid = false;
}
PluginsItemInterface *interface = qobject_cast<PluginsItemInterface *>(pluginLoader->instance());
if (!interface) {
// 如果识别当前插件失败就认为这个插件是v20的插件将其转换为v20插件接口
PluginsItemInterface_V20 *interface_v20 = qobject_cast<PluginsItemInterface_V20 *>(pluginLoader->instance());
if (interface_v20) {
// 将v20插件接口通过适配器转换成v23的接口方便在后面识别
PluginAdapter *pluginAdapter = new PluginAdapter(interface_v20, pluginLoader);
// 将适配器的地址保存到map列表中因为适配器自己会调用itemAdded方法转换成PluginsItemInterface类但是实际上它
// 对应的是PluginAdapter类因此这个map用于在后面的itemAdded方法中用来查找
m_pluginAdapterMap[(qulonglong)(interface_v20)] = pluginAdapter;
interface = pluginAdapter;
}
}
if (!interface) {
qDebug() << objectName() << "load plugin failed!!!" << pluginLoader->errorString() << pluginFile;
pluginLoader->unload();
pluginLoader->deleteLater();
pluginIsValid = false;
}
if (!pluginIsValid) {
for (auto &pair : m_pluginLoadMap.keys()) {
if (pair.first == pluginFile) {
m_pluginLoadMap.remove(pair);
}
}
QString notifyMessage(tr("The plugin %1 is not compatible with the system."));
Dtk::Core::DUtil::DNotifySender(notifyMessage.arg(QFileInfo(pluginFile).fileName())).appIcon("dialog-warning").call();
return;
}
if (interface->pluginName() == "multitasking" && (Utils::IS_WAYLAND_DISPLAY || Dtk::Core::DSysInfo::deepinType() == Dtk::Core::DSysInfo::DeepinServer)) {
for (auto &pair : m_pluginLoadMap.keys()) {
if (pair.first == pluginFile) {
m_pluginLoadMap.remove(pair);
}
}
return;
}
QMapIterator<QPair<QString, PluginsItemInterface *>, bool> it(m_pluginLoadMap);
while (it.hasNext()) {
it.next();
if (it.key().first == pluginFile) {
m_pluginLoadMap.remove(it.key());
QPair<QString, PluginsItemInterface *> newPair;
newPair.first = pluginFile;
newPair.second = interface;
m_pluginLoadMap.insert(newPair, false);
break;
}
}
// 保存 PluginLoader 对象指针
QMap<QString, QObject *> interfaceData;
interfaceData["pluginloader"] = pluginLoader;
m_pluginsMap.insert(interface, interfaceData);
QString dbusService = meta.value("depends-daemon-dbus-service").toString();
if (!dbusService.isEmpty() && !m_dbusDaemonInterface->isServiceRegistered(dbusService).value()) {
qDebug() << objectName() << dbusService << "daemon has not started, waiting for signal";
connect(m_dbusDaemonInterface, &QDBusConnectionInterface::serviceOwnerChanged, this,
[ = ](const QString & name, const QString & oldOwner, const QString & newOwner) {
Q_UNUSED(oldOwner);
if (name == dbusService && !newOwner.isEmpty()) {
qDebug() << objectName() << dbusService << "daemon started, init plugin and disconnect";
initPlugin(interface);
disconnect(m_dbusDaemonInterface);
}
}
);
return;
}
// NOTE(justforlxz): 插件的所有初始化工作都在init函数中进行
// loadPlugin函数是按队列执行的initPlugin函数会有可能导致
// 函数执行被阻塞。
QTimer::singleShot(1, this, [ = ] {
initPlugin(interface);
});
}
void DockPluginController::initPlugin(PluginsItemInterface *interface)
{
if (!interface)
return;
qDebug() << objectName() << "init plugin: " << interface->pluginName();
interface->init(this);
for (const auto &pair : m_pluginLoadMap.keys()) {
if (pair.second == interface)
m_pluginLoadMap.insert(pair, true);
}
bool loaded = true;
for (int i = 0; i < m_pluginLoadMap.keys().size(); ++i) {
if (!m_pluginLoadMap.values()[i]) {
loaded = false;
break;
}
}
// 插件全部加载完成
if (loaded) {
emit pluginLoadFinished();
}
qDebug() << objectName() << "init plugin finished: " << interface->pluginName();
}
void DockPluginController::refreshPluginSettings()
{
const QString &pluginSettings = m_dockDaemonInter->GetPluginSettings().value();
if (pluginSettings.isEmpty()) {
qDebug() << "Error! get plugin settings from dbus failed!";
return;
}
const QJsonObject &pluginSettingsObject = QJsonDocument::fromJson(pluginSettings.toLocal8Bit()).object();
if (pluginSettingsObject.isEmpty()) {
return;
}
// nothing changed
if (pluginSettingsObject == m_pluginSettingsObject) {
return;
}
for (auto pluginsIt = pluginSettingsObject.constBegin(); pluginsIt != pluginSettingsObject.constEnd(); ++pluginsIt) {
const QString &pluginName = pluginsIt.key();
const QJsonObject &settingsObject = pluginsIt.value().toObject();
QJsonObject newSettingsObject = m_pluginSettingsObject.value(pluginName).toObject();
for (auto settingsIt = settingsObject.constBegin(); settingsIt != settingsObject.constEnd(); ++settingsIt) {
newSettingsObject.insert(settingsIt.key(), settingsIt.value());
}
// TODO: remove not exists key-values
m_pluginSettingsObject.insert(pluginName, newSettingsObject);
}
// not notify plugins to refresh settings if this update is not emit by dock daemon
if (sender() != m_dockDaemonInter) {
return;
}
// notify all plugins to reload plugin settings
for (PluginsItemInterface *pluginInter : m_pluginsMap.keys()) {
pluginInter->pluginSettingsChanged();
}
// reload all plugin items for sort order or container
QMap<PluginsItemInterface *, QMap<QString, QObject *>> pluginsMapTemp = m_pluginsMap;
for (auto it = pluginsMapTemp.constBegin(); it != pluginsMapTemp.constEnd(); ++it) {
const QList<QString> &itemKeyList = it.value().keys();
for (auto key : itemKeyList) {
if (key != "pluginloader") {
itemRemoved(it.key(), key);
}
}
for (auto key : itemKeyList) {
if (key != "pluginloader") {
itemAdded(it.key(), key);
}
}
}
}
bool DockPluginController::eventFilter(QObject *object, QEvent *event)
{
if (object != qApp || event->type() != QEvent::DynamicPropertyChange)
return false;
QDynamicPropertyChangeEvent *const dpce = static_cast<QDynamicPropertyChangeEvent *>(event);
const QString propertyName = dpce->propertyName();
if (propertyName == PROP_POSITION)
positionChanged();
else if (propertyName == PROP_DISPLAY_MODE)
displayModeChanged();
return false;
}
bool DockPluginController::pluginCanDock(PluginsItemInterface *plugin) const
{
// 观察插件是否已经驻留在任务栏上,如果已经驻留在任务栏,则始终显示
if (plugin->flags() & PluginFlag::Attribute_ForceDock)
return true;
const QStringList configPlugins = SETTINGCONFIG->value(DOCK_QUICK_PLUGINS).toStringList();
return configPlugins.contains(plugin->pluginName());
}
void DockPluginController::updateDockInfo(PluginsItemInterface * const itemInter, const DockPart &part)
{
m_proxyInter->updateDockInfo(itemInter, part);
Q_EMIT pluginUpdated(itemInter, part);
}
void DockPluginController::onConfigChanged(const QString &key, const QVariant &value)
{
if (key != DOCK_QUICK_PLUGINS)
return;
QStringList pluginNames = value.toStringList();
// 这里只处理工具插件(回收站)和系统插件(电源插件)
for (PluginsItemInterface *plugin : plugins()) {
QString itemKey = this->itemKey(plugin);
if (!pluginNames.contains(plugin->pluginName()) && isPluginLoaded(plugin)) {
// 如果当前配置中不包含当前插件,但是当前插件已经加载,那么就移除该插件
removePluginItem(plugin, itemKey);
QWidget *itemWidget = plugin->itemWidget(itemKey);
if (itemWidget)
itemWidget->setVisible(false);
} else if (pluginNames.contains(plugin->pluginName()) && !isPluginLoaded(plugin)) {
// 如果当前配置中包含当前插件,但是当前插件并未加载,那么就加载该插件
addPluginItem(plugin, itemKey);
// 只有工具插件是通过QWidget的方式进行显示的因此这里只处理工具插件
if (plugin->flags() & PluginFlag::Type_Tool) {
QWidget *itemWidget = plugin->itemWidget(itemKey);
if (itemWidget)
itemWidget->setVisible(true);
}
}
}
}

View File

@ -0,0 +1,116 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef DOCKPLUGINCONTROLLER_H
#define DOCKPLUGINCONTROLLER_H
#include "pluginproxyinterface.h"
#include "pluginloader.h"
#include "dbusutil.h"
#include <QList>
#include <QMap>
#include <QDBusConnectionInterface>
class PluginsItemInterface;
class PluginAdapter;
class DockPluginController : public QObject, protected PluginProxyInterface
{
Q_OBJECT
public:
explicit DockPluginController(PluginProxyInterface *proxyInter, QObject *parent = Q_NULLPTR);
~ DockPluginController() override;
QList<PluginsItemInterface *> plugins() const; // 所有的插件
QList<PluginsItemInterface *> pluginsInSetting() const; // 控制中心用于可以设置是否显示或隐藏的插件
QList<PluginsItemInterface *> currentPlugins() const; // 当前使用的插件
QString itemKey(PluginsItemInterface *itemInter) const;
QJsonObject metaData(PluginsItemInterface *pluginItem);
virtual void savePluginValue(PluginsItemInterface *const itemInter, const QString &key, const QVariant &value);
virtual const QVariant getPluginValue(PluginsItemInterface *const itemInter, const QString &key, const QVariant& fallback = QVariant());
virtual void removePluginValue(PluginsItemInterface * const itemInter, const QStringList &keyList);
void startLoadPlugin(const QStringList &dirs);
Q_SIGNALS:
void pluginLoadFinished();
void pluginInserted(PluginsItemInterface *itemInter, QString);
void pluginRemoved(PluginsItemInterface *itemInter);
void pluginUpdated(PluginsItemInterface *, const DockPart);
void requestAppletVisible(PluginsItemInterface *, const QString &, bool);
protected:
bool isPluginLoaded(PluginsItemInterface *itemInter);
QObject *pluginItemAt(PluginsItemInterface * const itemInter, const QString &itemKey) const;
PluginsItemInterface *pluginInterAt(const QString &itemKey);
PluginsItemInterface *pluginInterAt(QObject *destItem);
bool eventFilter(QObject *object, QEvent *event) override;
bool pluginCanDock(PluginsItemInterface *plugin) const;
void updateDockInfo(PluginsItemInterface * const itemInter, const DockPart &part) override;
private:
// implements PluginProxyInterface
void saveValue(PluginsItemInterface *const itemInter, const QString &key, const QVariant &value) override;
const QVariant getValue(PluginsItemInterface *const itemInter, const QString &key, const QVariant& fallback = QVariant()) override;
void removeValue(PluginsItemInterface * const itemInter, const QStringList &keyList) override;
void itemAdded(PluginsItemInterface * const itemInter, const QString &itemKey) override;
void itemUpdate(PluginsItemInterface * const itemInter, const QString &itemKey) override;
void itemRemoved(PluginsItemInterface * const itemInter, const QString &itemKey) override;
void requestWindowAutoHide(PluginsItemInterface * const itemInter, const QString &itemKey, const bool autoHide) override;
void requestRefreshWindowVisible(PluginsItemInterface * const itemInter, const QString &itemKey) override;
void requestSetAppletVisible(PluginsItemInterface * const itemInter, const QString &itemKey, const bool visible) override;
PluginsItemInterface *getPluginInterface(PluginsItemInterface * const itemInter);
void addPluginItem(PluginsItemInterface * const itemInter, const QString &itemKey);
void removePluginItem(PluginsItemInterface * const itemInter, const QString &itemKey);
private Q_SLOTS:
void startLoader(PluginLoader *loader);
void displayModeChanged();
void positionChanged();
void loadPlugin(const QString &pluginFile);
void initPlugin(PluginsItemInterface *interface);
void refreshPluginSettings();
void onConfigChanged(const QString &key, const QVariant &value);
private:
QDBusConnectionInterface *m_dbusDaemonInterface;
DockInter *m_dockDaemonInter;
// interface, "pluginloader", PluginLoader指针对象
QMap<PluginsItemInterface *, QMap<QString, QObject *>> m_pluginsMap;
// filepath, interface, loaded
QMap<QPair<QString, PluginsItemInterface *>, bool> m_pluginLoadMap;
QJsonObject m_pluginSettingsObject;
QMap<qulonglong, PluginAdapter *> m_pluginAdapterMap;
PluginProxyInterface *m_proxyInter;
};
#endif // ABSTRACTPLUGINSCONTROLLER_H

View File

@ -0,0 +1,122 @@
/*
* Copyright (C) 2023 ~ 2023 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "iconmanager.h"
#include "dockplugincontroller.h"
#include "pluginsiteminterface.h"
#include <DDciIcon>
#include <QPainter>
#include <QPainterPath>
#define ITEMSPACE 6
#define ITEMHEIGHT 16
#define ITEMWIDTH 18
static QStringList pluginNames = {"power", "sound", "network"};
DGUI_USE_NAMESPACE
IconManager::IconManager(DockPluginController *pluginController, QObject *parent)
: QObject{parent}
, m_pluginController(pluginController)
, m_size(QSize(ITEMWIDTH, ITEMHEIGHT))
, m_position(Dock::Position::Bottom)
{
}
void IconManager::updateSize(QSize size)
{
m_size = size;
}
void IconManager::setPosition(Dock::Position position)
{
m_position = position;
}
QPixmap IconManager::pixmap() const
{
QList<PluginsItemInterface *> plugins;
for (const QString &pluginName : pluginNames) {
PluginsItemInterface *plugin = findPlugin(pluginName);
if (plugin)
plugins << plugin;
}
if (plugins.size() < 2) {
// 缺省图标
DDciIcon::Theme theme = DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::DarkType ? DDciIcon::Light : DDciIcon::Dark;
DDciIcon dciIcon(QString(":/resources/dock_control.dci"));
return dciIcon.pixmap(QCoreApplication::testAttribute(Qt::AA_UseHighDpiPixmaps) ? 1 : qApp->devicePixelRatio(), ITEMHEIGHT, theme, DDciIcon::Normal);
}
// 组合图标
QPixmap pixmap;
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) {
pixmap = QPixmap(ITEMWIDTH * plugins.size() + ITEMSPACE * (plugins.size() + 1), m_size.height() - 8);
} else {
pixmap = QPixmap(m_size.width() - 8, ITEMWIDTH * plugins.size() + ITEMSPACE * (plugins.size() + 1));
}
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing);
QColor backColor = DGuiApplicationHelper::ColorType::DarkType == DGuiApplicationHelper::instance()->themeType() ? QColor(20, 20, 20) : Qt::white;
backColor.setAlphaF(0.2);
QPainterPath path;
path.addRoundedRect(pixmap.rect(), 5, 5);
painter.fillPath(path, backColor);
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) {
QPoint pointPixmap(ITEMSPACE, (pixmap.height() - ITEMHEIGHT) / 2);
for (PluginsItemInterface *plugin : plugins) {
QIcon icon = plugin->icon(DockPart::QuickShow);
QPixmap pixmapDraw = icon.pixmap(ITEMHEIGHT, ITEMHEIGHT);
painter.drawPixmap(pointPixmap, pixmapDraw);
pointPixmap.setX(pointPixmap.x() + ITEMWIDTH + ITEMSPACE);
}
} else {
QPoint pointPixmap((pixmap.width() - ITEMWIDTH) / 2, ITEMSPACE);
for (PluginsItemInterface *plugin : plugins) {
QIcon icon = plugin->icon(DockPart::QuickShow);
QPixmap pixmapDraw = icon.pixmap(ITEMHEIGHT, ITEMHEIGHT);
painter.drawPixmap(pointPixmap, pixmapDraw);
pointPixmap.setY(pointPixmap.y() + ITEMWIDTH + ITEMSPACE);
}
}
painter.end();
return pixmap;
}
bool IconManager::isFixedPlugin(PluginsItemInterface *plugin) const
{
return pluginNames.contains(plugin->pluginName());
}
PluginsItemInterface *IconManager::findPlugin(const QString &pluginName) const
{
QList<PluginsItemInterface *> plugins = m_pluginController->currentPlugins();
for (PluginsItemInterface *plugin : plugins) {
if (plugin->pluginName() == pluginName)
return plugin;
}
return nullptr;
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2023 ~ 2023 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef ICONMANAGER_H
#define ICONMANAGER_H
#include "pluginsiteminterface.h"
#include <QObject>
#include <QPixmap>
class DockPluginController;
class PluginsItemInterface;
class IconManager : public QObject
{
Q_OBJECT
public:
explicit IconManager(DockPluginController *pluginController, QObject *parent = nullptr);
void updateSize(QSize size);
void setPosition(Dock::Position position);
QPixmap pixmap() const;
bool isFixedPlugin(PluginsItemInterface *plugin) const;
private:
PluginsItemInterface *findPlugin(const QString &pluginName) const;
private:
DockPluginController *m_pluginController;
QSize m_size;
Dock::Position m_position;
};
#endif // ICONMANAGER_H

View File

@ -0,0 +1,313 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "largerquickitem.h"
#include "pluginsiteminterface.h"
#include <DFontSizeManager>
#include <DGuiApplicationHelper>
#include <DPaletteHelper>
#include <QLabel>
#include <QHBoxLayout>
#include <QPainter>
#define BGSIZE 36
#define ICONWIDTH 24
#define ICONHEIGHT 24
DWIDGET_USE_NAMESPACE
static QSize expandSize = QSize(20, 20);
LargerQuickItem::LargerQuickItem(PluginsItemInterface *const pluginInter, const QString &itemKey, QWidget *parent)
: QuickSettingItem(pluginInter, itemKey, parent)
, m_iconWidget(nullptr)
, m_nameLabel(nullptr)
, m_stateLabel(nullptr)
, m_itemWidgetParent(nullptr)
{
initUi();
}
LargerQuickItem::~LargerQuickItem()
{
QWidget *itemWidget = pluginItem()->itemWidget(QUICK_ITEM_KEY);
if (itemWidget)
itemWidget->setParent(nullptr);
}
void LargerQuickItem::doUpdate()
{
if (m_iconWidget && m_nameLabel && m_stateLabel) {
m_iconWidget->update();
m_nameLabel->setText(QFontMetrics(m_nameLabel->font()).elidedText(pluginItem()->pluginDisplayName(), Qt::TextElideMode::ElideRight, m_nameLabel->width()));
m_stateLabel->setText(QFontMetrics(m_stateLabel->font()).elidedText(pluginItem()->description(), Qt::TextElideMode::ElideRight, m_stateLabel->width()));
} else {
QWidget *itemWidget = pluginItem()->itemWidget(QUICK_ITEM_KEY);
if (itemWidget) {
// 如果插件没有返回图标的显示则获取插件的itemWidget
itemWidget->update();
}
}
}
void LargerQuickItem::detachPlugin()
{
QWidget *itemWidget = pluginItem()->itemWidget(QUICK_ITEM_KEY);
if (itemWidget && itemWidget->parentWidget() == this)
itemWidget->setParent(m_itemWidgetParent);
}
QuickSettingItem::QuickItemStyle LargerQuickItem::type() const
{
return QuickSettingItem::QuickItemStyle::Larger;
}
bool LargerQuickItem::eventFilter(QObject *obj, QEvent *event)
{
if (!m_iconWidget)
return QuickSettingItem::eventFilter(obj, event);
switch (event->type()) {
case QEvent::MouseButtonRelease: {
if (obj->objectName() == "expandLabel") {
// 如果是鼠标的按下事件
QWidget *widget = pluginItem()->itemPopupApplet(QUICK_ITEM_KEY);
if (widget)
Q_EMIT requestShowChildWidget(widget);
break;
}
if (obj == this) {
QStringList commandArgumend = pluginItem()->itemCommand(itemKey()).split(" ");
if (commandArgumend.size() == 0)
break;
QString command = commandArgumend.first();
commandArgumend.removeFirst();
QProcess::startDetached(command, commandArgumend);
}
break;
}
case QEvent::Resize: {
QLabel *labelWidget = qobject_cast<QLabel *>(obj);
if (!labelWidget)
break;
if (labelWidget == m_nameLabel) {
labelWidget->setText(QFontMetrics(labelWidget->font()).elidedText(pluginItem()->pluginDisplayName(), Qt::TextElideMode::ElideRight, labelWidget->width()));
break;
}
if (labelWidget == m_stateLabel) {
labelWidget->setText(QFontMetrics(labelWidget->font()).elidedText(pluginItem()->description(), Qt::TextElideMode::ElideRight, labelWidget->width()));
}
break;
}
default:
break;
}
return QuickSettingItem::eventFilter(obj, event);
}
void LargerQuickItem::showEvent(QShowEvent *event)
{
QWidget *itemWidget = pluginItem()->itemWidget(QUICK_ITEM_KEY);
if (pluginItem()->icon(DockPart::QuickPanel).isNull() && itemWidget) {
itemWidget->setParent(this);
itemWidget->setVisible(true);
}
}
void LargerQuickItem::resizeEvent(QResizeEvent *event)
{
QWidget *itemWidget = pluginItem()->itemWidget(QUICK_ITEM_KEY);
if (pluginItem()->icon(DockPart::QuickPanel).isNull() && itemWidget) {
itemWidget->setFixedSize(size());
}
QuickSettingItem::resizeEvent(event);
}
void LargerQuickItem::initUi()
{
QWidget *itemWidget = pluginItem()->itemWidget(QUICK_ITEM_KEY);
if (pluginItem()->icon(DockPart::QuickPanel).isNull() && itemWidget) {
m_itemWidgetParent = itemWidget->parentWidget();
// 如果插件没有返回图标的显示则获取插件的itemWidget
QHBoxLayout *mainLayout = new QHBoxLayout(this);
itemWidget->setParent(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->addWidget(itemWidget);
itemWidget->setVisible(true);
} else {
// 如果插件获取到插件区域的图标,则让其按照图标来组合显示
// 如果是占用两排的插件则用横向Layout
QHBoxLayout *mainLayout = new QHBoxLayout(this);
mainLayout->setContentsMargins(10, 0, 10, 0);
mainLayout->setSpacing(0);
mainLayout->addStretch(10);
mainLayout->setAlignment(Qt::AlignCenter);
// 添加图标
QWidget *iconWidgetParent = new QWidget(this);
QVBoxLayout *iconLayout = new QVBoxLayout(iconWidgetParent);
iconLayout->setContentsMargins(0, 0, 0, 0);
iconLayout->setSpacing(0);
iconLayout->setAlignment(Qt::AlignCenter);
m_iconWidget = new QuickIconWidget(pluginItem(), itemKey(), iconWidgetParent);
m_iconWidget->setFixedSize(BGSIZE, BGSIZE);
iconLayout->addWidget(m_iconWidget);
mainLayout->addWidget(iconWidgetParent);
mainLayout->addSpacing(10);
// 添加中间的名称部分
QWidget *textWidget = new QWidget(this);
m_nameLabel = new QLabel(textWidget);
m_stateLabel = new QLabel(textWidget);
m_nameLabel->setObjectName("nameLabel");
m_stateLabel->setObjectName("stateLabel");
// 设置图标和文字的属性
QFont nameFont = DFontSizeManager::instance()->t6();
nameFont.setBold(true);
QPalette pe;
pe.setColor(QPalette::WindowText, Qt::black);
m_nameLabel->setPalette(pe);
m_stateLabel->setPalette(pe);
m_nameLabel->setFont(nameFont);
m_stateLabel->setFont(DFontSizeManager::instance()->t10());
m_nameLabel->setText(pluginItem()->pluginDisplayName());
m_stateLabel->setText(pluginItem()->description());
m_nameLabel->installEventFilter(this);
m_stateLabel->installEventFilter(this);
QVBoxLayout *textLayout = new QVBoxLayout(textWidget);
textLayout->setContentsMargins(0, 0, 0, 0);
textLayout->setSpacing(0);
textLayout->addWidget(m_nameLabel);
textLayout->addWidget(m_stateLabel);
textLayout->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
mainLayout->addWidget(textWidget);
// 添加右侧的展开按钮
QWidget *expandWidgetParent = new QWidget(this);
QVBoxLayout *expandLayout = new QVBoxLayout(expandWidgetParent);
expandLayout->setSpacing(0);
QLabel *expandLabel = new QLabel(expandWidgetParent);
expandLabel->setObjectName("expandLabel");
expandLabel->setPixmap(QPixmap(expandFileName()));
expandLabel->setFixedSize(expandSize);
expandLabel->setAutoFillBackground(true);
expandLabel->installEventFilter(this);
expandLayout->addWidget(expandLabel);
pe.setBrush(QPalette::Window, Qt::transparent);
expandLabel->setPalette(pe);
mainLayout->addWidget(expandWidgetParent);
}
}
QString LargerQuickItem::expandFileName() const
{
if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType)
return QString(":/icons/resources/arrow-right-dark.svg");
return QString(":/icons/resources/arrow-right.svg");
}
/**
* @brief QuickIconWidget::QuickIconWidget
* @param pluginInter
* @param parent
* widget
*/
QuickIconWidget::QuickIconWidget(PluginsItemInterface *pluginInter, const QString &itemKey, QWidget *parent)
: QWidget(parent)
, m_pluginInter(pluginInter)
, m_itemKey(itemKey)
{
}
void QuickIconWidget::paintEvent(QPaintEvent *event)
{
QPixmap pixmapIcon = pluginIcon();
if (pixmapIcon.isNull())
return QWidget::paintEvent(event);
pixmapIcon = pluginIcon(true);
QPainter painter(this);
painter.setRenderHint(QPainter::RenderHint::Antialiasing);
painter.setPen(foregroundColor());
DPalette dpa = DPaletteHelper::instance()->palette(this);
QPainter pa(&pixmapIcon);
pa.setCompositionMode(QPainter::CompositionMode_SourceIn);
pa.fillRect(pixmapIcon.rect(), painter.pen().brush());
// 如果是主图标,则显示阴影背景
painter.save();
painter.setPen(Qt::NoPen);
painter.setBrush(dpa.brush(DPalette::ColorRole::Midlight));
painter.drawEllipse(rect());
painter.restore();
QRect rctIcon((rect().width() - pixmapIcon.width()) / 2, (rect().height() - pixmapIcon.height()) / 2, pixmapIcon.width(), pixmapIcon.height());
painter.drawPixmap(rctIcon, pixmapIcon);
}
QColor QuickIconWidget::foregroundColor() const
{
DPalette dpa = DPaletteHelper::instance()->palette(this);
// TODO 此处的颜色是临时获取的,后期需要和设计师确认,改成正规的颜色
if (m_pluginInter->status() == PluginsItemInterface::PluginMode::Active)
return dpa.color(DPalette::ColorGroup::Active, DPalette::ColorRole::Text);
if (m_pluginInter->status() == PluginsItemInterface::PluginMode::Deactive)
return dpa.color(DPalette::ColorGroup::Disabled, DPalette::ColorRole::Text);
return dpa.color(DPalette::ColorGroup::Normal, DPalette::ColorRole::Text);
}
QPixmap QuickIconWidget::pluginIcon(bool contailGrab) const
{
QIcon icon = m_pluginInter->icon(DockPart::QuickPanel);
if (icon.isNull() && contailGrab) {
// 如果图标为空就使用itemWidget的截图作为它的图标这种一般是适用于老版本插件或者没有实现v23接口的插件
QWidget *itemWidget = m_pluginInter->itemWidget(m_itemKey);
if (itemWidget) {
itemWidget->setFixedSize(ICONWIDTH, ICONHEIGHT);
return itemWidget->grab();
}
return QPixmap();
}
// 获取icon接口返回的图标
int pixmapWidth = width();
int pixmapHeight = height();
QList<QSize> iconSizes = icon.availableSizes();
if (iconSizes.size() > 0) {
QSize size = iconSizes[0];
if (size.isValid() && !size.isEmpty() && !size.isNull()) {
pixmapWidth = size.width();
pixmapHeight = size.height();
}
}
return icon.pixmap(pixmapWidth, pixmapHeight);
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef LARGERQUICKITEM_H
#define LARGERQUICKITEM_H
#include <quicksettingitem.h>
class QuickIconWidget;
class QWidget;
class QLabel;
// 插件在快捷面板中的展示样式,这个为大图标,展示为两列的那种,例如网络和蓝牙
class LargerQuickItem : public QuickSettingItem
{
Q_OBJECT
public:
LargerQuickItem(PluginsItemInterface *const pluginInter, const QString &itemKey, QWidget *parent = nullptr);
~LargerQuickItem() override;
void doUpdate() override;
void detachPlugin() override;
QuickItemStyle type() const override;
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
void showEvent(QShowEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
private:
void initUi();
QString expandFileName() const;
private:
QuickIconWidget *m_iconWidget;
QLabel *m_nameLabel;
QLabel *m_stateLabel;
QWidget *m_itemWidgetParent;
};
/**
* @brief The QuickIconWidget class
* Widget
*/
class QuickIconWidget : public QWidget
{
Q_OBJECT
public:
explicit QuickIconWidget(PluginsItemInterface *pluginInter, const QString &itemKey, QWidget *parent = Q_NULLPTR);
protected:
void paintEvent(QPaintEvent *event) override;
private:
QColor foregroundColor() const;
QPixmap pluginIcon(bool contailGrab = false) const;
private:
PluginsItemInterface *m_pluginInter;
QString m_itemKey;
};
#endif // MULTIQUICKITEM_H

View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "linequickitem.h"
#include "pluginsiteminterface.h"
#include <DBlurEffectWidget>
#include <QHBoxLayout>
DWIDGET_USE_NAMESPACE
LineQuickItem::LineQuickItem(PluginsItemInterface *const pluginInter, const QString &itemKey, QWidget *parent)
: QuickSettingItem(pluginInter, itemKey, parent)
, m_centerWidget(pluginInter->itemWidget(QUICK_ITEM_KEY))
, m_centerParentWidget(nullptr)
, m_effectWidget(new DBlurEffectWidget(this))
{
initUi();
QMetaObject::invokeMethod(this, &LineQuickItem::resizeSelf, Qt::QueuedConnection);
}
LineQuickItem::~LineQuickItem()
{
if (m_centerWidget)
m_centerWidget->setParent(nullptr);
}
void LineQuickItem::doUpdate()
{
if (m_centerWidget)
m_centerWidget->update();
}
void LineQuickItem::detachPlugin()
{
if (m_centerWidget)
m_centerWidget->setParent(m_centerParentWidget);
}
QuickSettingItem::QuickItemStyle LineQuickItem::type() const
{
return QuickSettingItem::QuickItemStyle::Line;
}
bool LineQuickItem::eventFilter(QObject *obj, QEvent *event)
{
if (obj == m_centerWidget && event->type() == QEvent::Resize)
resizeSelf();
return QuickSettingItem::eventFilter(obj, event);
}
void LineQuickItem::initUi()
{
QColor maskColor(Qt::white);
maskColor.setAlphaF(0.8);
m_effectWidget->setMaskColor(maskColor);
m_effectWidget->setBlurRectXRadius(8);
m_effectWidget->setBlurRectYRadius(8);
// 如果图标不为空
if (!m_centerWidget)
return;
m_centerWidget->setVisible(true);
m_centerParentWidget = m_centerWidget->parentWidget();
QHBoxLayout *layout = new QHBoxLayout(m_effectWidget);
layout->setContentsMargins(0, 0, 0, 0);
layout->setAlignment(Qt::AlignHCenter);
layout->addWidget(m_centerWidget);
QHBoxLayout *mainLayout = new QHBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->addWidget(m_effectWidget);
m_centerWidget->installEventFilter(this);
}
void LineQuickItem::resizeSelf()
{
if (!m_centerWidget)
return;
m_effectWidget->setFixedHeight(m_centerWidget->height());
setFixedHeight(m_centerWidget->height());
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef LINEQUICKITEM_H
#define LINEQUICKITEM_H
#include "quicksettingitem.h"
namespace Dtk {
namespace Widget {
class DBlurEffectWidget;
}
}
// 插件在快捷面板中的展示的样式,这个为整行显示的插件,例如声音,亮度调整和音乐播放等
class LineQuickItem : public QuickSettingItem
{
Q_OBJECT
public:
LineQuickItem(PluginsItemInterface *const pluginInter, const QString &itemKey, QWidget *parent = nullptr);
~LineQuickItem() override;
void doUpdate() override;
void detachPlugin() override;
QuickItemStyle type() const override;
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
private:
void initUi();
void resizeSelf();
private:
QWidget *m_centerWidget;
QWidget *m_centerParentWidget;
Dtk::Widget::DBlurEffectWidget *m_effectWidget;
};
#endif // FULLQUICKITEM_H

View File

@ -0,0 +1,209 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "pluginadapter.h"
#include <QWidget>
#define ICONWIDTH 24
#define ICONHEIGHT 24
PluginAdapter::PluginAdapter(PluginsItemInterface_V20 *pluginInter, QPluginLoader *pluginLoader)
: m_pluginInter(pluginInter)
, m_pluginLoader(pluginLoader)
{
}
PluginAdapter::~PluginAdapter()
{
delete m_pluginInter;
}
const QString PluginAdapter::pluginName() const
{
return m_pluginInter->pluginName();
}
const QString PluginAdapter::pluginDisplayName() const
{
return m_pluginInter->pluginDisplayName();
}
void PluginAdapter::init(PluginProxyInterface *proxyInter)
{
m_pluginInter->init(proxyInter);
}
QWidget *PluginAdapter::itemWidget(const QString &itemKey)
{
return m_pluginInter->itemWidget(itemKey);
}
QWidget *PluginAdapter::itemTipsWidget(const QString &itemKey)
{
return m_pluginInter->itemTipsWidget(itemKey);
}
QWidget *PluginAdapter::itemPopupApplet(const QString &itemKey)
{
return m_pluginInter->itemPopupApplet(itemKey);
}
const QString PluginAdapter::itemCommand(const QString &itemKey)
{
return m_pluginInter->itemCommand(itemKey);
}
const QString PluginAdapter::itemContextMenu(const QString &itemKey)
{
return m_pluginInter->itemContextMenu(itemKey);
}
void PluginAdapter::invokedMenuItem(const QString &itemKey, const QString &menuId, const bool checked)
{
m_pluginInter->invokedMenuItem(itemKey, menuId, checked);
}
int PluginAdapter::itemSortKey(const QString &itemKey)
{
return m_pluginInter->itemSortKey(itemKey);
}
void PluginAdapter::setSortKey(const QString &itemKey, const int order)
{
m_pluginInter->setSortKey(itemKey, order);
}
bool PluginAdapter::itemAllowContainer(const QString &itemKey)
{
return m_pluginInter->itemAllowContainer(itemKey);
}
bool PluginAdapter::itemIsInContainer(const QString &itemKey)
{
return m_pluginInter->itemIsInContainer(itemKey);
}
void PluginAdapter::setItemIsInContainer(const QString &itemKey, const bool container)
{
m_pluginInter->setItemIsInContainer(itemKey, container);
}
bool PluginAdapter::pluginIsAllowDisable()
{
return m_pluginInter->pluginIsAllowDisable();
}
bool PluginAdapter::pluginIsDisable()
{
return m_pluginInter->pluginIsDisable();
}
void PluginAdapter::pluginStateSwitched()
{
m_pluginInter->pluginStateSwitched();
}
void PluginAdapter::displayModeChanged(const Dock::DisplayMode displayMode)
{
m_pluginInter->displayModeChanged(displayMode);
}
void PluginAdapter::positionChanged(const Dock::Position position)
{
m_pluginInter->positionChanged(position);
}
void PluginAdapter::refreshIcon(const QString &itemKey)
{
m_pluginInter->refreshIcon(itemKey);
}
void PluginAdapter::pluginSettingsChanged()
{
m_pluginInter->pluginSettingsChanged();
}
PluginsItemInterface::PluginType PluginAdapter::type()
{
switch (m_pluginInter->type()) {
case PluginsItemInterface_V20::PluginType::Fixed:
return PluginsItemInterface::PluginType::Fixed;
case PluginsItemInterface_V20::PluginType::Normal:
return PluginsItemInterface::PluginType::Normal;
}
return PluginsItemInterface::PluginType::Normal;
}
PluginsItemInterface::PluginSizePolicy PluginAdapter::pluginSizePolicy() const
{
switch (m_pluginInter->pluginSizePolicy()) {
case PluginsItemInterface_V20::PluginSizePolicy::Custom:
return PluginsItemInterface::PluginSizePolicy::Custom;
case PluginsItemInterface_V20::PluginSizePolicy::System:
return PluginsItemInterface::PluginSizePolicy::System;
}
return PluginsItemInterface::PluginSizePolicy::Custom;
}
QIcon PluginAdapter::icon(const DockPart &dockPart, DGuiApplicationHelper::ColorType themeType)
{
QWidget *itemWidget = m_pluginInter->itemWidget(m_itemKey);
if (!itemWidget)
return QIcon();
switch (dockPart) {
case DockPart::QuickPanel:
case DockPart::SystemPanel: {
// 如果图标为空就使用itemWidget的截图作为它的图标这种一般是适用于老版本插件或者没有实现v23接口的插件
QSize oldSize = itemWidget->size();
itemWidget->setFixedSize(ICONWIDTH, ICONHEIGHT);
QPixmap pixmap = itemWidget->grab();
itemWidget->setFixedSize(oldSize);
return pixmap;
}
default: break;
}
return QIcon();
}
PluginsItemInterface::PluginMode PluginAdapter::status() const
{
return PluginMode::Active;
}
QString PluginAdapter::description() const
{
return m_pluginInter->pluginDisplayName();
}
PluginFlags PluginAdapter::flags() const
{
if (m_pluginLoader->fileName().contains(TRAY_PATH))
return PluginFlag::Type_Tray | PluginFlag::Attribute_CanDrag | PluginFlag::Attribute_CanInsert;
return PluginsItemInterface::flags();
}
void PluginAdapter::setItemKey(const QString &itemKey)
{
m_itemKey = itemKey;
}

View File

@ -0,0 +1,81 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PLUGINADAPTER_H
#define PLUGINADAPTER_H
#include "pluginsiteminterface.h"
#include "pluginsiteminterface_v20.h"
#include <QObject>
/** 适配器当加载到v20插件的时候通过该接口来转成v23接口的插件
* @brief The PluginAdapter class
*/
class PluginAdapter : public QObject, public PluginsItemInterface
{
Q_OBJECT
Q_INTERFACES(PluginsItemInterface)
public:
PluginAdapter(PluginsItemInterface_V20 *pluginInter, QPluginLoader *pluginLoader);
~PluginAdapter();
const QString pluginName() const override;
const QString pluginDisplayName() const override;
void init(PluginProxyInterface *proxyInter) override;
QWidget *itemWidget(const QString &itemKey) override;
QWidget *itemTipsWidget(const QString &itemKey) override;
QWidget *itemPopupApplet(const QString &itemKey) override;
const QString itemCommand(const QString &itemKey) override;
const QString itemContextMenu(const QString &itemKey) override;
void invokedMenuItem(const QString &itemKey, const QString &menuId, const bool checked) override;
int itemSortKey(const QString &itemKey) override;
void setSortKey(const QString &itemKey, const int order) override;
bool itemAllowContainer(const QString &itemKey) override;
bool itemIsInContainer(const QString &itemKey) override;
void setItemIsInContainer(const QString &itemKey, const bool container) override;
bool pluginIsAllowDisable() override;
bool pluginIsDisable() override;
void pluginStateSwitched() override;
void displayModeChanged(const Dock::DisplayMode displayMode) override;
void positionChanged(const Dock::Position position) override;
void refreshIcon(const QString &itemKey) override;
void pluginSettingsChanged() override;
PluginType type() override;
PluginSizePolicy pluginSizePolicy() const override;
QIcon icon(const DockPart &dockPart, DGuiApplicationHelper::ColorType themeType = DGuiApplicationHelper::instance()->themeType()) override;
PluginMode status() const override;
QString description() const override;
PluginFlags flags() const override;
void setItemKey(const QString &itemKey);
private:
PluginsItemInterface_V20 *m_pluginInter;
QString m_itemKey;
QPluginLoader *m_pluginLoader;
};
#endif // PLUGINADAPTER_H

View File

@ -0,0 +1,261 @@
/*
* Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PLUGINSITEMINTERFACE_V20_H
#define PLUGINSITEMINTERFACE_V20_H
#include "pluginproxyinterface.h"
#include <QIcon>
#include <QtCore>
///
/// \brief The PluginsItemInterface_V20 class
/// the dock plugins item interface, all dock plugins should
/// inheirt this class and override all pure virtual function.
///
class PluginsItemInterface_V20
{
public:
enum PluginType {
Normal,
Fixed
};
/**
* @brief Plugin size policy
*/
enum PluginSizePolicy {
System = 1 << 0, // Follow the system
Custom = 1 << 1 // The custom
};
///
/// \brief ~PluginsItemInterface_V20
/// DON'T try to delete m_proxyInter.
///
virtual ~PluginsItemInterface_V20() {}
///
/// \brief pluginName
/// tell dock the unique plugin id
/// \return
///
virtual const QString pluginName() const = 0;
virtual const QString pluginDisplayName() const { return QString(); }
///
/// \brief init
/// init your plugins, you need to save proxyInter to m_proxyInter
/// member variable. but you shouldn't free this pointer.
/// \param proxyInter
/// DON'T try to delete this pointer.
///
virtual void init(PluginProxyInterface *proxyInter) = 0;
///
/// \brief itemWidget
/// your plugin item widget, each item should have a unique key.
/// \param itemKey
/// your widget' unqiue key.
/// \return
///
virtual QWidget *itemWidget(const QString &itemKey) = 0;
///
/// \brief itemTipsWidget
/// override this function if your item want to have a tips.
/// the tips will shown when user hover your item.
/// nullptr will be ignored.
/// \param itemKey
/// \return
///
virtual QWidget *itemTipsWidget(const QString &itemKey) {Q_UNUSED(itemKey); return nullptr;}
///
/// \brief itemPopupApplet
/// override this function if your item wants to have an popup applet.
/// the popup applet will shown when user click your item.
///
/// Tips:
/// dock should receive mouse press/release event to check user mouse operate,
/// if your item filter mouse event, this function will not be called.
/// so if you override mouse event and want to use popup applet, you
/// should pass event to your parent use QWidget::someEvent(e);
/// \param itemKey
/// \return
///
virtual QWidget *itemPopupApplet(const QString &itemKey) {Q_UNUSED(itemKey); return nullptr;}
///
/// \brief itemCommand
/// execute spec command when user clicked your item.
/// ensure your command do not get user input.
///
/// empty string will be ignored.
/// \param itemKey
/// \return
///
virtual const QString itemCommand(const QString &itemKey) {Q_UNUSED(itemKey); return QString();}
///
/// \brief itemContextMenu
/// context menu is shown when RequestPopupMenu called.
/// \param itemKey
/// \return
///
virtual const QString itemContextMenu(const QString &itemKey) {Q_UNUSED(itemKey); return QString();}
///
/// \brief invokedMenuItem
/// call if context menu item is clicked
/// \param itemKey
/// \param itemId
/// menu item id
/// \param checked
///
virtual void invokedMenuItem(const QString &itemKey, const QString &menuId, const bool checked) {Q_UNUSED(itemKey); Q_UNUSED(menuId); Q_UNUSED(checked);}
///
/// \brief itemSortKey
/// tell dock where your item wants to put on.
///
/// this index is start from 1 and
/// 0 for left side
/// -1 for right side
/// \param itemKey
/// \return
///
virtual int itemSortKey(const QString &itemKey) {Q_UNUSED(itemKey); return 1;}
///
/// \brief setSortKey
/// save your item new position
/// sort key will be changed when plugins order
/// changed(by user drag-drop)
/// \param itemKey
/// \param order
///
virtual void setSortKey(const QString &itemKey, const int order) {Q_UNUSED(itemKey); Q_UNUSED(order);}
///
/// \brief itemAllowContainer
/// tell dock is your item allow to move into container
///
/// if your item placed into container, popup tips and popup
/// applet will be disabled.
/// \param itemKey
/// \return
///
virtual bool itemAllowContainer(const QString &itemKey) {Q_UNUSED(itemKey); return false;}
///
/// \brief itemIsInContainer
/// tell dock your item is in container, this function
/// called at item init and if your item enable container.
/// \param itemKey
/// \return
///
virtual bool itemIsInContainer(const QString &itemKey) {Q_UNUSED(itemKey); return false;}
///
/// \brief setItemIsInContainer
/// save your item new state.
/// this function called when user drag out your item from
/// container or user drop item into container(if your item
/// allow drop into container).
/// \param itemKey
/// \param container
///
virtual void setItemIsInContainer(const QString &itemKey, const bool container) {Q_UNUSED(itemKey); Q_UNUSED(container);}
virtual bool pluginIsAllowDisable() { return false; }
virtual bool pluginIsDisable() { return false; }
virtual void pluginStateSwitched() {}
///
/// \brief displayModeChanged
/// override this function to receive display mode changed signal
/// \param displayMode
///
virtual void displayModeChanged(const Dock::DisplayMode displayMode) {Q_UNUSED(displayMode);}
///
/// \brief positionChanged
/// override this function to receive dock position changed signal
/// \param position
///
virtual void positionChanged(const Dock::Position position) {Q_UNUSED(position);}
///
/// \brief refreshIcon
/// refresh item icon, its triggered when system icon theme changed.
/// \param itemKey
/// item key
///
virtual void refreshIcon(const QString &itemKey) { Q_UNUSED(itemKey); }
///
/// \brief displayMode
/// get current dock display mode
/// \return
///
inline Dock::DisplayMode displayMode() const
{
return qApp->property(PROP_DISPLAY_MODE).value<Dock::DisplayMode>();
}
///
/// \brief position
/// get current dock position
/// \return
///
inline Dock::Position position() const
{
return qApp->property(PROP_POSITION).value<Dock::Position>();
}
///
/// \brief settingsChanged
/// override this function to receive plugin settings changed signal(DeepinSync)
///
virtual void pluginSettingsChanged() {}
///
/// \brief type
/// default plugin add dock right,fixed plugin add to dock fixed area
///
virtual PluginType type() { return Normal; }
///
/// \brief plugin size policy
/// default plugin size policy
///
virtual PluginSizePolicy pluginSizePolicy() const { return System; }
protected:
///
/// \brief m_proxyInter
/// NEVER delete this object.
///
PluginProxyInterface *m_proxyInter = nullptr;
};
QT_BEGIN_NAMESPACE
#define ModuleInterfaceV20_iid "com.deepin.dock.PluginsItemInterface"
Q_DECLARE_INTERFACE(PluginsItemInterface_V20, ModuleInterfaceV20_iid)
QT_END_NAMESPACE
#endif // PLUGINSITEMINTERFACE_H

View File

@ -0,0 +1,146 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "pluginchildpage.h"
#include <DStyle>
#include <DGuiApplicationHelper>
#include <QLabel>
#include <QVBoxLayout>
#include <QEvent>
#include <QPainterPath>
#include <QPushButton>
DWIDGET_USE_NAMESPACE
DGUI_USE_NAMESPACE
PluginChildPage::PluginChildPage(QWidget *parent)
: QWidget(parent)
, m_headerWidget(new QWidget(this))
, m_back(new QPushButton(m_headerWidget))
, m_title(new QLabel(m_headerWidget))
, m_container(new QWidget(this))
, m_topWidget(nullptr)
, m_containerLayout(new QVBoxLayout(m_container))
{
initUi();
initConnection();
}
PluginChildPage::~PluginChildPage()
{
}
void PluginChildPage::pushWidget(QWidget *widget)
{
// 首先将界面其他的窗体移除
for (int i = m_containerLayout->count() - 1; i >= 0; i--) {
QLayoutItem *item = m_containerLayout->itemAt(i);
item->widget()->removeEventFilter(this);
item->widget()->hide();
m_containerLayout->removeItem(item);
}
m_topWidget = widget;
if (widget) {
widget->installEventFilter(this);
m_containerLayout->addWidget(widget);
widget->show();
}
QMetaObject::invokeMethod(this, &PluginChildPage::resetHeight, Qt::QueuedConnection);
}
void PluginChildPage::setTitle(const QString &text)
{
m_title->setText(text);
}
void PluginChildPage::initUi()
{
m_back->setIcon(backPixmap());
m_back->setFixedWidth(24);
m_back->setFlat(true);
m_title->setAlignment(Qt::AlignCenter);
QHBoxLayout *headerLayout = new QHBoxLayout(m_headerWidget);
headerLayout->setContentsMargins(11, 12, 24 + 11, 12);
headerLayout->setSpacing(0);
headerLayout->addWidget(m_back);
headerLayout->addWidget(m_title);
m_headerWidget->setFixedHeight(48);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSpacing(0);
mainLayout->addWidget(m_headerWidget);
mainLayout->addWidget(m_container);
m_containerLayout->setContentsMargins(11, 0, 11, 0);
m_containerLayout->setSpacing(0);
}
void PluginChildPage::initConnection()
{
connect(m_back, &QPushButton::clicked, this, &PluginChildPage::back);
}
bool PluginChildPage::eventFilter(QObject *watched, QEvent *event)
{
if (watched == m_topWidget && event->type() == QEvent::Resize) {
resetHeight();
}
return QWidget::eventFilter(watched, event);
}
void PluginChildPage::resetHeight()
{
QMargins m = m_containerLayout->contentsMargins();
m_container->setFixedHeight(m.top() + m.bottom() + (m_topWidget ? m_topWidget->height() : 0));
setFixedHeight(m_headerWidget->height() + m_container->height());
}
QPixmap PluginChildPage::backPixmap() const
{
QPixmap pixmap(16, 16);
pixmap.fill(Qt::transparent);
// 设置背景色
QColor backColor;
if (DGuiApplicationHelper::ColorType::DarkType == DGuiApplicationHelper::instance()->themeType()) {
backColor = Qt::black;
backColor.setAlphaF(0.05);
} else {
backColor = Qt::white;
backColor.setAlphaF(0.2);
}
QPainter painter(&pixmap);
painter.setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
QPainterPath path;
path.addEllipse(pixmap.rect());
painter.fillPath(path, backColor);
QSize arrowSize(10, 10);
QPixmap arrowPixmap = DStyle::standardIcon(style(), DStyle::SP_ArrowLeave).pixmap(arrowSize);
// 让其居中显示
QSize backSize = pixmap.size();
painter.drawPixmap((backSize.width() - arrowSize.width()) / 2, (backSize.height() - arrowSize.height()) / 2,
arrowSize.width(), arrowSize.height(), arrowPixmap);
painter.end();
return pixmap;
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PLUGINCHILDPAGE_H
#define PLUGINCHILDPAGE_H
#include <QWidget>
class QPushButton;
class QLabel;
class QVBoxLayout;
class PluginChildPage : public QWidget
{
Q_OBJECT
public:
explicit PluginChildPage(QWidget *parent);
~PluginChildPage() override;
void pushWidget(QWidget *widget);
void setTitle(const QString &text);
Q_SIGNALS:
void back();
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
private:
void initUi();
void initConnection();
void resetHeight();
QPixmap backPixmap() const;
private:
QWidget *m_headerWidget;
QPushButton *m_back;
QLabel *m_title;
QWidget *m_container;
QWidget *m_topWidget;
QVBoxLayout *m_containerLayout;
};
#endif // PLUGINCHILDPAGE_H

View File

@ -0,0 +1,195 @@
/*
* Copyright (C) 2023 ~ 2023 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "pluginmanager.h"
#include "dockplugincontroller.h"
#include "quicksettingcontainer.h"
#include "iconmanager.h"
#include <QResizeEvent>
PluginManager::PluginManager(QObject *parent)
: m_dockController(nullptr)
, m_iconManager(nullptr)
{
}
const QString PluginManager::pluginName() const
{
return "pluginManager";
}
const QString PluginManager::pluginDisplayName() const
{
return "pluginManager";
}
void PluginManager::init(PluginProxyInterface *proxyInter)
{
if (m_proxyInter == proxyInter)
return;
m_proxyInter = proxyInter;
m_dockController.reset(new DockPluginController(proxyInter));
m_quickContainer.reset(new QuickSettingContainer(m_dockController.data()));
m_iconManager.reset(new IconManager(m_dockController.data()));
m_iconManager->setPosition(position());
connect(m_dockController.data(), &DockPluginController::pluginInserted, this, [ this ](PluginsItemInterface *itemInter) {
if (m_iconManager->isFixedPlugin(itemInter)) {
m_proxyInter->itemUpdate(this, pluginName());
}
});
connect(m_dockController.data(), &DockPluginController::pluginUpdated, this, [ this ](PluginsItemInterface *itemInter) {
if (m_iconManager->isFixedPlugin(itemInter)) {
m_proxyInter->itemUpdate(this, pluginName());
}
});
connect(m_dockController.data(), &DockPluginController::pluginRemoved, this, [ this ](PluginsItemInterface *itemInter) {
if (m_iconManager->isFixedPlugin(itemInter)) {
m_proxyInter->itemUpdate(this, pluginName());
}
});
connect(m_dockController.data(), &DockPluginController::requestAppletVisible, this, [ this ](PluginsItemInterface *itemInter, const QString &itemKey, bool visible) {
if (visible) {
QWidget *appletWidget = itemInter->itemPopupApplet(itemKey);
if (appletWidget)
m_quickContainer->showPage(appletWidget, itemInter);
} else {
// 显示主面板
m_quickContainer->topLevelWidget()->hide();
}
});
connect(m_dockController.data(), &DockPluginController::pluginLoadFinished, this, &PluginManager::pluginLoadFinished);
// 开始加载插件
m_dockController->startLoadPlugin(getPluginPaths());
m_proxyInter->itemAdded(this, pluginName());
}
QWidget *PluginManager::itemWidget(const QString &itemKey)
{
Q_UNUSED(itemKey);
return nullptr;
}
QWidget *PluginManager::itemPopupApplet(const QString &itemKey)
{
if (itemKey == QUICK_ITEM_KEY) {
// 返回快捷面板
return m_quickContainer.data();
}
return nullptr;
}
QIcon PluginManager::icon(const DockPart &dockPart, DGuiApplicationHelper::ColorType themeType)
{
if (dockPart == DockPart::QuickShow) {
return m_iconManager->pixmap();
}
return QIcon();
}
PluginFlags PluginManager::flags() const
{
// 当前快捷插件组合区域只支持在快捷区域显示
return PluginFlag::Type_Common | PluginFlag::Attribute_ForceDock;
}
PluginsItemInterface::PluginSizePolicy PluginManager::pluginSizePolicy() const
{
return PluginSizePolicy::Custom;
}
bool PluginManager::eventHandler(QEvent *event)
{
if (event->type() == QEvent::Resize) {
QResizeEvent *resizeEvent = static_cast<QResizeEvent *>(event);
m_iconManager->updateSize(resizeEvent->size());
}
return PluginsItemInterface::eventHandler(event);
}
void PluginManager::positionChanged(const Dock::Position position)
{
m_iconManager->setPosition(position);
m_proxyInter->itemUpdate(this, pluginName());
}
QList<PluginsItemInterface *> PluginManager::plugins() const
{
return m_dockController->plugins();
}
QList<PluginsItemInterface *> PluginManager::pluginsInSetting() const
{
return m_dockController->pluginsInSetting();
}
QList<PluginsItemInterface *> PluginManager::currentPlugins() const
{
return m_dockController->currentPlugins();
}
QString PluginManager::itemKey(PluginsItemInterface *itemInter) const
{
return m_dockController->itemKey(itemInter);
}
QJsonObject PluginManager::metaData(PluginsItemInterface *itemInter) const
{
return m_dockController->metaData(itemInter);
}
#ifndef QT_DEBUG
static QStringList getPathFromConf(const QString &key) {
QSettings set("/etc/deepin/dde-dock.conf", QSettings::IniFormat);
auto value = set.value(key).toString();
if (!value.isEmpty()) {
return value.split(':');
}
return QStringList();
}
#endif
QStringList PluginManager::getPluginPaths() const
{
QStringList pluginPaths;
#ifdef QT_DEBUG
pluginPaths << QString("%1/..%2").arg(qApp->applicationDirPath()).arg(QUICK_PATH)
<< QString("%1/..%2").arg(qApp->applicationDirPath()).arg(PLUGIN_PATH)
<< QString("%1/..%2").arg(qApp->applicationDirPath()).arg(TRAY_PATH);
#else
pluginPaths << QString("/usr/lib/dde-dock%1").arg(QUICK_PATH)
<< QString("/usr/lib/dde-dock%1").arg(PLUGIN_PATH)
<< QString("/usr/lib/dde-dock%1").arg(TRAY_PATH);
const QStringList pluginsDirs = (getPathFromConf("PATH") << getPathFromConf("SYSTEM_TRAY_PATH"));
if (!pluginsDirs.isEmpty())
pluginPaths << pluginsDirs;
#endif
return pluginPaths;
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2023 ~ 2023 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PLUGINMANAGER_H
#define PLUGINMANAGER_H
#include "pluginsiteminterface.h"
#include "pluginmanagerinterface.h"
#include <QObject>
class DockPluginController;
class QuickSettingContainer;
class IconManager;
class PluginManager : public PluginManagerInterface, public PluginsItemInterface
{
Q_OBJECT
Q_INTERFACES(PluginsItemInterface)
Q_PLUGIN_METADATA(IID "com.deepin.dock.PluginsItemInterface" FILE "pluginmanager.json")
public:
explicit PluginManager(QObject *parent = nullptr);
const QString pluginName() const override;
const QString pluginDisplayName() const override;
void init(PluginProxyInterface *proxyInter) override;
QWidget *itemWidget(const QString &itemKey) override;
QWidget *itemPopupApplet(const QString &itemKey) override;
QIcon icon(const DockPart &dockPart, DGuiApplicationHelper::ColorType themeType) override;
PluginFlags flags() const override;
PluginSizePolicy pluginSizePolicy() const override;
protected:
bool eventHandler(QEvent *event) override;
void positionChanged(const Dock::Position position) override;
protected:
// 实现PluginManagerInterface接口用于向dock提供所有已经加载的插件
QList<PluginsItemInterface *> plugins() const override;
QList<PluginsItemInterface *> pluginsInSetting() const override;
QList<PluginsItemInterface *> currentPlugins() const override;
QString itemKey(PluginsItemInterface *itemInter) const override;
QJsonObject metaData(PluginsItemInterface *itemInter) const override;
private:
QStringList getPluginPaths() const;
private:
QSharedPointer<DockPluginController> m_dockController;
QSharedPointer<QuickSettingContainer> m_quickContainer;
QSharedPointer<IconManager> m_iconManager;
};
#endif // PLUGINMANAGER_H

View File

@ -0,0 +1,4 @@
{
"api": "2.0.0",
"order":0
}

View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>resources/dock_control.dci</file>
</qresource>
</RCC>

View File

@ -0,0 +1,415 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "quicksettingcontainer.h"
#include "dockplugincontroller.h"
#include "pluginsiteminterface.h"
#include "quicksettingitem.h"
#include "pluginchildpage.h"
#include "utils.h"
#include "quickdragcore.h"
#include <DListView>
#include <DStyle>
#include <QDrag>
#include <QVBoxLayout>
#include <QMetaObject>
#include <QStackedLayout>
#include <QMouseEvent>
#include <QLabel>
#include <QBitmap>
#include <QPainterPath>
DWIDGET_USE_NAMESPACE
struct QuickDragInfo {
QPoint dragPosition;
QWidget *dragItem = nullptr;
PluginsItemInterface *pluginInter = nullptr;
void reset() {
dragPosition.setX(0);
dragPosition.setY(0);
dragItem = nullptr;
pluginInter = nullptr;
}
bool isNull() {
return !dragItem;
}
} QuickDragInfo;
#define ITEMWIDTH 70
#define ITEMHEIGHT 60
#define ITEMSPACE 10
#define COLUMNCOUNT 4
QuickSettingContainer::QuickSettingContainer(DockPluginController *pluginController, QWidget *parent)
: QWidget(parent)
, m_switchLayout(new QStackedLayout(this))
, m_mainWidget(new QWidget(this))
, m_pluginWidget(new QWidget(m_mainWidget))
, m_pluginLayout(new QGridLayout(m_pluginWidget))
, m_componentWidget(new QWidget(m_mainWidget))
, m_mainlayout(new QVBoxLayout(m_mainWidget))
, m_pluginController(pluginController)
, m_childPage(new PluginChildPage(this))
, m_dragInfo(new struct QuickDragInfo)
, m_childShowPlugin(nullptr)
{
initUi();
initConnection();
m_childPage->installEventFilter(this);
setMouseTracking(true);
}
QuickSettingContainer::~QuickSettingContainer()
{
delete m_dragInfo;
}
void QuickSettingContainer::showPage(QWidget *widget, PluginsItemInterface *pluginInter)
{
if (widget && pluginInter && widget != m_mainWidget) {
m_childShowPlugin = pluginInter;
m_childPage->setTitle(pluginInter->pluginDisplayName());
m_childPage->pushWidget(widget);
m_switchLayout->setCurrentWidget(m_childPage);
} else {
m_childShowPlugin = nullptr;
m_switchLayout->setCurrentIndex(0);
}
onResizeView();
}
bool QuickSettingContainer::eventFilter(QObject *watched, QEvent *event)
{
switch (event->type()) {
case QEvent::Resize: {
onResizeView();
break;
}
case QEvent::MouseButtonPress: {
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
QuickSettingItem *item = qobject_cast<QuickSettingItem *>(watched);
if (item) {
m_dragInfo->dragPosition = mouseEvent->pos();
m_dragInfo->dragItem = item;
m_dragInfo->pluginInter = item->pluginItem();
}
break;
}
case QEvent::MouseButtonRelease: {
m_dragInfo->reset();
break;
}
default:
break;
}
return QWidget::eventFilter(watched, event);
}
void QuickSettingContainer::showEvent(QShowEvent *event)
{
// 当面板显示的时候,直接默认显示快捷面板的窗口
QWidget::showEvent(event);
if (m_switchLayout->currentWidget() != m_mainWidget) {
m_childPage->pushWidget(nullptr);
m_switchLayout->setCurrentWidget(m_mainWidget);
onResizeView();
}
}
void QuickSettingContainer::appendPlugin(PluginsItemInterface *itemInter, QString itemKey, bool needLayout)
{
QuickSettingItem *quickItem = QuickSettingFactory::createQuickWidget(itemInter, itemKey);
if (!quickItem)
return;
quickItem->setParent(m_pluginWidget);
quickItem->setMouseTracking(true);
quickItem->installEventFilter(this);
connect(quickItem, &QuickSettingItem::requestShowChildWidget, this, &QuickSettingContainer::onShowChildWidget);
m_quickSettings << quickItem;
if (quickItem->type() == QuickSettingItem::QuickItemStyle::Line) {
// 插件位置占据整行,例如声音、亮度和音乐等
m_componentWidget->layout()->addWidget(quickItem);
updateFullItemLayout();
} else if (needLayout) {
// 插件占据两行或者一行
updateItemLayout();
}
onResizeView();
}
void QuickSettingContainer::onPluginRemove(PluginsItemInterface *itemInter)
{
QList<QuickSettingItem *>::Iterator removeItemIter = std::find_if(m_quickSettings.begin(), m_quickSettings.end(), [ = ](QuickSettingItem *item)->bool {
return item->pluginItem() == itemInter;
});
if (removeItemIter == m_quickSettings.end())
return;
QuickSettingItem *removeItem = *removeItemIter;
removeItem->detachPlugin();
if (removeItem->type() == QuickSettingItem::QuickItemStyle::Line)
m_componentWidget->layout()->removeWidget(removeItem);
else
m_pluginLayout->removeWidget(removeItem);
m_quickSettings.removeOne(removeItem);
removeItem->deleteLater();
if (m_childShowPlugin == itemInter)
showPage(nullptr);
updateItemLayout();
updateFullItemLayout();
onResizeView();
}
void QuickSettingContainer::onShowChildWidget(QWidget *childWidget)
{
QuickSettingItem *quickWidget = qobject_cast<QuickSettingItem *>(sender());
if (!quickWidget)
return;
showPage(childWidget, quickWidget->pluginItem());
}
void QuickSettingContainer::mouseMoveEvent(QMouseEvent *event)
{
if (m_dragInfo->isNull())
return;
QPoint pointCurrent = event->pos();
if (qAbs(m_dragInfo->dragPosition.x() - pointCurrent.x()) > 5
|| qAbs(m_dragInfo->dragPosition.y() - pointCurrent.y()) > 5) {
QuickSettingItem *moveItem = qobject_cast<QuickSettingItem *>(m_dragInfo->dragItem);
QuickIconDrag *drag = new QuickIconDrag(this, moveItem->dragPixmap());
QuickPluginMimeData *mimedata = new QuickPluginMimeData(m_dragInfo->pluginInter, drag);
drag->setMimeData(mimedata);
drag->setDragHotPot(m_dragInfo->dragPosition);
m_dragInfo->reset();
drag->exec(Qt::CopyAction);
}
}
void QuickSettingContainer::updateItemLayout()
{
// 清空之前的控件,重新添加
while (m_pluginLayout->count() > 0)
m_pluginLayout->takeAt(0);
// 将插件按照两列和一列的顺序来进行排序
QMap<QuickSettingItem::QuickItemStyle, QList<QuickSettingItem *>> quickSettings;
QMap<QuickSettingItem::QuickItemStyle, QMap<QuickSettingItem *, int>> orderQuickSettings;
for (QuickSettingItem *item : m_quickSettings) {
QuickSettingItem::QuickItemStyle type = item->type();
if (type == QuickSettingItem::QuickItemStyle::Line)
continue;
QJsonObject metaData = m_pluginController->metaData(item->pluginItem());
if (metaData.contains("order"))
orderQuickSettings[type][item] = metaData.value("order").toInt();
else
quickSettings[type] << item;
}
// 将需要排序的插件按照顺序插入到原来的数组中
for (auto itQuick = orderQuickSettings.begin(); itQuick != orderQuickSettings.end(); itQuick++) {
QuickSettingItem::QuickItemStyle type = itQuick.key();
QMap<QuickSettingItem *, int> &orderQuicks = itQuick.value();
for (auto it = orderQuicks.begin(); it != orderQuicks.end(); it++) {
int index = it.value();
if (index >= 0 && index < quickSettings[type].size())
quickSettings[type][index] = it.key();
else
quickSettings[type] << it.key();
}
}
auto insertQuickSetting = [ quickSettings, this ](QuickSettingItem::QuickItemStyle type, int &row, int &column) {
if (!quickSettings.contains(type))
return;
int usedColumn = (type == QuickSettingItem::QuickItemStyle::Larger ? 2 : 1);
QList<QuickSettingItem *> quickPlugins = quickSettings[type];
for (QuickSettingItem *quickItem : quickPlugins) {
quickItem->setVisible(true);
m_pluginLayout->addWidget(quickItem, row, column, 1, usedColumn);
column += usedColumn;
if (column >= COLUMNCOUNT) {
row++;
column = 0;
}
}
};
int row = 0;
int column = 0;
insertQuickSetting(QuickSettingItem::QuickItemStyle::Larger, row, column);
insertQuickSetting(QuickSettingItem::QuickItemStyle::Standard, row, column);
}
void QuickSettingContainer::updateFullItemLayout()
{
while (m_componentWidget->layout()->count() > 0)
m_componentWidget->layout()->takeAt(0);
QList<QuickSettingItem *> fullItems;
QMap<QuickSettingItem *, int> fullItemOrder;
for (QuickSettingItem *item : m_quickSettings) {
if (item->type() != QuickSettingItem::QuickItemStyle::Line)
continue;
fullItems << item;
int order = -1;
QJsonObject metaData = m_pluginController->metaData(item->pluginItem());
if (metaData.contains("order"))
order = metaData.value("order").toInt();
fullItemOrder[item] = order;
}
std::sort(fullItems.begin(), fullItems.end(), [ fullItemOrder, fullItems ](QuickSettingItem *item1, QuickSettingItem *item2) {
int order1 = fullItemOrder.value(item1, -1);
int order2 = fullItemOrder.value(item2, -1);
if (order1 == order2) {
// 如果两个值相等,就根据他们的加载顺序进行排序
return fullItems.indexOf(item1) < fullItems.indexOf(item2);
}
if (order1 == -1)
return false;
if (order2 == -1)
return true;
return order1 < order2;
});
for (QuickSettingItem *item : fullItems) {
item->setVisible(true);
m_componentWidget->layout()->addWidget(item);
}
}
void QuickSettingContainer::initUi()
{
m_mainlayout->setSpacing(ITEMSPACE);
m_mainlayout->setContentsMargins(ITEMSPACE, ITEMSPACE, ITEMSPACE, ITEMSPACE);
m_pluginLayout->setContentsMargins(0, 0, 0, 0);
m_pluginLayout->setSpacing(ITEMSPACE);
m_pluginLayout->setAlignment(Qt::AlignLeft);
for (int i = 0; i < COLUMNCOUNT; i++)
m_pluginLayout->setColumnMinimumWidth(i, ITEMWIDTH);
m_pluginWidget->setLayout(m_pluginLayout);
m_mainlayout->addWidget(m_pluginWidget);
QVBoxLayout *ctrlLayout = new QVBoxLayout(m_componentWidget);
ctrlLayout->setContentsMargins(0, 0, 0, 0);
ctrlLayout->setSpacing(ITEMSPACE);
ctrlLayout->setDirection(QBoxLayout::BottomToTop);
m_mainlayout->addWidget(m_componentWidget);
// 加载所有的可以在快捷面板显示的插件
QList<PluginsItemInterface *> plugins = m_pluginController->currentPlugins();
for (PluginsItemInterface *plugin : plugins) {
appendPlugin(plugin, m_pluginController->itemKey(plugin), false);
}
m_switchLayout->addWidget(m_mainWidget);
m_switchLayout->addWidget(m_childPage);
setMouseTracking(true);
setAcceptDrops(true);
QMetaObject::invokeMethod(this, [ = ] {
if (plugins.size() > 0) {
updateItemLayout();
updateFullItemLayout();
}
// 设置当前窗口的大小
onResizeView();
setFixedWidth(ITEMWIDTH * 4 + (ITEMSPACE * 5));
}, Qt::QueuedConnection);
}
void QuickSettingContainer::initConnection()
{
connect(m_pluginController, &DockPluginController::pluginInserted, this, [ = ](PluginsItemInterface *itemInter, QString itemKey) {
appendPlugin(itemInter, itemKey);
});
connect(m_pluginController, &DockPluginController::pluginRemoved, this, &QuickSettingContainer::onPluginRemove);
connect(m_pluginController, &DockPluginController::pluginUpdated, this, &QuickSettingContainer::onPluginUpdated);
connect(m_childPage, &PluginChildPage::back, this, [ this ] {
showPage(m_mainWidget);
});
}
// 调整尺寸
void QuickSettingContainer::onResizeView()
{
if (m_switchLayout->currentWidget() == m_mainWidget) {
int selfPluginCount = 0;
int fullItemHeight = 0;
int widgetCount = 0;
for (QuickSettingItem *item : m_quickSettings) {
item->setFixedHeight(ITEMHEIGHT);
if (item->type() == QuickSettingItem::QuickItemStyle::Line) {
fullItemHeight += item->height();
widgetCount++;
continue;
}
// 如果是置顶的插件,则认为它占用两个普通插件的位置
int increCount = (item->type() == QuickSettingItem::QuickItemStyle::Larger ? 2 : 1);
selfPluginCount += increCount;
}
int rowCount = selfPluginCount / COLUMNCOUNT;
if (selfPluginCount % COLUMNCOUNT > 0)
rowCount++;
m_pluginWidget->setFixedHeight(ITEMHEIGHT * rowCount + ITEMSPACE * (rowCount - 1));
m_componentWidget->setFixedHeight(fullItemHeight + (widgetCount - 1) * ITEMSPACE);
setFixedHeight(ITEMSPACE * 3 + m_pluginWidget->height() + m_componentWidget->height());
} else if (m_switchLayout->currentWidget() == m_childPage) {
setFixedHeight(m_childPage->height());
}
}
void QuickSettingContainer::onPluginUpdated(PluginsItemInterface *itemInter, const DockPart dockPart)
{
if (dockPart != DockPart::QuickPanel)
return;
for (QuickSettingItem *settingItem : m_quickSettings) {
if (settingItem->pluginItem() != itemInter)
continue;
settingItem->doUpdate();
break;
}
}

View File

@ -0,0 +1,94 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef QUICKSETTINGCONTAINER_H
#define QUICKSETTINGCONTAINER_H
#include "pluginproxyinterface.h"
#include "dtkwidget_global.h"
#include <DListView>
#include <QWidget>
class DockItem;
class QVBoxLayout;
class DockPluginController;
class BrightnessModel;
class BrightnessWidget;
class QuickSettingItem;
class QStackedLayout;
class VolumeDevicesWidget;
class QLabel;
class PluginChildPage;
class QGridLayout;
class DisplaySettingWidget;
struct QuickDragInfo;
DWIDGET_USE_NAMESPACE
class QuickSettingContainer : public QWidget
{
Q_OBJECT
public:
void showPage(QWidget *widget, PluginsItemInterface *pluginInter = nullptr);
explicit QuickSettingContainer(DockPluginController *pluginController, QWidget *parent = nullptr);
~QuickSettingContainer() override;
protected:
void mouseMoveEvent(QMouseEvent *event) override;
bool eventFilter(QObject *watched, QEvent *event) override;
void showEvent(QShowEvent *event) override;
private Q_SLOTS:
void onPluginRemove(PluginsItemInterface *itemInter);
void onShowChildWidget(QWidget *childWidget);
void onResizeView();
void onPluginUpdated(PluginsItemInterface *itemInter, const DockPart dockPart);
private:
// 加载UI
void initUi();
// 初始化槽函数
void initConnection();
// 调整控件位置
void updateItemLayout();
// 调整全列插件的位置
void updateFullItemLayout();
// 插入插件
void appendPlugin(PluginsItemInterface *itemInter, QString itemKey, bool needLayout = true);
private:
QStackedLayout *m_switchLayout;
QWidget *m_mainWidget;
QWidget *m_pluginWidget;
QGridLayout *m_pluginLayout;
QWidget *m_componentWidget;
QVBoxLayout *m_mainlayout;
DockPluginController *m_pluginController;
PluginChildPage *m_childPage;
QuickDragInfo *m_dragInfo;
QList<QuickSettingItem *> m_quickSettings;
PluginsItemInterface *m_childShowPlugin;
};
#endif // PLUGINCONTAINER_H

View File

@ -0,0 +1,148 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "quicksettingitem.h"
#include "pluginsiteminterface.h"
#include "imageutil.h"
#include "largerquickitem.h"
#include "standardquickitem.h"
#include "linequickitem.h"
#include <DGuiApplicationHelper>
#include <DFontSizeManager>
#include <DPaletteHelper>
#include <QIcon>
#include <QPainterPath>
#include <QPushButton>
#include <QFontMetrics>
#include <QPainter>
#define ICONWIDTH 24
#define ICONHEIGHT 24
#define ICONSPACE 10
#define RADIUS 8
#define FONTSIZE 10
#define BGWIDTH 128
#define BGSIZE 36
#define MARGINLEFTSPACE 10
#define OPENICONSIZE 12
#define MARGINRIGHTSPACE 9
DWIDGET_USE_NAMESPACE
QuickSettingItem::QuickSettingItem(PluginsItemInterface *const pluginInter, const QString &itemKey, QWidget *parent)
: QWidget(parent)
, m_pluginInter(pluginInter)
, m_itemKey(itemKey)
{
setAcceptDrops(true);
this->installEventFilter(this);
}
QuickSettingItem::~QuickSettingItem()
{
}
PluginsItemInterface *QuickSettingItem::pluginItem() const
{
return m_pluginInter;
}
const QPixmap QuickSettingItem::dragPixmap()
{
QPixmap pluginPixmap = m_pluginInter->icon(DockPart::QuickPanel, DGuiApplicationHelper::instance()->themeType()).pixmap(ICONWIDTH, ICONHEIGHT);
QPainter foregroundPainter(&pluginPixmap);
foregroundPainter.setPen(foregroundColor());
foregroundPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
foregroundPainter.fillRect(pluginPixmap.rect(), foregroundColor());
QPixmap pixmapDrag(ICONWIDTH + ICONSPACE + FONTSIZE * 2, ICONHEIGHT + ICONSPACE + FONTSIZE * 2);
pixmapDrag.fill(Qt::transparent);
QPainter painter(&pixmapDrag);
painter.drawPixmap(QPoint((ICONSPACE + FONTSIZE * 2) / 2, 0), pluginPixmap);
painter.setPen(foregroundPainter.pen());
QFont font;
font.setPixelSize(FONTSIZE);
painter.setFont(font);
QTextOption option;
option.setAlignment(Qt::AlignTop | Qt::AlignHCenter);
painter.drawText(QRect(QPoint(0, ICONHEIGHT + ICONSPACE),
QPoint(pixmapDrag.width(), pixmapDrag.height())), m_pluginInter->pluginDisplayName(), option);
return pixmapDrag;
}
const QString QuickSettingItem::itemKey() const
{
return m_itemKey;
}
void QuickSettingItem::paintEvent(QPaintEvent *e)
{
QWidget::paintEvent(e);
QPainter painter(this);
painter.setRenderHint(QPainter::RenderHint::Antialiasing);
painter.setPen(foregroundColor());
QPainterPath path;
path.addRoundedRect(rect(), RADIUS, RADIUS);
painter.setClipPath(path);
// 绘制背景色
QColor backColor(Qt::white);
if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::ColorType::DarkType) {
backColor = Qt::black;
backColor.setAlphaF(0.5);
}
DPalette dpa = DPaletteHelper::instance()->palette(this);
painter.fillRect(rect(), backColor);
}
QColor QuickSettingItem::foregroundColor() const
{
DPalette dpa = DPaletteHelper::instance()->palette(this);
// TODO: 此处的颜色是临时获取的,后期需要和设计师确认,改成正规的颜色
if (m_pluginInter->status() == PluginsItemInterface::PluginMode::Active)
return dpa.color(DPalette::ColorGroup::Active, DPalette::ColorRole::Text);
if (m_pluginInter->status() == PluginsItemInterface::PluginMode::Deactive)
return dpa.color(DPalette::ColorGroup::Disabled, DPalette::ColorRole::Text);
return dpa.color(DPalette::ColorGroup::Normal, DPalette::ColorRole::Text);
}
QuickSettingItem *QuickSettingFactory::createQuickWidget(PluginsItemInterface * const pluginInter, const QString &itemKey)
{
// 如果显示在面板的图标或者Widget为空则不让显示(例如电池插件)
if (!(pluginInter->flags() & PluginFlag::Type_Common))
return nullptr;
if (pluginInter->flags() & PluginFlag::Quick_Multi)
return new LargerQuickItem(pluginInter, itemKey);
if (pluginInter->flags() & PluginFlag::Quick_Full)
return new LineQuickItem(pluginInter, itemKey);
if (pluginInter->flags() & PluginFlag::Quick_Single)
return new StandardQuickItem(pluginInter, itemKey);
return nullptr;
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef QUICKSETTINGITEM_H
#define QUICKSETTINGITEM_H
#include <QWidget>
class PluginsItemInterface;
class QuickIconWidget;
class QuickSettingItem : public QWidget
{
Q_OBJECT
public:
enum class QuickItemStyle {
Standard = 1, // 插件的UI显示单列
Larger, // 插件的UI显示双列例如网络和蓝牙等
Line // 插件的UI整行显示例如声音亮度、音乐播放等
};
public:
QuickSettingItem(PluginsItemInterface *const pluginInter, const QString &itemKey, QWidget *parent = nullptr);
~QuickSettingItem() override;
PluginsItemInterface *pluginItem() const;
virtual const QPixmap dragPixmap();
virtual void doUpdate() {}
virtual void detachPlugin() {}
const QString itemKey() const;
virtual QuickItemStyle type() const = 0;
Q_SIGNALS:
void requestShowChildWidget(QWidget *);
protected:
void paintEvent(QPaintEvent *e) override;
QColor foregroundColor() const;
private:
PluginsItemInterface *m_pluginInter;
QString m_itemKey;
};
class QuickSettingFactory
{
public:
static QuickSettingItem *createQuickWidget(PluginsItemInterface *const pluginInter, const QString &itemKey);
};
#endif // QUICKSETTINGITEM_H

Binary file not shown.

View File

@ -0,0 +1,200 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "standardquickitem.h"
#include "pluginsiteminterface.h"
#include <DFontSizeManager>
#include <DGuiApplicationHelper>
#include <QLabel>
#include <QVBoxLayout>
#include <QHBoxLayout>
#define ICONHEIGHT 24
#define ICONWIDTH 24
#define TEXTHEIGHT 11
DWIDGET_USE_NAMESPACE
StandardQuickItem::StandardQuickItem(PluginsItemInterface *const pluginInter, const QString &itemKey, QWidget *parent)
: QuickSettingItem(pluginInter, itemKey, parent)
, m_itemParentWidget(nullptr)
, m_needPaint(true)
{
initUi();
}
StandardQuickItem::~StandardQuickItem()
{
}
QuickSettingItem::QuickItemStyle StandardQuickItem::type() const
{
return QuickSettingItem::QuickItemStyle::Standard;
}
void StandardQuickItem::mouseReleaseEvent(QMouseEvent *event)
{
Q_UNUSED(event);
QStringList commandArgument = pluginItem()->itemCommand(itemKey()).split(" ");
if (commandArgument.size() > 0) {
QString command = commandArgument.first();
commandArgument.removeFirst();
QProcess::startDetached(command, commandArgument);
}
}
void StandardQuickItem::resizeEvent(QResizeEvent *event)
{
doUpdate();
QuickSettingItem::resizeEvent(event);
}
void StandardQuickItem::initUi()
{
QWidget *topWidget = iconWidget(this);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(topWidget);
installEventFilter(this);
}
QWidget *StandardQuickItem::iconWidget(QWidget *parent)
{
// 显示图标的窗体
QWidget *widget = new QWidget(parent);
m_needPaint = true;
QIcon icon = pluginItem()->icon(DockPart::QuickPanel);
if (icon.isNull()) {
// 如果图标为空则将获取itemWidget作为它的显示
QWidget *itemWidget = pluginItem()->itemWidget(QUICK_ITEM_KEY);
if (itemWidget) {
m_itemParentWidget = itemWidget->parentWidget();
QHBoxLayout *layout = new QHBoxLayout(widget);
layout->setContentsMargins(0, 0, 0 ,0);
itemWidget->setParent(widget);
layout->addWidget(itemWidget);
itemWidget->setVisible(true);
m_needPaint = false;
}
}
if (m_needPaint) {
// 如果没有子窗体,则需要添加下方的文字
QVBoxLayout *layout = new QVBoxLayout(widget);
layout->setAlignment(Qt::AlignVCenter);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
QLabel *imageLabel = new QLabel(widget);
imageLabel->setObjectName("imageLabel");
imageLabel->setFixedHeight(ICONHEIGHT);
imageLabel->setAlignment(Qt::AlignCenter);
QLabel *labelText = new QLabel(widget);
labelText->setObjectName("textLabel");
labelText->setFixedHeight(TEXTHEIGHT);
updatePluginName(labelText);
labelText->setAlignment(Qt::AlignCenter);
labelText->setFont(DFontSizeManager::instance()->t10());
layout->addWidget(imageLabel);
layout->addSpacing(7);
layout->addWidget(labelText);
}
return widget;
}
QPixmap StandardQuickItem::pixmap() const
{
// 如果快捷面板区域的图标为空那么就获取itemWidget的截图
QIcon icon = pluginItem()->icon(DockPart::QuickPanel);
if (icon.isNull())
return QPixmap();
int pixmapWidth = ICONWIDTH;
int pixmapHeight = ICONHEIGHT;
QList<QSize> iconSizes = icon.availableSizes();
if (iconSizes.size() > 0) {
QSize size = iconSizes[0];
if (size.isValid() && !size.isEmpty() && !size.isNull()) {
pixmapWidth = size.width();
pixmapHeight = size.height();
}
}
return icon.pixmap(pixmapWidth / qApp->devicePixelRatio(), pixmapHeight / qApp->devicePixelRatio());
}
QLabel *StandardQuickItem::findChildLabel(QWidget *parent, const QString &childObjectName) const
{
QList<QObject *> childrends = parent->children();
for (QObject *child : childrends) {
QWidget *widget = qobject_cast<QWidget *>(child);
if (!widget)
continue;
QLabel *label = qobject_cast<QLabel *>(child);
if (label && widget->objectName() == childObjectName)
return label;
label = findChildLabel(widget, childObjectName);
if (label)
return label;
}
return nullptr;
}
void StandardQuickItem::updatePluginName(QLabel *textLabel)
{
if (!textLabel)
return;
QString text = pluginItem()->description();
if (text.isEmpty())
text = pluginItem()->pluginDisplayName();
QFontMetrics ftm(textLabel->font());
text = ftm.elidedText(text, Qt::TextElideMode::ElideRight, textLabel->width());
textLabel->setText(text);
}
void StandardQuickItem::doUpdate()
{
if (m_needPaint) {
QLabel *imageLabel = findChildLabel(this, "imageLabel");
if (imageLabel) {
// 更新图像
imageLabel->setPixmap(pixmap());
}
updatePluginName(findChildLabel(this, "textLabel"));
} else {
QWidget *itemWidget = pluginItem()->itemWidget(QUICK_ITEM_KEY);
if (itemWidget)
itemWidget->update();
}
}
void StandardQuickItem::detachPlugin()
{
QWidget *itemWidget = pluginItem()->itemWidget(QUICK_ITEM_KEY);
if (itemWidget && !m_needPaint)
itemWidget->setParent(m_itemParentWidget);
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef STANDARDQUICKITEM_H
#define STANDARDQUICKITEM_H
#include "quicksettingitem.h"
class QLabel;
// 插件在快捷面板中展示的样式,这个为默认,展示一行一列的那种
class StandardQuickItem : public QuickSettingItem
{
Q_OBJECT
public:
StandardQuickItem(PluginsItemInterface *const pluginInter, const QString &itemKey, QWidget *parent = nullptr);
~StandardQuickItem() override;
QuickItemStyle type() const override;
void doUpdate() override;
void detachPlugin() override;
protected:
void mouseReleaseEvent(QMouseEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
private:
void initUi();
QWidget *iconWidget(QWidget *parent);
QPixmap pixmap() const;
QLabel *findChildLabel(QWidget *parent, const QString &childObjectName) const;
void updatePluginName(QLabel *textLabel);
private:
QWidget *m_itemParentWidget;
bool m_needPaint;
};
#endif // SINGLEQUICKITEM_H