add more spacing
[personal-kdebase.git] / workspace / krunner / interfaces / default / resultscene.cpp
blob3bb1538725d2b89467621ce3e611f83e5f6b09c9
1 /***************************************************************************
2 * Copyright 2007 by Enrico Ros <enrico.ros@gmail.com> *
3 * Copyright 2007 by Riccardo Iaconelli <ruphy@kde.org> *
4 * Copyright 2008 by Aaron Seigo <aseigo@kde.org> *
5 * Copyright 2008 by Davide Bettio <davide.bettio@kdemail.net> *
6 * *
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. *
11 * *
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. *
16 * *
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 ***************************************************************************/
24 #include "resultscene.h"
25 #include <QtCore/QDebug>
26 #include <QtGui/QKeyEvent>
27 #include <QtCore/QMutexLocker>
28 #include <QtGui/QPainter>
29 #include <QtCore/QTimeLine>
30 #include <QtGui/QGraphicsSceneWheelEvent>
31 #include <QtGui/QGraphicsGridLayout>
32 #include <QtGui/QGraphicsWidget>
33 #include <QtGui/QGraphicsProxyWidget>
35 #include <KDE/KDebug>
36 #include <KDE/KLineEdit>
38 #include <Plasma/AbstractRunner>
39 #include <Plasma/FrameSvg>
40 #include <Plasma/RunnerManager>
42 #include "resultitem.h"
44 ResultScene::ResultScene(Plasma::RunnerManager *manager, QObject *parent)
45 : QGraphicsScene(parent),
46 m_runnerManager(manager),
47 m_cIndex(0),
48 m_rowStride(0),
49 m_pageStride(0),
50 m_pageCount(0),
51 m_currentPage(0)
53 setItemIndexMethod(NoIndex);
55 connect(m_runnerManager, SIGNAL(matchesChanged(const QList<Plasma::QueryMatch>&)),
56 this, SLOT(setQueryMatches(const QList<Plasma::QueryMatch>&)));
58 m_resizeTimer.setSingleShot(true);
59 connect(&m_resizeTimer, SIGNAL(timeout()), this, SLOT(layoutIcons()));
61 m_clearTimer.setSingleShot(true);
62 connect(&m_clearTimer, SIGNAL(timeout()), this, SLOT(clearMatches()));
64 m_frame = new Plasma::FrameSvg(this);
67 // lock because setImagePath uses KSycoca
68 QMutexLocker lock(Plasma::AbstractRunner::bigLock());
69 m_frame->setImagePath("widgets/viewitem");
72 m_frame->setCacheAllRenderedFrames(true);
73 m_frame->setElementPrefix("normal");
74 //QColor bg(255, 255, 255, 126);
75 //setBackgroundBrush(bg);
78 ResultScene::~ResultScene()
82 QSize ResultScene::minimumSizeHint() const
84 QFontMetrics fm(font());
85 return QSize(ResultItem::BOUNDING_WIDTH * 4 + 6, (ResultItem::BOUNDING_HEIGHT + fm.height()) * 2 + 6);
88 void ResultScene::resize(int width, int height)
90 // optimize
91 if (m_size.width() == width && m_size.height() == height) {
92 return;
95 m_size = QSize(width, height);
96 m_rowStride = width / (ResultItem::BOUNDING_WIDTH);
97 m_pageStride = height / (ResultItem::BOUNDING_WIDTH) * m_rowStride;
98 setSceneRect(0.0, 0.0, (qreal)width, (qreal)height);
99 m_resizeTimer.start(150);
102 void ResultScene::layoutIcons()
104 QListIterator<ResultItem *> it(m_items);
106 while (it.hasNext()) {
107 ResultItem *item = it.next();
108 item->setRowStride(m_rowStride);
112 void ResultScene::clearMatches()
114 foreach (ResultItem *item, m_items) {
115 item->remove();
118 m_itemsById.clear();
119 m_items.clear();
120 m_pageCount = 0;
121 setPage(0);
122 emit matchCountChanged(0);
125 void ResultScene::setQueryMatches(const QList<Plasma::QueryMatch> &m)
127 // kDebug() << "============================" << endl << "matches retrieved: " << m.count();
128 if (m.isEmpty()) {
129 //kDebug() << "clearing";
130 emit itemHoverEnter(0);
131 m_clearTimer.start(200);
132 return;
135 m_clearTimer.stop();
136 m_items.clear();
138 QList<Plasma::QueryMatch> matches = m;
139 QMutableListIterator<Plasma::QueryMatch> newMatchIt(matches);
141 // first pass: we try and match up items with existing ids (match persisitence)
142 while (!m_itemsById.isEmpty() && newMatchIt.hasNext()) {
143 ResultItem *item = addQueryMatch(newMatchIt.next(), false);
145 if (item) {
146 m_items.append(item);
147 newMatchIt.remove();
151 // second pass: now we just use any item that exists (item re-use)
152 newMatchIt.toFront();
153 while (newMatchIt.hasNext()) {
154 m_items.append(addQueryMatch(newMatchIt.next(), true));
157 // delete the stragglers
158 QMapIterator<QString, ResultItem *> it(m_itemsById);
159 while (it.hasNext()) {
160 it.next().value()->remove();
163 // organize the remainders
164 int i = 0;
165 m_itemsById.clear();
167 // this will leave them in *reverse* order
168 qSort(m_items.begin(), m_items.end(), ResultItem::compare);
170 m_pageCount = m.count();
171 m_pageCount = m_pageCount / m_pageStride + (m_pageCount % m_pageStride != 0 ? 1 : 0);
172 setPage(0);
173 //kDebug() << "gots us" << m_pageCount << "m_pageCount of items";
175 emit matchCountChanged(m.count());
177 QListIterator<ResultItem*> matchIt(m_items);
178 QGraphicsWidget *tab = 0;
179 while (matchIt.hasNext()) {
180 ResultItem *item = matchIt.next();
181 //kDebug() << item->name() << item->id() << item->priority() << i;
182 QGraphicsWidget::setTabOrder(tab, item);
183 m_itemsById.insert(item->id(), item);
184 item->setIndex(i);
186 // it is vital that focus is set *after* the index
187 if (i == 0) {
188 setFocusItem(item);
191 ++i;
192 tab = item;
195 emit itemHoverEnter(m_items.at(0));
198 ResultItem* ResultScene::addQueryMatch(const Plasma::QueryMatch &match, bool useAnyId)
200 QMap<QString, ResultItem*>::iterator it = useAnyId ? m_itemsById.begin() : m_itemsById.find(match.id());
201 ResultItem *item = 0;
202 //kDebug() << "attempting" << match.id();
204 if (it == m_itemsById.end()) {
205 //kDebug() << "did not find for" << match.id();
206 if (useAnyId) {
207 //kDebug() << "creating for" << match.id();
208 item = new ResultItem(match, 0, m_frame);
209 addItem(item);
210 item->hide();
211 int rowStride = sceneRect().width() / (ResultItem::BOUNDING_WIDTH);
212 item->setRowStride(rowStride);
213 connect(item, SIGNAL(activated(ResultItem*)), this, SIGNAL(itemActivated(ResultItem*)));
214 connect(item, SIGNAL(hoverEnter(ResultItem*)), this, SIGNAL(itemHoverEnter(ResultItem*)));
215 connect(item, SIGNAL(hoverLeave(ResultItem*)), this, SIGNAL(itemHoverLeave(ResultItem*)));
216 } else {
217 //kDebug() << "returning failure for" << match.id();
218 return 0;
220 } else {
221 item = it.value();
222 //kDebug() << "reusing" << item->name() << "for" << match.id();
223 item->setMatch(match);
224 m_itemsById.erase(it);
227 return item;
230 void ResultScene::focusOutEvent(QFocusEvent *focusEvent)
232 QGraphicsScene::focusOutEvent(focusEvent);
233 if (!m_items.isEmpty()) {
234 emit itemHoverEnter(m_items.at(0));
238 void ResultScene::keyPressEvent(QKeyEvent * keyEvent)
240 //kDebug() << "m_items (size): " << m_items.size() << "\n";
241 ResultItem *currentFocus = dynamic_cast<ResultItem*>(focusItem());
242 int m_cIndex = currentFocus ? currentFocus->index() : 0;
243 switch (keyEvent->key()) {
244 case Qt::Key_Up:{
245 if (m_cIndex < m_rowStride) {
246 if (m_items.size() < m_rowStride) {
247 // we have less than one row of items, so lets just move to the next item
248 m_cIndex = (m_cIndex + 1) % m_items.size();
249 } else {
250 m_cIndex = m_items.size() - (m_items.size() % m_rowStride) - 1 + (m_cIndex % m_items.size());
251 if (m_cIndex >= m_items.size()) {
252 // we should be on the bottom row, but there is nothing there; move up one row
253 m_cIndex -= m_rowStride % m_items.size();
256 } else {
257 m_cIndex = m_cIndex - m_rowStride;
259 break;
262 case Qt::Key_Down:{
263 if (m_cIndex + m_rowStride >= m_items.size()) {
264 // warp to the top
265 m_cIndex = (m_cIndex + 1) % m_rowStride % m_items.size();
266 } else {
267 // next row!
268 m_cIndex += m_rowStride;
271 break;
274 case Qt::Key_Left:
275 m_cIndex = (m_cIndex == 0) ? m_items.size() - 1 : m_cIndex - 1;
276 break;
278 case Qt::Key_Right:
279 m_cIndex = (m_cIndex + 1) % m_items.size();
280 break;
282 case Qt::Key_Return:
283 //TODO: run the item
284 case Qt::Key_Space:
285 default:
286 // pass the event to the item
287 QGraphicsScene::keyPressEvent(keyEvent);
288 return;
289 break;
292 if (m_items[m_cIndex]->pos().y() + m_items[m_cIndex]->size().height() > sceneRect().y() + sceneRect().height()){
293 setPage(m_currentPage + 1);
294 }else if (m_items[m_cIndex]->pos().y() < sceneRect().y()){
295 setPage(m_currentPage - 1);
298 // If we arrive here, it was due to an arrow button.
299 Q_ASSERT(m_cIndex >= 0);
300 Q_ASSERT(m_cIndex < m_items.count());
301 //kDebug() << "m_cIndex: " << m_cIndex << "\n";
302 setFocusItem(m_items.at(m_cIndex));
305 void ResultScene::wheelEvent(QGraphicsSceneWheelEvent *event)
307 if (event->delta() > 0) {
308 setPage(m_currentPage - 1);
309 }else{
310 setPage(m_currentPage + 1);
314 void ResultScene::slotArrowResultItemPressed()
319 void ResultScene::slotArrowResultItemReleased()
324 void ResultScene::launchQuery(const QString &term)
326 m_runnerManager->launchQuery(term);
329 void ResultScene::launchQuery(const QString &term, const QString &runner)
331 m_runnerManager->launchQuery(term, runner);
334 void ResultScene::clearQuery()
336 m_runnerManager->reset();
339 ResultItem* ResultScene::defaultResultItem() const
341 if (m_items.isEmpty()) {
342 kDebug() << "empty";
343 return 0;
346 kDebug() << (QObject*) m_items[0] << m_items.count();
347 return m_items[0];
350 void ResultScene::run(ResultItem *item) const
352 if (!item) {
353 return;
356 item->run(m_runnerManager);
359 Plasma::RunnerManager* ResultScene::manager() const
361 return m_runnerManager;
364 uint ResultScene::pageCount() const
366 return m_pageCount;
369 void ResultScene::nextPage()
371 setPage(m_currentPage + 1);
374 void ResultScene::previousPage()
376 setPage(m_currentPage - 1);
379 void ResultScene::setPage(uint index)
381 if (index > m_pageCount || index == m_currentPage) {
382 return;
385 m_currentPage = index;
386 setSceneRect(0.0, ((m_currentPage * (m_pageStride / m_rowStride))) * ResultItem::BOUNDING_HEIGHT,
387 width(), height());
389 #include "resultscene.moc"