]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kitemlistcontainer.cpp
Fix selection rect after porting from QFontMetrics::width()
[dolphin.git] / src / kitemviews / kitemlistcontainer.cpp
index 01a4cfd4eb14971f58f383cfa984759ca55f4d79..6279b15a994baf8f0f7579f57aa47a981ccf584d 100644 (file)
@@ -1,8 +1,7 @@
 /***************************************************************************
  *   Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com>             *
  *                                                                         *
- *   Based on the Itemviews NG project from Trolltech Labs:                *
- *   http://qt.gitorious.org/qt-labs/itemviews-ng                          *
+ *   Based on the Itemviews NG project from Trolltech Labs                 *
  *                                                                         *
  *   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  *
 
 #include "kitemlistcontroller.h"
 #include "kitemlistview.h"
-#include "kitemmodelbase.h"
-
 #include "private/kitemlistsmoothscroller.h"
 
 #include <QApplication>
+#include <QFontMetrics>
 #include <QGraphicsScene>
 #include <QGraphicsView>
-#include <QPropertyAnimation>
 #include <QScrollBar>
-#include <QStyle>
 #include <QStyleOption>
 
-#include <KDebug>
-
-#include "kitemlistviewaccessible.h"
-
 /**
  * Replaces the default viewport of KItemListContainer by a
  * non-scrollable viewport. The scrolling is done in an optimized
  */
 class KItemListContainerViewport : public QGraphicsView
 {
+    Q_OBJECT
+
 public:
     KItemListContainerViewport(QGraphicsScene* scene, QWidget* parent);
 protected:
-    virtual void wheelEvent(QWheelEvent* event);
+    void wheelEvent(QWheelEvent* event) override;
 };
 
 KItemListContainerViewport::KItemListContainerViewport(QGraphicsScene* scene, QWidget* parent) :
@@ -69,21 +63,11 @@ void KItemListContainerViewport::wheelEvent(QWheelEvent* event)
     event->ignore();
 }
 
-QAccessibleInterface* accessibleContainerFactory(const QString &key, QObject *object)
-{
-    Q_UNUSED(key)
-    if (KItemListContainer*view = qobject_cast<KItemListContainer*>(object))
-        return new KItemListContainerAccessible(view);
-    if (KItemListView *view = qobject_cast<KItemListView*>(object))
-        return new KItemListViewAccessible(view);
-    return 0;
-}
-
 KItemListContainer::KItemListContainer(KItemListController* controller, QWidget* parent) :
     QAbstractScrollArea(parent),
     m_controller(controller),
-    m_horizontalSmoothScroller(0),
-    m_verticalSmoothScroller(0)
+    m_horizontalSmoothScroller(nullptr),
+    m_verticalSmoothScroller(nullptr)
 {
     Q_ASSERT(controller);
     controller->setParent(this);
@@ -95,18 +79,16 @@ KItemListContainer::KItemListContainer(KItemListController* controller, QWidget*
     m_verticalSmoothScroller = new KItemListSmoothScroller(verticalScrollBar(), this);
 
     if (controller->model()) {
-        slotModelChanged(controller->model(), 0);
+        slotModelChanged(controller->model(), nullptr);
     }
     if (controller->view()) {
-        slotViewChanged(controller->view(), 0);
+        slotViewChanged(controller->view(), nullptr);
     }
 
-    connect(controller, SIGNAL(modelChanged(KItemModelBase*,KItemModelBase*)),
-            this, SLOT(slotModelChanged(KItemModelBase*,KItemModelBase*)));
-    connect(controller, SIGNAL(viewChanged(KItemListView*,KItemListView*)),
-            this, SLOT(slotViewChanged(KItemListView*,KItemListView*)));
-
-    QAccessible::installFactory(accessibleContainerFactory);
+    connect(controller, &KItemListController::modelChanged,
+            this, &KItemListContainer::slotModelChanged);
+    connect(controller, &KItemListController::viewChanged,
+            this, &KItemListContainer::slotViewChanged);
 }
 
 KItemListContainer::~KItemListContainer()
@@ -114,9 +96,7 @@ KItemListContainer::~KItemListContainer()
     // Don't rely on the QObject-order to delete the controller, otherwise
     // the QGraphicsScene might get deleted before the view.
     delete m_controller;
-    m_controller = 0;
-
-    QAccessible::removeFactory(accessibleContainerFactory);
+    m_controller = nullptr;
 }
 
 KItemListController* KItemListContainer::controller() const
@@ -163,7 +143,6 @@ void KItemListContainer::keyPressEvent(QKeyEvent* event)
     if (view) {
         QApplication::sendEvent(view, event);
     }
-    //QAccessible::updateAccessibility(view, 0, QAccessible::Focus);
 }
 
 void KItemListContainer::showEvent(QShowEvent* event)
@@ -202,25 +181,19 @@ void KItemListContainer::wheelEvent(QWheelEvent* event)
     KItemListSmoothScroller* smoothScroller = scrollHorizontally ?
                                               m_horizontalSmoothScroller : m_verticalSmoothScroller;
 
