Merge branch 'dev/drag-drop-fashion-trays'

https://github.com/linuxdeepin/internal-discussion/issues/2

Change-Id: Ie04b201fe62846615a2f01c17844a41c999c7b81
This commit is contained in:
listenerri 2018-11-28 19:16:50 +08:00
commit b9de38a404
Notes: gerrit 2018-11-28 19:42:04 +08:00
Verified+1: <jenkins@deepin.com>
Code-Review+2: listenerri <listenerri@gmail.com>
Submitted-by: listenerri <listenerri@gmail.com>
Submitted-at: Wed, 28 Nov 2018 19:42:03 +0800
Reviewed-on: https://cr.deepin.io/40136
Project: dde/dde-dock
Branch: refs/heads/master
10 changed files with 510 additions and 69 deletions

View File

@ -28,7 +28,6 @@
AbstractTrayWidget::AbstractTrayWidget(QWidget *parent, Qt::WindowFlags f)
: QWidget(parent, f)
{
}
AbstractTrayWidget::~AbstractTrayWidget()
@ -38,6 +37,8 @@ AbstractTrayWidget::~AbstractTrayWidget()
void AbstractTrayWidget::mousePressEvent(QMouseEvent *event)
{
// do not call Parent::mousePressEvent or the DockItem will catch this event
// and show dock-context-menu immediately when right button of mouse is pressed
event->accept();
}

View File

