dde-dock/frame/window/tray/widgets/systempluginitem.cpp
donghualin 5530675d05 fix: 修复U盘插件不显示的问题
老版本的U盘插件没有适配icon接口,需要根据实际情况将itemWidget显示

Log: 修复U盘插件不显示的问题
Influence: 系统中使用v20的U盘插件,插入U盘,查看U盘图标是否显示
Task: https://pms.uniontech.com/task-view-223159.html
Change-Id: I7d2e7867203962ced078087c66fbddb7020d30df
2022-12-05 15:00:43 +08:00

578 lines
16 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 <QMenu>
#include <xcb/xproto.h>
Dock::Position SystemPluginItem::DockPosition = Dock::Position::Bottom;
QPointer<DockPopupWindow> SystemPluginItem::PopupWindow = nullptr;
SystemPluginItem::SystemPluginItem(PluginsItemInterface *const pluginInter, const QString &itemKey, QWidget *parent)
: BaseTrayWidget(parent)
, m_popupShown(false)
, m_tapAndHold(false)
, m_contextMenu(new QMenu(this))
, 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;
QIcon icon = m_pluginInter->icon(DockPart::SystemPanel);
if (m_centralWidget) {
if (icon.isNull()) {
// 此处先创建一个Layout在该窗体show的时候将m_centralWidget添加到layout上面
QBoxLayout *hLayout = new QHBoxLayout(this);
hLayout->setSpacing(0);
hLayout->setMargin(0);
setLayout(hLayout);
m_centralWidget->installEventFilter(this);
} else {
m_centralWidget->setVisible(false);
}
}
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");
if (Utils::IS_WAYLAND_DISPLAY) {
Qt::WindowFlags flags = arrowRectangle->windowFlags() | Qt::FramelessWindowHint;
arrowRectangle->setWindowFlags(flags);
}
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);
installEventFilter(this);
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);
}
bool SystemPluginItem::eventFilter(QObject *watched, QEvent *event)
{
if (watched == this && event->type() == QEvent::DeferredDelete
&& m_centralWidget && m_centralWidget->parentWidget()) {
m_centralWidget->setParent(nullptr);
m_centralWidget->setVisible(false);
}
return BaseTrayWidget::eventFilter(watched, 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);
}
void SystemPluginItem::hideEvent(QHideEvent *event)
{
if (m_pluginInter->icon(DockPart::SystemPanel).isNull()
&& m_centralWidget && m_centralWidget->parentWidget() == this) {
layout()->removeWidget(m_centralWidget);
m_centralWidget->setParent(nullptr);
m_centralWidget->setVisible(false);
}
BaseTrayWidget::hideEvent(event);
}
void SystemPluginItem::paintEvent(QPaintEvent *event)
{
QIcon icon = m_pluginInter->icon(DockPart::SystemPanel);
if (icon.isNull()) {
showCentralWidget();
return BaseTrayWidget::paintEvent(event);
}
int x = 0;
int y = 0;
QSize iconSize = this->size();
QList<QSize> sizes = icon.availableSizes();
if (sizes.size() > 0) {
QSize availableSize = sizes.first();
if (iconSize.width() > availableSize.width()) {
x = (iconSize.width() - availableSize.width()) / 2;
y = (iconSize.height() - availableSize.height()) / 2;
iconSize = availableSize;
}
}
QPixmap pixmap = icon.pixmap(iconSize);
QPainter painter(this);
painter.drawPixmap(QRect(QPoint(x, y), iconSize), pixmap);
}
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::showCentralWidget()
{
if (!m_pluginInter->icon(DockPart::SystemPanel).isNull() || !m_centralWidget)
return;
m_centralWidget->setParent(this);
m_centralWidget->setVisible(true);
layout()->addWidget(m_centralWidget);
}
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();
}