1
/* ============================================================
3
* This file is a part of digiKam project
4
* http://www.digikam.org
7
* Description : icons view.
9
* Copyright (C) 2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
10
* Copyright (C) 2006-2011 by Gilles Caulier <caulier dot gilles at gmail dot com>
12
* This program is free software; you can redistribute it
13
* and/or modify it under the terms of the GNU General
14
* Public License as published by the Free Software Foundation;
15
* either version 2, or (at your option)
18
* This program is distributed in the hope that it will be useful,
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
* GNU General Public License for more details.
23
* ============================================================ */
25
#define RECT_EXTENSION 300
27
#include "iconview.moc"
42
#include <QApplication>
43
#include <QPaintEvent>
45
#include <QMouseEvent>
46
#include <QStyleOption>
47
#include <QRubberBand>
53
#include <kiconloader.h>
54
#include <kglobalsettings.h>
58
#include "ratingwidget.h"
59
#include "drubberband.h"
62
#include "icongroupitem.h"
63
#include "albumsettings.h"
68
class IconView::IconViewPriv
95
rearrangeTimerInterval = 0;
96
storedVisibleItem = 0;
97
needEmitSelectionChanged = false;
99
thumbnailBorderCache.setMaxCost(10);
101
selectPix = SmallIcon("list-add");
102
deselectPix = SmallIcon("list-remove");
109
bool needEmitSelectionChanged; // store for slotRearrange
111
int rearrangeTimerInterval;
114
QSet<IconItem*> selectedItems;
115
QSet<IconItem*> prevSelectedItems;
120
QCache<QString, QPixmap> thumbnailBorderCache;
126
QTimer* rearrangeTimer;
127
QTimer* toolTipTimer;
129
IconItem* toolTipItem;
131
IconItem* anchorItem;
132
IconItem* storedVisibleItem; // store position for slotRearrange
133
IconItem* highlightedItem;
134
IconItem* ratingItem;
136
IconGroupItem* firstGroup;
137
IconGroupItem* lastGroup;
139
RatingWidget* ratingWidget;
143
ItemContainer(ItemContainer* p, ItemContainer* n, const QRect& r)
144
: prev(p), next(n), rect(r)
157
ItemContainer* prev, *next;
159
QList<IconItem*> items;
160
} *firstContainer, *lastContainer;
164
IconGroupItem* group;
168
// -----------------------------------------------------------------------
170
IconView::IconView(QWidget* parent, const char* name)
171
: Q3ScrollView(parent), d(new IconViewPriv)
174
setWindowFlags(Qt::WStaticContents | Qt::WNoAutoErase);
176
viewport()->setFocusProxy(this);
177
viewport()->setFocusPolicy(Qt::WheelFocus);
178
viewport()->setMouseTracking(true);
180
d->rearrangeTimer = new QTimer(this);
181
d->toolTipTimer = new QTimer(this);
182
d->rubber = new DRubberBand(this);
183
d->ratingWidget = new RatingWidget(viewport());
184
d->ratingWidget->setTracking(false);
185
d->ratingWidget->hide();
187
connect(d->rearrangeTimer, SIGNAL(timeout()),
188
this, SLOT(slotRearrange()));
190
connect(d->toolTipTimer, SIGNAL(timeout()),
191
this, SLOT(slotToolTip()));
193
connect(AlbumSettings::instance(), SIGNAL(setupChanged()),
194
this, SLOT(slotIconViewFontChanged()));
196
connect(d->ratingWidget, SIGNAL(signalRatingChanged(int)),
197
this, SLOT(slotEditRatingFromItem(int)));
199
slotIconViewFontChanged();
200
setEnableToolTips(true);
203
IconView::~IconView()
207
delete d->rearrangeTimer;
208
delete d->toolTipTimer;
213
IconGroupItem* IconView::firstGroup() const
215
return d->firstGroup;
218
IconGroupItem* IconView::lastGroup() const
223
IconItem* IconView::firstItem() const
230
return d->firstGroup->firstItem();
233
IconItem* IconView::lastItem() const
240
return d->lastGroup->lastItem();
243
IconItem* IconView::currentItem() const
248
void IconView::setCurrentItem(IconItem* item)
251
d->anchorItem = d->currItem;
255
d->currItem->setSelected(true, true);
256
ensureItemVisible(d->currItem);
260
IconItem* IconView::ratingItem() const
262
return d->ratingItem;
265
IconItem* IconView::findItem(const QPoint& pos)
267
IconViewPriv::ItemContainer* c = d->firstContainer;
269
for (; c; c = c->next)
271
if (c->rect.contains(pos))
273
foreach(IconItem* item, c->items)
275
if (item->rect().contains(pos))
286
IconGroupItem* IconView::findGroup(const QPoint& pos)
288
QPoint p = viewportToContents(viewport()->mapFromGlobal(pos));
290
for (IconGroupItem* group = d->firstGroup; group; group = group->nextGroup())
292
QRect rect = group->rect();
295
if (group == d->lastGroup)
297
bottom = contentsHeight();
301
bottom = group->nextGroup()->rect().top();
304
rect.setBottom(bottom);
306
if (rect.contains(p))
315
int IconView::count() const
319
for (IconGroupItem* group = d->firstGroup; group; group = group->nextGroup())
328
int IconView::countSelected() const
332
for (IconGroupItem* group = d->firstGroup; group; group = group->nextGroup())
334
for (IconItem* it = group->firstItem(); it; it = it->nextItem())
335
if (it->isSelected())
344
int IconView::groupCount() const
348
for (IconGroupItem* group = d->firstGroup; group; group = group->nextGroup())
356
void IconView::clear(bool update)
359
d->highlightedItem = 0;
361
d->toolTipTimer->stop();
366
d->ratingItem->setEditRating(false);
369
d->ratingWidget->hide();
374
d->selectedItems.clear();
376
IconGroupItem* group = d->firstGroup;
380
IconGroupItem* tmp = group->m_next;
390
viewport()->setUpdatesEnabled(false);
391
resizeContents(0, 0);
392
setContentsPos(0, 0);
393
viewport()->setUpdatesEnabled(true);
402
emit signalSelectionChanged();
405
void IconView::clearSelection()
407
bool wasBlocked = signalsBlocked();
414
QSet<IconItem*> selItems = d->selectedItems;
415
foreach(IconItem* item, selItems)
417
item->setSelected(false, false);
420
d->selectedItems.clear();
427
emit signalSelectionChanged();
430
void IconView::selectAll()
432
bool wasBlocked = signalsBlocked();
439
for (IconItem* item = firstItem(); item; item = item->nextItem())
441
if (!item->isSelected())
443
item->setSelected(true, false);
452
emit signalSelectionChanged();
455
void IconView::invertSelection()
457
bool wasBlocked = signalsBlocked();
464
for (IconItem* item = firstItem(); item; item = item->nextItem())
466
if (!item->isSelected())
468
item->setSelected(true, false);
472
item->setSelected(false, false);
481
emit signalSelectionChanged();
484
void IconView::selectItem(IconItem* item, bool select)
493
d->selectedItems.insert(item);
497
d->selectedItems.remove(item);
500
emit signalSelectionChanged();
503
void IconView::setStoredVisibleItem(IconItem* item)
505
d->storedVisibleItem = item;
508
void IconView::insertGroup(IconGroupItem* group)
517
d->firstGroup = group;
518
d->lastGroup = group;
524
d->lastGroup->m_next = group;
525
group->m_prev = d->lastGroup;
527
d->lastGroup = group;
530
d->storedVisibleItem = findFirstVisibleItem();
531
startRearrangeTimer();
534
void IconView::takeGroup(IconGroupItem* group)
541
// this is only to find an alternative visible item if all visible items
543
IconGroupItem* alternativeVisibleGroup = 0;
544
d->storedVisibleItem = 0;
546
if (group == d->firstGroup)
548
d->firstGroup = d->firstGroup->m_next;
552
d->firstGroup->m_prev = 0;
556
d->firstGroup = d->lastGroup = 0;
559
alternativeVisibleGroup = d->firstGroup;
561
else if (group == d->lastGroup)
563
d->lastGroup = d->lastGroup->m_prev;
567
d->lastGroup->m_next = 0;
571
d->firstGroup = d->lastGroup = 0;
574
alternativeVisibleGroup = d->lastGroup->m_prev;
578
IconGroupItem* i = group;
584
i->m_prev->m_next = i->m_next;
589
i->m_next->m_prev = i->m_prev;
594
alternativeVisibleGroup = i->m_prev;
598
alternativeVisibleGroup = i->m_next;
605
d->storedVisibleItem = findFirstVisibleItem();
607
if (!d->storedVisibleItem && alternativeVisibleGroup)
609
// find an alternative visible item
610
d->storedVisibleItem = alternativeVisibleGroup->lastItem();
613
startRearrangeTimer();
617
void IconView::insertItem(IconItem* item)
624
d->storedVisibleItem = findFirstVisibleItem();
625
startRearrangeTimer();
628
void IconView::takeItem(IconItem* item)
635
// First remove item from any containers holding it
636
IconViewPriv::ItemContainer* tmp = d->firstContainer;
640
tmp->items.removeAll(item);
644
// Remove from selected item list
645
d->selectedItems.remove(item);
648
if (d->selectedItems.count() || item->isSelected())
650
d->needEmitSelectionChanged = true;
653
if (d->toolTipItem == item)
656
d->toolTipTimer->stop();
660
if (d->highlightedItem == item)
662
d->highlightedItem = 0;
665
if (d->ratingItem == item)
667
d->ratingItem->setEditRating(false);
670
d->ratingWidget->hide();
673
// if it is current item, change the current item
674
if (d->currItem == item)
676
d->currItem = item->nextItem();
680
d->currItem = item->prevItem();
681
// defer calling d->currItem->setSelected (and emitting the signals) to slotRearrange
685
d->anchorItem = d->currItem;
689
d->storedVisibleItem = findFirstVisibleItem();
691
if (d->storedVisibleItem == item)
693
d->storedVisibleItem = d->currItem;
696
startRearrangeTimer();
700
void IconView::triggerRearrangement()
702
d->storedVisibleItem = findFirstVisibleItem();
703
startRearrangeTimer();
706
void IconView::setDelayedRearrangement(bool delayed)
708
// if it is known that e.g. several items will be added or deleted in the next time,
709
// but not from the same event queue thread stack location, it may be desirable to delay
710
// the rearrangeTimer a bit
713
d->rearrangeTimerInterval = 50;
717
d->rearrangeTimerInterval = 0;
721
void IconView::startRearrangeTimer()
723
// We want to reduce the number of updates, but not remove all updates
724
if (!d->rearrangeTimer->isActive())
726
d->rearrangeTimer->setSingleShot(true);
727
d->rearrangeTimer->start(d->rearrangeTimerInterval);
731
void IconView::sort()
733
// first sort the groups
734
for (IconGroupItem* group = d->firstGroup; group;
735
group = group->nextGroup())
740
int gcount = groupCount();
742
// then sort the groups themselves
743
QScopedArrayPointer<IconViewPriv::SortableItem> groups(new IconViewPriv::SortableItem[ gcount ]);
745
IconGroupItem* group = d->firstGroup;
748
for (; group; group = group->m_next)
750
groups[i++].group = group;
753
qsort(groups.data(), gcount, sizeof(IconViewPriv::SortableItem), cmpItems);
755
IconGroupItem* prev = 0;
758
for (i = 0; i < (int) gcount; ++i)
760
group = groups[i].group;
764
group->m_prev = prev;
768
group->m_prev->m_next = group;
776
d->firstGroup = group;
779
if (i == (int) gcount - 1)
781
d->lastGroup = group;
788
void IconView::slotRearrange()
790
if (d->highlightedItem)
792
d->highlightedItem->setHighlighted(false);
793
d->highlightedItem = 0;
798
d->ratingItem->setEditRating(false);
801
d->ratingWidget->hide();
806
d->toolTipTimer->stop();
812
// ensure there is a current item
815
// set the currItem to first item
818
d->currItem = d->firstGroup->firstItem();
822
d->anchorItem = d->currItem;
824
// ensure there is a selection
825
if (d->selectedItems.isEmpty() && d->currItem)
827
d->currItem->setSelected(true, true);
829
else if (d->needEmitSelectionChanged)
831
emit signalSelectionChanged();
834
d->needEmitSelectionChanged = false;
836
// set first visible item if they where stored before update was triggered
837
if (d->storedVisibleItem)
839
ensureItemVisible(d->storedVisibleItem);
841
d->storedVisibleItem = 0;
845
ensureItemVisible(d->currItem);
848
viewport()->update();
849
emit signalItemsRearranged();
852
bool IconView::arrangeItems()
855
int itemW = itemRect().width();
856
int itemH = itemRect().height();
859
int numItemsPerRow = visibleWidth() / (itemW + d->spacing);
861
bool changed = false;
863
IconGroupItem* group = d->firstGroup;
868
changed = group->move(y) || changed;
869
y += group->rect().height() + d->spacing;
871
item = group->firstItem();
878
changed = item->move(x, y) || changed;
879
x += itemW + d->spacing;
882
if (col >= numItemsPerRow)
885
y += itemH + d->spacing;
889
maxW = qMax(maxW, x + itemW);
895
y += itemH + d->spacing;
899
group = group->m_next;
902
viewport()->setUpdatesEnabled(false);
903
resizeContents(maxW, y);
904
viewport()->setUpdatesEnabled(true);
911
QRect IconView::itemRect() const
913
return QRect(0, 0, 100, 100);
916
QRect IconView::bannerRect() const
918
return QRect(0, 0, visibleWidth(), 0);
921
void IconView::viewportPaintEvent(QPaintEvent* pe)
923
QRect contentsPaintRect(viewportToContents(pe->rect().topLeft()), viewportToContents(pe->rect().bottomRight()));
924
QRegion unpaintedRegion(pe->region());
926
QPainter painter(viewport());
928
// paint any group banners which intersect this paintevent rect
929
for (IconGroupItem* group = d->firstGroup; group; group = group->nextGroup())
931
if (contentsPaintRect.intersects(group->rect()))
933
QRect viewportRect = contentsRectToViewport(group->rect());
935
painter.translate(viewportRect.x(), viewportRect.y());
936
group->paintBanner(&painter);
937
painter.translate(- viewportRect.x(), - viewportRect.y());
939
unpaintedRegion -= QRegion(viewportRect);
943
// now paint any items which intersect
944
QList<IconItem*> itemsToRepaint;
946
for (IconViewPriv::ItemContainer* c = d->firstContainer; c;
949
if (contentsPaintRect.intersects(c->rect))
951
foreach(IconItem* item, c->items)
953
if (contentsPaintRect.intersects(item->rect()))
955
itemsToRepaint << item;
961
foreach(IconItem* item, itemsToRepaint)
963
QRect viewportRect = contentsRectToViewport(item->rect());
965
painter.translate(viewportRect.x(), viewportRect.y());
966
item->paintItem(&painter);
967
painter.translate(- viewportRect.x(), - viewportRect.y());
969
unpaintedRegion -= QRegion(viewportRect);
972
painter.setClipRegion(unpaintedRegion);
973
painter.fillRect(pe->rect(), palette().color(QPalette::Base));
976
QRect IconView::contentsRectToViewport(const QRect& r) const
978
QRect vr = QRect(contentsToViewport(QPoint(r.x(), r.y())), r.size());
982
void IconView::resizeEvent(QResizeEvent* e)
984
Q3ScrollView::resizeEvent(e);
985
triggerRearrangement();
988
void IconView::rebuildContainers()
997
item = d->firstGroup->firstItem();
1000
IconViewPriv::ItemContainer* c = d->lastContainer;
1004
if (c->rect.contains(item->rect()))
1007
item = item->nextItem();
1009
else if (c->rect.intersects(item->rect()))
1017
c = d->lastContainer;
1021
item = item->nextItem();
1026
if (item->y() < c->rect.y() && c->prev)
1037
c = d->lastContainer;
1043
void IconView::appendContainer()
1045
QSize s(INT_MAX - 1, RECT_EXTENSION);
1047
if (!d->firstContainer)
1049
d->firstContainer = new IconViewPriv::ItemContainer(0, 0, QRect(QPoint(0, 0), s));
1050
d->lastContainer = d->firstContainer;
1054
d->lastContainer = new IconViewPriv::ItemContainer(
1055
d->lastContainer, 0, QRect(d->lastContainer->rect.bottomLeft(), s));
1059
void IconView::deleteContainers()
1061
IconViewPriv::ItemContainer* c = d->firstContainer;
1062
IconViewPriv::ItemContainer* tmp;
1071
d->firstContainer = d->lastContainer = 0;
1074
void IconView::leaveEvent(QEvent* e)
1077
// if the mouse leaves the widget we are not dragging
1079
d->dragging = false;
1081
Q3ScrollView::leaveEvent(e);
1084
void IconView::focusOutEvent(QFocusEvent* e)
1086
if (d->highlightedItem)
1088
d->highlightedItem->setHighlighted(false);
1089
d->highlightedItem = 0;
1094
d->ratingItem->setEditRating(false);
1097
d->ratingWidget->hide();
1102
d->toolTipTimer->stop();
1105
Q3ScrollView::focusOutEvent(e);
1108
bool IconView::acceptToolTip(IconItem*, const QPoint&)
1113
void IconView::contentsMousePressEvent(QMouseEvent* e)
1115
d->pressedMoved = false;
1119
d->toolTipTimer->stop();
1122
// Clear any existing rubber -------------------------------
1123
d->rubber->setActive(false);
1125
if (e->button() == Qt::RightButton)
1127
IconItem* item = findItem(e->pos());
1131
IconItem* prevCurrItem = d->currItem;
1133
d->anchorItem = item;
1137
prevCurrItem->repaint();
1140
if (!item->isSelected())
1142
item->setSelected(true, true);
1147
emit signalRightButtonClicked(item, e->globalPos());
1152
emit signalRightButtonClicked(e->globalPos());
1158
IconItem* item = findItem(e->pos());
1162
if (e->modifiers() == Qt::ControlModifier)
1164
item->setSelected(!item->isSelected(), false);
1166
else if (e->modifiers() == Qt::ShiftModifier
1167
|| e->modifiers() == (Qt::ShiftModifier | Qt::ControlModifier))
1173
if (!(e->modifiers() & Qt::ControlModifier))
1178
// select all items from/upto the current item
1179
bool bwdSelect = false;
1181
// find if the current item is before the clicked item
1182
for (IconItem* it = item->prevItem(); it; it = it->prevItem())
1184
if (it == d->currItem)
1193
for (IconItem* it = item; it; it = it->prevItem())
1195
it->setSelected(true, false);
1197
if (it == d->currItem)
1205
for (IconItem* it = item; it; it = it->nextItem())
1207
it->setSelected(true, false);
1209
if (it == d->currItem)
1218
item->setSelected(true, false);
1221
blockSignals(false);
1223
emit signalSelectionChanged();
1225
else if (e->modifiers() == Qt::NoModifier)
1227
if (item->clickToToggleSelectRect().contains(e->pos()))
1229
item->setSelected(!item->isSelected(), false);
1231
else if (!item->isSelected())
1233
item->setSelected(true, true);
1237
IconItem* prevCurrItem = d->currItem;
1239
d->anchorItem = item;
1243
prevCurrItem->repaint();
1246
d->currItem->repaint();
1249
d->dragStartPos = e->pos();
1254
// Press outside any item.
1255
if (!(e->modifiers() & Qt::ControlModifier))
1257
// unselect all if the ctrl button is not pressed
1262
// ctrl is pressed. make sure our current selection is not lost
1263
d->prevSelectedItems = d->selectedItems;
1266
d->rubber->setFirstPointOnViewport(e->pos());
1269
void IconView::contentsMouseMoveEvent(QMouseEvent* e)
1271
if (e->buttons() == Qt::NoButton)
1273
IconItem* item = findItem(e->pos());
1277
if (!isActiveWindow())
1280
d->toolTipTimer->stop();
1285
if (item != d->toolTipItem)
1288
d->toolTipTimer->stop();
1291
if (acceptToolTip(item, e->pos()))
1293
d->toolTipItem = item;
1294
d->toolTipTimer->setSingleShot(true);
1295
d->toolTipTimer->start(500);
1299
if (item == d->toolTipItem && !acceptToolTip(item, e->pos()))
1302
d->toolTipTimer->stop();
1307
if (item && KGlobalSettings::changeCursorOverIcon() && item->clickToOpenRect().contains(e->pos()))
1309
setCursor(Qt::PointingHandCursor);
1310
d->ratingWidget->hide();
1314
d->ratingItem->setEditRating(false);
1319
else if (item && item->clickToRateRect().contains(e->pos()))
1321
setCursor(Qt::CrossCursor);
1322
d->ratingItem = item;
1326
d->ratingItem->setEditRating(true);
1329
QRect rect = item->clickToRateRect();
1330
rect.moveTopLeft(contentsToViewport(rect.topLeft()));
1331
d->ratingWidget->setFixedSize(rect.width() + 1, rect.height() + 1);
1332
d->ratingWidget->move(rect.topLeft().x(), rect.topLeft().y());
1333
d->ratingWidget->setRating(item->rating());
1334
d->ratingWidget->show();
1339
d->ratingWidget->hide();
1343
d->ratingItem->setEditRating(false);
1349
// Draw item highlightment when mouse is over.
1351
if (item != d->highlightedItem)
1353
if (d->highlightedItem)
1355
d->highlightedItem->setHighlighted(false);
1358
d->highlightedItem = item;
1360
if (d->highlightedItem)
1362
d->highlightedItem->setHighlighted(true);
1370
d->toolTipTimer->stop();
1373
if (d->dragging && (e->buttons() & Qt::LeftButton))
1375
if ((d->dragStartPos - e->pos()).manhattanLength()
1376
> QApplication::startDragDistance())
1384
if (!d->rubber->isActive())
1389
QRect oldArea = d->rubber->rubberBandAreaOnContents();
1391
d->rubber->setSecondPointOnViewport(e->pos());
1393
QRect newArea = d->rubber->rubberBandAreaOnContents();
1394
QRect rubberUnion = oldArea.unite(newArea);
1395
bool changed = false;
1397
QRegion paintRegion;
1398
viewport()->setUpdatesEnabled(false);
1401
IconViewPriv::ItemContainer* c = d->firstContainer;
1403
for (; c; c = c->next)
1405
if (rubberUnion.intersects(c->rect))
1407
foreach(IconItem* item, c->items)
1409
if (newArea.intersects(item->rect()))
1411
if (!item->isSelected())
1413
item->setSelected(true, false);
1415
paintRegion += QRect(item->rect());
1420
if (item->isSelected() && !d->prevSelectedItems.contains(item))
1422
item->setSelected(false, false);
1424
paintRegion += QRect(item->rect());
1431
blockSignals(false);
1432
viewport()->setUpdatesEnabled(true);
1436
paintRegion.translate(-contentsX(), -contentsY());
1437
viewport()->repaint(paintRegion);
1440
ensureVisible(e->pos().x(), e->pos().y());
1442
d->pressedMoved = true;
1446
emit signalSelectionChanged();
1450
void IconView::contentsMouseReleaseEvent(QMouseEvent* e)
1452
d->dragging = false;
1453
d->prevSelectedItems.clear();
1455
if (d->rubber->isActive())
1457
d->rubber->setActive(false);
1460
if (e->button() == Qt::LeftButton
1461
&& e->buttons() == Qt::NoButton
1462
&& e->modifiers() == Qt::NoModifier)
1464
if (d->pressedMoved)
1466
emit signalSelectionChanged();
1467
d->pressedMoved = false;
1472
IconItem* item = findItem(e->pos());
1474
if (item && !item->clickToToggleSelectRect().contains(e->pos()))
1476
IconItem* prevCurrItem = d->currItem;
1477
item->setSelected(true, true);
1479
d->anchorItem = item;
1483
prevCurrItem->repaint();
1486
if (KGlobalSettings::singleClick())
1488
if (item->clickToOpenRect().contains(e->pos()))
1490
itemClickedToOpen(item);
1497
void IconView::contentsWheelEvent(QWheelEvent* e)
1501
if (d->highlightedItem)
1503
d->highlightedItem->setHighlighted(false);
1504
d->highlightedItem = 0;
1509
d->ratingItem->setEditRating(false);
1512
d->ratingWidget->hide();
1516
d->toolTipTimer->stop();
1518
viewport()->update();
1520
if (e->modifiers() & Qt::ControlModifier)
1524
emit signalZoomOut();
1526
else if (e->delta() > 0)
1528
emit signalZoomIn();
1531
// We don't want to scroll contents.
1535
Q3ScrollView::contentsWheelEvent(e);
1538
void IconView::contentsMouseDoubleClickEvent(QMouseEvent* e)
1540
if (KGlobalSettings::singleClick())
1545
IconItem* item = findItem(e->pos());
1549
itemClickedToOpen(item);
1553
void IconView::keyPressEvent(QKeyEvent* e)
1555
bool handled = false;
1566
if (e->modifiers() & Qt::ShiftModifier)
1568
IconItem* const tmp = d->currItem;
1569
d->currItem = firstItem();
1576
// select items: anchor until before firstItem
1577
// block signals while selecting all except the firstItem
1580
for (IconItem* i = d->anchorItem; i && (i != firstItem()); i = i->prevItem())
1582
i->setSelected(true, false);
1585
blockSignals(false);
1587
// select the firstItem with signals enabled to ensure updates
1588
firstItem()->setSelected(true, false);
1592
IconItem* const tmp = d->currItem;
1593
d->currItem = firstItem();
1594
d->anchorItem = d->currItem;
1601
// select only the first item
1602
firstItem()->setSelected(true, true);
1605
ensureItemVisible(firstItem());
1612
if (e->modifiers() & Qt::ShiftModifier)
1614
IconItem* const tmp = d->currItem;
1615
d->currItem = lastItem();
1622
// select items: current until lastItem
1623
// block signals while selecting all except the lastItem
1626
for (IconItem* i = d->anchorItem; i && (i != lastItem()); i = i->nextItem())
1628
i->setSelected(true, false);
1631
blockSignals(false);
1633
// select the lastItem with signals enabled to ensure updates
1634
lastItem()->setSelected(true, false);
1638
IconItem* const tmp = d->currItem;
1639
d->currItem = lastItem();
1640
d->anchorItem = d->currItem;
1647
lastItem()->setSelected(true, true);
1650
ensureItemVisible(lastItem());
1656
case Qt::Key_Return:
1660
emit signalReturnPressed(d->currItem);
1673
if (d->currItem->nextItem())
1675
if (e->modifiers() & Qt::ControlModifier)
1677
IconItem* tmp = d->currItem;
1678
d->currItem = d->currItem->nextItem();
1679
d->anchorItem = d->currItem;
1681
d->currItem->repaint();
1685
else if (e->modifiers() & Qt::ShiftModifier)
1687
IconItem* tmp = d->currItem;
1688
d->currItem = d->currItem->nextItem();
1691
// if the anchor is behind us, move forward preserving
1692
// the previously selected item. otherwise unselect the
1693
// previously selected item
1694
if (!anchorIsBehind())
1696
tmp->setSelected(false, false);
1699
d->currItem->setSelected(true, false);
1705
IconItem* tmp = d->currItem;
1706
d->currItem = d->currItem->nextItem();
1707
d->anchorItem = d->currItem;
1708
d->currItem->setSelected(true, true);
1717
d->currItem = firstItem();
1718
d->anchorItem = d->currItem;
1719
d->currItem->setSelected(true, true);
1723
ensureItemVisible(item);
1734
if (d->currItem->prevItem())
1736
if (e->modifiers() & Qt::ControlModifier)
1738
IconItem* tmp = d->currItem;
1739
d->currItem = d->currItem->prevItem();
1740
d->anchorItem = d->currItem;
1742
d->currItem->repaint();
1746
else if (e->modifiers() & Qt::ShiftModifier)
1748
IconItem* tmp = d->currItem;
1749
d->currItem = d->currItem->prevItem();
1752
// if the anchor is ahead of us, move forward preserving
1753
// the previously selected item. otherwise unselect the
1754
// previously selected item
1755
if (anchorIsBehind())
1757
tmp->setSelected(false, false);
1760
d->currItem->setSelected(true, false);
1766
IconItem* tmp = d->currItem;
1767
d->currItem = d->currItem->prevItem();
1768
d->anchorItem = d->currItem;
1769
d->currItem->setSelected(true, true);
1778
d->currItem = firstItem();
1779
d->anchorItem = d->currItem;
1780
d->currItem->setSelected(true, true);
1784
ensureItemVisible(item);
1795
int x = d->currItem->x() + itemRect().width() / 2;
1796
int y = d->currItem->y() - d->spacing * 2;
1800
while (!it && y > 0)
1802
it = findItem(QPoint(x, y));
1803
y -= d->spacing * 2;
1808
if (e->modifiers() & Qt::ControlModifier)
1810
IconItem* tmp = d->currItem;
1814
d->currItem->repaint();
1818
else if (e->modifiers() & Qt::ShiftModifier)
1820
IconItem* tmp = d->currItem;
1826
if (anchorIsBehind())
1828
for (IconItem* i = d->currItem; i; i = i->prevItem())
1830
i->setSelected(true, false);
1832
if (i == d->anchorItem)
1840
for (IconItem* i = d->currItem; i; i = i->nextItem())
1842
i->setSelected(true, false);
1844
if (i == d->anchorItem)
1855
IconItem* tmp = d->currItem;
1858
d->currItem->setSelected(true, true);
1867
d->currItem = firstItem();
1868
d->anchorItem = d->currItem;
1869
d->currItem->setSelected(true, true);
1873
ensureItemVisible(item);
1884
int x = d->currItem->x() + itemRect().width() / 2;
1885
int y = d->currItem->y() + itemRect().height() + d->spacing * 2;
1889
while (!it && y < contentsHeight())
1891
it = findItem(QPoint(x, y));
1892
y += d->spacing * 2;
1897
if (e->modifiers() & Qt::ControlModifier)
1899
IconItem* tmp = d->currItem;
1903
d->currItem->repaint();
1907
else if (e->modifiers() & Qt::ShiftModifier)
1909
IconItem* tmp = d->currItem;
1915
if (anchorIsBehind())
1917
for (IconItem* i = d->currItem; i; i = i->prevItem())
1919
i->setSelected(true, false);
1921
if (i == d->anchorItem)
1929
for (IconItem* i = d->currItem; i; i = i->nextItem())
1931
i->setSelected(true, false);
1933
if (i == d->anchorItem)
1944
IconItem* tmp = d->currItem;
1947
d->currItem->setSelected(true, true);
1956
d->currItem = firstItem();
1957
d->anchorItem = d->currItem;
1958
d->currItem->setSelected(true, true);
1962
ensureItemVisible(item);
1967
case Qt::Key_PageDown:
1973
QRect r(0, d->currItem->y() + visibleHeight(),
1974
contentsWidth(), visibleHeight());
1975
IconItem* ni = findFirstVisibleItem(r, false);
1979
r = QRect(0, d->currItem->y() + itemRect().height(),
1980
contentsWidth(), contentsHeight());
1981
ni = findLastVisibleItem(r, false);
1986
IconItem* tmp = d->currItem;
1991
d->currItem->setSelected(true, true);
1996
d->currItem = firstItem();
1997
d->anchorItem = d->currItem;
1998
d->currItem->setSelected(true, true);
2002
ensureItemVisible(item);
2007
case Qt::Key_PageUp:
2013
QRect r(0, d->currItem->y() - visibleHeight(),
2014
contentsWidth(), visibleHeight());
2016
IconItem* ni = findFirstVisibleItem(r, false);
2020
r = QRect(0, 0, contentsWidth(), d->currItem->y());
2021
ni = findFirstVisibleItem(r, false);
2026
IconItem* tmp = d->currItem;
2031
d->currItem->setSelected(true, true);
2036
d->currItem = firstItem();
2037
d->anchorItem = d->currItem;
2038
d->currItem->setSelected(true, true);
2042
ensureItemVisible(item);
2047
// Qt::Key_Space is used as a global shortcut in DigikamApp.
2048
// Ctrl+Space comes through, Shift+Space is filtered out.
2053
if ((e->modifiers() & Qt::ControlModifier) || (e->modifiers() & Qt::ShiftModifier))
2055
d->currItem->setSelected(!d->currItem->isSelected(), false);
2059
if (!d->currItem->isSelected())
2061
d->currItem->setSelected(true, true);
2075
if (!d->currItem->isSelected())
2077
d->currItem->setSelected(true, false);
2080
ensureItemVisible(d->currItem);
2082
QRect r(itemRect());
2085
QPoint p(d->currItem->x() + w / 2, d->currItem->y() + h / 2);
2087
emit signalRightButtonClicked(d->currItem, mapToGlobal(contentsToViewport(p)));
2103
if (d->highlightedItem)
2105
d->highlightedItem->setHighlighted(false);
2106
d->highlightedItem = 0;
2111
d->ratingItem->setEditRating(false);
2114
d->ratingWidget->hide();
2117
emit signalSelectionChanged();
2118
viewport()->update();
2120
d->toolTipTimer->stop();
2125
bool IconView::anchorIsBehind() const
2127
if (!d->anchorItem || !d->currItem)
2132
for (IconItem* it = d->anchorItem; it; it = it->nextItem())
2134
if (it == d->currItem)
2144
void IconView::startDrag()
2148
void IconView::ensureItemVisible(IconItem* item)
2155
if (item->y() == firstItem()->y())
2157
QRect r(itemRect());
2159
ensureVisible(item->x() + w / 2, 0, w / 2 + 1, 0);
2163
QRect r(itemRect());
2166
ensureVisible(item->x() + w / 2, item->y() + h / 2,
2167
w / 2 + 1, h / 2 + 1);
2171
IconItem* IconView::findFirstVisibleItem(bool useThumbnailRect) const
2173
QRect r(contentsX(), contentsY(), visibleWidth(), visibleHeight());
2174
return findFirstVisibleItem(r, useThumbnailRect);
2177
IconItem* IconView::findLastVisibleItem(bool useThumbnailRect) const
2179
QRect r(contentsX(), contentsY(), visibleWidth(), visibleHeight());
2180
return findLastVisibleItem(r, useThumbnailRect);
2183
IconItem* IconView::findFirstVisibleItem(const QRect& r, bool useThumbnailRect) const
2185
IconViewPriv::ItemContainer* c = d->firstContainer;
2186
bool alreadyIntersected = false;
2189
for (; c; c = c->next)
2191
if (c->rect.intersects(r))
2193
alreadyIntersected = true;
2194
foreach(IconItem* item, c->items)
2196
// if useThumbnailRect, we only check for the clickToOpenRect, which is the thumbnail,
2197
// otherwise, we take the whole item rect
2198
if (r.intersects(useThumbnailRect ? item->clickToOpenRect() : item->rect()))
2206
QRect r2 = item->rect();
2207
QRect r3 = i->rect();
2209
if (r2.y() < r3.y())
2213
else if (r2.y() == r3.y() &&
2224
if (alreadyIntersected)
2234
IconItem* IconView::findLastVisibleItem(const QRect& r, bool useThumbnailRect) const
2236
IconViewPriv::ItemContainer* c = d->firstContainer;
2238
bool alreadyIntersected = false;
2240
for (; c; c = c->next)
2242
if (c->rect.intersects(r))
2244
alreadyIntersected = true;
2245
foreach(IconItem* item, c->items)
2247
if (r.intersects(useThumbnailRect ? item->clickToOpenRect() : item->rect()))
2255
QRect r2 = item->rect();
2256
QRect r3 = i->rect();
2258
if (r2.y() > r3.y())
2262
else if (r2.y() == r3.y() &&
2273
if (alreadyIntersected)
2283
void IconView::drawFrameRaised(QPainter* p)
2285
QRect r = frameRect();
2286
int lwidth = lineWidth();
2287
const QColorGroup& g = QColorGroup(palette());
2288
qDrawShadeRect(p, r, g, false, lwidth, midLineWidth());
2291
void IconView::drawFrameSunken(QPainter* p)
2293
QRect r = frameRect();
2294
int lwidth = lineWidth();
2295
const QColorGroup& g = QColorGroup(palette());
2296
qDrawShadeRect(p, r, g, true, lwidth, midLineWidth());
2299
void IconView::setEnableToolTips(bool val)
2306
d->toolTipTimer->stop();
2311
void IconView::slotToolTip()
2313
emit signalShowToolTip(d->toolTipItem);
2316
void IconView::itemClickedToOpen(IconItem* item)
2323
IconItem* prevCurrItem = d->currItem;
2325
d->anchorItem = item;
2329
prevCurrItem->repaint();
2332
item->setSelected(true);
2333
emit signalDoubleClicked(item);
2336
int IconView::cmpItems(const void* n1, const void* n2)
2343
IconViewPriv::SortableItem* i1 = (IconViewPriv::SortableItem*)n1;
2344
IconViewPriv::SortableItem* i2 = (IconViewPriv::SortableItem*)n2;
2346
return i1->group->compare(i2->group);
2349
QPixmap IconView::thumbnailBorderPixmap(const QSize& pixSize)
2351
const int radius = 3;
2352
const QColor borderColor = QColor(0, 0, 0, 128);
2354
QString cacheKey = QString::number(pixSize.width()) + '-' + QString::number(pixSize.height());
2355
QPixmap* cachePix = d->thumbnailBorderCache.object(cacheKey);
2359
QPixmap pix = ThumbBarView::generateFuzzyRect(QSize(pixSize.width() + 2 * radius,
2360
pixSize.height() + 2 * radius),
2361
borderColor, radius);
2362
d->thumbnailBorderCache.insert(cacheKey, new QPixmap(pix));
2369
void IconView::clearThumbnailBorderCache()
2371
d->thumbnailBorderCache.clear();
2374
QPixmap IconView::selectPixmap() const
2376
return d->selectPix;
2379
QPixmap IconView::deselectPixmap() const
2381
return d->deselectPix;
2384
void IconView::slotIconViewFontChanged()
2386
setFont(AlbumSettings::instance()->getIconViewFont());
2389
} // namespace Digikam