dde-dock/frame/window/tray/widgets/systempluginitem.cpp
donghualin 728b700dba feat: 特效模式下右侧插件区域功能
完成插件区域的引用图标加载、快捷设置的展示、老插件的加载等功能

Log: 完成特效模式下右侧插件区域的功能
Influence: v23任务栏右侧插件区域
Task: https://pms.uniontech.com/task-view-110311.html
Change-Id: I1599907d4529c57070ee2e21b70cc0c17f132e5e
2022-05-12 17:36:19 +08:00

509 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
*
* Author: listenerri <listenerri@gmail.com>
*
* Maintainer: listenerri <listenerri@gmail.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 "systempluginitem.h"
#include "utils.h"
#include "dockpopupwindow.h"
#include <QProcess>
#include <QDebug>
#include <QPointer>
#include <xcb/xproto.h>
Dock::Position SystemPluginItem::DockPosition = Dock::Position::Top;
QPointer<DockPopupWindow> SystemPluginItem::PopupWindow = nullptr;
SystemPluginItem::SystemPluginItem(PluginsItemInterface *const pluginInter, const QString &itemKey, QWidget *parent)
: BaseTrayWidget(parent)
, m_popupShown(false)
, m_tapAndHold(false)
, m_pluginInter(pluginInter)
, m_centralWidget(m_pluginInter->itemWidget(itemKey))
, m_popupTipsDelayTimer(new QTimer(this))
, m_popupAdjustDelayTimer(new QTimer(this))
, m_itemKey(itemKey)
, m_gsettings(Utils::ModuleSettingsPtr(pluginInter->pluginName(), QByteArray(), this))
{
qDebug() << "load tray plugins item: " << m_pluginInter->pluginName() << itemKey << m_centralWidget;
m_centralWidget->setParent(this);
m_centralWidget->setVisible(true);
m_centralWidget->installEventFilter(this);
QBoxLayout *hLayout = new QHBoxLayout(this);
hLayout->addWidget(m_centralWidget);
hLayout->setSpacing(0);
hLayout->setMargin(0);
setLayout(hLayout);
setAccessibleName(m_itemKey);
setAttribute(Qt::WA_TranslucentBackground);
if (PopupWindow.isNull()) {
DockPopupWindow *arrowRectangle = new DockPopupWindow(nullptr);
arrowRectangle->setShadowBlurRadius(20);
arrowRectangle->setRadius(6);
arrowRectangle->setShadowYOffset(2);
arrowRectangle->setShadowXOffset(0);
arrowRectangle->setArrowWidth(18);
arrowRectangle->setArrowHeight(10);
arrowRectangle->setObjectName("systemtraypopup");
PopupWindow = arrowRectangle;
connect(qApp, &QApplication::aboutToQuit, PopupWindow, &DockPopupWindow::deleteLater);
}
// 必须初始化父窗口否则当主题切换之后再设置父窗口的时候palette会更改为主题切换前的palette
if (QWidget *w = m_pluginInter->itemPopupApplet(m_itemKey)) {
w->setParent(PopupWindow.data());
w->setVisible(false);
}
m_popupTipsDelayTimer->setInterval(500);
m_popupTipsDelayTimer->setSingleShot(true);
m_popupAdjustDelayTimer->setInterval(10);
m_popupAdjustDelayTimer->setSingleShot(true);
connect(m_popupTipsDelayTimer, &QTimer::timeout, this, &SystemPluginItem::showHoverTips);
connect(m_popupAdjustDelayTimer, &QTimer::timeout, this, &SystemPluginItem::updatePopupPosition, Qt::QueuedConnection);
connect(&m_contextMenu, &QMenu::triggered, this, &SystemPluginItem::menuActionClicked);
if (m_gsettings)
connect(m_gsettings, &QGSettings::changed, this, &SystemPluginItem::onGSettingsChanged);
grabGesture(Qt::TapAndHoldGesture);
}
SystemPluginItem::~SystemPluginItem()
{
if (m_popupShown)
popupWindowAccept();
}
QString SystemPluginItem::itemKeyForConfig()
{
return m_itemKey;
}
void SystemPluginItem::updateIcon()
{
m_pluginInter->refreshIcon(m_itemKey);
}
void SystemPluginItem::sendClick(uint8_t mouseButton, int x, int y)
{
Q_UNUSED(mouseButton);
Q_UNUSED(x);
Q_UNUSED(y);
// do not process this callback
// handle all mouse event in override mouse function
}
QWidget *SystemPluginItem::trayTipsWidget()
{
if (m_pluginInter->itemTipsWidget(m_itemKey)) {
m_pluginInter->itemTipsWidget(m_itemKey)->setAccessibleName(m_pluginInter->pluginName());
}
return m_pluginInter->itemTipsWidget(m_itemKey);
}
QWidget *SystemPluginItem::trayPopupApplet()
{
if (m_pluginInter->itemPopupApplet(m_itemKey)) {
m_pluginInter->itemPopupApplet(m_itemKey)->setAccessibleName(m_pluginInter->pluginName());
}
return m_pluginInter->itemPopupApplet(m_itemKey);
}
const QString SystemPluginItem::trayClickCommand()
{
return m_pluginInter->itemCommand(m_itemKey);
}
const QString SystemPluginItem::contextMenu() const
{
return m_pluginInter->itemContextMenu(m_itemKey);
}
void SystemPluginItem::invokedMenuItem(const QString &menuId, const bool checked)
{
m_pluginInter->invokedMenuItem(m_itemKey, menuId, checked);
}
QWidget *SystemPluginItem::centralWidget() const
{
return m_centralWidget;
}
void SystemPluginItem::detachPluginWidget()
{
QWidget *widget = m_pluginInter->itemWidget(m_itemKey);
if (widget)
widget->setParent(nullptr);
}
bool SystemPluginItem::event(QEvent *event)
{
if (m_popupShown) {
switch (event->type()) {
case QEvent::Paint:
if (!m_popupAdjustDelayTimer->isActive())
m_popupAdjustDelayTimer->start();
break;
default:;
}
}
if (event->type() == QEvent::Gesture)
gestureEvent(static_cast<QGestureEvent *>(event));
return BaseTrayWidget::event(event);
}
void SystemPluginItem::enterEvent(QEvent *event)
{
if (checkGSettingsControl()) {
//网络需要显示Tips需要特殊处理。
if (m_pluginInter->pluginName() != "network")
return;
}
// 触屏不显示hover效果
if (!qApp->property(IS_TOUCH_STATE).toBool()) {
m_popupTipsDelayTimer->start();
}
update();
BaseTrayWidget::enterEvent(event);
}
void SystemPluginItem::leaveEvent(QEvent *event)
{
m_popupTipsDelayTimer->stop();
// auto hide if popup is not model window
if (m_popupShown && !PopupWindow->model())
hidePopup();
update();
BaseTrayWidget::leaveEvent(event);
}
void SystemPluginItem::mousePressEvent(QMouseEvent *event)
{
if (checkGSettingsControl()) {
return;
}
m_popupTipsDelayTimer->stop();
hideNonModel();
if (event->button() == Qt::RightButton
&& perfectIconRect().contains(event->pos(), true)) {
return (m_gsettings && (!m_gsettings->keys().contains("menuEnable") || m_gsettings->get("menuEnable").toBool())) ? showContextMenu() : void();
}
BaseTrayWidget::mousePressEvent(event);
}
void SystemPluginItem::mouseReleaseEvent(QMouseEvent *event)
{
if (checkGSettingsControl()) {
return;
}
if (event->button() != Qt::LeftButton) {
return;
}
if (checkAndResetTapHoldGestureState() && event->source() == Qt::MouseEventSynthesizedByQt) {
qDebug() << "SystemTray: tap and hold gesture detected, ignore the synthesized mouse release event";
return;
}
event->accept();
showPopupApplet(trayPopupApplet());
if (!trayClickCommand().isEmpty()) {
QProcess::startDetached(trayClickCommand());
}
BaseTrayWidget::mouseReleaseEvent(event);
}
void SystemPluginItem::showEvent(QShowEvent *event)
{
QTimer::singleShot(0, this, [ = ] {
onGSettingsChanged("enable");
});
return BaseTrayWidget::showEvent(event);
}
const QPoint SystemPluginItem::popupMarkPoint() const
{
QPoint p(topleftPoint());
const QRect r = rect();
const QRect wr = window()->rect();
switch (DockPosition) {
case Dock::Position::Top:
p += QPoint(r.width() / 2, r.height() + (wr.height() - r.height()) / 2);
break;
case Dock::Position::Bottom:
p += QPoint(r.width() / 2, 0 - (wr.height() - r.height()) / 2);
break;
case Dock::Position::Left:
p += QPoint(r.width() + (wr.width() - r.width()) / 2, r.height() / 2);
break;
case Dock::Position::Right:
p += QPoint(0 - (wr.width() - r.width()) / 2, r.height() / 2);
break;
}
return p;
}
// 获取在最外层的窗口(MainWindow)中的位置
const QPoint SystemPluginItem::topleftPoint() const
{
QPoint p;
const QWidget *w = this;
do {
p += w->pos();
w = qobject_cast<QWidget *>(w->parent());
} while (w);
return p;
}
void SystemPluginItem::hidePopup()
{
m_popupTipsDelayTimer->stop();
m_popupAdjustDelayTimer->stop();
m_popupShown = false;
PopupWindow->hide();
DockPopupWindow *popup = PopupWindow.data();
QWidget *content = popup->getContent();
if (content) {
content->setVisible(false);
}
emit PopupWindow->accept();
emit requestWindowAutoHide(true);
}
void SystemPluginItem::hideNonModel()
{
// auto hide if popup is not model window
if (m_popupShown && !PopupWindow->model())
hidePopup();
}
void SystemPluginItem::popupWindowAccept()
{
if (!PopupWindow->isVisible())
return;
disconnect(PopupWindow.data(), &DockPopupWindow::accept, this, &SystemPluginItem::popupWindowAccept);
hidePopup();
}
void SystemPluginItem::showPopupApplet(QWidget *const applet)
{
if (!applet)
return;
// another model popup window already exists
if (PopupWindow->model()) {
applet->setVisible(false);
return;
}
showPopupWindow(applet, true);
}
void SystemPluginItem::showPopupWindow(QWidget *const content, const bool model)
{
m_popupShown = true;
m_lastPopupWidget = content;
if (model)
emit requestWindowAutoHide(false);
DockPopupWindow *popup = PopupWindow.data();
QWidget *lastContent = popup->getContent();
if (lastContent)
lastContent->setVisible(false);
switch (DockPosition) {
case Dock::Position::Top: popup->setArrowDirection(DockPopupWindow::ArrowTop); break;
case Dock::Position::Bottom: popup->setArrowDirection(DockPopupWindow::ArrowBottom); break;
case Dock::Position::Left: popup->setArrowDirection(DockPopupWindow::ArrowLeft); break;
case Dock::Position::Right: popup->setArrowDirection(DockPopupWindow::ArrowRight); break;
}
popup->resize(content->sizeHint());
popup->setContent(content);
QPoint p = popupMarkPoint();
if (!popup->isVisible())
QMetaObject::invokeMethod(popup, "show", Qt::QueuedConnection, Q_ARG(QPoint, p), Q_ARG(bool, model));
else
popup->show(p, model);
connect(popup, &DockPopupWindow::accept, this, &SystemPluginItem::popupWindowAccept, Qt::UniqueConnection);
}
void SystemPluginItem::showHoverTips()
{
// another model popup window already exists
if (PopupWindow->model())
return;
// if not in geometry area
const QRect r(topleftPoint(), size());
if (!r.contains(QCursor::pos()))
return;
QWidget *const content = trayTipsWidget();
if (!content)
return;
showPopupWindow(content);
}
/*!
* \sa DockItem::checkAndResetTapHoldGestureState
*/
bool SystemPluginItem::checkAndResetTapHoldGestureState()
{
bool ret = m_tapAndHold;
m_tapAndHold = false;
return ret;
}
void SystemPluginItem::gestureEvent(QGestureEvent *event)
{
if (!event)
return;
QGesture *gesture = event->gesture(Qt::TapAndHoldGesture);
if (!gesture)
return;
qDebug() << "SystemTray: got TapAndHoldGesture";
m_tapAndHold = true;
}
void SystemPluginItem::showContextMenu()
{
const QString menuJson = contextMenu();
if (menuJson.isEmpty())
return;
QJsonDocument jsonDocument = QJsonDocument::fromJson(menuJson.toLocal8Bit().data());
if (jsonDocument.isNull())
return;
QJsonObject jsonMenu = jsonDocument.object();
qDeleteAll(m_contextMenu.actions());
QJsonArray jsonMenuItems = jsonMenu.value("items").toArray();
for (auto item : jsonMenuItems) {
QJsonObject itemObj = item.toObject();
QAction *action = new QAction(itemObj.value("itemText").toString());
action->setCheckable(itemObj.value("isCheckable").toBool());
action->setChecked(itemObj.value("checked").toBool());
action->setData(itemObj.value("itemId").toString());
action->setEnabled(itemObj.value("isActive").toBool());
m_contextMenu.addAction(action);
}
hidePopup();
emit requestWindowAutoHide(false);
m_contextMenu.exec(QCursor::pos());
onContextMenuAccepted();
}
void SystemPluginItem::menuActionClicked(QAction *action)
{
invokedMenuItem(action->data().toString(), true);
}
void SystemPluginItem::onContextMenuAccepted()
{
emit requestRefershWindowVisible();
emit requestWindowAutoHide(true);
}
void SystemPluginItem::updatePopupPosition()
{
Q_ASSERT(sender() == m_popupAdjustDelayTimer);
if (!m_popupShown || !PopupWindow->model())
return;
if (PopupWindow->getContent() != m_lastPopupWidget.data())
return popupWindowAccept();
const QPoint p = popupMarkPoint();
PopupWindow->show(p, PopupWindow->model());
}
void SystemPluginItem::onGSettingsChanged(const QString &key) {
if (key != "enable") {
return;
}
if (m_gsettings && m_gsettings->keys().contains("enable")) {
const bool visible = m_gsettings->get("enable").toBool();
setVisible(visible);
emit itemVisibleChanged(visible);
}
}
bool SystemPluginItem::checkGSettingsControl() const
{
// 优先判断com.deepin.dde.dock.module.systemtray的control值是否为true优先级更高如果不为true再判断每一个托盘对应的gsetting配置的control值
bool isEnable = Utils::SettingValue("com.deepin.dde.dock.module.systemtray", QByteArray(), "control", false).toBool();
return (isEnable || (m_gsettings && m_gsettings->get("control").toBool()));
}
QPixmap SystemPluginItem::icon()
{
return QPixmap();
}