diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 69c9ae1a2..e25d02945 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -287,6 +287,8 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") macosdockbadge/badger.mm macosdockbadge/badgeview.h macosdockbadge/badgeview.mm + macosshiftclickhandler.h + macosshiftclickhandler.cpp macutilities.h macutilities.mm ) diff --git a/src/gui/macosshiftclickhandler.cpp b/src/gui/macosshiftclickhandler.cpp new file mode 100644 index 000000000..81ba81926 --- /dev/null +++ b/src/gui/macosshiftclickhandler.cpp @@ -0,0 +1,73 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2025 Luke Memet (lukemmtt) + * + * 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 2 + * of the License, or (at your option) 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#include "macosshiftclickhandler.h" + +#include +#include + +MacOSShiftClickHandler::MacOSShiftClickHandler(QTreeView *treeView) + : QObject(treeView) + , m_treeView {treeView} +{ + treeView->installEventFilter(this); +} + +bool MacOSShiftClickHandler::eventFilter(QObject *watched, QEvent *event) +{ + if ((watched == m_treeView) && (event->type() == QEvent::MouseButtonPress)) + { + const auto *mouseEvent = static_cast(event); + if (mouseEvent->button() != Qt::LeftButton) + return false; + + const QModelIndex clickedIndex = m_treeView->indexAt(mouseEvent->position().toPoint()); + if (!clickedIndex.isValid()) + return false; + + const Qt::KeyboardModifiers modifiers = mouseEvent->modifiers(); + const bool shiftPressed = modifiers.testFlag(Qt::ShiftModifier); + + if (shiftPressed && m_lastClickedIndex.isValid()) + { + const QItemSelection selection(m_lastClickedIndex, clickedIndex); + const bool commandPressed = modifiers.testFlag(Qt::ControlModifier); + if (commandPressed) + m_treeView->selectionModel()->select(selection, (QItemSelectionModel::Select | QItemSelectionModel::Rows)); + else + m_treeView->selectionModel()->select(selection, (QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows)); + m_treeView->selectionModel()->setCurrentIndex(clickedIndex, QItemSelectionModel::NoUpdate); + return true; + } + + if (!modifiers.testFlags(Qt::AltModifier | Qt::MetaModifier)) + m_lastClickedIndex = clickedIndex; + } + + return QObject::eventFilter(watched, event); +} diff --git a/src/gui/macosshiftclickhandler.h b/src/gui/macosshiftclickhandler.h new file mode 100644 index 000000000..43d6fda16 --- /dev/null +++ b/src/gui/macosshiftclickhandler.h @@ -0,0 +1,50 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2025 Luke Memet (lukemmtt) + * + * 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 2 + * of the License, or (at your option) 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#pragma once + +#include +#include + +class QTreeView; + +// Workaround for QTBUG-115838: Shift-click range selection not working properly on macOS +class MacOSShiftClickHandler final : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY_MOVE(MacOSShiftClickHandler) + +public: + explicit MacOSShiftClickHandler(QTreeView *treeView); + +private: + bool eventFilter(QObject *watched, QEvent *event) override; + + QTreeView *m_treeView = nullptr; + QPersistentModelIndex m_lastClickedIndex; +}; diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index 9435b05be..cd6b44653 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -74,6 +74,7 @@ #include "utils.h" #ifdef Q_OS_MACOS +#include "macosshiftclickhandler.h" #include "macutilities.h" #endif @@ -158,6 +159,7 @@ TransferListWidget::TransferListWidget(IGUIApplication *app, QWidget *parent) setDropIndicatorShown(true); #if defined(Q_OS_MACOS) setAttribute(Qt::WA_MacShowFocusRect, false); + new MacOSShiftClickHandler(this); #endif header()->setFirstSectionMovable(true); header()->setStretchLastSection(false);