diff --git a/tray/CMakeLists.txt b/tray/CMakeLists.txt index 89fa70b..eaa5f7a 100644 --- a/tray/CMakeLists.txt +++ b/tray/CMakeLists.txt @@ -17,7 +17,8 @@ set(WIDGETS_HEADER_FILES gui/downloaditemdelegate.h gui/dirview.h gui/devview.h - gui/downloadview.h) + gui/downloadview.h + gui/helper.h) set(WIDGETS_SRC_FILES application/main.cpp application/singleinstance.cpp @@ -29,7 +30,8 @@ set(WIDGETS_SRC_FILES gui/downloaditemdelegate.cpp gui/dirview.cpp gui/devview.cpp - gui/downloadview.cpp) + gui/downloadview.cpp + gui/helper.cpp) set(RES_FILES resources/${META_PROJECT_NAME}icons.qrc) set(WIDGETS_UI_FILES gui/traywidget.ui) diff --git a/tray/gui/devview.cpp b/tray/gui/devview.cpp index f745879..8d89484 100644 --- a/tray/gui/devview.cpp +++ b/tray/gui/devview.cpp @@ -1,5 +1,6 @@ #include "./devview.h" #include "./devbuttonsitemdelegate.h" +#include "./helper.h" #include "../../model/syncthingdevicemodel.h" @@ -63,14 +64,7 @@ void DevView::showContextMenu(const QPoint &position) tr("Copy ID")), &QAction::triggered, this, &DevView::copySelectedItemId); } - - // map the coordinates to top-level widget if it is a QMenu (not sure why this is required) - const auto *const topLevelWidget = this->topLevelWidget(); - if (qobject_cast(topLevelWidget)) { - menu.exec(topLevelWidget->mapToGlobal(position)); - } else { - menu.exec(viewport()->mapToGlobal(position)); - } + showViewMenu(position, *this, menu); } void DevView::copySelectedItem() diff --git a/tray/gui/dirview.cpp b/tray/gui/dirview.cpp index 551e864..7193d54 100644 --- a/tray/gui/dirview.cpp +++ b/tray/gui/dirview.cpp @@ -1,5 +1,6 @@ #include "./dirview.h" #include "./dirbuttonsitemdelegate.h" +#include "./helper.h" #include "../../connector/syncthingconnection.h" #include "../../model/syncthingdirectorymodel.h" @@ -87,14 +88,7 @@ void DirView::showContextMenu(const QPoint &position) tr("Copy path")), &QAction::triggered, this, &DirView::copySelectedItemPath); } - - // map the coordinates to top-level widget if it is a QMenu (not sure why this is required) - const auto *const topLevelWidget = this->topLevelWidget(); - if (qobject_cast(topLevelWidget)) { - menu.exec(topLevelWidget->mapToGlobal(position)); - } else { - menu.exec(viewport()->mapToGlobal(position)); - } + showViewMenu(position, *this, menu); } void DirView::copySelectedItem() diff --git a/tray/gui/downloadview.cpp b/tray/gui/downloadview.cpp index c831da1..72075a7 100644 --- a/tray/gui/downloadview.cpp +++ b/tray/gui/downloadview.cpp @@ -1,5 +1,6 @@ #include "./downloadview.h" #include "./downloaditemdelegate.h" +#include "./helper.h" #include "../../model/syncthingdownloadmodel.h" @@ -65,14 +66,7 @@ void DownloadView::showContextMenu(const QPoint &position) tr("Copy label/ID")), &QAction::triggered, this, &DownloadView::copySelectedItem); } - - // map the coordinates to top-level widget if it is a QMenu (not sure why this is required) - const auto *const topLevelWidget = this->topLevelWidget(); - if (qobject_cast(topLevelWidget)) { - menu.exec(topLevelWidget->mapToGlobal(position)); - } else { - menu.exec(viewport()->mapToGlobal(position)); - } + showViewMenu(position, *this, menu); } void DownloadView::copySelectedItem() diff --git a/tray/gui/helper.cpp b/tray/gui/helper.cpp new file mode 100644 index 0000000..6945def --- /dev/null +++ b/tray/gui/helper.cpp @@ -0,0 +1,20 @@ +#include "./helper.h" + +#include +#include +#include + +namespace QtGui { + +void showViewMenu(const QPoint &position, const QTreeView &view, QMenu &menu) +{ + // map the coordinates to top-level widget if it is a QMenu (not sure why this is required) + const auto *const topLevelWidget = view.topLevelWidget(); + if (qobject_cast(topLevelWidget)) { + menu.exec(topLevelWidget->mapToGlobal(position)); + } else { + menu.exec(view.viewport()->mapToGlobal(position)); + } +} + +} // namespace QtGui diff --git a/tray/gui/helper.h b/tray/gui/helper.h new file mode 100644 index 0000000..73c9fff --- /dev/null +++ b/tray/gui/helper.h @@ -0,0 +1,16 @@ +#ifndef TRAY_GUI_HELPER_H +#define TRAY_GUI_HELPER_H + +#include + +QT_FORWARD_DECLARE_CLASS(QPoint) +QT_FORWARD_DECLARE_CLASS(QTreeView) +QT_FORWARD_DECLARE_CLASS(QMenu) + +namespace QtGui { + +void showViewMenu(const QPoint &position, const QTreeView &view, QMenu &menu); + +} // namespace QtGui + +#endif // TRAY_GUI_HELPER_H diff --git a/tray/gui/traywidget.cpp b/tray/gui/traywidget.cpp index 921feb5..5eb2e1f 100644 --- a/tray/gui/traywidget.cpp +++ b/tray/gui/traywidget.cpp @@ -1,4 +1,5 @@ #include "./traywidget.h" +#include "./helper.h" #include "./trayicon.h" #include "./traymenu.h" @@ -89,6 +90,7 @@ TrayWidget::TrayWidget(TrayMenu *parent) m_ui->devsTreeView->setModel(&m_devModel); m_ui->downloadsTreeView->setModel(&m_dlModel); m_ui->recentChangesTreeView->setModel(&m_recentChangesModel); + m_ui->recentChangesTreeView->setContextMenuPolicy(Qt::CustomContextMenu); // setup sync-all button m_cornerFrame = new QFrame(this); @@ -175,6 +177,7 @@ TrayWidget::TrayWidget(TrayMenu *parent) connect(m_ui->devsTreeView, &DevView::pauseResumeDev, this, &TrayWidget::pauseResumeDev); connect(m_ui->downloadsTreeView, &DownloadView::openDir, this, &TrayWidget::openDir); connect(m_ui->downloadsTreeView, &DownloadView::openItemDir, this, &TrayWidget::openItemDir); + connect(m_ui->recentChangesTreeView, &QTreeView::customContextMenuRequested, this, &TrayWidget::showRecentChangesContextMenu); connect(scanAllButton, &QPushButton::clicked, &m_connection, &SyncthingConnection::rescanAllDirs); connect(viewIdButton, &QPushButton::clicked, this, &TrayWidget::showOwnDeviceId); connect(showLogButton, &QPushButton::clicked, this, &TrayWidget::showLog); @@ -546,6 +549,31 @@ void TrayWidget::pauseResumeDir(const SyncthingDir &dir) } } +void TrayWidget::showRecentChangesContextMenu(const QPoint &position) +{ + const auto *const selectionModel = m_ui->recentChangesTreeView->selectionModel(); + if (!selectionModel || selectionModel->selectedRows().size() != 1) { + return; + } + const auto copyRole = [this](SyncthingRecentChangesModel::SyncthingRecentChangesModelRole role) { + return [this, role] { + const auto *const selectionModel = m_ui->recentChangesTreeView->selectionModel(); + if (selectionModel && selectionModel->selectedRows().size() == 1) { + QGuiApplication::clipboard()->setText(m_recentChangesModel.data(selectionModel->selectedRows().at(0), role).toString()); + } + }; + }; + QMenu menu(this); + connect(menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/edit-copy.svg"))), + tr("Copy path")), + &QAction::triggered, this, copyRole(SyncthingRecentChangesModel::Path)); + connect(menu.addAction(QIcon::fromTheme(QStringLiteral("network-server-symbolic"), + QIcon(QStringLiteral(":/icons/hicolor/scalable/places/network-workgroup.svg"))), + tr("Copy device ID")), + &QAction::triggered, this, copyRole(SyncthingRecentChangesModel::ModifiedBy)); + showViewMenu(position, *m_ui->recentChangesTreeView, menu); +} + void TrayWidget::changeStatus() { switch (m_connection.status()) { diff --git a/tray/gui/traywidget.h b/tray/gui/traywidget.h index 6332f33..9b028fe 100644 --- a/tray/gui/traywidget.h +++ b/tray/gui/traywidget.h @@ -21,6 +21,7 @@ QT_FORWARD_DECLARE_CLASS(QFrame) QT_FORWARD_DECLARE_CLASS(QMenu) QT_FORWARD_DECLARE_CLASS(QActionGroup) QT_FORWARD_DECLARE_CLASS(QPushButton) +QT_FORWARD_DECLARE_CLASS(QTreeView) namespace CppUtilities { class QtConfigArguments; @@ -82,6 +83,7 @@ private slots: void scanDir(const Data::SyncthingDir &dir); void pauseResumeDev(const Data::SyncthingDev &dev); void pauseResumeDir(const Data::SyncthingDir &dir); + void showRecentChangesContextMenu(const QPoint &position); void changeStatus(); void updateTraffic(); void updateOverallStatistics();