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 "kitemlistsmoothscroller_p.h"
27 #include "kitemlistview.h"
28 #include "kitemmodelbase.h"
30 #include <QApplication>
31 #include <QGraphicsScene>
32 #include <QGraphicsView>
33 #include <QPropertyAnimation>
36 #include <QStyleOption>
41 * Replaces the default viewport of KItemListContainer by a
42 * non-scrollable viewport. The scrolling is done in an optimized
43 * way by KItemListView internally.
45 class KItemListContainerViewport
: public QGraphicsView
48 KItemListContainerViewport(QGraphicsScene
* scene
, QWidget
* parent
);
50 virtual void wheelEvent(QWheelEvent
* event
);
53 KItemListContainerViewport::KItemListContainerViewport(QGraphicsScene
* scene
, QWidget
* parent
) :
54 QGraphicsView(scene
, parent
)
56 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff
);
57 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff
);
58 setViewportMargins(0, 0, 0, 0);
59 setFrameShape(QFrame::NoFrame
);
62 void KItemListContainerViewport::wheelEvent(QWheelEvent
* event
)
64 // Assure that the wheel-event gets forwarded to the parent
65 // and not handled at all by QGraphicsView.
71 KItemListContainer::KItemListContainer(KItemListController
* controller
, QWidget
* parent
) :
72 QAbstractScrollArea(parent
),
73 m_controller(controller
),
74 m_horizontalSmoothScroller(0),
75 m_verticalSmoothScroller(0)
78 controller
->setParent(this);
82 KItemListContainer::KItemListContainer(QWidget
* parent
) :
83 QAbstractScrollArea(parent
),
85 m_horizontalSmoothScroller(0),
86 m_verticalSmoothScroller(0)
91 KItemListContainer::~KItemListContainer()
95 KItemListController
* KItemListContainer::controller() const
100 void KItemListContainer::keyPressEvent(QKeyEvent
* event
)
102 // TODO: We should find a better way to handle the key press events in the view.
103 // The reasons why we need this hack are:
104 // 1. Without reimplementing keyPressEvent() here, the event would not reach the QGraphicsView.
105 // 2. By default, the KItemListView does not have the keyboard focus in the QGraphicsScene, so
106 // simply sending the event to the QGraphicsView which is the KItemListContainer's viewport
108 KItemListView
* view
= m_controller
->view();
110 QApplication::sendEvent(view
, event
);
114 void KItemListContainer::showEvent(QShowEvent
* event
)
116 QAbstractScrollArea::showEvent(event
);
120 void KItemListContainer::resizeEvent(QResizeEvent
* event
)
122 QAbstractScrollArea::resizeEvent(event
);
126 void KItemListContainer::scrollContentsBy(int dx
, int dy
)
128 m_horizontalSmoothScroller
->scrollContentsBy(dx
);
129 m_verticalSmoothScroller
->scrollContentsBy(dy
);
132 void KItemListContainer::wheelEvent(QWheelEvent
* event
)
134 if (event
->modifiers().testFlag(Qt::ControlModifier
)) {
139 KItemListView
* view
= m_controller
->view();
145 const bool scrollHorizontally
= (event
->orientation() == Qt::Horizontal
) ||
146 (event
->orientation() == Qt::Vertical
&& !verticalScrollBar()->isVisible());
147 KItemListSmoothScroller
* smoothScroller
= scrollHorizontally
?
148 m_horizontalSmoothScroller
: m_verticalSmoothScroller
;
150 const int numDegrees
= event
->delta() / 8;
151 const int numSteps
= numDegrees
/ 15;
153 const QScrollBar
* scrollBar
= smoothScroller
->scrollBar();
154 smoothScroller
->scrollTo(scrollBar
->value() - numSteps
* scrollBar
->pageStep() / 4);
159 void KItemListContainer::slotScrollOrientationChanged(Qt::Orientation current
, Qt::Orientation previous
)
162 updateSmoothScrollers(current
);
165 void KItemListContainer::slotModelChanged(KItemModelBase
* current
, KItemModelBase
* previous
)
171 void KItemListContainer::slotViewChanged(KItemListView
* current
, KItemListView
* previous
)
173 QGraphicsScene
* scene
= static_cast<QGraphicsView
*>(viewport())->scene();
175 scene
->removeItem(previous
);
176 disconnect(current
, SIGNAL(scrollOrientationChanged(Qt::Orientation
,Qt::Orientation
)), this, SLOT(slotScrollOrientationChanged(Qt::Orientation
,Qt::Orientation
)));
177 disconnect(previous
, SIGNAL(scrollOffsetChanged(qreal
,qreal
)), this, SLOT(updateScrollOffsetScrollBar()));
178 disconnect(previous
, SIGNAL(maximumScrollOffsetChanged(qreal
,qreal
)), this, SLOT(updateScrollOffsetScrollBar()));
179 disconnect(previous
, SIGNAL(itemOffsetChanged(qreal
,qreal
)), this, SLOT(updateItemOffsetScrollBar()));
180 disconnect(previous
, SIGNAL(maximumItemOffsetChanged(qreal
,qreal
)), this, SLOT(updateItemOffsetScrollBar()));
181 disconnect(previous
, SIGNAL(scrollTo(qreal
)), this, SLOT(scrollTo(qreal
)));
182 m_horizontalSmoothScroller
->setTargetObject(0);
183 m_verticalSmoothScroller
->setTargetObject(0);
186 scene
->addItem(current
);
187 connect(current
, SIGNAL(scrollOrientationChanged(Qt::Orientation
,Qt::Orientation
)), this, SLOT(slotScrollOrientationChanged(Qt::Orientation
,Qt::Orientation
)));
188 connect(current
, SIGNAL(scrollOffsetChanged(qreal
,qreal
)), this, SLOT(updateScrollOffsetScrollBar()));
189 connect(current
, SIGNAL(maximumScrollOffsetChanged(qreal
,qreal
)), this, SLOT(updateScrollOffsetScrollBar()));
190 connect(current
, SIGNAL(itemOffsetChanged(qreal
,qreal
)), this, SLOT(updateItemOffsetScrollBar()));
191 connect(current
, SIGNAL(maximumItemOffsetChanged(qreal
,qreal
)), this, SLOT(updateItemOffsetScrollBar()));
192 connect(current
, SIGNAL(scrollTo(qreal
)), this, SLOT(scrollTo(qreal
)));
193 m_horizontalSmoothScroller
->setTargetObject(current
);
194 m_verticalSmoothScroller
->setTargetObject(current
);
195 updateSmoothScrollers(current
->scrollOrientation());
199 void KItemListContainer::scrollTo(qreal offset
)
201 const KItemListView
* view
= m_controller
->view();
203 if (view
->scrollOrientation() == Qt::Vertical
) {
204 m_verticalSmoothScroller
->scrollTo(offset
);
206 m_horizontalSmoothScroller
->scrollTo(offset
);
211 void KItemListContainer::updateScrollOffsetScrollBar()
213 const KItemListView
* view
= m_controller
->view();
218 KItemListSmoothScroller
* smoothScroller
= 0;
219 QScrollBar
* scrollOffsetScrollBar
= 0;
222 if (view
->scrollOrientation() == Qt::Vertical
) {
223 smoothScroller
= m_verticalSmoothScroller
;
224 scrollOffsetScrollBar
= verticalScrollBar();
225 singleStep
= view
->itemSize().height();
226 pageStep
= view
->size().height();
228 smoothScroller
= m_horizontalSmoothScroller
;
229 scrollOffsetScrollBar
= horizontalScrollBar();
230 singleStep
= view
->itemSize().width();
231 pageStep
= view
->size().width();
234 const int value
= view
->scrollOffset();
235 const int maximum
= qMax(0, int(view
->maximumScrollOffset() - pageStep
));
236 if (smoothScroller
->requestScrollBarUpdate(maximum
)) {
237 scrollOffsetScrollBar
->setSingleStep(singleStep
);
238 scrollOffsetScrollBar
->setPageStep(pageStep
);
239 scrollOffsetScrollBar
->setMinimum(0);
240 scrollOffsetScrollBar
->setMaximum(maximum
);
241 scrollOffsetScrollBar
->setValue(value
);
245 void KItemListContainer::updateItemOffsetScrollBar()
247 const KItemListView
* view
= m_controller
->view();
252 KItemListSmoothScroller
* smoothScroller
= 0;
253 QScrollBar
* itemOffsetScrollBar
= 0;
256 if (view
->scrollOrientation() == Qt::Vertical
) {
257 smoothScroller
= m_horizontalSmoothScroller
;
258 itemOffsetScrollBar
= horizontalScrollBar();
259 singleStep
= view
->size().width() / 10;
260 pageStep
= view
->size().width();
262 smoothScroller
= m_verticalSmoothScroller
;
263 itemOffsetScrollBar
= verticalScrollBar();
264 singleStep
= view
->size().height() / 10;
265 pageStep
= view
->size().height();
268 const int value
= view
->itemOffset();
269 const int maximum
= qMax(0, int(view
->maximumItemOffset()) - pageStep
);
270 if (smoothScroller
->requestScrollBarUpdate(maximum
)) {
271 itemOffsetScrollBar
->setSingleStep(singleStep
);
272 itemOffsetScrollBar
->setPageStep(pageStep
);
273 itemOffsetScrollBar
->setMinimum(0);
274 itemOffsetScrollBar
->setMaximum(maximum
);
275 itemOffsetScrollBar
->setValue(value
);
279 void KItemListContainer::updateGeometries()
281 QRect rect
= geometry();
283 int extra
= frameWidth() * 2;
285 option
.initFrom(this);
286 if (style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents
, &option
, this)) {
287 extra
+= style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing
, &option
, this);
290 const int widthDec
= verticalScrollBar()->isVisible()
291 ? extra
+ style()->pixelMetric(QStyle::PM_ScrollBarExtent
, &option
, this)
294 const int heightDec
= horizontalScrollBar()->isVisible()
295 ? extra
+ style()->pixelMetric(QStyle::PM_ScrollBarExtent
, &option
, this)
298 rect
.adjust(0, 0, -widthDec
, -heightDec
);
300 const QRectF
newGeometry(0, 0, rect
.width(), rect
.height());
301 if (m_controller
->view()->geometry() != newGeometry
) {
302 m_controller
->view()->setGeometry(newGeometry
);
304 static_cast<KItemListContainerViewport
*>(viewport())->scene()->setSceneRect(0, 0, rect
.width(), rect
.height());
305 static_cast<KItemListContainerViewport
*>(viewport())->viewport()->setGeometry(QRect(0, 0, rect
.width(), rect
.height()));
307 updateScrollOffsetScrollBar();
308 updateItemOffsetScrollBar();
312 void KItemListContainer::updateSmoothScrollers(Qt::Orientation orientation
)
314 if (orientation
== Qt::Vertical
) {
315 m_verticalSmoothScroller
->setPropertyName("scrollOffset");
316 m_horizontalSmoothScroller
->setPropertyName("itemOffset");
318 m_horizontalSmoothScroller
->setPropertyName("scrollOffset");
319 m_verticalSmoothScroller
->setPropertyName("itemOffset");
323 void KItemListContainer::initialize()
326 if (m_controller
->model()) {
327 slotModelChanged(m_controller
->model(), 0);
329 if (m_controller
->view()) {
330 slotViewChanged(m_controller
->view(), 0);
333 m_controller
= new KItemListController(this);
336 connect(m_controller
, SIGNAL(modelChanged(KItemModelBase
*,KItemModelBase
*)),
337 this, SLOT(slotModelChanged(KItemModelBase
*,KItemModelBase
*)));
338 connect(m_controller
, SIGNAL(viewChanged(KItemListView
*,KItemListView
*)),
339 this, SLOT(slotViewChanged(KItemListView
*,KItemListView
*)));
341 QGraphicsView
* graphicsView
= new KItemListContainerViewport(new QGraphicsScene(this), this);
342 setViewport(graphicsView
);
344 m_horizontalSmoothScroller
= new KItemListSmoothScroller(horizontalScrollBar(), this);
345 m_verticalSmoothScroller
= new KItemListSmoothScroller(verticalScrollBar(), this);
348 #include "kitemlistcontainer.moc"