/***************************************************************************
* Copyright (C) 2008 by <haraldhv (at) stud.ntnu.no> *
+ * Copyright (C) 2008 by <peter.penz@gmx.at> *
* *
* 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 *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
-#include <KGlobalSettings>
-
-#include <QDebug>
-#include <QScrollBar>
-
#include "ktreeview.h"
#include "ktreeview_p.h"
-KTreeView::KTreeViewPrivate::KTreeViewPrivate(KTreeView *parent)
- : parent(parent),
- autoHorizontalScroll(true),
- scrollTowards(0),
- scrollPixels(5),
- scrollDelay(50),
- leftSideMargin(30),
- considerDelay(500),
- topLeftPoint(QPoint(10,10))
-{
- Q_ASSERT(parent->verticalScrollBar());
-
- considerDelayTimer.setInterval(considerDelay);
-
- connect( &considerDelayTimer,
- SIGNAL(timeout()),
- this,
- SLOT(considerAutoScroll())
- );
-
- connect( parent->verticalScrollBar(),
- SIGNAL(rangeChanged(int, int)),
- &considerDelayTimer,
- SLOT(start())
- );
-
- connect( parent->verticalScrollBar(),
- SIGNAL(valueChanged(int)),
- &considerDelayTimer,
- SLOT(start())
- );
-
- connect( parent,
- SIGNAL( collapsed ( const QModelIndex &)),
- &considerDelayTimer,
- SLOT(start())
- );
-
- connect( parent,
- SIGNAL( expanded ( const QModelIndex &)),
- &considerDelayTimer,
- SLOT(start())
- );
+#include <KGlobalSettings>
+#include <QItemSelectionModel>
+#include <QScrollBar>
+#include <QTimer>
+#include <QTimeLine>
+
+KTreeView::KTreeViewPrivate::KTreeViewPrivate(KTreeView *parent) :
+ parent(parent),
+ autoHorizontalScroll(false),
+ timeLine(0),
+ startScrollTimer(0)
+{
+ startScrollTimer = new QTimer(this);
+ startScrollTimer->setSingleShot(true);
+ startScrollTimer->setInterval(300);
+ connect(startScrollTimer, SIGNAL(timeout()),
+ this, SLOT(startScrolling()));
+
+ timeLine = new QTimeLine(300, this);
+ connect(timeLine, SIGNAL(frameChanged(int)),
+ this, SLOT(updateVerticalScrollBar(int)));
+
+ connect(parent->verticalScrollBar(), SIGNAL(rangeChanged(int, int)),
+ startScrollTimer, SLOT(start()));
+ connect(parent->verticalScrollBar(), SIGNAL(valueChanged(int)),
+ startScrollTimer, SLOT(start()));
+ connect(parent, SIGNAL(collapsed(const QModelIndex&)),
+ startScrollTimer, SLOT(start()));
+ connect(parent, SIGNAL(expanded(const QModelIndex&)),
+ startScrollTimer, SLOT(start()));
}
-void KTreeView::KTreeViewPrivate::considerAutoScroll()
+void KTreeView::KTreeViewPrivate::startScrolling()
{
- qDebug() << "Considering auto scroll";
-
- QModelIndex i = parent->indexAt(topLeftPoint);
- int smallest = parent->width();
-
- while (i.isValid())
- {
- QRect r = parent->visualRect(i);
- if (r.top() > parent->height())
- break;
-
- int leftSide = r.left();
-
- smallest = qMin(smallest, leftSide);
- i = parent->indexBelow(i);
- }
-
- int currentScroll = parent->horizontalScrollBar()->value();
+ QModelIndex index;
+
+ const int viewportHeight = parent->viewport()->height();
+
+ // check whether there is a selected index which is partly visible
+ const QModelIndexList selectedIndexes = parent->selectionModel()->selectedIndexes();
+ if (selectedIndexes.count() == 1) {
+ QModelIndex selectedIndex = selectedIndexes.first();
+ const QRect rect = parent->visualRect(selectedIndex);
+ if ((rect.bottom() >= 0) && (rect.top() <= viewportHeight)) {
+ // the selected index is (at least partly) visible, use it as
+ // scroll target
+ index = selectedIndex;
+ }
+ }
+
+ if (!index.isValid()) {
+ // no partly selected index is visible, determine the most left visual index
+ QModelIndex visibleIndex = parent->indexAt(QPoint(0, 0));
+ if (!visibleIndex.isValid()) {
+ return;
+ }
+
+ index = visibleIndex;
+ int minimum = parent->width();
+ do {
+ const QRect rect = parent->visualRect(visibleIndex);
+ if (rect.top() > viewportHeight) {
+ // the current index and all successors are not visible anymore
+ break;
+ }
+ if (rect.left() < minimum) {
+ minimum = rect.left();
+ index = visibleIndex;
+ }
+ visibleIndex = parent->indexBelow(visibleIndex);
+ } while (visibleIndex.isValid());
+ }
+
+ // start the horizontal scrolling to assure that the item indicated by 'index' gets fully visible
+ Q_ASSERT(index.isValid());
+ const QRect rect = parent->visualRect(index);
+
+ QScrollBar *scrollBar = parent->horizontalScrollBar();
+ const int oldScrollBarPos = scrollBar->value();
+
+ const int itemRight = oldScrollBarPos + rect.left() + rect.width() - 1;
+ const int availableWidth = parent->viewport()->width();
+ int scrollBarPos = itemRight - availableWidth;
+ const int scrollBarPosMax = oldScrollBarPos + rect.left() - parent->indentation();
+ if (scrollBarPos > scrollBarPosMax) {
+ scrollBarPos = scrollBarPosMax;
+ }
+
+ if (scrollBarPos != oldScrollBarPos) {
+ timeLine->setFrameRange(oldScrollBarPos, scrollBarPos);
+ timeLine->start();
+ }
+}
- setScrollTowards(smallest + currentScroll - leftSideMargin);
+void KTreeView::KTreeViewPrivate::updateVerticalScrollBar(int value)
+{
+ QScrollBar *scrollBar = parent->horizontalScrollBar();
+ scrollBar->setValue(value);
+ startScrollTimer->stop();
+}
- considerDelayTimer.stop();
+// ************************************************
+KTreeView::KTreeView(QWidget *parent) :
+ QTreeView(parent),
+ d(new KTreeViewPrivate(this))
+{
+ if (KGlobalSettings::graphicEffectsLevel() >= KGlobalSettings::SimpleAnimationEffects) {
+ setAutoHorizontalScroll(true);
+ }
}
-void KTreeView::KTreeViewPrivate::autoScrollTimeout()
+KTreeView::~KTreeView()
{
-
- Q_ASSERT(parent);
-
- QScrollBar *scrollBar = parent->horizontalScrollBar();
- if (scrollBar == NULL)
- {
- qDebug() << "Warning: no scrollbar present, but told to scroll.";
- scrollTimer.stop();
- return;
- }
-
- int currentScroll = scrollBar->value();
-
- int difference = currentScroll - scrollTowards;
-
- if (qAbs(difference) < scrollPixels)
- {
- scrollBar->setValue(scrollTowards);
- scrollTimer.stop();
- return;
- }
-
- if (difference < 0)
- {
- scrollBar->setValue(currentScroll + scrollPixels);
- }
- else
- {
- scrollBar->setValue(currentScroll - scrollPixels);
- }
}
-void KTreeView::KTreeViewPrivate::setScrollTowards( int scrollTowards )
+void KTreeView::setAutoHorizontalScroll(bool value)
{
- if (scrollTowards < 0)
- scrollTowards = 0;
- this->scrollTowards = scrollTowards;
- scrollTimer.start(scrollDelay);
+ d->autoHorizontalScroll = value;
}
-//************************************************
-
-KTreeView::KTreeView(QWidget *parent)
- : QTreeView(parent)
- , d(new KTreeViewPrivate(this))
+bool KTreeView::autoHorizontalScroll() const
{
- /* The graphicEffectsLevel was not available in the 4.0.3 version of
- * the libs I was compiling with, so this is left out for now and
- * enabled by default...
- */
- //if (KGlobalSettings::graphicEffectsLevel() >=
- //KGlobalSettings::SimpleAnimationEffects)
- //{
- setAutoHorizontalScroll(true);
- //}
- connect(
- &d->scrollTimer,
- SIGNAL(timeout()),
- d,
- SLOT(autoScrollTimeout())
- );
+ return d->autoHorizontalScroll;
+}
+void KTreeView::setSelectionModel(QItemSelectionModel *selectionModel)
+{
+ QTreeView::setSelectionModel(selectionModel);
+ connect(selectionModel,
+ SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
+ d->startScrollTimer, SLOT(start()));
}
-void KTreeView::setAutoHorizontalScroll(bool value)
+void KTreeView::scrollTo(const QModelIndex& index, ScrollHint hint)
{
- d->autoHorizontalScroll = value;
+ if (d->autoHorizontalScroll) {
+ // assure that the value of the horizontal scrollbar stays on its current value,
+ // KTreeView will adjust the value manually
+ const int value = horizontalScrollBar()->value();
+ QTreeView::scrollTo(index, hint);
+ horizontalScrollBar()->setValue(value);
+ } else {
+ QTreeView::scrollTo(index, hint);
+ }
}
-bool KTreeView::autoHorizontalScroll( void )
+void KTreeView::hideEvent(QHideEvent *event)
{
- return d->autoHorizontalScroll;
+ d->startScrollTimer->stop();
+ d->timeLine->stop();
+ QTreeView::hideEvent(event);
}
#include "ktreeview.moc"