-    const int numDegrees = event->delta() / 8;
-    const int numSteps = numDegrees / 15;
-
-    const QScrollBar* scrollBar = smoothScroller->scrollBar();
-    smoothScroller->scrollTo(scrollBar->value() - numSteps * scrollBar->pageStep() / 4);
-
-    event->accept();
+    smoothScroller->handleWheelEvent(event);
 }
 
 void KItemListContainer::slotScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous)
 {
-    Q_UNUSED(previous);
+    Q_UNUSED(previous)
     updateSmoothScrollers(current);
 }
 
 void KItemListContainer::slotModelChanged(KItemModelBase* current, KItemModelBase* previous)
 {
-    Q_UNUSED(current);
-    Q_UNUSED(previous);
+    Q_UNUSED(current)
+    Q_UNUSED(previous)
 }
 
 void KItemListContainer::slotViewChanged(KItemListView* current, KItemListView* previous)
@@ -228,23 +201,33 @@ void KItemListContainer::slotViewChanged(KItemListView* current, KItemListView*
     QGraphicsScene* scene = static_cast<QGraphicsView*>(viewport())->scene();
     if (previous) {
         scene->removeItem(previous);
-        disconnect(previous, SIGNAL(scrollOrientationChanged(Qt::Orientation,Qt::Orientation)), this, SLOT(slotScrollOrientationChanged(Qt::Orientation,Qt::Orientation)));
-        disconnect(previous, SIGNAL(scrollOffsetChanged(qreal,qreal)),        this, SLOT(updateScrollOffsetScrollBar()));
-        disconnect(previous, SIGNAL(maximumScrollOffsetChanged(qreal,qreal)), this, SLOT(updateScrollOffsetScrollBar()));
-        disconnect(previous, SIGNAL(itemOffsetChanged(qreal,qreal)),          this, SLOT(updateItemOffsetScrollBar()));
-        disconnect(previous, SIGNAL(maximumItemOffsetChanged(qreal,qreal)),   this, SLOT(updateItemOffsetScrollBar()));
-        disconnect(previous, SIGNAL(scrollTo(qreal)),                         this, SLOT(scrollTo(qreal)));
-        m_horizontalSmoothScroller->setTargetObject(0);
-        m_verticalSmoothScroller->setTargetObject(0);
+        disconnect(previous, &KItemListView::scrollOrientationChanged,
+                   this, &KItemListContainer::slotScrollOrientationChanged);
+        disconnect(previous, &KItemListView::scrollOffsetChanged,
+                   this, &KItemListContainer::updateScrollOffsetScrollBar);
+        disconnect(previous, &KItemListView::maximumScrollOffsetChanged,
+                   this, &KItemListContainer::updateScrollOffsetScrollBar);
+        disconnect(previous, &KItemListView::itemOffsetChanged,
+                   this, &KItemListContainer::updateItemOffsetScrollBar);
+        disconnect(previous, &KItemListView::maximumItemOffsetChanged,
+                   this, &KItemListContainer::updateItemOffsetScrollBar);
+        disconnect(previous, &KItemListView::scrollTo, this, &KItemListContainer::scrollTo);
+        m_horizontalSmoothScroller->setTargetObject(nullptr);
+        m_verticalSmoothScroller->setTargetObject(nullptr);
     }
     if (current) {
         scene->addItem(current);
-        connect(current, SIGNAL(scrollOrientationChanged(Qt::Orientation,Qt::Orientation)), this, SLOT(slotScrollOrientationChanged(Qt::Orientation,Qt::Orientation)));
-        connect(current, SIGNAL(scrollOffsetChanged(qreal,qreal)),        this, SLOT(updateScrollOffsetScrollBar()));
-        connect(current, SIGNAL(maximumScrollOffsetChanged(qreal,qreal)), this, SLOT(updateScrollOffsetScrollBar()));
-        connect(current, SIGNAL(itemOffsetChanged(qreal,qreal)),          this, SLOT(updateItemOffsetScrollBar()));
-        connect(current, SIGNAL(maximumItemOffsetChanged(qreal,qreal)),   this, SLOT(updateItemOffsetScrollBar()));
-        connect(current, SIGNAL(scrollTo(qreal)),                         this, SLOT(scrollTo(qreal)));
+        connect(current, &KItemListView::scrollOrientationChanged,
+                this, &KItemListContainer::slotScrollOrientationChanged);
+        connect(current, &KItemListView::scrollOffsetChanged,
+                this, &KItemListContainer::updateScrollOffsetScrollBar);
+        connect(current, &KItemListView::maximumScrollOffsetChanged,
+                this, &KItemListContainer::updateScrollOffsetScrollBar);
+        connect(current, &KItemListView::itemOffsetChanged,
+                this, &KItemListContainer::updateItemOffsetScrollBar);
+        connect(current, &KItemListView::maximumItemOffsetChanged,
+                this, &KItemListContainer::updateItemOffsetScrollBar);
+        connect(current, &KItemListView::scrollTo, this, &KItemListContainer::scrollTo);
         m_horizontalSmoothScroller->setTargetObject(current);
         m_verticalSmoothScroller->setTargetObject(current);
         updateSmoothScrollers(current->scrollOrientation());
@@ -270,24 +253,40 @@ void KItemListContainer::updateScrollOffsetScrollBar()
         return;
     }
 
-    KItemListSmoothScroller* smoothScroller = 0;
-    QScrollBar* scrollOffsetScrollBar = 0;
+    KItemListSmoothScroller* smoothScroller = nullptr;
+    QScrollBar* scrollOffsetScrollBar = nullptr;
     int singleStep = 0;
     int pageStep = 0;
+    int maximum = 0;
     if (view->scrollOrientation() == Qt::Vertical) {
         smoothScroller = m_verticalSmoothScroller;
         scrollOffsetScrollBar = verticalScrollBar();
-        singleStep = view->itemSize().height();
-        pageStep = view->size().height();
+
+        // Don't scroll super fast when using a wheel mouse:
+        // We want to consider one "line" to be the text label which has a
+        // roughly fixed height rather than using the height of the icon which
+        // may be very tall
+        const QFontMetrics metrics(font());
+        singleStep = metrics.height() * QApplication::wheelScrollLines();
+
+        // We cannot use view->size().height() because this height might
+        // include the header widget, which is not part of the scrolled area.
+        pageStep = view->verticalPageStep();
+
+        // However, the total height of the view must be considered for the
+        // maximum value of the scroll bar. Note that the view's scrollOffset()
+        // refers to the offset of the top part of the view, which might be
+        // hidden behind the header.
+        maximum = qMax(0, int(view->maximumScrollOffset() - view->size().height()));
     } else {
         smoothScroller = m_horizontalSmoothScroller;
         scrollOffsetScrollBar = horizontalScrollBar();
         singleStep = view->itemSize().width();
         pageStep = view->size().width();
+        maximum = qMax(0, int(view->maximumScrollOffset() - view->size().width()));
     }
 
     const int value = view->scrollOffset();
-    const int maximum = qMax(0, int(view->maximumScrollOffset() - pageStep));
     if (smoothScroller->requestScrollBarUpdate(maximum)) {
         const bool updatePolicy = (scrollOffsetScrollBar->maximum() > 0 && maximum == 0)
                                   || horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOn;
@@ -312,8 +311,8 @@ void KItemListContainer::updateItemOffsetScrollBar()
         return;
     }
 
-    KItemListSmoothScroller* smoothScroller = 0;
-    QScrollBar* itemOffsetScrollBar = 0;
+    KItemListSmoothScroller* smoothScroller = nullptr;
+    QScrollBar* itemOffsetScrollBar = nullptr;
     int singleStep = 0;
     int pageStep = 0;
     if (view->scrollOrientation() == Qt::Vertical) {
@@ -346,26 +345,28 @@ void KItemListContainer::updateGeometries()
     int extra = frameWidth() * 2;
     QStyleOption option;
     option.initFrom(this);
+    int scrollbarSpacing = 0;
     if (style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, &option, this)) {
-        extra += style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, &option, this);
+        scrollbarSpacing = style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, &option, this);
     }
 
     const int widthDec = verticalScrollBar()->isVisible()
