File indexing completed on 2024-05-12 17:22:02

0001 /*
0002     SPDX-FileCopyrightText: 2009 Csaba Karai <cskarai@freemail.hu>
0003     SPDX-FileCopyrightText: 2009-2022 Krusader Krew <https://krusader.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "krmousehandler.h"
0009 #include "../defaults.h"
0010 #include "../krglobal.h"
0011 #include "krselectionmode.h"
0012 #include "krview.h"
0013 #include "krviewitem.h"
0014 
0015 // QtCore
0016 #include <QStandardPaths>
0017 // QtWidgets
0018 #include <QApplication>
0019 #include <QStyle>
0020 
0021 #include <KConfigCore/KSharedConfig>
0022 #include <KCoreAddons/KUrlMimeData>
0023 
0024 #define CANCEL_TWO_CLICK_RENAME                                                                                                                                \
0025     {                                                                                                                                                          \
0026         _singleClicked = false;                                                                                                                                \
0027         _renameTimer.stop();                                                                                                                                   \
0028     }
0029 
0030 KrMouseHandler::KrMouseHandler(KrView *view, int contextMenuShift)
0031     : _view(view)
0032     , _rightClickedItem(nullptr)
0033     , _contextMenuShift(contextMenuShift)
0034     , _singleClicked(false)
0035     , _dragStartPos(-1, -1)
0036     , _emptyContextMenu(false)
0037 {
0038     KConfigGroup grpSvr(krConfig, "Look&Feel");
0039     // decide on single click/double click selection
0040     bool singleClickTmp = QApplication::style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick);
0041     _singleClick = grpSvr.readEntry("Single Click Selects", _SingleClickSelects) && singleClickTmp;
0042     connect(&_contextMenuTimer, &QTimer::timeout, this, &KrMouseHandler::showContextMenu);
0043     connect(&_renameTimer, &QTimer::timeout, this, &KrMouseHandler::renameCurrentItem);
0044 }
0045 
0046 bool KrMouseHandler::mousePressEvent(QMouseEvent *e)
0047 {
0048     _rightClickedItem = _clickedItem = nullptr;
0049     KrViewItem *item = _view->getKrViewItemAt(e->pos());
0050     KrSelectionMode *mode = KrSelectionMode::getSelectionHandler();
0051 
0052     if (!_view->isFocused())
0053         _view->op()->emitNeedFocus();
0054     if (e->button() == Qt::LeftButton) {
0055         _dragStartPos = e->pos();
0056         if (e->modifiers() == Qt::NoModifier) {
0057             if (item) {
0058                 if (mode->leftButtonSelects()) {
0059                     if (mode->leftButtonPreservesSelection())
0060                         item->setSelected(!item->isSelected());
0061                     else {
0062                         if (item->isSelected())
0063                             _clickedItem = item;
0064                         else {
0065                             // clear the current selection
0066                             _view->unselectAll();
0067                             item->setSelected(true);
0068                         }
0069                     }
0070                 }
0071                 _view->setCurrentKrViewItem(item);
0072             } else {
0073                 // empty space under items clicked
0074                 if (mode->leftButtonSelects() && !mode->leftButtonPreservesSelection()) {
0075                     // clear the current selection
0076                     _view->unselectAll();
0077                 }
0078             }
0079             e->accept();
0080             return true;
0081         } else if (e->modifiers() == Qt::ControlModifier) {
0082             if (item && (mode->shiftCtrlLeftButtonSelects() || mode->leftButtonSelects())) {
0083                 // get current selected item names
0084                 _selectedItemNames.clear();
0085                 _view->getSelectedItems(&_selectedItemNames, false);
0086 
0087                 item->setSelected(!item->isSelected());
0088 
0089                 // select also the focused item if there are no other selected items
0090                 KrViewItem *previousItem = _view->getCurrentKrViewItem();
0091                 if (previousItem->name() != ".." && _selectedItemNames.empty()) {
0092                     previousItem->setSelected(true);
0093                 }
0094             }
0095             if (item) {
0096                 _view->setCurrentKrViewItem(item);
0097             }
0098             e->accept();
0099             return true;
0100         } else if (e->modifiers() == Qt::ShiftModifier) {
0101             if (item && (mode->shiftCtrlLeftButtonSelects() || mode->leftButtonSelects())) {
0102                 KrViewItem *current = _view->getCurrentKrViewItem();
0103                 if (current != nullptr)
0104                     _view->selectRegion(item, current, true);
0105             }
0106             if (item)
0107                 _view->setCurrentKrViewItem(item);
0108             e->accept();
0109             return true;
0110         }
0111     }
0112     if (e->button() == Qt::RightButton) {
0113         // dragStartPos = e->pos();
0114         if (e->modifiers() == Qt::NoModifier) {
0115             if (item) {
0116                 if (mode->rightButtonSelects()) {
0117                     if (mode->rightButtonPreservesSelection()) {
0118                         if (mode->showContextMenu() >= 0) {
0119                             _rightClickSelects = !item->isSelected();
0120                             _rightClickedItem = item;
0121                         }
0122                         item->setSelected(!item->isSelected());
0123                     } else {
0124                         if (item->isSelected()) {
0125                             _clickedItem = item;
0126                         } else {
0127                             // clear the current selection
0128                             _view->unselectAll();
0129                             item->setSelected(true);
0130                         }
0131                     }
0132                 }
0133                 _view->setCurrentKrViewItem(item);
0134             }
0135             handleContextMenu(item, e->globalPos());
0136             e->accept();
0137             return true;
0138         } else if (e->modifiers() == Qt::ControlModifier) {
0139             if (item && (mode->shiftCtrlRightButtonSelects() || mode->rightButtonSelects())) {
0140                 item->setSelected(!item->isSelected());
0141             }
0142             if (item)
0143                 _view->setCurrentKrViewItem(item);
0144             e->accept();
0145             return true;
0146         } else if (e->modifiers() == Qt::ShiftModifier) {
0147             if (item && (mode->shiftCtrlRightButtonSelects() || mode->rightButtonSelects())) {
0148                 KrViewItem *current = _view->getCurrentKrViewItem();
0149                 if (current != nullptr)
0150                     _view->selectRegion(item, current, true);
0151             }
0152             if (item)
0153                 _view->setCurrentKrViewItem(item);
0154             e->accept();
0155             return true;
0156         }
0157     }
0158     if (e->button() == Qt::ForwardButton) {
0159         _view->op()->emitGoForward();
0160         return true;
0161     }
0162     if (e->button() == Qt::BackButton) {
0163         _view->op()->emitGoBack();
0164         return true;
0165     }
0166     return false;
0167 }
0168 
0169 bool KrMouseHandler::mouseReleaseEvent(QMouseEvent *e)
0170 {
0171     if (e->button() == Qt::LeftButton)
0172         _dragStartPos = QPoint(-1, -1);
0173 
0174     KrViewItem *item = _view->getKrViewItemAt(e->pos());
0175     KrSelectionMode *mode = KrSelectionMode::getSelectionHandler();
0176 
0177     if (item && item == _clickedItem) {
0178         if (((e->button() == Qt::LeftButton) && (e->modifiers() == Qt::NoModifier) && (mode->leftButtonSelects()) && !(mode->leftButtonPreservesSelection()))
0179             || ((e->button() == Qt::RightButton) && (e->modifiers() == Qt::NoModifier) && (mode->rightButtonSelects())
0180                 && !(mode->rightButtonPreservesSelection()))) {
0181             // clear the current selection
0182             _view->unselectAll();
0183             item->setSelected(true);
0184         }
0185     }
0186 
0187     if (mode->resetSelectionItems()) {
0188         bool leftButtonClicked = (e->button() == Qt::LeftButton) && (e->modifiers() == Qt::NoModifier);
0189         bool rightButtonClicked = (e->button() == Qt::RightButton) && (e->modifiers() == Qt::NoModifier);
0190 
0191         bool leftTriggerCondition = !mode->leftButtonSelects() && mode->shiftCtrlLeftButtonSelects();
0192         bool rightTriggerCondition = !mode->rightButtonSelects() && mode->shiftCtrlRightButtonSelects();
0193 
0194         if ((leftButtonClicked && leftTriggerCondition) || (rightButtonClicked && rightTriggerCondition)) {
0195             // clear the current selection
0196             _view->unselectAll();
0197         }
0198     }
0199 
0200     if (e->button() == Qt::RightButton) {
0201         _rightClickedItem = nullptr;
0202         _contextMenuTimer.stop();
0203     }
0204     if (_singleClick && e->button() == Qt::LeftButton && e->modifiers() == Qt::NoModifier) {
0205         CANCEL_TWO_CLICK_RENAME;
0206         e->accept();
0207         if (item == nullptr)
0208             return true;
0209         QString tmp = item->name();
0210         _view->op()->emitExecuted(tmp);
0211         return true;
0212     } else if (!_singleClick && e->button() == Qt::LeftButton) {
0213         if (item && e->modifiers() == Qt::NoModifier) {
0214             if (_singleClicked && !_renameTimer.isActive() && _singleClickedItem == item) {
0215                 KSharedConfigPtr config = KSharedConfig::openConfig();
0216                 KConfigGroup group(krConfig, "KDE");
0217                 int doubleClickInterval = group.readEntry("DoubleClickInterval", 400);
0218 
0219                 int msecsFromLastClick = _singleClickTime.msecsTo(QTime::currentTime());
0220 
0221                 if (msecsFromLastClick > doubleClickInterval && msecsFromLastClick < 5 * doubleClickInterval) {
0222                     _singleClicked = false;
0223                     _renameTimer.setSingleShot(true);
0224                     _renameTimer.start(doubleClickInterval);
0225                     return true;
0226                 }
0227             }
0228 
0229             CANCEL_TWO_CLICK_RENAME;
0230             _singleClicked = true;
0231             _singleClickedItem = item;
0232             _singleClickTime = QTime::currentTime();
0233 
0234             return true;
0235         }
0236     }
0237 
0238     CANCEL_TWO_CLICK_RENAME;
0239 
0240     if (e->button() == Qt::MidButton && item != nullptr) {
0241         e->accept();
0242         if (item == nullptr)
0243             return true;
0244         _view->op()->emitMiddleButtonClicked(item);
0245         return true;
0246     }
0247     return false;
0248 }
0249 
0250 bool KrMouseHandler::mouseDoubleClickEvent(QMouseEvent *e)
0251 {
0252     CANCEL_TWO_CLICK_RENAME;
0253 
0254     KrViewItem *item = _view->getKrViewItemAt(e->pos());
0255     if (_singleClick)
0256         return false;
0257     if (e->button() == Qt::LeftButton && item != nullptr) {
0258         e->accept();
0259         const QString &tmp = item->name();
0260         _view->op()->emitExecuted(tmp);
0261         return true;
0262     }
0263     return false;
0264 }
0265 
0266 bool KrMouseHandler::mouseMoveEvent(QMouseEvent *e)
0267 {
0268     KrViewItem *item = _view->getKrViewItemAt(e->pos());
0269     KrSelectionMode *mode = KrSelectionMode::getSelectionHandler();
0270 
0271     if ((_singleClicked || _renameTimer.isActive()) && item != _singleClickedItem)
0272         CANCEL_TWO_CLICK_RENAME;
0273 
0274     if (!item)
0275         return false;
0276 
0277     const QString desc = item->description();
0278     _view->op()->emitItemDescription(desc);
0279 
0280     if (_dragStartPos != QPoint(-1, -1) && (e->buttons() & Qt::LeftButton)
0281         && (_dragStartPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) {
0282         _view->op()->startDrag();
0283         return true;
0284     }
0285 
0286     if (mode->rightButtonPreservesSelection() && mode->rightButtonSelects() && mode->showContextMenu() >= 0 && e->buttons() == Qt::RightButton) {
0287         e->accept();
0288         if (item != _rightClickedItem && item && _rightClickedItem) {
0289             _view->selectRegion(item, _rightClickedItem, _rightClickSelects);
0290             _rightClickedItem = item;
0291             _view->setCurrentKrViewItem(item);
0292             _contextMenuTimer.stop();
0293         }
0294         return true;
0295     }
0296     return false;
0297 }
0298 
0299 bool KrMouseHandler::wheelEvent(QWheelEvent *e)
0300 {
0301     if (!_view->isFocused())
0302         _view->op()->emitNeedFocus();
0303 
0304     if (e->modifiers() == Qt::ControlModifier) {
0305         if (e->angleDelta().y() > 0) {
0306             _view->zoomIn();
0307         } else {
0308             _view->zoomOut();
0309         }
0310         e->accept();
0311         return true;
0312     }
0313 
0314     return false;
0315 }
0316 
0317 void KrMouseHandler::showContextMenu()
0318 {
0319     if (_rightClickedItem)
0320         _rightClickedItem->setSelected(true);
0321     if (_emptyContextMenu)
0322         _view->op()->emitEmptyContextMenu(_contextMenuPoint);
0323     else
0324         _view->op()->emitContextMenu(_contextMenuPoint);
0325 }
0326 
0327 void KrMouseHandler::handleContextMenu(KrViewItem *it, const QPoint &pos)
0328 {
0329     if (!_view->isFocused())
0330         _view->op()->emitNeedFocus();
0331     int i = KrSelectionMode::getSelectionHandler()->showContextMenu();
0332     _contextMenuPoint = QPoint(pos.x(), pos.y() - _contextMenuShift);
0333     if (i < 0) {
0334         if (!it || it->isDummy())
0335             _view->op()->emitEmptyContextMenu(_contextMenuPoint);
0336         else {
0337             _view->setCurrentKrViewItem(it);
0338             _view->op()->emitContextMenu(_contextMenuPoint);
0339         }
0340     } else if (i > 0) {
0341         _emptyContextMenu = !it || it->isDummy();
0342         _contextMenuTimer.setSingleShot(true);
0343         _contextMenuTimer.start(i);
0344     }
0345 }
0346 
0347 void KrMouseHandler::otherEvent(QEvent *e)
0348 {
0349     switch (e->type()) {
0350     case QEvent::Timer:
0351     case QEvent::MouseMove:
0352     case QEvent::MouseButtonPress:
0353     case QEvent::MouseButtonRelease:
0354         break;
0355     default:
0356         CANCEL_TWO_CLICK_RENAME;
0357     }
0358 }
0359 
0360 void KrMouseHandler::cancelTwoClickRename()
0361 {
0362     CANCEL_TWO_CLICK_RENAME;
0363 }
0364 
0365 bool KrMouseHandler::dragEnterEvent(QDragEnterEvent *e)
0366 {
0367     QList<QUrl> URLs = KUrlMimeData::urlsFromMimeData(e->mimeData());
0368     e->setAccepted(!URLs.isEmpty());
0369     return true;
0370 }
0371 
0372 bool KrMouseHandler::dragMoveEvent(QDragMoveEvent *e)
0373 {
0374     QList<QUrl> URLs = KUrlMimeData::urlsFromMimeData(e->mimeData());
0375     e->setAccepted(!URLs.isEmpty());
0376     return true;
0377 }
0378 
0379 bool KrMouseHandler::dragLeaveEvent(QDragLeaveEvent * /*e*/)
0380 {
0381     return false;
0382 }
0383 
0384 bool KrMouseHandler::dropEvent(QDropEvent *e)
0385 {
0386     _view->op()->emitGotDrop(e);
0387     return true;
0388 }