1 /***************************************************************************
2 * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
4 * Based on the Itemviews NG project from Trolltech Labs: *
5 * http://qt.gitorious.org/qt-labs/itemviews-ng *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
21 ***************************************************************************/
23 #include "kitemlistcontainer.h"
25 #include "kitemlistcontroller.h"
26 #include "kitemlistview.h"
27 #include "kitemmodelbase.h"
29 #include <QGraphicsScene>
30 #include <QGraphicsView>
31 #include <QPropertyAnimation>
37 class KItemListContainerViewport
: public QGraphicsView
40 KItemListContainerViewport(QGraphicsScene
* scene
, QWidget
* parent
)
41 : QGraphicsView(scene
, parent
)
43 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff
);
44 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff
);
45 setViewportMargins(0, 0, 0, 0);
46 setFrameShape(QFrame::NoFrame
);
49 void scrollContentsBy(int dx
, int dy
)
53 // Do nothing. This prevents that e.g. the wheel-event
54 // results in a moving of the scene items.
58 KItemListContainer::KItemListContainer(KItemListController
* controller
, QWidget
* parent
) :
59 QAbstractScrollArea(parent
),
60 m_controller(controller
),
61 m_sliderMovedByUser(false),
62 m_viewOffsetAnimation(0)
65 controller
->setParent(this);
69 KItemListContainer::KItemListContainer(QWidget
* parent
) :
70 QAbstractScrollArea(parent
),
76 KItemListContainer::~KItemListContainer()
80 KItemListController
* KItemListContainer::controller() const
85 void KItemListContainer::showEvent(QShowEvent
* event
)
87 QAbstractScrollArea::showEvent(event
);
91 void KItemListContainer::resizeEvent(QResizeEvent
* event
)
93 QAbstractScrollArea::resizeEvent(event
);
97 void KItemListContainer::scrollContentsBy(int dx
, int dy
)
99 KItemListView
* view
= m_controller
->view();
104 const qreal currentOffset
= view
->offset();
105 qreal offsetDiff
= (view
->scrollOrientation() == Qt::Vertical
) ? dy
: dx
;
107 const bool animRunning
= (m_viewOffsetAnimation
->state() == QAbstractAnimation::Running
);
109 // Stopping a running animation means skipping the range from the current offset
110 // until the target offset. To prevent skipping of the range the difference
111 // is added to the new target offset.
112 m_viewOffsetAnimation
->stop();
113 const qreal targetOffset
= m_viewOffsetAnimation
->endValue().toReal();
114 offsetDiff
+= (currentOffset
- targetOffset
);
117 const qreal newOffset
= currentOffset
- offsetDiff
;
119 if (m_sliderMovedByUser
|| animRunning
) {
120 m_viewOffsetAnimation
->stop();
121 m_viewOffsetAnimation
->setStartValue(currentOffset
);
122 m_viewOffsetAnimation
->setEndValue(newOffset
);
123 m_viewOffsetAnimation
->setEasingCurve(animRunning
? QEasingCurve::OutQuad
: QEasingCurve::InOutQuad
);
124 m_viewOffsetAnimation
->start();
126 view
->setOffset(newOffset
);
130 bool KItemListContainer::eventFilter(QObject
* obj
, QEvent
* event
)
132 Q_ASSERT(obj
== horizontalScrollBar() || obj
== verticalScrollBar());
134 // Check whether the scrollbar has been adjusted by a mouse-event
135 // triggered by the user and remember this in m_sliderMovedByUser.
136 // The smooth scrolling will only get active if m_sliderMovedByUser
137 // is true (see scrollContentsBy()).
138 const bool scrollVertical
= (m_controller
->view()->scrollOrientation() == Qt::Vertical
);
139 const bool checkEvent
= ( scrollVertical
&& obj
== verticalScrollBar()) ||
140 (!scrollVertical
&& obj
== horizontalScrollBar());
142 switch (event
->type()) {
143 case QEvent::MouseButtonPress
:
144 m_sliderMovedByUser
= true;
147 case QEvent::MouseButtonRelease
:
148 m_sliderMovedByUser
= false;
152 wheelEvent(static_cast<QWheelEvent
*>(event
));
160 return QAbstractScrollArea::eventFilter(obj
, event
);
163 void KItemListContainer::wheelEvent(QWheelEvent
* event
)
165 KItemListView
* view
= m_controller
->view();
166 if (!view
|| event
->orientation() != view
->scrollOrientation()) {
170 const int numDegrees
= event
->delta() / 8;
171 const int numSteps
= numDegrees
/ 15;
173 const bool previous
= m_sliderMovedByUser
;
174 m_sliderMovedByUser
= true;
175 if (view
->scrollOrientation() == Qt::Vertical
) {
176 const int value
= verticalScrollBar()->value();
177 verticalScrollBar()->setValue(value
- numSteps
* view
->size().height());
179 const int value
= horizontalScrollBar()->value();
180 horizontalScrollBar()->setValue(value
- numSteps
* view
->size().width());
182 m_sliderMovedByUser
= previous
;
187 void KItemListContainer::slotModelChanged(KItemModelBase
* current
, KItemModelBase
* previous
)
193 void KItemListContainer::slotViewChanged(KItemListView
* current
, KItemListView
* previous
)
195 QGraphicsScene
* scene
= static_cast<QGraphicsView
*>(viewport())->scene();
197 scene
->removeItem(previous
);
198 disconnect(previous
, SIGNAL(offsetChanged(int,int)), this, SLOT(updateScrollBars()));
199 disconnect(previous
, SIGNAL(maximumOffsetChanged(int,int)), this, SLOT(updateScrollBars()));
200 m_viewOffsetAnimation
->setTargetObject(0);
203 scene
->addItem(current
);
204 connect(current
, SIGNAL(offsetChanged(int,int)), this, SLOT(updateScrollBars()));
205 connect(current
, SIGNAL(maximumOffsetChanged(int,int)), this, SLOT(updateScrollBars()));
206 m_viewOffsetAnimation
->setTargetObject(current
);
210 void KItemListContainer::updateScrollBars()
212 const KItemListView
* view
= m_controller
->view();
217 QScrollBar
* scrollBar
= 0;
220 if (view
->scrollOrientation() == Qt::Vertical
) {
221 scrollBar
= verticalScrollBar();
222 singleStep
= view
->itemSize().height();
223 pageStep
= view
->size().height();
225 scrollBar
= horizontalScrollBar();
226 singleStep
= view
->itemSize().width();
227 pageStep
= view
->size().width();
230 const int value
= view
->offset();
231 const int maximum
= qMax(0, int(view
->maximumOffset() - pageStep
));
232 if (m_viewOffsetAnimation
->state() == QAbstractAnimation::Running
) {
233 if (maximum
== scrollBar
->maximum()) {
234 // The value has been changed by the animation, no update
235 // of the scrollbars is required as their target state will be
236 // reached with the end of the animation.
240 // The maximum has been changed which indicates that the content
241 // of the view has been changed. Stop the animation in any case and
242 // update the scrollbars immediately.
243 m_viewOffsetAnimation
->stop();
246 scrollBar
->setSingleStep(singleStep
);
247 scrollBar
->setPageStep(pageStep
);
248 scrollBar
->setMinimum(0);
249 scrollBar
->setMaximum(maximum
);
250 scrollBar
->setValue(value
);
253 void KItemListContainer::updateGeometries()
255 QRect rect
= geometry();
257 int widthDec
= frameWidth() * 2;
258 if (verticalScrollBar()->isVisible()) {
259 widthDec
+= style()->pixelMetric(QStyle::PM_ScrollBarExtent
);
262 int heightDec
= frameWidth() * 2;
263 if (horizontalScrollBar()->isVisible()) {
264 heightDec
+= style()->pixelMetric(QStyle::PM_ScrollBarExtent
);
267 rect
.adjust(0, 0, -widthDec
, -heightDec
);
269 m_controller
->view()->setGeometry(QRect(0, 0, rect
.width(), rect
.height()));
271 static_cast<KItemListContainerViewport
*>(viewport())->scene()->setSceneRect(0, 0, rect
.width(), rect
.height());
272 static_cast<KItemListContainerViewport
*>(viewport())->viewport()->setGeometry(QRect(0, 0, rect
.width(), rect
.height()));
277 void KItemListContainer::initialize()
280 m_controller
= new KItemListController(this);
283 connect(m_controller
, SIGNAL(modelChanged(KItemModelBase
*,KItemModelBase
*)),
284 this, SLOT(slotModelChanged(KItemModelBase
*,KItemModelBase
*)));
285 connect(m_controller
, SIGNAL(viewChanged(KItemListView
*,KItemListView
*)),
286 this, SLOT(slotViewChanged(KItemListView
*,KItemListView
*)));
288 QGraphicsView
* graphicsView
= new KItemListContainerViewport(new QGraphicsScene(this), this);
289 setViewport(graphicsView
);
291 m_viewOffsetAnimation
= new QPropertyAnimation(this, "offset");
292 m_viewOffsetAnimation
->setDuration(500);
294 horizontalScrollBar()->installEventFilter(this);
295 verticalScrollBar()->installEventFilter(this);
298 #include "kitemlistcontainer.moc"