@ -33,17 +33,21 @@
int FashionTrayItem::TrayWidgetWidth = TrayWidgetWidthMin;
int FashionTrayItem::TrayWidgetHeight = TrayWidgetHeightMin;
FashionTrayItem::FashionTrayItem(Dock::Position pos, QWidget *parent)
FashionTrayItem::FashionTrayItem(TrayPlugin *trayPlugin, QWidget *parent)
: QWidget(parent),
m_mainBoxLayout(new QBoxLayout(QBoxLayout::Direction::LeftToRight)),
m_trayBoxLayout(new QBoxLayout(QBoxLayout::Direction::LeftToRight)),
m_leftSpliter(new QLabel),
m_rightSpliter(new QLabel),
m_controlWidget(new FashionTrayControlWidget(pos)),
m_currentAttentionTray(nullptr),
m_attentionDelayTimer(new QTimer(this)),
m_dockPosistion(pos)
m_dockPosistion(trayPlugin->dockPosition()),
m_trayPlugin(trayPlugin),
m_controlWidget(new FashionTrayControlWidget(m_dockPosistion)),
m_currentAttentionTray(nullptr),
m_currentDraggingTray(nullptr)
{
setAcceptDrops(true);
m_leftSpliter->setStyleSheet("background-color: rgba(255, 255, 255, 0.1);");
m_rightSpliter->setStyleSheet("background-color: rgba(255, 255, 255, 0.1);");
@ -74,32 +78,37 @@ FashionTrayItem::FashionTrayItem(Dock::Position pos, QWidget *parent)
m_attentionDelayTimer->setInterval(3000);
m_attentionDelayTimer->setSingleShot(true);
setDockPostion(pos);
setDockPostion(m_dockPosistion);
onTrayListExpandChanged(m_controlWidget->expanded());
connect(m_controlWidget, &FashionTrayControlWidget::expandChanged, this, &FashionTrayItem::onTrayListExpandChanged);
}
void FashionTrayItem::setTrayWidgets(const QList<AbstractTrayWidget *> &trayWidgetList)
void FashionTrayItem::setTrayWidgets(const QMap<QString, AbstractTrayWidget *> &itemTrayMap)
{
clearTrayWidgets();
for (auto widget : trayWidgetList) {
trayWidgetAdded(widget);
for (auto it = itemTrayMap.constBegin(); it != itemTrayMap.constEnd(); ++it) {
trayWidgetAdded(it.key(), it.value());
}
}
void FashionTrayItem::trayWidgetAdded(AbstractTrayWidget *trayWidget)
void FashionTrayItem::trayWidgetAdded(const QString &itemKey, AbstractTrayWidget *trayWidget)
{
if (m_trayWidgetWrapperMap.keys().contains(trayWidget)) {
return;
for (auto w : m_wrapperList) {
if (w->absTrayWidget() == trayWidget) {
qDebug() << "Reject! want to isert duplicate trayWidget:" << itemKey << trayWidget;
return;
}
}
FashionTrayWidgetWrapper *wrapper = new FashionTrayWidgetWrapper(trayWidget);
FashionTrayWidgetWrapper *wrapper = new FashionTrayWidgetWrapper(itemKey, trayWidget);
wrapper->setFixedSize(QSize(TrayWidgetWidth, TrayWidgetHeight));
m_trayWidgetWrapperMap.insert(trayWidget, wrapper);
m_trayBoxLayout->addWidget(wrapper);
const int index = whereToInsert(wrapper);
m_trayBoxLayout->insertWidget(index, wrapper);
m_wrapperList.insert(index, wrapper);
wrapper->setVisible(m_controlWidget->expanded());
if (wrapper->attention()) {
@ -107,6 +116,9 @@ void FashionTrayItem::trayWidgetAdded(AbstractTrayWidget *trayWidget)
}
connect(wrapper, &FashionTrayWidgetWrapper::attentionChanged, this, &FashionTrayItem::onTrayAttentionChanged, static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection));
connect(wrapper, &FashionTrayWidgetWrapper::dragStart, this, &FashionTrayItem::onItemDragStart, Qt::UniqueConnection);
connect(wrapper, &FashionTrayWidgetWrapper::dragStop, this, &FashionTrayItem::onItemDragStop, Qt::UniqueConnection);
connect(wrapper, &FashionTrayWidgetWrapper::requestSwapWithDragging, this, &FashionTrayItem::onItemRequestSwapWithDragging, Qt::UniqueConnection);
if (trayWidget->trayTyep() == AbstractTrayWidget::TrayType::SystemTray) {
SystemTrayItem * sysTrayWidget = static_cast<SystemTrayItem *>(trayWidget);
@ -119,13 +131,13 @@ void FashionTrayItem::trayWidgetAdded(AbstractTrayWidget *trayWidget)
void FashionTrayItem::trayWidgetRemoved(AbstractTrayWidget *trayWidget)
{
auto it = m_trayWidgetWrapperMap.constBegin();
bool founded = false;
for (; it != m_trayWidgetWrapperMap.constEnd(); ++it) {
for (auto wrapper : m_wrapperList) {
// found the removed tray
if (it.key() == trayWidget) {
if (wrapper->absTrayWidget() == trayWidget) {
// the removed tray is a attention tray
if (m_currentAttentionTray == it.value()) {
if (m_currentAttentionTray == wrapper) {
if (m_controlWidget->expanded()) {
m_trayBoxLayout->removeWidget(m_currentAttentionTray);
} else {
@ -133,21 +145,20 @@ void FashionTrayItem::trayWidgetRemoved(AbstractTrayWidget *trayWidget)
}
m_currentAttentionTray = nullptr;
} else {
m_trayBoxLayout->removeWidget(it.value());
m_trayBoxLayout->removeWidget(wrapper);
}
// do not delete real tray object, just delete it's wrapper object
// the real tray object should be deleted in TrayPlugin class
trayWidget->setParent(nullptr);
it.value()->deleteLater();
m_trayWidgetWrapperMap.remove(it.key());
wrapper->deleteLater();
m_wrapperList.removeAll(wrapper);
founded = true;
break;
}
}
if (it == m_trayWidgetWrapperMap.constEnd()) {
qDebug() << "can not find the tray widget in fashion tray list";
Q_UNREACHABLE();
return;
if (!founded) {
qDebug() << "Error! can not find the tray widget in fashion tray list" << trayWidget;
}
requestResize();
@ -155,13 +166,13 @@ void FashionTrayItem::trayWidgetRemoved(AbstractTrayWidget *trayWidget)
void FashionTrayItem::clearTrayWidgets()
{
QMap<AbstractTrayWidget *, FashionTrayWidgetWrapper *> mMap = m_trayWidgetWrapperMap;
QList<QPointer<FashionTrayWidgetWrapper>> mList = m_wrapperList;
for (auto it = mMap.begin(); it != mMap.end(); ++it) {
trayWidgetRemoved(it.key());
for (auto wrapper : mList) {
trayWidgetRemoved(wrapper->absTrayWidget());
}
m_trayWidgetWrapperMap.clear();
m_wrapperList.clear();
requestResize();
}
@ -224,7 +235,7 @@ void FashionTrayItem::setSuggestIconSize(QSize size)
m_controlWidget->setFixedSize(newSize);
for (auto wrapper : m_trayWidgetWrapperMap.values()) {
for (auto wrapper : m_wrapperList) {
wrapper->setFixedSize(newSize);
}
@ -269,6 +280,18 @@ void FashionTrayItem::resizeEvent(QResizeEvent *event)
QWidget::resizeEvent(event);
}
void FashionTrayItem::dragEnterEvent(QDragEnterEvent *event)
{
// accept but do not handle the trays drag event
// in order to avoid the for forbidden label displayed on the mouse
if (event->mimeData()->hasFormat(TRAY_ITEM_DRAG_MIMEDATA)) {
event->accept();
return;
}
QWidget::dragEnterEvent(event);
}
QSize FashionTrayItem::sizeHint() const
{
return wantedTotalSize();
@ -280,19 +303,19 @@ QSize FashionTrayItem::wantedTotalSize() const
if (m_controlWidget->expanded()) {
if (m_dockPosistion == Dock::Position::Top || m_dockPosistion == Dock::Position::Bottom) {
size.setWidth(m_trayWidgetWrapperMap.size() * TrayWidgetWidth // 所有插件
size.setWidth(m_wrapperList.size() * TrayWidgetWidth // 所有插件
+ TrayWidgetWidth // 控制按钮
+ SpliterSize * 2 // 两个分隔条
+ 3 * TraySpace // MainBoxLayout所有space
+ (m_trayWidgetWrapperMap.size() - 1) * TraySpace); // TrayBoxLayout所有space
+ (m_wrapperList.size() - 1) * TraySpace); // TrayBoxLayout所有space
size.setHeight(height());
} else {
size.setWidth(width());
size.setHeight(m_trayWidgetWrapperMap.size() * TrayWidgetHeight // 所有插件
size.setHeight(m_wrapperList.size() * TrayWidgetHeight // 所有插件
+ TrayWidgetHeight // 控制按钮
+ SpliterSize * 2 // 两个分隔条
+ 3 * TraySpace // MainBoxLayout所有space
+ (m_trayWidgetWrapperMap.size() - 1) * TraySpace); // TrayBoxLayout所有space
+ (m_wrapperList.size() - 1) * TraySpace); // TrayBoxLayout所有space
}
} else {
if (m_dockPosistion == Dock::Position::Top || m_dockPosistion == Dock::Position::Bottom) {
@ -313,6 +336,162 @@ QSize FashionTrayItem::wantedTotalSize() const
return size;
}
int FashionTrayItem::whereToInsert(FashionTrayWidgetWrapper *wrapper) const
{
// 如果已经对图标进行过排序则完全按照从配置文件中获取的顺序来插入图标
if (m_trayPlugin->traysSortedInFashionMode()) {
return whereToInsertBySortKey(wrapper);
}
// 如果没有对图标进行过排序则使用下面的默认排序算法:
// 所有应用图标在系统图标的左侧
// 新的应用图标在最左侧的应用图标处插入
// 新的系统图标在最左侧的系统图标处插入
return whereToInsertByDefault(wrapper);
}
int FashionTrayItem::whereToInsertBySortKey(FashionTrayWidgetWrapper *wrapper) const
{
if (m_wrapperList.isEmpty()) {
return 0;
}
const int destSortKey = m_trayPlugin->itemSortKey(wrapper->itemKey());
if (destSortKey < -1) {
return 0;
}
if (destSortKey == -1) {
return m_wrapperList.size();
}
// 当目标插入位置为列表的大小时将从最后面追加到列表中
int destIndex = m_wrapperList.size();
for (int i = 0; i < m_wrapperList.size(); ++i) {
if (destSortKey > m_trayPlugin->itemSortKey(m_wrapperList.at(i)->itemKey())) {
continue;
}
destIndex = i;
break;
}
return destIndex;
}
int FashionTrayItem::whereToInsertByDefault(FashionTrayWidgetWrapper *wrapper) const
{
int index = 0;
switch (wrapper->absTrayWidget()->trayTyep()) {
case AbstractTrayWidget::TrayType::ApplicationTray:
index = whereToInsertAppTrayByDefault(wrapper);
break;
case AbstractTrayWidget::TrayType::SystemTray:
index = whereToInsertSystemTrayByDefault(wrapper);
break;
default:
Q_UNREACHABLE();
break;
}
return index;
}
int FashionTrayItem::whereToInsertAppTrayByDefault(FashionTrayWidgetWrapper *wrapper) const
{
if (m_wrapperList.isEmpty() || wrapper->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::ApplicationTray) {
return 0;
}
int lastAppTrayIndex = -1;
for (int i = 0; i < m_wrapperList.size(); ++i) {
if (m_wrapperList.at(i)->absTrayWidget()->trayTyep() == AbstractTrayWidget::TrayType::ApplicationTray) {
lastAppTrayIndex = i;
continue;
}
break;
}
// there is no AppTray
if (lastAppTrayIndex == -1) {
return 0;
}
// the inserting tray is not a AppTray
if (wrapper->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::ApplicationTray) {
return lastAppTrayIndex + 1;
}
int insertIndex = m_trayPlugin->itemSortKey(wrapper->itemKey());
// invalid index
if (insertIndex < -1) {
return 0;
}
for (int i = 0; i < m_wrapperList.size(); ++i) {
if (m_wrapperList.at(i)->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::ApplicationTray) {
insertIndex = i;
break;
}
if (insertIndex > m_trayPlugin->itemSortKey(m_wrapperList.at(i)->itemKey())) {
continue;
}
insertIndex = i;
break;
}
if (insertIndex > lastAppTrayIndex + 1) {
insertIndex = lastAppTrayIndex + 1;
}
return insertIndex;
}
int FashionTrayItem::whereToInsertSystemTrayByDefault(FashionTrayWidgetWrapper *wrapper) const
{
if (m_wrapperList.isEmpty()) {
return 0;
}
int firstSystemTrayIndex = -1;
for (int i = 0; i < m_wrapperList.size(); ++i) {
if (m_wrapperList.at(i)->absTrayWidget()->trayTyep() == AbstractTrayWidget::TrayType::SystemTray) {
firstSystemTrayIndex = i;
break;
}
}
// there is no SystemTray
if (firstSystemTrayIndex == -1) {
return m_wrapperList.size();
}
// the inserting tray is not a SystemTray
if (wrapper->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::SystemTray) {
return firstSystemTrayIndex;
}
int insertIndex = m_trayPlugin->itemSortKey(wrapper->itemKey());
// invalid index
if (insertIndex < -1) {
return firstSystemTrayIndex;
}
for (int i = 0; i < m_wrapperList.size(); ++i) {
if (m_wrapperList.at(i)->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::SystemTray) {
continue;
}
if (insertIndex > m_trayPlugin->itemSortKey(m_wrapperList.at(i)->itemKey())) {
continue;
}
insertIndex = i;
break;
}
if (insertIndex < firstSystemTrayIndex) {
return firstSystemTrayIndex;
}
return insertIndex;
}
void FashionTrayItem::saveCurrentOrderToConfig()
{
for (int i = 0; i < m_wrapperList.size(); ++i) {
m_trayPlugin->setSortKey(m_wrapperList.at(i)->itemKey(), i + 1);
}
}
void FashionTrayItem::onTrayAttentionChanged(const bool attention)
{
// 设置attention为false之后启动timer在timer处于Active状态期间不重设attention为true
@ -392,7 +571,7 @@ void FashionTrayItem::moveInAttionTray()
}
m_mainBoxLayout->removeWidget(m_currentAttentionTray);
m_trayBoxLayout->addWidget(m_currentAttentionTray);
m_trayBoxLayout->insertWidget(whereToInsert(m_currentAttentionTray), m_currentAttentionTray);
m_currentAttentionTray->setVisible(false);
m_currentAttentionTray->setAttention(false);
}
@ -405,7 +584,7 @@ void FashionTrayItem::switchAttionTray(FashionTrayWidgetWrapper *attentionWrappe
m_mainBoxLayout->replaceWidget(m_currentAttentionTray, attentionWrapper);
m_trayBoxLayout->removeWidget(attentionWrapper);
m_trayBoxLayout->addWidget(m_currentAttentionTray);
m_trayBoxLayout->insertWidget(whereToInsert(m_currentAttentionTray), m_currentAttentionTray);
attentionWrapper->setVisible(true);
m_currentAttentionTray->setVisible(m_controlWidget->expanded());
@ -436,19 +615,64 @@ void FashionTrayItem::refreshTraysVisible()
if (m_currentAttentionTray) {
if (expand) {
m_mainBoxLayout->removeWidget(m_currentAttentionTray);
m_trayBoxLayout->addWidget(m_currentAttentionTray);
m_trayBoxLayout->insertWidget(whereToInsert(m_currentAttentionTray), m_currentAttentionTray);
}
m_currentAttentionTray = nullptr;
}
for (auto i = m_trayWidgetWrapperMap.begin(); i != m_trayWidgetWrapperMap.end(); ++i) {
i.value()->setVisible(expand);
for (auto wrapper : m_wrapperList) {
wrapper->setVisible(expand);
// reset all tray item attention state
i.value()->setAttention(false);
wrapper->setAttention(false);
}
m_attentionDelayTimer->start();
requestResize();
}
void FashionTrayItem::onItemDragStart()
{
FashionTrayWidgetWrapper *wrapper = static_cast<FashionTrayWidgetWrapper *>(sender());
if (!wrapper) {
return;
}
m_currentDraggingTray = wrapper;
}
void FashionTrayItem::onItemDragStop()
{
FashionTrayWidgetWrapper *wrapper = static_cast<FashionTrayWidgetWrapper *>(sender());
if (!wrapper) {
return;
}
if (m_currentDraggingTray == wrapper) {
m_currentDraggingTray = nullptr;
} else {
Q_UNREACHABLE();
}
saveCurrentOrderToConfig();
}
void FashionTrayItem::onItemRequestSwapWithDragging()
{
FashionTrayWidgetWrapper *wrapper = static_cast<FashionTrayWidgetWrapper *>(sender());
if (!wrapper || !m_currentDraggingTray || wrapper == m_currentDraggingTray) {
return;
}
const int indexOfDest = m_trayBoxLayout->indexOf(wrapper);
const int indexOfDragging = m_trayBoxLayout->indexOf(m_currentDraggingTray);
m_trayBoxLayout->removeWidget(m_currentDraggingTray);
m_trayBoxLayout->insertWidget(indexOfDest, m_currentDraggingTray);
m_wrapperList.insert(indexOfDest, m_wrapperList.takeAt(indexOfDragging));
}

View File

@ -23,6 +23,7 @@
#define FASHIONTRAYITEM_H
#include "constants.h"
#include "trayplugin.h"
#include "fashiontraywidgetwrapper.h"
#include "fashiontraycontrolwidget.h"
@ -38,10 +39,10 @@ class FashionTrayItem : public QWidget
Q_OBJECT
public:
explicit FashionTrayItem(Dock::Position pos, QWidget *parent = 0);
explicit FashionTrayItem(TrayPlugin *trayPlugin, QWidget *parent = 0);
void setTrayWidgets(const QList<AbstractTrayWidget *> &trayWidgetList);
void trayWidgetAdded(AbstractTrayWidget *trayWidget);
void setTrayWidgets(const QMap<QString, AbstractTrayWidget *> &itemTrayMap);
void trayWidgetAdded(const QString &itemKey, AbstractTrayWidget *trayWidget);
void trayWidgetRemoved(AbstractTrayWidget *trayWidget);
void clearTrayWidgets();
@ -56,10 +57,17 @@ protected:
void showEvent(QShowEvent *event) Q_DECL_OVERRIDE;
void hideEvent(QHideEvent *event) Q_DECL_OVERRIDE;
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE;
private:
QSize sizeHint() const Q_DECL_OVERRIDE;
QSize wantedTotalSize() const;
int whereToInsert(FashionTrayWidgetWrapper *wrapper) const;
int whereToInsertBySortKey(FashionTrayWidgetWrapper *wrapper) const;
int whereToInsertByDefault(FashionTrayWidgetWrapper *wrapper) const;
int whereToInsertAppTrayByDefault(FashionTrayWidgetWrapper *wrapper) const;
int whereToInsertSystemTrayByDefault(FashionTrayWidgetWrapper *wrapper) const;
void saveCurrentOrderToConfig();
private Q_SLOTS:
void onTrayAttentionChanged(const bool attention);
@ -73,19 +81,26 @@ private Q_SLOTS:
void expandWithAnimation();
void foldWithAnimation();
void refreshTraysVisible();
void onItemDragStart();
void onItemDragStop();
void onItemRequestSwapWithDragging();
private:
QMap<AbstractTrayWidget *, FashionTrayWidgetWrapper *> m_trayWidgetWrapperMap;
QBoxLayout *m_mainBoxLayout;
QBoxLayout *m_trayBoxLayout;
QLabel *m_leftSpliter;
QLabel *m_rightSpliter;
FashionTrayControlWidget *m_controlWidget;
FashionTrayWidgetWrapper *m_currentAttentionTray;
QTimer *m_attentionDelayTimer;
Dock::Position m_dockPosistion;
TrayPlugin *m_trayPlugin;
FashionTrayControlWidget *m_controlWidget;
FashionTrayWidgetWrapper *m_currentAttentionTray;
FashionTrayWidgetWrapper *m_currentDraggingTray;
QList<QPointer<FashionTrayWidgetWrapper>> m_wrapperList;
static int TrayWidgetWidth;
static int TrayWidgetHeight;
};

View File

@ -23,15 +23,26 @@
#include <QPainter>
#include <QDebug>
#include <QMouseEvent>
#include <QDrag>
#include <QMimeData>
FashionTrayWidgetWrapper::FashionTrayWidgetWrapper(AbstractTrayWidget *absTrayWidget, QWidget *parent)
#define TRAY_ITEM_DRAG_THRESHOLD 20
FashionTrayWidgetWrapper::FashionTrayWidgetWrapper(const QString &itemKey, AbstractTrayWidget *absTrayWidget, QWidget *parent)
: QWidget(parent),
m_absTrayWidget(absTrayWidget),
m_layout(new QVBoxLayout(this)),
m_attention(false)
m_attention(false),
m_dragging(false),
m_itemKey(itemKey)
{
setStyleSheet("background: transparent;");
setAcceptDrops(true);
m_absTrayWidget->setVisible(true);
m_absTrayWidget->installEventFilter(this);
m_layout->setSpacing(0);
m_layout->setMargin(0);
@ -50,8 +61,19 @@ AbstractTrayWidget *FashionTrayWidgetWrapper::absTrayWidget() const
return m_absTrayWidget;
}
QString FashionTrayWidgetWrapper::itemKey() const
{
return m_itemKey;
}
void FashionTrayWidgetWrapper::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
if (m_dragging) {
return;
}
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setOpacity(0.5);
@ -61,6 +83,77 @@ void FashionTrayWidgetWrapper::paintEvent(QPaintEvent *event)
painter.fillPath(path, QColor::fromRgb(40, 40, 40));
}
bool FashionTrayWidgetWrapper::eventFilter(QObject *watched, QEvent *event)
{
if (watched == m_absTrayWidget) {
if (event->type() == QEvent::Type::MouseButtonPress) {
mousePressEvent(static_cast<QMouseEvent *>(event));
} else if (event->type() == QEvent::Type::MouseMove) {
handleMouseMove(static_cast<QMouseEvent *>(event));
}
}
return false;
}
void FashionTrayWidgetWrapper::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::MouseButton::LeftButton) {
MousePressPoint = event->pos();
}
QWidget::mousePressEvent(event);
}
void FashionTrayWidgetWrapper::mouseMoveEvent(QMouseEvent *event)
{
return QWidget::mouseMoveEvent(event);
}
void FashionTrayWidgetWrapper::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasFormat(TRAY_ITEM_DRAG_MIMEDATA)) {
event->accept();
Q_EMIT requestSwapWithDragging();
return;
}
QWidget::dragEnterEvent(event);
}
void FashionTrayWidgetWrapper::handleMouseMove(QMouseEvent *event)
{
if (event->buttons() != Qt::MouseButton::LeftButton) {
return QWidget::mouseMoveEvent(event);
}
// if ((event->pos() - MousePressPoint).manhattanLength() < TRAY_ITEM_DRAG_THRESHOLD) {
// return QWidget::mouseMoveEvent(event);
// }
event->accept();
QDrag drag(this);
QMimeData *mimeData = new QMimeData;
mimeData->setData(TRAY_ITEM_DRAG_MIMEDATA, m_itemKey.toLocal8Bit());
QPixmap pixmap = grab();
drag.setMimeData(mimeData);
drag.setPixmap(pixmap);
drag.setHotSpot(pixmap.rect().center() / pixmap.devicePixelRatioF());
m_absTrayWidget->setVisible(false);
m_dragging = true;
Q_EMIT dragStart();
// start drag
drag.exec();
m_absTrayWidget->setVisible(true);
m_dragging = false;
Q_EMIT dragStop();
}
void FashionTrayWidgetWrapper::onTrayWidgetNeedAttention()
{
setAttention(true);

View File

@ -27,24 +27,35 @@
#include <QWidget>
#include <QVBoxLayout>
#define TRAY_ITEM_DRAG_MIMEDATA "TrayItemDragDrop"
class FashionTrayWidgetWrapper : public QWidget
{
Q_OBJECT
public:
FashionTrayWidgetWrapper(AbstractTrayWidget *absTrayWidget, QWidget *parent = nullptr);
FashionTrayWidgetWrapper(const QString &itemKey, AbstractTrayWidget *absTrayWidget, QWidget *parent = nullptr);
AbstractTrayWidget *absTrayWidget() const;
QString itemKey() const;
bool attention() const;
void setAttention(bool attention);
Q_SIGNALS:
void attentionChanged(const bool attention);
void dragStart();
void dragStop();
void requestSwapWithDragging();
protected:
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
bool eventFilter(QObject *watched, QEvent *event) Q_DECL_OVERRIDE;
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE;
private:
void handleMouseMove(QMouseEvent *event);
void onTrayWidgetNeedAttention();
void onTrayWidgetClicked();
@ -53,6 +64,9 @@ private:
QVBoxLayout *m_layout;
bool m_attention;
bool m_dragging;
QString m_itemKey;
QPoint MousePressPoint;
};
#endif //FASHIONTRAYWIDGETWRAPPER_H

View File

@ -39,15 +39,15 @@ SystemTraysController::SystemTraysController(QObject *parent)
void SystemTraysController::itemAdded(PluginsItemInterface * const itemInter, const QString &itemKey)
{
// check if same item added
if (m_pluginList.contains(itemInter))
if (m_pluginList[itemInter].contains(itemKey))
if (m_pluginsMap.contains(itemInter))
if (m_pluginsMap[itemInter].contains(itemKey))
return;
SystemTrayItem *item = new SystemTrayItem(itemInter, itemKey);
item->setVisible(false);
m_pluginList[itemInter][itemKey] = item;
m_pluginsMap[itemInter][itemKey] = item;
emit systemTrayAdded(itemKey, item);
}
@ -74,7 +74,7 @@ void SystemTraysController::itemRemoved(PluginsItemInterface * const itemInter,
emit systemTrayRemoved(itemKey);
m_pluginList[itemInter].remove(itemKey);
m_pluginsMap[itemInter].remove(itemKey);
// do not delete the itemWidget object(specified in the plugin interface)
item->centralWidget()->setParent(nullptr);
@ -104,7 +104,7 @@ void SystemTraysController::startLoader()
void SystemTraysController::displayModeChanged()
{
const Dock::DisplayMode displayMode = qApp->property(PROP_DISPLAY_MODE).value<Dock::DisplayMode>();
const auto inters = m_pluginList.keys();
const auto inters = m_pluginsMap.keys();
for (auto inter : inters)
inter->displayModeChanged(displayMode);
@ -113,7 +113,7 @@ void SystemTraysController::displayModeChanged()
void SystemTraysController::positionChanged()
{
const Dock::Position position = qApp->property(PROP_POSITION).value<Dock::Position>();
const auto inters = m_pluginList.keys();
const auto inters = m_pluginsMap.keys();
for (auto inter : inters)
inter->positionChanged(position);
@ -138,7 +138,7 @@ void SystemTraysController::loadPlugin(const QString &pluginFile)
return;
}
m_pluginList.insert(interface, QMap<QString, SystemTrayItem *>());
m_pluginsMap.insert(interface, QMap<QString, SystemTrayItem *>());
QString dbusService = meta.value("depends-daemon-dbus-service").toString();
if (!dbusService.isEmpty() && !m_dbusDaemonInterface->isServiceRegistered(dbusService).value()) {
@ -184,10 +184,36 @@ bool SystemTraysController::eventFilter(QObject *o, QEvent *e)
SystemTrayItem *SystemTraysController::pluginItemAt(PluginsItemInterface * const itemInter, const QString &itemKey) const
{
if (!m_pluginList.contains(itemInter))
if (!m_pluginsMap.contains(itemInter))
return nullptr;
return m_pluginList[itemInter][itemKey];
return m_pluginsMap[itemInter][itemKey];
}
PluginsItemInterface *SystemTraysController::pluginInterAt(const QString &itemKey) const
{
for (auto it = m_pluginsMap.constBegin(); it != m_pluginsMap.constEnd(); ++it) {
for (auto key : it.value().keys()) {
if (key == itemKey) {
return it.key();
}
}
}
return nullptr;
}
PluginsItemInterface *SystemTraysController::pluginInterAt(SystemTrayItem *systemTrayItem) const
{
for (auto it = m_pluginsMap.constBegin(); it != m_pluginsMap.constEnd(); ++it) {
for (auto item : it.value().values()) {
if (item == systemTrayItem) {
return it.key();
}
}
}
return nullptr;
}
void SystemTraysController::saveValue(PluginsItemInterface *const itemInter, const QString &key, const QVariant &value) {
@ -202,3 +228,25 @@ const QVariant SystemTraysController::getValue(PluginsItemInterface *const itemI
m_pluginsSetting.endGroup();
return std::move(value);
}
int SystemTraysController::systemTrayItemSortKey(const QString &itemKey)
{
auto inter = pluginInterAt(itemKey);
if (!inter) {
return -1;
}
return inter->itemSortKey(itemKey);
}
void SystemTraysController::setSystemTrayItemSortKey(const QString &itemKey, const int order)
{
auto inter = pluginInterAt(itemKey);
if (!inter) {
return;
}
inter->setSortKey(itemKey, order);
}

View File

@ -46,6 +46,9 @@ public:
void saveValue(PluginsItemInterface *const itemInter, const QString &key, const QVariant &value);
const QVariant getValue(PluginsItemInterface *const itemInter, const QString &key, const QVariant& failback = QVariant());
int systemTrayItemSortKey(const QString &itemKey);
void setSystemTrayItemSortKey(const QString &itemKey, const int order);
public slots:
void startLoader();
@ -63,10 +66,12 @@ private slots:
private:
bool eventFilter(QObject *o, QEvent *e);
SystemTrayItem *pluginItemAt(PluginsItemInterface * const itemInter, const QString &itemKey) const;
PluginsItemInterface *pluginInterAt(const QString &itemKey) const;
PluginsItemInterface *pluginInterAt(SystemTrayItem *systemTrayItem) const;
private:
QDBusConnectionInterface *m_dbusDaemonInterface;
QMap<PluginsItemInterface *, QMap<QString, SystemTrayItem *>> m_pluginList;
QMap<PluginsItemInterface *, QMap<QString, SystemTrayItem *>> m_pluginsMap;
QSettings m_pluginsSetting;
};

View File

@ -33,6 +33,7 @@
#include "xcb/xcb_icccm.h"
#define FASHION_MODE_ITEM "fashion-mode-item"
#define FASHION_MODE_TRAYS_SORTED "fashion-mode-trays-sorted"
TrayPlugin::TrayPlugin(QObject *parent)
: QObject(parent),
@ -40,7 +41,7 @@ TrayPlugin::TrayPlugin(QObject *parent)
m_systemTraysController(new SystemTraysController(this)),
m_tipsLabel(new TipsWidget)
{
m_fashionItem = new FashionTrayItem(position());
m_fashionItem = new FashionTrayItem(this);
m_tipsLabel->setObjectName("tray");
m_tipsLabel->setText(tr("System Tray"));
@ -156,14 +157,31 @@ bool TrayPlugin::itemIsInContainer(const QString &itemKey)
int TrayPlugin::itemSortKey(const QString &itemKey)
{
Dock::DisplayMode mode = displayMode();
const QString key = QString("pos_%1_%2").arg(itemKey).arg(mode);
// 如果是系统托盘图标则调用内部插件的相应接口
if (isSystemTrayItem(itemKey)) {
return m_systemTraysController->systemTrayItemSortKey(itemKey);
}
return m_proxyInter->getValue(this, key, mode == Dock::DisplayMode::Fashion ? 1 : 0).toInt();
if (itemKey == FASHION_MODE_ITEM) {
return 1;
}
const QString key = QString("pos_%1_%2").arg(itemKey).arg(displayMode());
return m_proxyInter->getValue(this, key, displayMode() == Dock::DisplayMode::Fashion ? 0 : 0).toInt();
}
void TrayPlugin::setSortKey(const QString &itemKey, const int order)
{
if (displayMode() == Dock::DisplayMode::Fashion && !traysSortedInFashionMode()) {
m_proxyInter->saveValue(this, FASHION_MODE_TRAYS_SORTED, true);
}
// 如果是系统托盘图标则调用内部插件的相应接口
if (isSystemTrayItem(itemKey)) {
return m_systemTraysController->setSystemTrayItemSortKey(itemKey, order);
}
const QString key = QString("pos_%1_%2").arg(itemKey).arg(displayMode());
m_proxyInter->saveValue(this, key, order);
}
@ -175,6 +193,16 @@ void TrayPlugin::setItemIsInContainer(const QString &itemKey, const bool contain
m_proxyInter->saveValue(this, widKey.isEmpty() ? itemKey : widKey, container);
}
Dock::Position TrayPlugin::dockPosition() const
{
return position();
}
bool TrayPlugin::traysSortedInFashionMode()
{
return m_proxyInter->getValue(this, FASHION_MODE_TRAYS_SORTED, false).toBool();
}
const QString TrayPlugin::getWindowClass(quint32 winId)
{
auto *connection = QX11Info::connection();
@ -196,6 +224,17 @@ const QString TrayPlugin::getWindowClass(quint32 winId)
return ret;
}
bool TrayPlugin::isSystemTrayItem(const QString &itemKey)
{
AbstractTrayWidget * const trayWidget = m_trayMap.value(itemKey, nullptr);
if (trayWidget && trayWidget->trayTyep() == AbstractTrayWidget::TrayType::SystemTray) {
return true;
}
return false;
}
void TrayPlugin::sniItemsChanged()
{
const QStringList &itemServicePaths = m_sniWatcher->RegisteredStatusNotifierItems();
@ -247,7 +286,7 @@ void TrayPlugin::addTrayWidget(const QString &itemKey, AbstractTrayWidget *trayW
m_proxyInter->itemAdded(this, itemKey);
} else {
m_proxyInter->itemAdded(this, FASHION_MODE_ITEM);
m_fashionItem->trayWidgetAdded(trayWidget);
m_fashionItem->trayWidgetAdded(itemKey, trayWidget);
}
}
@ -341,7 +380,7 @@ void TrayPlugin::switchToMode(const Dock::DisplayMode mode)
if (m_trayMap.isEmpty()) {
m_proxyInter->itemRemoved(this, FASHION_MODE_ITEM);
} else {
m_fashionItem->setTrayWidgets(m_trayMap.values());
m_fashionItem->setTrayWidgets(m_trayMap);
m_proxyInter->itemAdded(this, FASHION_MODE_ITEM);
}
} else {

View File

@ -60,9 +60,13 @@ public:
void setSortKey(const QString &itemKey, const int order) Q_DECL_OVERRIDE;
void setItemIsInContainer(const QString &itemKey, const bool container) Q_DECL_OVERRIDE;
Dock::Position dockPosition() const;
bool traysSortedInFashionMode();
private:
void loadIndicator();
const QString getWindowClass(quint32 winId);
bool isSystemTrayItem(const QString &itemKey);
private slots:
void addTrayWidget(const QString &itemKey, AbstractTrayWidget *trayWidget);

View File

@ -82,8 +82,6 @@ XWindowTrayWidget::XWindowTrayWidget(quint32 winId, QWidget *parent)
connect(m_sendHoverEvent, &QTimer::timeout, this, &XWindowTrayWidget::sendHoverEvent);
#endif
setMouseTracking(true);
m_updateTimer->start();
}
@ -131,7 +129,7 @@ void XWindowTrayWidget::paintEvent(QPaintEvent *e)
void XWindowTrayWidget::mouseMoveEvent(QMouseEvent *e)
{
QWidget::mouseMoveEvent(e);
AbstractTrayWidget::mouseMoveEvent(e);
m_sendHoverEvent->start();
}