From 362817d1834f2ada3ea4552a25fa39bbbb540f8c Mon Sep 17 00:00:00 2001 From: Peter Penz Date: Sat, 26 Nov 2011 01:05:58 +0100 Subject: [PATCH] Folders Panel fixes The following functionality from Dolphin 1.x has been ported to the new view-engine: - Allow expanding/collapsing of items - Automatically select the current item - Context menu for items Related improvements to the view-engine: - Make the expanding/collapsing interface already accessible in the base classes KItemModelBase and KItemListView. If no expanding/collapsing is supported at all by derived models (which is usually the default case) simply not reimplementing those 3 methods is sufficient and it does not introduce an additional complexity like in QAbstractItemModel/QModelIndex. - Automatically handle the expanding/collapsing in KItemListController. This also includes the key-handling, which is quite special for expandable items. - Don't let KItemListView automatically scroll to the current item if the current item got changed. The automatic scrolling should only be done if the current item has been changed by the user. Hence this functionality has been moved to the KItemListController which currently only triggers the automatic scrolling if the current item has been changed by the keyboard (we might extend the usecases later if required). --- src/CMakeLists.txt | 1 - src/kitemviews/kfileitemlistview.cpp | 5 + src/kitemviews/kfileitemlistview.h | 3 + src/kitemviews/kfileitemmodel.h | 7 +- src/kitemviews/kitemlistcontroller.cpp | 60 ++++-- src/kitemviews/kitemlistview.cpp | 61 +++--- src/kitemviews/kitemlistview.h | 16 ++ src/kitemviews/kitemmodelbase.cpp | 19 ++ src/kitemviews/kitemmodelbase.h | 29 +++ src/panels/folders/folderspanel.cpp | 134 +++++++++---- src/panels/folders/folderspanel.h | 48 ++--- src/panels/folders/ktreeview_p.h | 46 ----- src/panels/folders/treeviewcontextmenu.cpp | 54 ++--- src/panels/folders/treeviewcontextmenu.h | 16 +- src/views/dolphinview.cpp | 12 -- src/views/dolphinview.h | 1 - src/views/dolphinviewautoscroller.cpp | 223 --------------------- src/views/dolphinviewautoscroller.h | 79 -------- 18 files changed, 293 insertions(+), 521 deletions(-) delete mode 100644 src/panels/folders/ktreeview_p.h delete mode 100644 src/views/dolphinviewautoscroller.cpp delete mode 100644 src/views/dolphinviewautoscroller.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a10f6b448..af82e74fe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,7 +53,6 @@ set(dolphinprivate_LIB_SRCS views/dolphinremoteencoding.cpp views/dolphinview.cpp views/dolphinviewactionhandler.cpp - views/dolphinviewautoscroller.cpp views/draganddrophelper.cpp views/renamedialog.cpp views/tooltips/filemetadatatooltip.cpp diff --git a/src/kitemviews/kfileitemlistview.cpp b/src/kitemviews/kfileitemlistview.cpp index b0ffd3c20..d7dd5cf67 100644 --- a/src/kitemviews/kfileitemlistview.cpp +++ b/src/kitemviews/kfileitemlistview.cpp @@ -222,6 +222,11 @@ QHash KFileItemListView::visibleRolesSizes(const KItemRangeL return sizes; } +bool KFileItemListView::supportsItemExpanding() const +{ + return m_itemLayout == DetailsLayout; +} + QPixmap KFileItemListView::createDragPixmap(const QSet& indexes) const { if (!model()) { diff --git a/src/kitemviews/kfileitemlistview.h b/src/kitemviews/kfileitemlistview.h index d90d8ecf9..a41d091b7 100644 --- a/src/kitemviews/kfileitemlistview.h +++ b/src/kitemviews/kfileitemlistview.h @@ -63,6 +63,9 @@ public: /** @reimp */ virtual QHash visibleRolesSizes(const KItemRangeList& itemRanges) const; + /** @reimp */ + virtual bool supportsItemExpanding() const; + /** @reimp */ virtual QPixmap createDragPixmap(const QSet& indexes) const; diff --git a/src/kitemviews/kfileitemmodel.h b/src/kitemviews/kfileitemmodel.h index 17524b82a..8cbcb1216 100644 --- a/src/kitemviews/kfileitemmodel.h +++ b/src/kitemviews/kfileitemmodel.h @@ -116,9 +116,10 @@ public: void setRoles(const QSet& roles); QSet roles() const; - bool setExpanded(int index, bool expanded); - bool isExpanded(int index) const; - bool isExpandable(int index) const; + virtual bool setExpanded(int index, bool expanded); + virtual bool isExpanded(int index) const; + virtual bool isExpandable(int index) const; + QSet expandedUrls() const; /** diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index b24e6df14..60bfef518 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -135,17 +135,31 @@ bool KItemListController::hideEvent(QHideEvent* event) bool KItemListController::keyPressEvent(QKeyEvent* event) { + int index = m_selectionManager->currentItem(); + int key = event->key(); + + // Handle the expanding/collapsing of items + if (m_view->supportsItemExpanding() && m_model->isExpandable(index)) { + if (key == Qt::Key_Right) { + if (m_model->setExpanded(index, true)) { + return true; + } + } else if (key == Qt::Key_Left) { + if (m_model->setExpanded(index, false)) { + return true; + } + } + } + const bool shiftPressed = event->modifiers() & Qt::ShiftModifier; const bool controlPressed = event->modifiers() & Qt::ControlModifier; const bool shiftOrControlPressed = shiftPressed || controlPressed; - int index = m_selectionManager->currentItem(); const int itemCount = m_model->count(); const int itemsPerRow = m_view->itemsPerOffset(); // For horizontal scroll orientation, transform // the arrow keys to simplify the event handling. - int key = event->key(); if (m_view->scrollOrientation() == Qt::Horizontal) { switch (key) { case Qt::Key_Up: key = Qt::Key_Left; break; @@ -156,6 +170,7 @@ bool KItemListController::keyPressEvent(QKeyEvent* event) } } + switch (key) { case Qt::Key_Home: index = 0; @@ -234,6 +249,8 @@ bool KItemListController::keyPressEvent(QKeyEvent* event) if (!shiftPressed) { m_selectionManager->beginAnchoredSelection(index); } + + m_view->scrollToItem(index); } return true; } @@ -348,25 +365,27 @@ bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const return true; } - KItemListRubberBand* rubberBand = m_view->rubberBand(); - QPointF startPos = m_pressedMousePos; - if (m_view->scrollOrientation() == Qt::Vertical) { - startPos.ry() += m_view->scrollOffset(); - if (m_view->itemSize().width() < 0) { - // Use a special rubberband for views that have only one column and - // expand the rubberband to use the whole width of the view. - startPos.setX(0); + if (m_selectionBehavior == MultiSelection) { + QPointF startPos = m_pressedMousePos; + if (m_view->scrollOrientation() == Qt::Vertical) { + startPos.ry() += m_view->scrollOffset(); + if (m_view->itemSize().width() < 0) { + // Use a special rubberband for views that have only one column and + // expand the rubberband to use the whole width of the view. + startPos.setX(0); + } + } else { + startPos.rx() += m_view->scrollOffset(); } - } else { - startPos.rx() += m_view->scrollOffset(); - } - m_oldSelection = m_selectionManager->selectedItems(); - rubberBand->setStartPosition(startPos); - rubberBand->setEndPosition(startPos); - rubberBand->setActive(true); - connect(rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandChanged())); - m_view->setAutoScroll(true); + m_oldSelection = m_selectionManager->selectedItems(); + KItemListRubberBand* rubberBand = m_view->rubberBand(); + rubberBand->setStartPosition(startPos); + rubberBand->setEndPosition(startPos); + rubberBand->setActive(true); + connect(rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandChanged())); + m_view->setAutoScroll(true); + } return false; } @@ -461,6 +480,9 @@ bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, con if (event->button() & Qt::LeftButton) { bool emitItemActivated = true; if (m_view->isAboveExpansionToggle(index, pos)) { + const bool expanded = m_model->isExpanded(index); + m_model->setExpanded(index, !expanded); + emit itemExpansionToggleClicked(index); emitItemActivated = false; } else if (shiftOrControlPressed) { diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 389069ce3..c4c1e3167 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -427,11 +427,45 @@ QHash KItemListView::visibleRolesSizes(const KItemRangeList& return QHash(); } +bool KItemListView::supportsItemExpanding() const +{ + return false; +} + QRectF KItemListView::itemRect(int index) const { return m_layouter->itemRect(index); } +void KItemListView::scrollToItem(int index) +{ + const QRectF viewGeometry = geometry(); + const QRectF currentRect = itemRect(index); + + if (!viewGeometry.contains(currentRect)) { + qreal newOffset = scrollOffset(); + if (currentRect.top() < viewGeometry.top()) { + Q_ASSERT(scrollOrientation() == Qt::Vertical); + newOffset += currentRect.top() - viewGeometry.top(); + } else if ((currentRect.bottom() > viewGeometry.bottom())) { + Q_ASSERT(scrollOrientation() == Qt::Vertical); + newOffset += currentRect.bottom() - viewGeometry.bottom(); + } else if (currentRect.left() < viewGeometry.left()) { + if (scrollOrientation() == Qt::Horizontal) { + newOffset += currentRect.left() - viewGeometry.left(); + } + } else if ((currentRect.right() > viewGeometry.right())) { + if (scrollOrientation() == Qt::Horizontal) { + newOffset += currentRect.right() - viewGeometry.right(); + } + } + + if (newOffset != scrollOffset()) { + emit scrollTo(newOffset); + } + } +} + int KItemListView::itemsPerOffset() const { return m_layouter->itemsPerOffset(); @@ -950,33 +984,6 @@ void KItemListView::slotCurrentChanged(int current, int previous) Q_ASSERT(!currentWidget->isCurrent()); currentWidget->setCurrent(true); } - - const QRectF viewGeometry = geometry(); - const QRectF currentRect = itemRect(current); - - if (!viewGeometry.contains(currentRect)) { - // Make sure that the new current item is fully visible in the view. - qreal newOffset = scrollOffset(); - if (currentRect.top() < viewGeometry.top()) { - Q_ASSERT(scrollOrientation() == Qt::Vertical); - newOffset += currentRect.top() - viewGeometry.top(); - } else if ((currentRect.bottom() > viewGeometry.bottom())) { - Q_ASSERT(scrollOrientation() == Qt::Vertical); - newOffset += currentRect.bottom() - viewGeometry.bottom(); - } else if (currentRect.left() < viewGeometry.left()) { - if (scrollOrientation() == Qt::Horizontal) { - newOffset += currentRect.left() - viewGeometry.left(); - } - } else if ((currentRect.right() > viewGeometry.right())) { - if (scrollOrientation() == Qt::Horizontal) { - newOffset += currentRect.right() - viewGeometry.right(); - } - } - - if (newOffset != scrollOffset()) { - emit scrollTo(newOffset); - } - } } void KItemListView::slotSelectionChanged(const QSet& current, const QSet& previous) diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index 481dd90f6..1da0cd7d2 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -168,12 +168,28 @@ public: */ virtual QHash visibleRolesSizes(const KItemRangeList& itemRanges) const; + /** + * @return True if the view supports the expanding of items. Per default false + * is returned. If expanding of items is supported, the methods + * KItemModelBase::setExpanded(), KItemModelBase::isExpanded() and + * KItemModelBase::isExpandable() must be reimplemented. The view-implementation + * has to take care itself how to visually represent the expanded items provided + * by the model. + */ + virtual bool supportsItemExpanding() const; + /** * @return The rectangle of the item relative to the top/left of * the currently visible area (see KItemListView::offset()). */ QRectF itemRect(int index) const; + /** + * Scrolls to the item with the index \a index so that the item + * will be fully visible. + */ + void scrollToItem(int index); + /** * @return The number of items that can be shown in parallel for one offset. * Assuming the scrolldirection is vertical then a value of 4 means diff --git a/src/kitemviews/kitemmodelbase.cpp b/src/kitemviews/kitemmodelbase.cpp index 3e6114027..e2b86d8a0 100644 --- a/src/kitemviews/kitemmodelbase.cpp +++ b/src/kitemviews/kitemmodelbase.cpp @@ -109,6 +109,25 @@ QList > KItemModelBase::groups() const return QList >(); } +bool KItemModelBase::setExpanded(int index, bool expanded) +{ + Q_UNUSED(index); + Q_UNUSED(expanded); + return false; +} + +bool KItemModelBase::isExpanded(int index) const +{ + Q_UNUSED(index); + return false; +} + +bool KItemModelBase::isExpandable(int index) const +{ + Q_UNUSED(index); + return false; +} + QMimeData* KItemModelBase::createMimeData(const QSet& indexes) const { Q_UNUSED(indexes); diff --git a/src/kitemviews/kitemmodelbase.h b/src/kitemviews/kitemmodelbase.h index edca15bd1..1dffaf8cf 100644 --- a/src/kitemviews/kitemmodelbase.h +++ b/src/kitemviews/kitemmodelbase.h @@ -53,6 +53,9 @@ typedef QList KItemRangeList; * One item consists of a variable number of role/value-pairs. * * A model can optionally provide sorting- and grouping-capabilities. + * + * Also optionally it is possible to provide a tree of items by implementing the methods + * setExpanded(), isExpanded() and isExpandable(). */ class LIBDOLPHINPRIVATE_EXPORT KItemModelBase : public QObject { @@ -116,6 +119,32 @@ public: */ virtual QList > groups() const; + /** + * Expands the item with the index \a index if \a expanded is true. + * If \a expanded is false the item will be collapsed. + * + * Per default no expanding of items is implemented. When implementing + * this method it is mandatory to overwrite KItemModelBase::isExpandable() + * and KItemListView::supportsExpandableItems() to return true. + * + * @return True if the operation has been successful. + */ + virtual bool setExpanded(int index, bool expanded); + + /** + * @return True if the item with the index \a index is expanded. + * Per default no expanding of items is implemented. When implementing + * this method it is mandatory to overwrite KItemModelBase::isExpandable() + * and KItemListView::supportsExpandableItems() to return true. + */ + virtual bool isExpanded(int index) const; + + /** + * @return True if expanding and collapsing of the item with the index \a index + * is supported. Per default false is returned. + */ + virtual bool isExpandable(int index) const; + /** * @return MIME-data for the items given by \a indexes. The default implementation * returns 0. The ownership of the returned instance is in the hand of the diff --git a/src/panels/folders/folderspanel.cpp b/src/panels/folders/folderspanel.cpp index cf458e508..484d8c2ed 100644 --- a/src/panels/folders/folderspanel.cpp +++ b/src/panels/folders/folderspanel.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -45,11 +46,9 @@ FoldersPanel::FoldersPanel(QWidget* parent) : Panel(parent), - m_setLeafVisible(false), - m_mouseButtons(Qt::NoButton), + m_updateCurrentItem(false), m_dirLister(0), - m_controller(0), - m_leafDir() + m_controller(0) { setLayoutDirection(Qt::LeftToRight); } @@ -121,7 +120,6 @@ bool FoldersPanel::urlChanged() } if (m_dirLister) { - m_setLeafVisible = true; loadTree(url()); } @@ -158,6 +156,10 @@ void FoldersPanel::showEvent(QShowEvent* event) const qreal itemHeight = qMax(int(KIconLoader::SizeSmall), styleOption.fontMetrics.height()); view->setItemSize(QSizeF(-1, itemHeight + 2 * styleOption.margin)); view->setItemLayout(KFileItemListView::DetailsLayout); + // Set the opacity to 0 initially. The opacity will be increased after the loading of the initial tree + // has been finished in slotLoadingCompleted(). This prevents an unnecessary animation-mess when + // opening the folders panel. + view->setOpacity(0); KFileItemModel* model = new KFileItemModel(m_dirLister, this); // Use a QueuedConnection to give the view the possibility to react first on the @@ -168,6 +170,12 @@ void FoldersPanel::showEvent(QShowEvent* event) m_controller = container->controller(); m_controller->setView(view); m_controller->setModel(model); + m_controller->setSelectionBehavior(KItemListController::SingleSelection); + + connect(m_controller, SIGNAL(itemActivated(int)), this, SLOT(slotItemActivated(int))); + connect(m_controller, SIGNAL(itemMiddleClicked(int)), this, SLOT(slotItemMiddleClicked(int))); + connect(m_controller, SIGNAL(itemContextMenuRequested(int,QPointF)), this, SLOT(slotItemContextMenuRequested(int,QPointF))); + connect(m_controller, SIGNAL(viewContextMenuRequested(QPointF)), this, SLOT(slotViewContextMenuRequested(QPointF))); // TODO: Check whether it makes sense to make an explicit API for KItemListContainer // to make the background transparent. @@ -194,22 +202,6 @@ void FoldersPanel::showEvent(QShowEvent* event) Panel::showEvent(event); } -void FoldersPanel::contextMenuEvent(QContextMenuEvent* event) -{ - Panel::contextMenuEvent(event); - - KFileItem item; - /*const QModelIndex index = m_treeView->indexAt(event->pos()); - if (index.isValid()) { - const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index); - item = m_dolphinModel->itemForIndex(dolphinModelIndex); - }*/ - - QPointer contextMenu = new TreeViewContextMenu(this, item); - contextMenu->open(); - delete contextMenu; -} - void FoldersPanel::keyPressEvent(QKeyEvent* event) { const int key = event->key(); @@ -221,17 +213,65 @@ void FoldersPanel::keyPressEvent(QKeyEvent* event) } } -void FoldersPanel::updateMouseButtons() +void FoldersPanel::slotItemActivated(int index) { - m_mouseButtons = QApplication::mouseButtons(); + const KFileItem item = fileItemModel()->fileItem(index); + if (!item.isNull()) { + emit changeUrl(item.url(), Qt::LeftButton); + } +} + +void FoldersPanel::slotItemMiddleClicked(int index) +{ + const KFileItem item = fileItemModel()->fileItem(index); + if (!item.isNull()) { + emit changeUrl(item.url(), Qt::MiddleButton); + } +} + +void FoldersPanel::slotItemContextMenuRequested(int index, const QPointF& pos) +{ + Q_UNUSED(pos); + + const KFileItem fileItem = fileItemModel()->fileItem(index); + + QWeakPointer contextMenu = new TreeViewContextMenu(this, fileItem); + contextMenu.data()->open(); + if (contextMenu.data()) { + delete contextMenu.data(); + } +} + +void FoldersPanel::slotViewContextMenuRequested(const QPointF& pos) +{ + Q_UNUSED(pos); + + QWeakPointer contextMenu = new TreeViewContextMenu(this, KFileItem()); + contextMenu.data()->open(); + if (contextMenu.data()) { + delete contextMenu.data(); + } } void FoldersPanel::slotLoadingCompleted() { - const int index = fileItemModel()->index(url()); - if (index >= 0) { - m_controller->selectionManager()->setCurrentItem(index); + if (m_controller->view()->opacity() == 0) { + // The loading of the initial tree after opening the Folders panel + // has been finished. Trigger the increasing of the opacity after + // a short delay to give the view the chance to finish its internal + // animations. + // TODO: Check whether it makes sense to allow accessing the + // view-internal delay for usecases like this. + QTimer::singleShot(250, this, SLOT(startFadeInAnimation())); + } + + if (!m_updateCurrentItem) { + return; } + + const int index = fileItemModel()->index(url()); + updateCurrentItem(index); + m_updateCurrentItem = false; } void FoldersPanel::slotHorizontalScrollBarMoved(int value) @@ -250,10 +290,21 @@ void FoldersPanel::slotVerticalScrollBarMoved(int value) //m_treeView->setAutoHorizontalScroll(FoldersPanelSettings::autoScrolling()); } +void FoldersPanel::startFadeInAnimation() +{ + QPropertyAnimation* anim = new QPropertyAnimation(m_controller->view(), "opacity", this); + anim->setStartValue(0); + anim->setEndValue(1); + anim->setEasingCurve(QEasingCurve::InOutQuad); + anim->start(QAbstractAnimation::DeleteWhenStopped); + anim->setDuration(200); +} + void FoldersPanel::loadTree(const KUrl& url) { Q_ASSERT(m_dirLister); - m_leafDir = url; + + m_updateCurrentItem = false; KUrl baseUrl; if (url.isLocalFile()) { @@ -266,6 +317,7 @@ void FoldersPanel::loadTree(const KUrl& url) } if (m_dirLister->url() != baseUrl) { + m_updateCurrentItem = true; m_dirLister->stop(); m_dirLister->openUrl(baseUrl, KDirLister::Reload); } @@ -273,29 +325,23 @@ void FoldersPanel::loadTree(const KUrl& url) KFileItemModel* model = fileItemModel(); const int index = model->index(url); if (index >= 0) { - m_controller->selectionManager()->setCurrentItem(index); + updateCurrentItem(index); } else { + m_updateCurrentItem = true; model->setExpanded(QSet() << url); + // slotLoadingCompleted() will be invoked after the model has + // expanded the url } } -void FoldersPanel::selectLeafDirectory() +void FoldersPanel::updateCurrentItem(int index) { - /*const QModelIndex dirIndex = m_dolphinModel->indexForUrl(m_leafDir); - const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex); - - if (proxyIndex.isValid()) { - QItemSelectionModel* selModel = m_treeView->selectionModel(); - selModel->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect); - - if (m_setLeafVisible) { - // Invoke scrollToLeaf() asynchronously. This assures that - // the horizontal scrollbar is shown after resizing the column - // (otherwise the scrollbar might hide the leaf). - QTimer::singleShot(0, this, SLOT(scrollToLeaf())); - m_setLeafVisible = false; - } - }*/ + KItemListSelectionManager* selectionManager = m_controller->selectionManager(); + selectionManager->setCurrentItem(index); + selectionManager->clearSelection(); + selectionManager->setSelected(index); + + m_controller->view()->scrollToItem(index); } KFileItemModel* FoldersPanel::fileItemModel() const diff --git a/src/panels/folders/folderspanel.h b/src/panels/folders/folderspanel.h index 70390da60..d249f850f 100644 --- a/src/panels/folders/folderspanel.h +++ b/src/panels/folders/folderspanel.h @@ -63,37 +63,14 @@ protected: /** @see QWidget::showEvent() */ virtual void showEvent(QShowEvent* event); - /** @see QWidget::contextMenuEvent() */ - virtual void contextMenuEvent(QContextMenuEvent* event); - /** @see QWidget::keyPressEvent() */ virtual void keyPressEvent(QKeyEvent* event); private slots: - /** - * Updates the active view to the URL - * which is given by the item with the index \a index. - */ - //void updateActiveView(const QModelIndex& index); - - /** - * Is emitted if URLs have been dropped - * to the index \a index. - */ - //void dropUrls(const QModelIndex& index, QDropEvent* event); - - /** - * Expands the treeview to show the directory - * specified by \a index. - */ - //void expandToDir(const QModelIndex& index); - - /** - * Assures that the leaf folder gets visible. - */ - //void scrollToLeaf(); - - void updateMouseButtons(); + void slotItemActivated(int index); + void slotItemMiddleClicked(int index); + void slotItemContextMenuRequested(int index, const QPointF& pos); + void slotViewContextMenuRequested(const QPointF& pos); void slotLoadingCompleted(); @@ -101,6 +78,12 @@ private slots: void slotVerticalScrollBarMoved(int value); + /** + * Increases the opacity of the view step by step until it is fully + * opaque. + */ + void startFadeInAnimation(); + private: /** * Initializes the base URL of the tree and expands all @@ -110,20 +93,17 @@ private: void loadTree(const KUrl& url); /** - * Selects the current leaf directory m_leafDir and assures - * that the directory is visible if the leaf has been set by - * FoldersPanel::setUrl(). + * Sets the item with the index \a index as current item, selects + * the item and assures that the item will be visible. */ - void selectLeafDirectory(); + void updateCurrentItem(int index); KFileItemModel* fileItemModel() const; private: - bool m_setLeafVisible; - Qt::MouseButtons m_mouseButtons; + bool m_updateCurrentItem; KDirLister* m_dirLister; KItemListController* m_controller; - KUrl m_leafDir; }; #endif // FOLDERSPANEL_H diff --git a/src/panels/folders/ktreeview_p.h b/src/panels/folders/ktreeview_p.h deleted file mode 100644 index 9ea4ac7ee..000000000 --- a/src/panels/folders/ktreeview_p.h +++ /dev/null @@ -1,46 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by * - * Copyright (C) 2008 by * - * * - * 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 * - ***************************************************************************/ - -#ifndef KTREEVIEW_P_H -#define KTREEVIEW_P_H - -#include - -#include "ktreeview.h" - -class QTimeLine; - -class KTreeView::KTreeViewPrivate : public QObject -{ - Q_OBJECT - -public Q_SLOTS: - void startScrolling(); - void updateVerticalScrollBar(int value); - -public: - KTreeViewPrivate(KTreeView *parent); - KTreeView *parent; - - bool autoHorizontalScroll; - QTimeLine *timeLine; -}; - -#endif /* ifndef KTREEVIEW_P_H */ diff --git a/src/panels/folders/treeviewcontextmenu.cpp b/src/panels/folders/treeviewcontextmenu.cpp index 5db3e2c2a..daf14ab4a 100644 --- a/src/panels/folders/treeviewcontextmenu.cpp +++ b/src/panels/folders/treeviewcontextmenu.cpp @@ -39,7 +39,7 @@ TreeViewContextMenu::TreeViewContextMenu(FoldersPanel* parent, const KFileItem& fileInfo) : QObject(parent), m_parent(parent), - m_fileInfo(fileInfo) + m_fileItem(fileInfo) { } @@ -51,8 +51,8 @@ void TreeViewContextMenu::open() { KMenu* popup = new KMenu(m_parent); - if (!m_fileInfo.isNull()) { - KFileItemListProperties capabilities(KFileItemList() << m_fileInfo); + if (!m_fileItem.isNull()) { + KFileItemListProperties capabilities(KFileItemList() << m_fileItem); // insert 'Cut', 'Copy' and 'Paste' QAction* cutAction = new QAction(KIcon("edit-cut"), i18nc("@action:inmenu", "Cut"), this); @@ -85,7 +85,7 @@ void TreeViewContextMenu::open() KConfigGroup configGroup(globalConfig, "KDE"); bool showDeleteCommand = configGroup.readEntry("ShowDeleteCommand", false); - const KUrl url = m_fileInfo.url(); + const KUrl url = m_fileItem.url(); if (url.isLocalFile()) { QAction* moveToTrashAction = new QAction(KIcon("user-trash"), i18nc("@action:inmenu", "Move to Trash"), this); @@ -115,34 +115,40 @@ void TreeViewContextMenu::open() popup->addSeparator(); } - QAction* showHiddenFilesAction = new QAction(i18nc("@action:inmenu", "Show Hidden Files"), this); - showHiddenFilesAction->setCheckable(true); - showHiddenFilesAction->setChecked(m_parent->hiddenFilesShown()); - popup->addAction(showHiddenFilesAction); - connect(showHiddenFilesAction, SIGNAL(toggled(bool)), this, SLOT(setShowHiddenFiles(bool))); - - QAction* autoScrollingAction = new QAction(i18nc("@action:inmenu", "Automatic Scrolling"), this); - autoScrollingAction->setCheckable(true); - autoScrollingAction->setChecked(m_parent->autoScrolling()); - popup->addAction(autoScrollingAction); - connect(autoScrollingAction, SIGNAL(toggled(bool)), this, SLOT(setAutoScrolling(bool))); + if (m_fileItem.isNull()) { + QAction* showHiddenFilesAction = new QAction(i18nc("@action:inmenu", "Show Hidden Files"), this); + showHiddenFilesAction->setCheckable(true); + showHiddenFilesAction->setChecked(m_parent->hiddenFilesShown()); + popup->addAction(showHiddenFilesAction); + connect(showHiddenFilesAction, SIGNAL(toggled(bool)), this, SLOT(setShowHiddenFiles(bool))); + + QAction* autoScrollingAction = new QAction(i18nc("@action:inmenu", "Automatic Scrolling"), this); + autoScrollingAction->setCheckable(true); + autoScrollingAction->setChecked(m_parent->autoScrolling()); + // TODO: Temporary disabled. Horizontal autoscrolling will be implemented later either + // in KItemViews or manually as part of the FoldersPanel + //popup->addAction(autoScrollingAction); + connect(autoScrollingAction, SIGNAL(toggled(bool)), this, SLOT(setAutoScrolling(bool))); + } - popup->addSeparator(); foreach (QAction* action, m_parent->customContextMenuActions()) { popup->addAction(action); } + QWeakPointer popupPtr = popup; popup->exec(QCursor::pos()); - popup->deleteLater(); + if (popupPtr.data()) { + popupPtr.data()->deleteLater(); + } } void TreeViewContextMenu::populateMimeData(QMimeData* mimeData, bool cut) { KUrl::List kdeUrls; - kdeUrls.append(m_fileInfo.url()); + kdeUrls.append(m_fileItem.url()); KUrl::List mostLocalUrls; bool dummy; - mostLocalUrls.append(m_fileInfo.mostLocalUrl(dummy)); + mostLocalUrls.append(m_fileItem.mostLocalUrl(dummy)); KonqMimeData::populateMimeData(mimeData, kdeUrls, mostLocalUrls, cut); } @@ -166,7 +172,7 @@ void TreeViewContextMenu::paste() const QMimeData* mimeData = clipboard->mimeData(); const KUrl::List source = KUrl::List::fromMimeData(mimeData); - const KUrl& dest = m_fileInfo.url(); + const KUrl& dest = m_fileItem.url(); if (KonqMimeData::decodeIsCutSelection(mimeData)) { KonqOperations::copy(m_parent, KonqOperations::MOVE, source, dest); clipboard->clear(); @@ -177,22 +183,22 @@ void TreeViewContextMenu::paste() void TreeViewContextMenu::rename() { - m_parent->rename(m_fileInfo); + m_parent->rename(m_fileItem); } void TreeViewContextMenu::moveToTrash() { - KonqOperations::del(m_parent, KonqOperations::TRASH, m_fileInfo.url()); + KonqOperations::del(m_parent, KonqOperations::TRASH, m_fileItem.url()); } void TreeViewContextMenu::deleteItem() { - KonqOperations::del(m_parent, KonqOperations::DEL, m_fileInfo.url()); + KonqOperations::del(m_parent, KonqOperations::DEL, m_fileItem.url()); } void TreeViewContextMenu::showProperties() { - KPropertiesDialog* dialog = new KPropertiesDialog(m_fileInfo.url(), m_parent); + KPropertiesDialog* dialog = new KPropertiesDialog(m_fileItem.url(), m_parent); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->show(); } diff --git a/src/panels/folders/treeviewcontextmenu.h b/src/panels/folders/treeviewcontextmenu.h index e33bb70c5..0b3fd79bd 100644 --- a/src/panels/folders/treeviewcontextmenu.h +++ b/src/panels/folders/treeviewcontextmenu.h @@ -50,25 +50,25 @@ public: void open(); private slots: - /** Cuts the item m_fileInfo. */ + /** Cuts the item m_fileItem. */ void cut(); - /** Copies the item m_fileInfo. */ + /** Copies the item m_fileItem. */ void copy(); - /** Paste the clipboard to m_fileInfo. */ + /** Paste the clipboard to m_fileItem. */ void paste(); - /** Renames the item m_fileInfo. */ + /** Renames the item m_fileItem. */ void rename(); - /** Moves the item m_fileInfo to the trash. */ + /** Moves the item m_fileItem to the trash. */ void moveToTrash(); - /** Deletes the item m_fileInfo. */ + /** Deletes the item m_fileItem. */ void deleteItem(); - /** Shows the properties of the item m_fileInfo. */ + /** Shows the properties of the item m_fileItem. */ void showProperties(); /** @@ -88,7 +88,7 @@ private: private: FoldersPanel* m_parent; - KFileItem m_fileInfo; + KFileItem m_fileItem; }; #endif diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index c5c13e97f..379cd9f90 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -141,7 +141,6 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) : connect(controller, SIGNAL(itemContextMenuRequested(int,QPointF)), this, SLOT(slotItemContextMenuRequested(int,QPointF))); connect(controller, SIGNAL(viewContextMenuRequested(QPointF)), this, SLOT(slotViewContextMenuRequested(QPointF))); connect(controller, SIGNAL(headerContextMenuRequested(QPointF)), this, SLOT(slotHeaderContextMenuRequested(QPointF))); - connect(controller, SIGNAL(itemExpansionToggleClicked(int)), this, SLOT(slotItemExpansionToggleClicked(int))); connect(controller, SIGNAL(itemHovered(int)), this, SLOT(slotItemHovered(int))); connect(controller, SIGNAL(itemUnhovered(int)), this, SLOT(slotItemUnhovered(int))); connect(controller, SIGNAL(itemDropEvent(int,QGraphicsSceneDragDropEvent*)), this, SLOT(slotItemDropEvent(int,QGraphicsSceneDragDropEvent*))); @@ -788,17 +787,6 @@ void DolphinView::slotHeaderContextMenuRequested(const QPointF& pos) delete menu.data(); } -void DolphinView::slotItemExpansionToggleClicked(int index) -{ - // TODO: When doing a model->setExpanded(false) it should - // be checked here whether the current index is part of the - // closed sub-tree. If this is the case, the current index - // should be adjusted to the parent index. - KFileItemModel* model = fileItemModel(); - const bool expanded = model->isExpanded(index); - model->setExpanded(index, !expanded); -} - void DolphinView::slotItemHovered(int index) { const KFileItem item = fileItemModel()->fileItem(index); diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h index 2bbdf2b71..e0be25e42 100644 --- a/src/views/dolphinview.h +++ b/src/views/dolphinview.h @@ -559,7 +559,6 @@ private slots: void slotItemContextMenuRequested(int index, const QPointF& pos); void slotViewContextMenuRequested(const QPointF& pos); void slotHeaderContextMenuRequested(const QPointF& pos); - void slotItemExpansionToggleClicked(int index); void slotItemHovered(int index); void slotItemUnhovered(int index); void slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* event); diff --git a/src/views/dolphinviewautoscroller.cpp b/src/views/dolphinviewautoscroller.cpp deleted file mode 100644 index 5b338cc37..000000000 --- a/src/views/dolphinviewautoscroller.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Peter Penz * - * * - * 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 * - ***************************************************************************/ - -#include "dolphinviewautoscroller.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -DolphinViewAutoScroller::DolphinViewAutoScroller(QAbstractItemView* parent) : - QObject(parent), - m_rubberBandSelection(false), - m_keyPressed(false), - m_initializedTimestamp(false), - m_horizontalScrollInc(0), - m_verticalScrollInc(0), - m_itemView(parent), - m_timer(0), - m_timestamp() -{ - m_itemView->setAutoScroll(false); - m_itemView->viewport()->installEventFilter(this); - m_itemView->installEventFilter(this); - - m_timer = new QTimer(this); - m_timer->setSingleShot(false); - m_timer->setInterval(1000 / 25); // 25 frames per second - connect(m_timer, SIGNAL(timeout()), this, SLOT(scrollViewport())); -} - -DolphinViewAutoScroller::~DolphinViewAutoScroller() -{ -} - -bool DolphinViewAutoScroller::isActive() const -{ - return m_timer->isActive(); -} - -void DolphinViewAutoScroller::handleCurrentIndexChange(const QModelIndex& current, - const QModelIndex& previous) -{ - // When the autoscroller is inactive and a key has been pressed, it must be - // assured that the current item stays visible. The check whether the previous - // item is valid is important because of #197951. The keypress check is done - // because of #199833. - if (current.isValid() && (previous.isValid() || m_keyPressed) && !isActive()) { - m_itemView->scrollTo(current); - } -} - -bool DolphinViewAutoScroller::eventFilter(QObject* watched, QEvent* event) -{ - if (watched == m_itemView->viewport()) { - switch (event->type()) { - case QEvent::MouseButtonPress: - if (static_cast(event)->button() == Qt::LeftButton) { - m_rubberBandSelection = true; - } - break; - - case QEvent::MouseMove: - if (m_rubberBandSelection) { - triggerAutoScroll(); - } - break; - - case QEvent::MouseButtonRelease: - m_rubberBandSelection = false; - stopAutoScroll(); - break; - - case QEvent::DragEnter: - case QEvent::DragMove: - m_rubberBandSelection = false; - triggerAutoScroll(); - break; - - case QEvent::Drop: - case QEvent::DragLeave: - m_rubberBandSelection = false; - stopAutoScroll(); - break; - - default: - break; - } - } else if (watched == m_itemView) { - switch (event->type()) { - case QEvent::KeyPress: - m_keyPressed = true; - break; - - case QEvent::KeyRelease: - m_keyPressed = false; - break; - - default: - break; - } - } - - return QObject::eventFilter(watched, event); -} - -void DolphinViewAutoScroller::scrollViewport() -{ - if (m_timestamp.elapsed() < QApplication::startDragTime()) { - return; - } - - QScrollBar* verticalScrollBar = m_itemView->verticalScrollBar(); - if (verticalScrollBar) { - const int value = verticalScrollBar->value(); - verticalScrollBar->setValue(value + m_verticalScrollInc); - - } - QScrollBar* horizontalScrollBar = m_itemView->horizontalScrollBar(); - if (horizontalScrollBar) { - const int value = horizontalScrollBar->value(); - horizontalScrollBar->setValue(value + m_horizontalScrollInc); - - } - - if (m_rubberBandSelection) { - // The scrolling does not lead to an update of the rubberband - // selection. Fake a mouse move event to let the QAbstractItemView - // update the rubberband. - QWidget* viewport = m_itemView->viewport(); - const QPoint pos = viewport->mapFromGlobal(QCursor::pos()); - QMouseEvent event(QEvent::MouseMove, pos, Qt::LeftButton, Qt::LeftButton, QApplication::keyboardModifiers()); - QCoreApplication::sendEvent(viewport, &event); - } -} - -void DolphinViewAutoScroller::triggerAutoScroll() -{ - const bool verticalScrolling = m_itemView->verticalScrollBar() && - m_itemView->verticalScrollBar()->isVisible(); - const bool horizontalScrolling = m_itemView->horizontalScrollBar() && - m_itemView->horizontalScrollBar()->isVisible(); - if (!verticalScrolling && !horizontalScrolling) { - // no scrollbars are shown at all, so no autoscrolling is necessary - stopAutoScroll(); - return; - } - - QWidget* viewport = m_itemView->viewport(); - const QPoint pos = viewport->mapFromGlobal(QCursor::pos()); - if (verticalScrolling) { - m_verticalScrollInc = calculateScrollIncrement(pos.y(), viewport->height()); - } - if (horizontalScrolling) { - m_horizontalScrollInc = calculateScrollIncrement(pos.x(), viewport->width()); - } - - if (m_timer->isActive()) { - if ((m_horizontalScrollInc == 0) && (m_verticalScrollInc == 0)) { - stopAutoScroll(); - } - } else if ((m_horizontalScrollInc != 0) || (m_verticalScrollInc != 0)) { - if (!m_initializedTimestamp) { - m_initializedTimestamp = true; - m_timestamp.start(); - } - m_timer->start(); - } -} - -void DolphinViewAutoScroller::stopAutoScroll() -{ - m_timer->stop(); - m_horizontalScrollInc = 0; - m_verticalScrollInc = 0; - m_initializedTimestamp = false; -} - -int DolphinViewAutoScroller::calculateScrollIncrement(int cursorPos, int rangeSize) const -{ - int inc = 0; - - const int minSpeed = 4; - const int maxSpeed = 768; - const int speedLimiter = 48; - const int autoScrollBorder = 64; - - if (cursorPos < autoScrollBorder) { - inc = -minSpeed + qAbs(cursorPos - autoScrollBorder) * (cursorPos - autoScrollBorder) / speedLimiter; - if (inc < -maxSpeed) { - inc = -maxSpeed; - } - } else if (cursorPos > rangeSize - autoScrollBorder) { - inc = minSpeed + qAbs(cursorPos - rangeSize + autoScrollBorder) * (cursorPos - rangeSize + autoScrollBorder) / speedLimiter; - if (inc > maxSpeed) { - inc = maxSpeed; - } - } - - return inc; -} - -#include "dolphinviewautoscroller.moc" diff --git a/src/views/dolphinviewautoscroller.h b/src/views/dolphinviewautoscroller.h deleted file mode 100644 index 04d91a8f6..000000000 --- a/src/views/dolphinviewautoscroller.h +++ /dev/null @@ -1,79 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Peter Penz * - * * - * 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 * - ***************************************************************************/ - -#ifndef DOLPHINVIEWAUTOSCROLLER_H -#define DOLPHINVIEWAUTOSCROLLER_H - -#include -#include - -class QAbstractItemView; -class QModelIndex; -class QTimer; - -/** - * @brief Assures that an autoscrolling is done for item views. - * - * This is a workaround as QAbstractItemView::setAutoScroll() is not usable - * when selecting items (see Qt issue #214542). - */ -class DolphinViewAutoScroller : public QObject -{ - Q_OBJECT - -public: - DolphinViewAutoScroller(QAbstractItemView* parent); - virtual ~DolphinViewAutoScroller(); - bool isActive() const; - - /** - * Must be invoked by the parent item view, when QAbstractItemView::currentChanged() - * has been called. Assures that the current item stays visible when it has been - * changed by the keyboard. - */ - void handleCurrentIndexChange(const QModelIndex& current, const QModelIndex& previous); - -protected: - virtual bool eventFilter(QObject* watched, QEvent* event); - -private slots: - void scrollViewport(); - -private: - void triggerAutoScroll(); - void stopAutoScroll(); - - /** - * Calculates the scroll increment dependent from - * the cursor position \a cursorPos and the range 0 - \a rangeSize - 1. - */ - int calculateScrollIncrement(int cursorPos, int rangeSize) const; - -private: - bool m_rubberBandSelection; - bool m_keyPressed; - bool m_initializedTimestamp; - int m_horizontalScrollInc; - int m_verticalScrollInc; - QAbstractItemView* m_itemView; - QTimer* m_timer; - QTime m_timestamp; -}; - -#endif -- 2.47.3