diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index 60bfef5182..746df4d1dc 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -46,10 +47,16 @@ KItemListController::KItemListController(QObject* parent) : m_keyboardManager(new KItemListKeyboardSearchManager(this)), m_pressedIndex(-1), m_pressedMousePos(), + m_autoActivationTimer(0), m_oldSelection() { connect(m_keyboardManager, SIGNAL(changeCurrentItem(QString,bool)), this, SLOT(slotChangeCurrentItem(QString,bool))); + + m_autoActivationTimer = new QTimer(this); + m_autoActivationTimer->setSingleShot(true); + m_autoActivationTimer->setInterval(-1); + connect(m_autoActivationTimer, SIGNAL(timeout()), this, SLOT(slotAutoActivationTimeout())); } KItemListController::~KItemListController() @@ -121,6 +128,16 @@ KItemListController::SelectionBehavior KItemListController::selectionBehavior() return m_selectionBehavior; } +void KItemListController::setAutoActivationDelay(int delay) +{ + m_autoActivationTimer->setInterval(delay); +} + +int KItemListController::autoActivationDelay() const +{ + return m_autoActivationTimer->interval(); +} + bool KItemListController::showEvent(QShowEvent* event) { Q_UNUSED(event); @@ -217,9 +234,17 @@ bool KItemListController::keyPressEvent(QKeyEvent* event) break; case Qt::Key_Enter: - case Qt::Key_Return: - emit itemActivated(index); + case Qt::Key_Return: { + const QSet selectedItems = m_selectionManager->selectedItems(); + if (selectedItems.count() >= 2) { + emit itemsActivated(selectedItems); + } else if (selectedItems.count() == 1) { + emit itemActivated(selectedItems.toList().first()); + } else { + emit itemActivated(index); + } break; + } case Qt::Key_Space: if (controlPressed) { @@ -276,6 +301,27 @@ void KItemListController::slotChangeCurrentItem(const QString& text, bool search } } +void KItemListController::slotAutoActivationTimeout() +{ + if (!m_model || !m_view) { + return; + } + + const int index = m_autoActivationTimer->property("index").toInt(); + if (index < 0 || index >= m_model->count()) { + return; + } + + if (m_model->supportsDropping(index)) { + if (m_view->supportsItemExpanding() && m_model->isExpandable(index)) { + const bool expanded = m_model->isExpanded(index); + m_model->setExpanded(index, !expanded); + } else { + emit itemActivated(index); + } + } +} + bool KItemListController::inputMethodEvent(QInputMethodEvent* event) { Q_UNUSED(event); @@ -542,8 +588,13 @@ bool KItemListController::dragMoveEvent(QGraphicsSceneDragDropEvent* event, cons } KItemListWidget* oldHoveredWidget = hoveredWidget(); - KItemListWidget* newHoveredWidget = widgetForPos(event->pos()); + + const QPointF pos = transform.map(event->pos()); + KItemListWidget* newHoveredWidget = widgetForPos(pos); + if (oldHoveredWidget != newHoveredWidget) { + m_autoActivationTimer->stop(); + if (oldHoveredWidget) { oldHoveredWidget->setHovered(false); emit itemUnhovered(oldHoveredWidget->index()); @@ -555,6 +606,11 @@ bool KItemListController::dragMoveEvent(QGraphicsSceneDragDropEvent* event, cons newHoveredWidget->setHovered(true); } emit itemHovered(index); + + if (m_autoActivationTimer->interval() >= 0) { + m_autoActivationTimer->setProperty("index", index); + m_autoActivationTimer->start(); + } } } @@ -568,6 +624,8 @@ bool KItemListController::dropEvent(QGraphicsSceneDragDropEvent* event, const QT return false; } + m_autoActivationTimer->stop(); + const QPointF pos = transform.map(event->pos()); const int index = m_view->itemAt(pos); emit itemDropEvent(index, event); @@ -590,7 +648,9 @@ bool KItemListController::hoverMoveEvent(QGraphicsSceneHoverEvent* event, const } KItemListWidget* oldHoveredWidget = hoveredWidget(); - KItemListWidget* newHoveredWidget = widgetForPos(event->pos()); + const QPointF pos = transform.map(event->pos()); + KItemListWidget* newHoveredWidget = widgetForPos(pos); + if (oldHoveredWidget != newHoveredWidget) { if (oldHoveredWidget) { oldHoveredWidget->setHovered(false); diff --git a/src/kitemviews/kitemlistcontroller.h b/src/kitemviews/kitemlistcontroller.h index aa2fe2176c..29ab6be63a 100644 --- a/src/kitemviews/kitemlistcontroller.h +++ b/src/kitemviews/kitemlistcontroller.h @@ -86,6 +86,24 @@ public: void setSelectionBehavior(SelectionBehavior behavior); SelectionBehavior selectionBehavior() const; + /** + * Sets the delay in milliseconds when dragging an object above an item + * until the item gets activated automatically. A value of -1 indicates + * that no automatic activation will be done at all (= default value). + * + * The hovered item must support dropping (see KItemModelBase::supportsDropping()), + * otherwise the automatic activation is not available. + * + * After activating the item the signal itemActivated() will be + * emitted. If the view supports the expanding of items + * (KItemListView::supportsItemExpanding() returns true) and the item + * itself is expandable (see KItemModelBase::isExpandable()) then instead + * of activating the item it gets expanded instead (see + * KItemModelBase::setExpanded()). + */ + void setAutoActivationDelay(int delay); + int autoActivationDelay() const; + virtual bool showEvent(QShowEvent* event); virtual bool hideEvent(QHideEvent* event); virtual bool keyPressEvent(QKeyEvent* event); @@ -106,7 +124,18 @@ public: virtual bool processEvent(QEvent* event, const QTransform& transform); signals: + /** + * Is emitted if exactly one item has been activated by e.g. a mouse-click + * or by pressing Return/Enter. + */ void itemActivated(int index); + + /** + * Is emitted if more than one item has been activated by pressing Return/Enter + * when having a selection. + */ + void itemsActivated(const QSet& indexes); + void itemMiddleClicked(int index); /** @@ -160,6 +189,8 @@ private slots: void slotChangeCurrentItem(const QString& text, bool searchFromNextItem); + void slotAutoActivationTimeout(); + private: /** * Creates a QDrag object and initiates a drag-operation. @@ -188,6 +219,8 @@ private: int m_pressedIndex; QPointF m_pressedMousePos; + QTimer* m_autoActivationTimer; + /** * When starting a rubberband selection during a Shift- or Control-key has been * pressed the current selection should never be deleted. To be able to restore diff --git a/src/panels/folders/folderspanel.cpp b/src/panels/folders/folderspanel.cpp index 484d8c2ed4..26c7250484 100644 --- a/src/panels/folders/folderspanel.cpp +++ b/src/panels/folders/folderspanel.cpp @@ -171,6 +171,7 @@ void FoldersPanel::showEvent(QShowEvent* event) m_controller->setView(view); m_controller->setModel(model); m_controller->setSelectionBehavior(KItemListController::SingleSelection); + m_controller->setAutoActivationDelay(750); connect(m_controller, SIGNAL(itemActivated(int)), this, SLOT(slotItemActivated(int))); connect(m_controller, SIGNAL(itemMiddleClicked(int)), this, SLOT(slotItemMiddleClicked(int))); diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index 379cd9f902..829e1a302d 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -135,8 +135,11 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) : KItemListController* controller = m_container->controller(); controller->setSelectionBehavior(KItemListController::MultiSelection); - connect(controller, SIGNAL(itemActivated(int)), - this, SLOT(slotItemActivated(int))); + if (GeneralSettings::autoExpandFolders()) { + controller->setAutoActivationDelay(750); + } + connect(controller, SIGNAL(itemActivated(int)), this, SLOT(slotItemActivated(int))); + connect(controller, SIGNAL(itemsActivated(QSet)), this, SLOT(slotItemsActivated(QSet))); connect(controller, SIGNAL(itemMiddleClicked(int)), this, SLOT(slotItemMiddleClicked(int))); connect(controller, SIGNAL(itemContextMenuRequested(int,QPointF)), this, SLOT(slotItemContextMenuRequested(int,QPointF))); connect(controller, SIGNAL(viewContextMenuRequested(QPointF)), this, SLOT(slotViewContextMenuRequested(QPointF))); @@ -692,22 +695,30 @@ void DolphinView::activate() void DolphinView::slotItemActivated(int index) { - Q_UNUSED(index); + const KFileItem item = fileItemModel()->fileItem(index); + if (!item.isNull()) { + emit itemActivated(item); + } +} - const KFileItemList items = selectedItems(); - if (items.isEmpty()) { - return; +void DolphinView::slotItemsActivated(const QSet& indexes) +{ + Q_ASSERT(indexes.count() >= 2); + + KFileItemList items; + + KFileItemModel* model = fileItemModel(); + QSetIterator it(indexes); + while (it.hasNext()) { + const int index = it.next(); + items.append(model->fileItem(index)); } - if (items.count() == 1) { - emit itemActivated(items.at(0)); // caught by DolphinViewContainer or DolphinPart - } else { - foreach (const KFileItem& item, items) { - if (item.isDir()) { - emit tabRequested(item.url()); - } else { - emit itemActivated(item); - } + foreach (const KFileItem& item, items) { + if (item.isDir()) { + emit tabRequested(item.url()); + } else { + emit itemActivated(item); } } } diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h index e0be25e425..9111516b43 100644 --- a/src/views/dolphinview.h +++ b/src/views/dolphinview.h @@ -555,6 +555,7 @@ private slots: void activate(); void slotItemActivated(int index); + void slotItemsActivated(const QSet& indexes); void slotItemMiddleClicked(int index); void slotItemContextMenuRequested(int index, const QPointF& pos); void slotViewContextMenuRequested(const QPointF& pos);