-                         ? extra + style()->pixelMetric(QStyle::PM_ScrollBarExtent, &option, this)
+                         ? extra + scrollbarSpacing + style()->pixelMetric(QStyle::PM_ScrollBarExtent, &option, this)
                          : extra;
 
     const int heightDec = horizontalScrollBar()->isVisible()
-                          ? extra + style()->pixelMetric(QStyle::PM_ScrollBarExtent, &option, this)
+                          ? extra + scrollbarSpacing + style()->pixelMetric(QStyle::PM_ScrollBarExtent, &option, this)
                           : extra;
 
-    rect.adjust(0, 0, -widthDec, -heightDec);
-
-    const QRectF newGeometry(0, 0, rect.width(), rect.height());
+    const QRectF newGeometry(0, 0, rect.width() - widthDec,
+                             rect.height() - heightDec);
     if (m_controller->view()->geometry() != newGeometry) {
         m_controller->view()->setGeometry(newGeometry);
 
-        static_cast<KItemListContainerViewport*>(viewport())->scene()->setSceneRect(0, 0, rect.width(), rect.height());
-        static_cast<KItemListContainerViewport*>(viewport())->viewport()->setGeometry(QRect(0, 0, rect.width(), rect.height()));
+        // Get the real geometry of the view again since the scrollbars
+        // visibilities and the view geometry may have changed in re-layout.
+        static_cast<KItemListContainerViewport*>(viewport())->scene()->setSceneRect(m_controller->view()->geometry());
+        static_cast<KItemListContainerViewport*>(viewport())->viewport()->setGeometry(m_controller->view()->geometry().toRect());
 
         updateScrollOffsetScrollBar();
         updateItemOffsetScrollBar();