source: trunk/src/qt3support/itemviews/q3iconview.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 177.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the Qt3Support module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qglobal.h"
43#if defined(Q_CC_BOR)
44// needed for qsort() because of a std namespace problem on Borland
45#include "qplatformdefs.h"
46#endif
47
48#include "q3iconview.h"
49
50#ifndef QT_NO_ICONVIEW
51
52#include "private/q3richtext_p.h"
53#include "q3textedit.h"
54#include "qapplication.h"
55#include "qbitmap.h"
56#include "qbrush.h"
57#include "q3cleanuphandler.h"
58#include "qcursor.h"
59#include "qevent.h"
60#include "qfontmetrics.h"
61#include "qhash.h"
62#include "qimage.h"
63#include "qmime.h"
64#include "qpainter.h"
65#include "qpalette.h"
66#include "qpen.h"
67#include "qpixmapcache.h"
68#include "qstringlist.h"
69#include "qstyle.h"
70#include "qstyleoption.h"
71#include "qtimer.h"
72#include "qtooltip.h"
73#include "q3strlist.h"
74
75#include <limits.h>
76#include <stdlib.h>
77
78QT_BEGIN_NAMESPACE
79
80#define RECT_EXTENSION 300
81
82static const char * const unknown_xpm[] = {
83 "32 32 11 1",
84 "c c #ffffff",
85 "g c #c0c0c0",
86 "a c #c0ffc0",
87 "h c #a0a0a4",
88 "d c #585858",
89 "f c #303030",
90 "i c #400000",
91 "b c #00c000",
92 "e c #000000",
93 "# c #000000",
94 ". c None",
95 "...###..........................",
96 "...#aa##........................",
97 ".###baaa##......................",
98 ".#cde#baaa##....................",
99 ".#cccdeebaaa##..##f.............",
100 ".#cccccdeebaaa##aaa##...........",
101 ".#cccccccdeebaaaaaaaa##.........",
102 ".#cccccccccdeebaaaaaaa#.........",
103 ".#cccccgcgghhebbbbaaaaa#........",
104 ".#ccccccgcgggdebbbbbbaa#........",
105 ".#cccgcgcgcgghdeebiebbba#.......",
106 ".#ccccgcggggggghdeddeeba#.......",
107 ".#cgcgcgcggggggggghghdebb#......",
108 ".#ccgcggggggggghghghghd#b#......",
109 ".#cgcgcggggggggghghghhd#b#......",
110 ".#gcggggggggghghghhhhhd#b#......",
111 ".#cgcggggggggghghghhhhd#b#......",
112 ".#ggggggggghghghhhhhhhdib#......",
113 ".#gggggggggghghghhhhhhd#b#......",
114 ".#hhggggghghghhhhhhhhhd#b#......",
115 ".#ddhhgggghghghhhhhhhhd#b#......",
116 "..##ddhhghghhhhhhhhhhhdeb#......",
117 "....##ddhhhghhhhhhhhhhd#b#......",
118 "......##ddhhhhhhhhhhhhd#b#......",
119 "........##ddhhhhhhhhhhd#b#......",
120 "..........##ddhhhhhhhhd#b#......",
121 "............##ddhhhhhhd#b###....",
122 "..............##ddhhhhd#b#####..",
123 "................##ddhhd#b######.",
124 "..................##dddeb#####..",
125 "....................##d#b###....",
126 "......................####......"};
127
128static QPixmap *unknown_icon = 0;
129static QPixmap *qiv_buffer_pixmap = 0;
130#if !defined(Q_WS_X11)
131static QPixmap *qiv_selection = 0;
132#endif
133static bool optimize_layout = false;
134
135
136static void qt_cleanup_iv_pixmaps();
137typedef QList<QPixmap *> IVPixmaps;
138Q_GLOBAL_STATIC_WITH_INITIALIZER(IVPixmaps, qiv_pixmaps, qAddPostRoutine(qt_cleanup_iv_pixmaps))
139
140static void qt_cleanup_iv_pixmaps()
141{
142 qDeleteAll(*qiv_pixmaps());
143}
144
145static QPixmap *get_qiv_buffer_pixmap(const QSize &s)
146{
147 if (!qiv_buffer_pixmap) {
148 qiv_buffer_pixmap = new QPixmap(s);
149 qiv_pixmaps()->append(qiv_buffer_pixmap);
150 return qiv_buffer_pixmap;
151 }
152
153 qiv_buffer_pixmap->resize(s);
154 return qiv_buffer_pixmap;
155}
156
157#ifndef QT_NO_DRAGANDDROP
158
159class Q_COMPAT_EXPORT Q3IconDragData
160{
161public:
162 Q3IconDragData();
163 Q3IconDragData(const QRect &ir, const QRect &tr);
164
165 QRect pixmapRect() const;
166 QRect textRect() const;
167
168 void setPixmapRect(const QRect &r);
169 void setTextRect(const QRect &r);
170
171 QRect iconRect_, textRect_;
172 QString key_;
173
174 bool operator==(const Q3IconDragData &i) const;
175};
176
177class Q_COMPAT_EXPORT Q3IconDragDataItem
178{
179public:
180 Q3IconDragDataItem() {}
181 Q3IconDragDataItem(const Q3IconDragItem &i1, const Q3IconDragData &i2) : data(i1), item(i2) {}
182 Q3IconDragItem data;
183 Q3IconDragData item;
184 bool operator== (const Q3IconDragDataItem&) const;
185};
186
187class Q3IconDragPrivate
188{
189public:
190 QLinkedList<Q3IconDragDataItem> items;
191 static bool decode(QMimeSource* e, QLinkedList<Q3IconDragDataItem> &lst);
192};
193
194#endif
195
196class Q3IconViewPrivate
197{
198public:
199 Q3IconViewItem *firstItem, *lastItem;
200 uint count;
201 Q3IconView::SelectionMode selectionMode;
202 Q3IconViewItem *currentItem, *tmpCurrentItem, *highlightedItem,
203 *startDragItem, *pressedItem, *selectAnchor, *renamingItem;
204 QRect *rubber;
205 QTimer *scrollTimer, *adjustTimer, *updateTimer, *inputTimer,
206 *fullRedrawTimer;
207 int rastX, rastY, spacing;
208 int dragItems;
209 QPoint oldDragPos;
210 Q3IconView::Arrangement arrangement;
211 Q3IconView::ResizeMode resizeMode;
212 QSize oldSize;
213#ifndef QT_NO_DRAGANDDROP
214 QLinkedList<Q3IconDragDataItem> iconDragData;
215#endif
216 int numDragItems, cachedW, cachedH;
217 int maxItemWidth, maxItemTextLength;
218 QPoint dragStart;
219 QString currInputString;
220 Q3IconView::ItemTextPos itemTextPos;
221#ifndef QT_NO_CURSOR
222 QCursor oldCursor;
223#endif
224 int cachedContentsX, cachedContentsY;
225 QBrush itemTextBrush;
226 QRegion clipRegion;
227 QPoint dragStartPos;
228 QFontMetrics *fm;
229 int minLeftBearing, minRightBearing;
230
231 uint mousePressed : 1;
232 uint cleared : 1;
233 uint dropped : 1;
234 uint clearing : 1;
235 uint oldDragAcceptAction : 1;
236 uint isIconDrag : 1;
237 uint drawDragShapes : 1;
238 uint dirty : 1;
239 uint rearrangeEnabled : 1;
240 uint reorderItemsWhenInsert : 1;
241 uint drawAllBack : 1;
242 uint resortItemsWhenInsert : 1;
243 uint sortDirection : 1;
244 uint wordWrapIconText : 1;
245 uint containerUpdateLocked : 1;
246 uint firstSizeHint : 1;
247 uint showTips : 1;
248 uint pressedSelected : 1;
249 uint dragging : 1;
250 uint drawActiveSelection : 1;
251 uint inMenuMode : 1;
252
253 QPoint dragPos;
254 QPixmapCache maskCache;
255 QHash<Q3IconViewItem *, Q3IconViewItem *> selectedItems;
256
257 struct ItemContainer {
258 ItemContainer(ItemContainer *pr, ItemContainer *nx, const QRect &r)
259 : p(pr), n(nx), rect(r)
260 {
261 if (p)
262 p->n = this;
263 if (n)
264 n->p = this;
265 }
266 ItemContainer *p, *n;
267 QRect rect;
268 QList<Q3IconViewItem*> items;
269 } *firstContainer, *lastContainer;
270
271 struct SortableItem {
272 Q3IconViewItem *item;
273 };
274
275public:
276
277 /* finds the containers that intersect with \a searchRect in the direction \a dir relative to \a relativeTo */
278 QList<ItemContainer* >* findContainers(
279 Q3IconView:: Direction dir,
280 const QPoint &relativeTo,
281 const QRect &searchRect) const;
282 // friend int cmpIconViewItems(const void *n1, const void *n2);
283};
284
285
286QList<Q3IconViewPrivate::ItemContainer *>* Q3IconViewPrivate::findContainers(
287 Q3IconView:: Direction dir,
288 const QPoint &relativeTo,
289 const QRect &searchRect) const
290{
291
292 QList<Q3IconViewPrivate::ItemContainer *>* list =
293 new QList<Q3IconViewPrivate::ItemContainer*>();
294
295 if (arrangement == Q3IconView::LeftToRight) {
296 if (dir == Q3IconView::DirLeft || dir == Q3IconView::DirRight) {
297 ItemContainer *c = firstContainer;
298 for (; c; c = c->n)
299 if (c->rect.intersects(searchRect))
300 list->append(c);
301 } else {
302 if (dir == Q3IconView::DirDown) {
303 ItemContainer *c = firstContainer;
304 for (; c; c = c->n)
305 if (c->rect.intersects(searchRect) &&
306 c->rect.bottom() >= relativeTo.y())
307 list->append(c);
308 } else {
309 ItemContainer *c = lastContainer;
310 for (; c; c = c->p)
311 if (c->rect.intersects(searchRect) &&
312 c->rect.top() <= relativeTo.y())
313 list->append(c);
314 }
315 }
316 } else {
317 if (dir == Q3IconView::DirUp || dir == Q3IconView::DirDown) {
318 ItemContainer *c = firstContainer;
319 for (; c; c = c->n)
320 if (c->rect.intersects(searchRect))
321 list->append(c);
322 } else {
323 if (dir == Q3IconView::DirRight) {
324 ItemContainer *c = firstContainer;
325 for (; c; c = c->n)
326 if (c->rect.intersects(searchRect) &&
327 c->rect.right() >= relativeTo.x())
328 list->append(c);
329 } else {
330 ItemContainer *c = lastContainer;
331 for (; c; c = c->p)
332 if (c->rect.intersects(searchRect) &&
333 c->rect.left() <= relativeTo.x())
334 list->append(c);
335 }
336 }
337 }
338 return list;
339}
340
341
342#if defined(Q_C_CALLBACKS)
343extern "C" {
344#endif
345
346#ifdef Q_OS_WINCE
347static int _cdecl cmpIconViewItems(const void *n1, const void *n2)
348#else
349static int cmpIconViewItems(const void *n1, const void *n2)
350#endif
351{
352 if (!n1 || !n2)
353 return 0;
354
355 Q3IconViewPrivate::SortableItem *i1 = (Q3IconViewPrivate::SortableItem *)n1;
356 Q3IconViewPrivate::SortableItem *i2 = (Q3IconViewPrivate::SortableItem *)n2;
357
358 return i1->item->compare(i2->item);
359}
360
361#if defined(Q_C_CALLBACKS)
362}
363#endif
364
365class Q3IconViewItemPrivate
366{
367public:
368 Q3IconViewPrivate::ItemContainer *container1, *container2;
369};
370
371#ifndef QT_NO_TEXTEDIT
372
373class Q3IconViewItemLineEdit : public Q3TextEdit
374{
375 friend class Q3IconViewItem;
376
377public:
378 Q3IconViewItemLineEdit(const QString &text, QWidget *parent, Q3IconViewItem *theItem, const char* name=0);
379
380protected:
381 void keyPressEvent(QKeyEvent *e);
382 void focusOutEvent(QFocusEvent *e);
383
384protected:
385 Q3IconViewItem *item;
386 QString startText;
387
388private:
389 Q_DISABLE_COPY(Q3IconViewItemLineEdit)
390};
391
392Q3IconViewItemLineEdit::Q3IconViewItemLineEdit(const QString &text, QWidget *parent,
393 Q3IconViewItem *theItem, const char *name)
394 : Q3TextEdit(parent, name), item(theItem), startText(text)
395{
396 setFrameStyle(QFrame::Plain | QFrame::Box);
397 setLineWidth(1);
398
399 setHScrollBarMode(AlwaysOff);
400 setVScrollBarMode(AlwaysOff);
401
402 setWordWrap(WidgetWidth);
403 setWrapColumnOrWidth(item->iconView()->maxItemWidth() -
404 (item->iconView()->itemTextPos() == Q3IconView::Bottom ?
405 0 : item->pixmapRect().width()));
406 document()->formatter()->setAllowBreakInWords(true);
407 resize(200, 200); // ### some size, there should be a forceReformat()
408 setTextFormat(Qt::PlainText);
409 setText(text);
410 setAlignment(Qt::AlignCenter);
411
412 resize(wrapColumnOrWidth() + 2, heightForWidth(wrapColumnOrWidth()) + 2);
413}
414
415void Q3IconViewItemLineEdit::keyPressEvent(QKeyEvent *e)
416{
417 if (e->key() == Qt::Key_Escape) {
418 item->Q3IconViewItem::setText(startText);
419 item->cancelRenameItem();
420 } else if (e->key() == Qt::Key_Enter ||
421 e->key() == Qt::Key_Return) {
422 item->renameItem();
423 } else {
424 Q3TextEdit::keyPressEvent(e);
425 sync();
426 resize(width(), document()->height() + 2);
427
428 }
429}
430
431void Q3IconViewItemLineEdit::focusOutEvent(QFocusEvent *e)
432{
433 Q_UNUSED(e) // I need this to get rid of a Borland warning
434 if (e->reason() != Qt::PopupFocusReason)
435 item->cancelRenameItem();
436}
437#endif
438
439#ifndef QT_NO_DRAGANDDROP
440
441
442/*!
443 \class Q3IconDragItem
444 \brief The Q3IconDragItem class encapsulates a drag item.
445 \compat
446
447 The Q3IconDrag class uses a list of Q3IconDragItems to support drag
448 and drop operations.
449
450 In practice a Q3IconDragItem object (or an object of a class derived
451 from Q3IconDragItem) is created for each icon view item which is
452 dragged. Each of these Q3IconDragItems is stored in a Q3IconDrag
453 object.
454
455 See Q3IconView::dragObject() for more information.
456*/
457
458/*!
459 Constructs a Q3IconDragItem with no data.
460*/
461
462Q3IconDragItem::Q3IconDragItem()
463{
464 ba = "no data";
465}
466
467/*!
468 Destructor.
469*/
470
471Q3IconDragItem::~Q3IconDragItem()
472{
473}
474
475/*!
476 Returns the data contained in the Q3IconDragItem.
477*/
478
479QByteArray Q3IconDragItem::data() const
480{
481 return ba;
482}
483
484/*!
485 Sets the data for the Q3IconDragItem to the data stored in the
486 QByteArray \a d.
487*/
488
489void Q3IconDragItem::setData(const QByteArray &d)
490{
491 ba = d;
492}
493
494/*!
495 \internal
496*/
497
498bool Q3IconDragItem::operator==(const Q3IconDragItem &i) const
499{
500 return ba == i.ba;
501}
502
503/*!
504 \reimp
505*/
506
507bool Q3IconDragDataItem::operator==(const Q3IconDragDataItem &i) const
508{
509 return (i.item == item &&
510 i.data == data);
511}
512
513/*!
514 \reimp
515*/
516
517bool Q3IconDragData::operator==(const Q3IconDragData &i) const
518{
519 return key_ == i.key_;
520}
521
522
523/*!
524 \class Q3IconDrag
525 \brief The Q3IconDrag class supports drag and drop operations
526 within a Q3IconView.
527
528 \compat
529
530 A Q3IconDrag object is used to maintain information about the
531 positions of dragged items and the data associated with them.
532 Q3IconViews are able to use this information to paint the dragged
533 items in the correct positions. Internally, Q3IconDrag stores the
534 data associated with drag items in Q3IconDragItem objects.
535
536 If you want to use the extended drag and drop functionality of
537 Q3IconView, create a Q3IconDrag object in a reimplementation of
538 Q3IconView::dragObject(). Then create a Q3IconDragItem for each item
539 which should be dragged, set the data it represents with
540 Q3IconDragItem::setData(), and add each Q3IconDragItem to the drag
541 object using append().
542
543 The data in Q3IconDragItems is stored in a QByteArray and is
544 mime-typed (see QMimeSource and the
545 \link http://qt.nokia.com/doc/dnd.html Drag and Drop\endlink
546 overview). If you want to use your own mime-types derive a class
547 from Q3IconDrag and reimplement format(), encodedData() and
548 canDecode().
549
550 The fileiconview example program demonstrates the use of the
551 Q3IconDrag class including subclassing and reimplementing
552 dragObject(), format(), encodedData() and canDecode().
553
554 \sa QMimeSource::format()
555*/
556
557/*!
558 Constructs a drag object called \a name, which is a child of \a
559 dragSource.
560
561 Note that the drag object will be deleted when \a dragSource is deleted.
562*/
563
564Q3IconDrag::Q3IconDrag(QWidget * dragSource, const char* name)
565 : Q3DragObject(dragSource, name)
566{
567 d = new Q3IconDragPrivate;
568}
569
570/*!
571 Destructor.
572*/
573
574Q3IconDrag::~Q3IconDrag()
575{
576 delete d;
577}
578
579/*!
580 Append the Q3IconDragItem, \a i, to the Q3IconDrag object's list of
581 items. You must also supply the geometry of the pixmap, \a pr, and
582 the textual caption, \a tr.
583
584 \sa Q3IconDragItem
585*/
586
587void Q3IconDrag::append(const Q3IconDragItem &i, const QRect &pr, const QRect &tr)
588{
589 d->items.append(Q3IconDragDataItem(i, Q3IconDragData(pr, tr)));
590}
591
592/*!
593 \reimp
594*/
595
596const char* Q3IconDrag::format(int i) const
597{
598 if (i == 0)
599 return "application/x-qiconlist";
600 return 0;
601}
602
603/*!
604 Returns the encoded data of the drag object if \a mime is
605 application/x-qiconlist.
606*/
607
608QByteArray Q3IconDrag::encodedData(const char* mime) const
609{
610 if (d->items.size() <= 0 || QString::fromLatin1(mime) !=
611 QString::fromLatin1("application/x-qiconlist"))
612 return QByteArray();
613
614 QLinkedList<Q3IconDragDataItem>::ConstIterator it = d->items.begin();
615 QString s;
616 for (; it != d->items.end(); ++it) {
617 QString k(QLatin1String("%1$@@$%2$@@$%3$@@$%4$@@$%5$@@$%6$@@$%7$@@$%8$@@$"));
618 k = k.arg((*it).item.pixmapRect().x()).arg(
619 (*it).item.pixmapRect().y()).arg((*it).item.pixmapRect().width()).
620 arg((*it).item.pixmapRect().height()).arg(
621 (*it).item.textRect().x()).arg((*it).item.textRect().y()).
622 arg((*it).item.textRect().width()).arg(
623 (*it).item.textRect().height());
624 k += QString::fromLatin1((*it).data.data()) + QLatin1String("$@@$");
625 s += k;
626 }
627
628 QByteArray a;
629 a.resize(s.length() + 1);
630 memcpy(a.data(), s.latin1(), a.size());
631 return a;
632}
633
634/*!
635 Returns true if \a e can be decoded by the Q3IconDrag, otherwise
636 return false.
637*/
638
639bool Q3IconDrag::canDecode(QMimeSource* e)
640{
641 if (e->provides("application/x-qiconlist"))
642 return true;
643 return false;
644}
645
646/*!
647 Decodes the data which is stored (encoded) in \a e and, if
648 successful, fills the \a list of icon drag items with the decoded
649 data. Returns true if there was some data, false otherwise.
650*/
651
652bool Q3IconDragPrivate::decode(QMimeSource* e, QLinkedList<Q3IconDragDataItem> &lst)
653{
654 QByteArray ba = e->encodedData("application/x-qiconlist");
655 if (ba.size()) {
656 lst.clear();
657 // #### unicode clean????
658 QString s = QString::fromLatin1(ba);
659 Q3IconDragDataItem item;
660 QRect ir, tr;
661 QStringList l = QStringList::split(QLatin1String("$@@$"), s);
662
663 int i = 0;
664 QStringList::Iterator it = l.begin();
665 for (; it != l.end(); ++it) {
666 if (i == 0) {
667 ir.setX((*it).toInt());
668 } else if (i == 1) {
669 ir.setY((*it).toInt());
670 } else if (i == 2) {
671 ir.setWidth((*it).toInt());
672 } else if (i == 3) {
673 ir.setHeight((*it).toInt());
674 } else if (i == 4) {
675 tr.setX((*it).toInt());
676 } else if (i == 5) {
677 tr.setY((*it).toInt());
678 } else if (i == 6) {
679 tr.setWidth((*it).toInt());
680 } else if (i == 7) {
681 tr.setHeight((*it).toInt());
682 } else if (i == 8) {
683 QByteArray d;
684 d.resize((*it).length());
685 memcpy(d.data(), (*it).latin1(), (*it).length());
686 item.item.setPixmapRect(ir);
687 item.item.setTextRect(tr);
688 item.data.setData(d);
689 lst.append(item);
690 }
691 ++i;
692 if (i > 8)
693 i = 0;
694 }
695 return true;
696 }
697
698 return false;
699}
700
701Q3IconDragData::Q3IconDragData()
702 : iconRect_(), textRect_()
703{
704}
705
706Q3IconDragData::Q3IconDragData(const QRect &ir, const QRect &tr)
707 : iconRect_(ir), textRect_(tr)
708{
709}
710
711QRect Q3IconDragData::textRect() const
712{
713 return textRect_;
714}
715
716QRect Q3IconDragData::pixmapRect() const
717{
718 return iconRect_;
719}
720
721void Q3IconDragData::setPixmapRect(const QRect &r)
722{
723 iconRect_ = r;
724}
725
726void Q3IconDragData::setTextRect(const QRect &r)
727{
728 textRect_ = r;
729}
730
731#endif
732
733
734/*!
735 \class Q3IconViewItem
736 \brief The Q3IconViewItem class provides a single item in a Q3IconView.
737
738 \compat
739
740 A Q3IconViewItem contains an icon, a string and optionally a sort
741 key, and can display itself in a Q3IconView.
742
743 The simplest way to create a Q3IconViewItem and insert it into a
744 Q3IconView is to construct the item passing the constructor a
745 pointer to the icon view, a string and an icon:
746
747 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 0
748
749 By default the text of an icon view item may not be edited by the
750 user but calling setRenameEnabled(true) will allow the user to
751 perform in-place editing of the item's text.
752
753 When the icon view is deleted all items in it are deleted
754 automatically.
755
756 The Q3IconView::firstItem() and Q3IconViewItem::nextItem() functions
757 provide a means of iterating over all the items in a Q3IconView:
758
759 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 1
760
761 The item's icon view is available from iconView(), and its
762 position in the icon view from index().
763
764 The item's selection status is available from isSelected() and is
765 set and controlled by setSelected() and isSelectable().
766
767 The text and icon can be set with setText() and setPixmap() and
768 retrieved with text() and pixmap(). The item's sort key defaults
769 to text() but may be set with setKey() and retrieved with key().
770 The comparison function, compare() uses key().
771
772 Items may be repositioned with move() and moveBy(). An item's
773 geometry is available from rect(), x(), y(), width(), height(),
774 size(), pos(), textRect() and pixmapRect(). You can also test
775 against the position of a point with contains() and intersects().
776
777 To remove an item from an icon view, just delete the item. The
778 Q3IconViewItem destructor removes it cleanly from its icon view.
779
780 Because the icon view is designed to use drag-and-drop, the icon
781 view item also has functions for drag-and-drop which may be
782 reimplemented.
783
784 The class is designed to be very similar to Q3ListView and Q3ListBox
785 in use, both via instantiation and subclassing.
786*/
787
788/*!
789 Constructs a Q3IconViewItem and inserts it into icon view \a parent
790 with no text and a default icon.
791*/
792
793Q3IconViewItem::Q3IconViewItem(Q3IconView *parent)
794 : view(parent), itemText(), itemIcon(unknown_icon)
795{
796 init();
797}
798
799/*!
800 Constructs a Q3IconViewItem and inserts it into the icon view \a
801 parent with no text and a default icon, after the icon view item
802 \a after.
803*/
804
805Q3IconViewItem::Q3IconViewItem(Q3IconView *parent, Q3IconViewItem *after)
806 : view(parent), itemText(), itemIcon(unknown_icon),
807 prev(0), next(0)
808{
809 init(after);
810}
811
812/*!
813 Constructs an icon view item and inserts it into the icon view \a
814 parent using \a text as the text and a default icon.
815*/
816
817Q3IconViewItem::Q3IconViewItem(Q3IconView *parent, const QString &text)
818 : view(parent), itemText(text), itemIcon(unknown_icon)
819{
820 init(0);
821}
822
823/*!
824 Constructs an icon view item and inserts it into the icon view \a
825 parent using \a text as the text and a default icon, after the
826 icon view item \a after.
827*/
828
829Q3IconViewItem::Q3IconViewItem(Q3IconView *parent, Q3IconViewItem *after,
830 const QString &text)
831 : view(parent), itemText(text), itemIcon(unknown_icon)
832{
833 init(after);
834}
835
836/*!
837 Constructs an icon view item and inserts it into the icon view \a
838 parent using \a text as the text and \a icon as the icon.
839*/
840
841Q3IconViewItem::Q3IconViewItem(Q3IconView *parent, const QString &text,
842 const QPixmap &icon)
843 : view(parent),
844 itemText(text), itemIcon(new QPixmap(icon))
845{
846 init(0);
847}
848
849
850/*!
851 Constructs an icon view item and inserts it into the icon view \a
852 parent using \a text as the text and \a icon as the icon, after
853 the icon view item \a after.
854*/
855
856Q3IconViewItem::Q3IconViewItem(Q3IconView *parent, Q3IconViewItem *after,
857 const QString &text, const QPixmap &icon)
858 : view(parent), itemText(text), itemIcon(new QPixmap(icon))
859{
860 init(after);
861}
862
863/*!
864 Constructs an icon view item and inserts it into the icon view \a
865 parent using \a text as the text and \a picture as the icon.
866*/
867
868#ifndef QT_NO_PICTURE
869Q3IconViewItem::Q3IconViewItem(Q3IconView *parent, const QString &text,
870 const QPicture &picture)
871 : view(parent), itemText(text), itemIcon(0)
872{
873 init(0, new QPicture(picture));
874}
875
876/*!
877 Constructs an icon view item and inserts it into the icon view \a
878 parent using \a text as the text and \a picture as the icon, after
879 the icon view item \a after.
880*/
881
882Q3IconViewItem::Q3IconViewItem(Q3IconView *parent, Q3IconViewItem *after,
883 const QString &text, const QPicture &picture)
884 : view(parent), itemText(text), itemIcon(0)
885{
886 init(after, new QPicture(picture));
887}
888#endif
889
890/*!
891 This private function initializes the icon view item and inserts it
892 into the icon view.
893*/
894
895void Q3IconViewItem::init(Q3IconViewItem *after
896#ifndef QT_NO_PICTURE
897 , QPicture *pic
898#endif
899 )
900{
901 d = new Q3IconViewItemPrivate;
902 d->container1 = 0;
903 d->container2 = 0;
904 prev = next = 0;
905 allow_rename = false;
906 allow_drag = true;
907 allow_drop = true;
908 selected = false;
909 selectable = true;
910#ifndef QT_NO_TEXTEDIT
911 renameBox = 0;
912#endif
913#ifndef QT_NO_PICTURE
914 itemPic = pic;
915#endif
916 if (view) {
917 itemKey = itemText;
918 dirty = true;
919 wordWrapDirty = true;
920 itemRect = QRect(-1, -1, 0, 0);
921 calcRect();
922 view->insertItem(this, after);
923 }
924}
925
926/*!
927 Destroys the icon view item and tells the parent icon view that
928 the item has been destroyed.
929*/
930
931Q3IconViewItem::~Q3IconViewItem()
932{
933#ifndef QT_NO_TEXTEDIT
934 removeRenameBox();
935#endif
936 if (view && !view->d->clearing)
937 view->takeItem(this);
938 view = 0;
939 if (itemIcon && itemIcon->serialNumber() != unknown_icon->serialNumber())
940 delete itemIcon;
941#ifndef QT_NO_PICTURE
942 delete itemPic;
943#endif
944 delete d;
945}
946
947int Q3IconViewItem::RTTI = 0;
948
949/*!
950 Returns 0.
951
952 Make your derived classes return their own values for rtti(), so
953 that you can distinguish between icon view item types. You should
954 use values greater than 1000, preferably a large random number, to
955 allow for extensions to this class.
956*/
957
958int Q3IconViewItem::rtti() const
959{
960 return RTTI;
961}
962
963
964/*!
965 Sets \a text as the text of the icon view item. This function
966 might be a no-op if you reimplement text().
967
968 \sa text()
969*/
970
971void Q3IconViewItem::setText(const QString &text)
972{
973 if (text == itemText)
974 return;
975
976 wordWrapDirty = true;
977 itemText = text;
978 if (itemKey.isEmpty())
979 itemKey = itemText;
980
981 QRect oR = rect();
982 calcRect();
983 oR = oR.united(rect());
984
985 if (view) {
986 if (QRect(view->contentsX(), view->contentsY(),
987 view->visibleWidth(), view->visibleHeight()).
988 intersects(oR))
989 view->repaintContents(oR.x() - 1, oR.y() - 1, oR.width() + 2, oR.height() + 2);
990 }
991}
992
993/*!
994 Sets \a k as the sort key of the icon view item. By default
995 text() is used for sorting.
996
997 \sa compare()
998*/
999
1000void Q3IconViewItem::setKey(const QString &k)
1001{
1002 if (k == itemKey)
1003 return;
1004
1005 itemKey = k;
1006}
1007
1008/*!
1009 Sets \a icon as the item's icon in the icon view. This function
1010 might be a no-op if you reimplement pixmap().
1011
1012 \sa pixmap()
1013*/
1014
1015void Q3IconViewItem::setPixmap(const QPixmap &icon)
1016{
1017 if (itemIcon && itemIcon == unknown_icon)
1018 itemIcon = 0;
1019
1020 if (itemIcon)
1021 *itemIcon = icon;
1022 else
1023 itemIcon = new QPixmap(icon);
1024 QRect oR = rect();
1025 calcRect();
1026 oR = oR.united(rect());
1027
1028 if (view) {
1029 if (QRect(view->contentsX(), view->contentsY(),
1030 view->visibleWidth(), view->visibleHeight()).
1031 intersects(oR))
1032 view->repaintContents(oR.x() - 1, oR.y() - 1, oR.width() + 2, oR.height() + 2);
1033 }
1034}
1035
1036/*!
1037 Sets \a icon as the item's icon in the icon view. This function
1038 might be a no-op if you reimplement picture().
1039
1040 \sa picture()
1041*/
1042
1043#ifndef QT_NO_PICTURE
1044void Q3IconViewItem::setPicture(const QPicture &icon)
1045{
1046 // clear assigned pixmap if any
1047 if (itemIcon) {
1048 if (itemIcon == unknown_icon) {
1049 itemIcon = 0;
1050 } else {
1051 delete itemIcon;
1052 itemIcon = 0;
1053 }
1054 }
1055 if (itemPic)
1056 delete itemPic;
1057 itemPic = new QPicture(icon);
1058
1059 QRect oR = rect();
1060 calcRect();
1061 oR = oR.united(rect());
1062
1063 if (view) {
1064 if (QRect(view->contentsX(), view->contentsY(),
1065 view->visibleWidth(), view->visibleHeight()).
1066 intersects(oR))
1067 view->repaintContents(oR.x() - 1, oR.y() - 1, oR.width() + 2, oR.height() + 2);
1068 }
1069}
1070#endif
1071
1072/*!
1073 \overload
1074
1075 Sets \a text as the text of the icon view item. If \a recalc is
1076 true, the icon view's layout is recalculated. If \a redraw is true
1077 (the default), the icon view is repainted.
1078
1079 \sa text()
1080*/
1081
1082void Q3IconViewItem::setText(const QString &text, bool recalc, bool redraw)
1083{
1084 if (text == itemText)
1085 return;
1086
1087 wordWrapDirty = true;
1088 itemText = text;
1089
1090 if (recalc)
1091 calcRect();
1092 if (redraw)
1093 repaint();
1094}
1095
1096/*!
1097 \overload
1098
1099 Sets \a icon as the item's icon in the icon view. If \a recalc is
1100 true, the icon view's layout is recalculated. If \a redraw is true
1101 (the default), the icon view is repainted.
1102
1103 \sa pixmap()
1104*/
1105
1106void Q3IconViewItem::setPixmap(const QPixmap &icon, bool recalc, bool redraw)
1107{
1108 if (itemIcon && itemIcon == unknown_icon)
1109 itemIcon = 0;
1110
1111 if (itemIcon)
1112 *itemIcon = icon;
1113 else
1114 itemIcon = new QPixmap(icon);
1115
1116 if (redraw) {
1117 if (recalc) {
1118 QRect oR = rect();
1119 calcRect();
1120 oR = oR.united(rect());
1121
1122 if (view) {
1123 if (QRect(view->contentsX(), view->contentsY(),
1124 view->visibleWidth(), view->visibleHeight()).
1125 intersects(oR))
1126 view->repaintContents(oR.x() - 1, oR.y() - 1, oR.width() + 2, oR.height() + 2);
1127 }
1128 } else {
1129 repaint();
1130 }
1131 } else if (recalc) {
1132 calcRect();
1133 }
1134}
1135
1136/*!
1137 If \a allow is true, the user can rename the icon view item by
1138 clicking on the text (or pressing F2) while the item is selected
1139 (in-place renaming). If \a allow is false, in-place renaming is
1140 not possible.
1141*/
1142
1143void Q3IconViewItem::setRenameEnabled(bool allow)
1144{
1145 allow_rename = (uint)allow;
1146}
1147
1148/*!
1149 If \a allow is true, the icon view permits the user to drag the
1150 icon view item either to another position within the icon view or
1151 to somewhere outside of it. If \a allow is false, the item cannot
1152 be dragged.
1153*/
1154
1155void Q3IconViewItem::setDragEnabled(bool allow)
1156{
1157 allow_drag = (uint)allow;
1158}
1159
1160/*!
1161 If \a allow is true, the icon view lets the user drop something on
1162 this icon view item.
1163*/
1164
1165void Q3IconViewItem::setDropEnabled(bool allow)
1166{
1167 allow_drop = (uint)allow;
1168}
1169
1170/*!
1171 Returns the text of the icon view item. Normally you set the text
1172 of the item with setText(), but sometimes it's inconvenient to
1173 call setText() for every item; so you can subclass Q3IconViewItem,
1174 reimplement this function, and return the text of the item. If you
1175 do this, you must call calcRect() manually each time the text
1176 (and therefore its size) changes.
1177
1178 \sa setText()
1179*/
1180
1181QString Q3IconViewItem::text() const
1182{
1183 return itemText;
1184}
1185
1186/*!
1187 Returns the key of the icon view item or text() if no key has been
1188 explicitly set.
1189
1190 \sa setKey(), compare()
1191*/
1192
1193QString Q3IconViewItem::key() const
1194{
1195 return itemKey;
1196}
1197
1198/*!
1199 Returns the icon of the icon view item if it is a pixmap, or 0 if
1200 it is a picture. In the latter case use picture() instead.
1201 Normally you set the pixmap of the item with setPixmap(), but
1202 sometimes it's inconvenient to call setPixmap() for every item. So
1203 you can subclass Q3IconViewItem, reimplement this function and
1204 return a pointer to the item's pixmap. If you do this, you \e must
1205 call calcRect() manually each time the size of this pixmap
1206 changes.
1207
1208 \sa setPixmap()
1209*/
1210
1211QPixmap *Q3IconViewItem::pixmap() const
1212{
1213 return itemIcon;
1214}
1215
1216/*!
1217 Returns the icon of the icon view item if it is a picture, or 0 if
1218 it is a pixmap. In the latter case use pixmap() instead. Normally
1219 you set the picture of the item with setPicture(), but sometimes
1220 it's inconvenient to call setPicture() for every item. So you can
1221 subclass Q3IconViewItem, reimplement this function and return a
1222 pointer to the item's picture. If you do this, you \e must call
1223 calcRect() manually each time the size of this picture changes.
1224
1225 \sa setPicture()
1226*/
1227
1228#ifndef QT_NO_PICTURE
1229QPicture *Q3IconViewItem::picture() const
1230{
1231 return itemPic;
1232}
1233#endif
1234
1235/*!
1236 Returns true if the item can be renamed by the user with in-place
1237 renaming; otherwise returns false.
1238
1239 \sa setRenameEnabled()
1240*/
1241
1242bool Q3IconViewItem::renameEnabled() const
1243{
1244 return (bool)allow_rename;
1245}
1246
1247/*!
1248 Returns true if the user is allowed to drag the icon view item;
1249 otherwise returns false.
1250
1251 \sa setDragEnabled()
1252*/
1253
1254bool Q3IconViewItem::dragEnabled() const
1255{
1256 return (bool)allow_drag;
1257}
1258
1259/*!
1260 Returns true if the user is allowed to drop something onto the
1261 item; otherwise returns false.
1262
1263 \sa setDropEnabled()
1264*/
1265
1266bool Q3IconViewItem::dropEnabled() const
1267{
1268 return (bool)allow_drop;
1269}
1270
1271/*!
1272 Returns a pointer to this item's icon view parent.
1273*/
1274
1275Q3IconView *Q3IconViewItem::iconView() const
1276{
1277 return view;
1278}
1279
1280/*!
1281 Returns a pointer to the previous item, or 0 if this is the first
1282 item in the icon view.
1283
1284 \sa nextItem() Q3IconView::firstItem()
1285*/
1286
1287Q3IconViewItem *Q3IconViewItem::prevItem() const
1288{
1289 return prev;
1290}
1291
1292/*!
1293 Returns a pointer to the next item, or 0 if this is the last item
1294 in the icon view.
1295
1296 To find the first item use Q3IconView::firstItem().
1297
1298 Example:
1299 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 2
1300
1301 \sa prevItem()
1302*/
1303
1304Q3IconViewItem *Q3IconViewItem::nextItem() const
1305{
1306 return next;
1307}
1308
1309/*!
1310 Returns the index of this item in the icon view, or -1 if an error
1311 occurred.
1312*/
1313
1314int Q3IconViewItem::index() const
1315{
1316 if (view)
1317 return view->index(this);
1318
1319 return -1;
1320}
1321
1322
1323
1324/*!
1325 \overload
1326
1327 This variant is equivalent to calling the other variant with \e cb
1328 set to false.
1329*/
1330
1331void Q3IconViewItem::setSelected(bool s)
1332{
1333 setSelected(s, false);
1334}
1335
1336/*!
1337 Selects or unselects the item, depending on \a s; it may also
1338 unselect other items, depending on Q3IconView::selectionMode() and
1339 \a cb.
1340
1341 If \a s is false, the item is unselected.
1342
1343 If \a s is true and Q3IconView::selectionMode() is
1344 Q3IconView::Single, the item is selected and the item previously
1345 selected is unselected.
1346
1347 If \a s is true and Q3IconView::selectionMode() is
1348 Q3IconView::Extended, the item is selected. If \a cb is true, the
1349 selection state of the other items is left unchanged. If \a cb is
1350 false (the default) all other items are unselected.
1351
1352 If \a s is true and Q3IconView::selectionMode() is
1353 Q3IconView::Multi, the item is selected.
1354
1355 Note that \a cb is used only if Q3IconView::selectionMode() is
1356 Q3IconView::Extended; cb defaults to false.
1357
1358 All items whose selection status changes repaint themselves.
1359*/
1360
1361void Q3IconViewItem::setSelected(bool s, bool cb)
1362{
1363 if (!view)
1364 return;
1365 if (view->selectionMode() != Q3IconView::NoSelection &&
1366 selectable && s != (bool)selected) {
1367
1368 if (view->d->selectionMode == Q3IconView::Single && this != view->d->currentItem) {
1369 Q3IconViewItem *o = view->d->currentItem;
1370 if (o && o->selected)
1371 o->selected = false;
1372 view->d->currentItem = this;
1373 if (o)
1374 o->repaint();
1375 emit view->currentChanged(this);
1376 }
1377
1378 if (!s) {
1379 selected = false;
1380 } else {
1381 if (view->d->selectionMode == Q3IconView::Single && view->d->currentItem) {
1382 view->d->currentItem->selected = false;
1383 }
1384 if ((view->d->selectionMode == Q3IconView::Extended && !cb) ||
1385 view->d->selectionMode == Q3IconView::Single) {
1386 bool b = view->signalsBlocked();
1387 view->blockSignals(true);
1388 view->selectAll(false);
1389 view->blockSignals(b);
1390 }
1391 selected = s;
1392 }
1393
1394 repaint();
1395 if (!view->signalsBlocked()) {
1396 bool emitIt = view->d->selectionMode == Q3IconView::Single && s;
1397 Q3IconView *v = view;
1398 emit v->selectionChanged();
1399 if (emitIt)
1400 emit v->selectionChanged(this);
1401 }
1402 }
1403}
1404
1405/*!
1406 Sets this item to be selectable if \a enable is true (the default)
1407 or unselectable if \a enable is false.
1408
1409 The user is unable to select a non-selectable item using either
1410 the keyboard or the mouse. (The application programmer can select
1411 an item in code regardless of this setting.)
1412
1413 \sa isSelectable()
1414*/
1415
1416void Q3IconViewItem::setSelectable(bool enable)
1417{
1418 selectable = (uint)enable;
1419}
1420
1421/*!
1422 Returns true if the item is selected; otherwise returns false.
1423
1424 \sa setSelected()
1425*/
1426
1427bool Q3IconViewItem::isSelected() const
1428{
1429 return (bool)selected;
1430}
1431
1432/*!
1433 Returns true if the item is selectable; otherwise returns false.
1434
1435 \sa setSelectable()
1436*/
1437
1438bool Q3IconViewItem::isSelectable() const
1439{
1440 return (bool)selectable;
1441}
1442
1443/*!
1444 Repaints the item.
1445*/
1446
1447void Q3IconViewItem::repaint()
1448{
1449 if (view)
1450 view->repaintItem(this);
1451}
1452
1453/*!
1454 Moves the item to position (\a x, \a y) in the icon view (these
1455 are contents coordinates). Returns true if the item is moved.
1456 Returns false if the item is already at the specified position.
1457*/
1458
1459bool Q3IconViewItem::move(int x, int y)
1460{
1461 if (x == this->x() && y == this->y())
1462 return false;
1463 itemRect.setRect(x, y, itemRect.width(), itemRect.height());
1464 checkRect();
1465 if (view)
1466 view->updateItemContainer(this);
1467 return true;
1468}
1469
1470/*!
1471 Moves the item \a dx pixels in the x-direction and \a dy pixels in
1472 the y-direction.
1473*/
1474
1475void Q3IconViewItem::moveBy(int dx, int dy)
1476{
1477 itemRect.moveBy(dx, dy);
1478 checkRect();
1479 if (view)
1480 view->updateItemContainer(this);
1481}
1482
1483/*!
1484 \overload
1485
1486 Moves the item to the point \a pnt.
1487*/
1488
1489bool Q3IconViewItem::move(const QPoint &pnt)
1490{
1491 return move(pnt.x(), pnt.y());
1492}
1493
1494/*!
1495 \overload
1496
1497 Moves the item by the x, y values in point \a pnt.
1498*/
1499
1500void Q3IconViewItem::moveBy(const QPoint &pnt)
1501{
1502 moveBy(pnt.x(), pnt.y());
1503}
1504
1505/*!
1506 Returns the bounding rectangle of the item (in contents
1507 coordinates).
1508*/
1509
1510QRect Q3IconViewItem::rect() const
1511{
1512 return itemRect;
1513}
1514
1515/*!
1516 Returns the x-coordinate of the item (in contents coordinates).
1517*/
1518
1519int Q3IconViewItem::x() const
1520{
1521 return itemRect.x();
1522}
1523
1524/*!
1525 Returns the y-coordinate of the item (in contents coordinates).
1526*/
1527
1528int Q3IconViewItem::y() const
1529{
1530 return itemRect.y();
1531}
1532
1533/*!
1534 Returns the width of the item.
1535*/
1536
1537int Q3IconViewItem::width() const
1538{
1539 return qMax(itemRect.width(), QApplication::globalStrut().width());
1540}
1541
1542/*!
1543 Returns the height of the item.
1544*/
1545
1546int Q3IconViewItem::height() const
1547{
1548 return qMax(itemRect.height(), QApplication::globalStrut().height());
1549}
1550
1551/*!
1552 Returns the size of the item.
1553*/
1554
1555QSize Q3IconViewItem::size() const
1556{
1557 return QSize(itemRect.width(), itemRect.height());
1558}
1559
1560/*!
1561 Returns the position of the item (in contents coordinates).
1562*/
1563
1564QPoint Q3IconViewItem::pos() const
1565{
1566 return QPoint(itemRect.x(), itemRect.y());
1567}
1568
1569/*!
1570 Returns the bounding rectangle of the item's text.
1571
1572 If \a relative is true, (the default), the returned rectangle is
1573 relative to the origin of the item's rectangle. If \a relative is
1574 false, the returned rectangle is relative to the origin of the
1575 icon view's contents coordinate system.
1576*/
1577
1578QRect Q3IconViewItem::textRect(bool relative) const
1579{
1580 if (relative)
1581 return itemTextRect;
1582 else
1583 return QRect(x() + itemTextRect.x(), y() + itemTextRect.y(), itemTextRect.width(), itemTextRect.height());
1584}
1585
1586/*!
1587 Returns the bounding rectangle of the item's icon.
1588
1589 If \a relative is true, (the default), the rectangle is relative to
1590 the origin of the item's rectangle. If \a relative is false, the
1591 returned rectangle is relative to the origin of the icon view's
1592 contents coordinate system.
1593*/
1594
1595QRect Q3IconViewItem::pixmapRect(bool relative) const
1596{
1597 if (relative)
1598 return itemIconRect;
1599 else
1600 return QRect(x() + itemIconRect.x(), y() + itemIconRect.y(), itemIconRect.width(), itemIconRect.height());
1601}
1602
1603/*!
1604 Returns true if the item contains the point \a pnt (in contents
1605 coordinates); otherwise returns false.
1606*/
1607
1608bool Q3IconViewItem::contains(const QPoint& pnt) const
1609{
1610 QRect textArea = textRect(false);
1611 QRect pixmapArea = pixmapRect(false);
1612 if (iconView()->itemTextPos() == Q3IconView::Bottom)
1613 textArea.setTop(pixmapArea.bottom());
1614 else
1615 textArea.setLeft(pixmapArea.right());
1616 return textArea.contains(pnt) || pixmapArea.contains(pnt);
1617}
1618
1619/*!
1620 Returns true if the item intersects the rectangle \a r (in
1621 contents coordinates); otherwise returns false.
1622*/
1623
1624bool Q3IconViewItem::intersects(const QRect& r) const
1625{
1626 return (textRect(false).intersects(r) ||
1627 pixmapRect(false).intersects(r));
1628}
1629
1630/*!
1631 \fn bool Q3IconViewItem::acceptDrop(const QMimeSource *mime) const
1632
1633 Returns true if you can drop things with a QMimeSource of \a mime
1634 onto this item; otherwise returns false.
1635
1636 The default implementation always returns false. You must subclass
1637 Q3IconViewItem and reimplement acceptDrop() to accept drops.
1638*/
1639
1640bool Q3IconViewItem::acceptDrop(const QMimeSource *) const
1641{
1642 return false;
1643}
1644
1645#ifndef QT_NO_TEXTEDIT
1646/*!
1647 Starts in-place renaming of an icon, if allowed.
1648
1649 This function sets up the icon view so that the user can edit the
1650 item text, and then returns. When the user is done, setText() will
1651 be called and Q3IconView::itemRenamed() will be emitted (unless the
1652 user canceled, e.g. by pressing the Escape key).
1653
1654 \sa setRenameEnabled()
1655*/
1656
1657void Q3IconViewItem::rename()
1658{
1659 if (!view)
1660 return;
1661 if (renameBox)
1662 removeRenameBox();
1663 oldRect = rect();
1664 renameBox = new Q3IconViewItemLineEdit(itemText, view->viewport(), this, "qt_renamebox");
1665 iconView()->ensureItemVisible(this);
1666 QRect tr(textRect(false));
1667 view->addChild(renameBox, tr.x() + (tr.width() / 2 - renameBox->width() / 2), tr.y() - 3);
1668 renameBox->selectAll();
1669 view->viewport()->setFocusProxy(renameBox);
1670 renameBox->setFocus();
1671 renameBox->show();
1672 Q_ASSERT(view->d->renamingItem == 0L);
1673 view->d->renamingItem = this;
1674}
1675#endif
1676
1677/*!
1678 Compares this icon view item to \a i. Returns -1 if this item is
1679 less than \a i, 0 if they are equal, and 1 if this icon view item
1680 is greater than \a i.
1681
1682 The default implementation compares the item keys (key()) using
1683 QString::localeAwareCompare(). A reimplementation may use
1684 different values and a different comparison function. Here is a
1685 reimplementation that uses plain Unicode comparison:
1686
1687 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 3
1688
1689 \sa key() QString::localeAwareCompare() QString::compare()
1690*/
1691
1692int Q3IconViewItem::compare(Q3IconViewItem *i) const
1693{
1694 return key().localeAwareCompare(i->key());
1695}
1696
1697#ifndef QT_NO_TEXTEDIT
1698/*!
1699 This private function is called when the user pressed Return during
1700 in-place renaming.
1701*/
1702
1703void Q3IconViewItem::renameItem()
1704{
1705 if (!renameBox || !view)
1706 return;
1707
1708 if (!view->d->wordWrapIconText) {
1709 wordWrapDirty = true;
1710 calcRect();
1711 }
1712 QRect r = itemRect;
1713 setText(renameBox->text());
1714 view->repaintContents(oldRect.x() - 1, oldRect.y() - 1, oldRect.width() + 2, oldRect.height() + 2);
1715 view->repaintContents(r.x() - 1, r.y() - 1, r.width() + 2, r.height() + 2);
1716 removeRenameBox();
1717
1718 view->emitRenamed(this);
1719}
1720
1721/*!
1722 Cancels in-place renaming.
1723*/
1724
1725void Q3IconViewItem::cancelRenameItem()
1726{
1727 if (!view)
1728 return;
1729
1730 QRect r = itemRect;
1731 calcRect();
1732 view->repaintContents(oldRect.x() - 1, oldRect.y() - 1, oldRect.width() + 2, oldRect.height() + 2);
1733 view->repaintContents(r.x() - 1, r.y() - 1, r.width() + 2, r.height() + 2);
1734
1735 if (!renameBox)
1736 return;
1737
1738 removeRenameBox();
1739}
1740
1741/*!
1742 Removes the editbox that is used for in-place renaming.
1743*/
1744
1745void Q3IconViewItem::removeRenameBox()
1746{
1747 if (!renameBox || !view)
1748 return;
1749
1750 bool resetFocus = view->viewport()->focusProxy() == renameBox;
1751 renameBox->hide();
1752 renameBox->deleteLater();
1753 renameBox = 0;
1754 if (resetFocus) {
1755 view->viewport()->setFocusProxy(view);
1756 view->setFocus();
1757 }
1758 Q_ASSERT(view->d->renamingItem == this);
1759 view->d->renamingItem = 0L;
1760}
1761#endif
1762
1763/*!
1764 This virtual function is responsible for calculating the
1765 rectangles returned by rect(), textRect() and pixmapRect().
1766 setRect(), setTextRect() and setPixmapRect() are provided mainly
1767 for reimplementations of this function.
1768
1769 \a text_ is an internal parameter which defaults to an empty
1770 string.
1771*/
1772
1773void Q3IconViewItem::calcRect(const QString &text_)
1774{
1775 if (!view) // #####
1776 return;
1777
1778 wordWrapDirty = true;
1779 int pw = 0;
1780 int ph = 0;
1781
1782#ifndef QT_NO_PICTURE
1783 if (picture()) {
1784 QRect br = picture()->boundingRect();
1785 pw = br.width() + 2;
1786 ph = br.height() + 2;
1787 } else
1788#endif
1789 {
1790 pw = (pixmap() ? pixmap() : unknown_icon)->width() + 2;
1791 ph = (pixmap() ? pixmap() : unknown_icon)->height() + 2;
1792 }
1793
1794 itemIconRect.setWidth(pw);
1795 itemIconRect.setHeight(ph);
1796
1797 calcTmpText();
1798
1799 QString t = text_;
1800 if (t.isEmpty()) {
1801 if (view->d->wordWrapIconText)
1802 t = itemText;
1803 else
1804 t = tmpText;
1805 }
1806
1807 int tw = 0;
1808 int th = 0;
1809 // ##### TODO: fix font bearings!
1810 QRect r;
1811 if (view->d->wordWrapIconText) {
1812 r = QRect(view->d->fm->boundingRect(0, 0, iconView()->maxItemWidth() -
1813 (iconView()->itemTextPos() == Q3IconView::Bottom ? 0 :
1814 pixmapRect().width()),
1815 0xFFFFFFFF, Qt::AlignHCenter | Qt::WordBreak | Qt::BreakAnywhere, t));
1816 r.setWidth(r.width() + 4);
1817 } else {
1818 r = QRect(0, 0, view->d->fm->width(t), view->d->fm->height());
1819 r.setWidth(r.width() + 4);
1820 }
1821
1822 if (r.width() > iconView()->maxItemWidth() -
1823 (iconView()->itemTextPos() == Q3IconView::Bottom ? 0 :
1824 pixmapRect().width()))
1825 r.setWidth(iconView()->maxItemWidth() - (iconView()->itemTextPos() == Q3IconView::Bottom ? 0 :
1826 pixmapRect().width()));
1827
1828 tw = r.width();
1829 th = r.height();
1830 if (tw < view->d->fm->width(QLatin1Char('X')))
1831 tw = view->d->fm->width(QLatin1Char('X'));
1832
1833 itemTextRect.setWidth(tw);
1834 itemTextRect.setHeight(th);
1835
1836 int w = 0;
1837 int h = 0;
1838 if (view->itemTextPos() == Q3IconView::Bottom) {
1839 w = qMax(itemTextRect.width(), itemIconRect.width());
1840 h = itemTextRect.height() + itemIconRect.height() + 1;
1841
1842 itemRect.setWidth(w);
1843 itemRect.setHeight(h);
1844
1845 itemTextRect = QRect((width() - itemTextRect.width()) / 2, height() - itemTextRect.height(),
1846 itemTextRect.width(), itemTextRect.height());
1847 itemIconRect = QRect((width() - itemIconRect.width()) / 2, 0,
1848 itemIconRect.width(), itemIconRect.height());
1849 } else {
1850 h = qMax(itemTextRect.height(), itemIconRect.height());
1851 w = itemTextRect.width() + itemIconRect.width() + 1;
1852
1853 itemRect.setWidth(w);
1854 itemRect.setHeight(h);
1855
1856 itemTextRect = QRect(width() - itemTextRect.width(), (height() - itemTextRect.height()) / 2,
1857 itemTextRect.width(), itemTextRect.height());
1858 itemIconRect = QRect(0, (height() - itemIconRect.height()) / 2,
1859 itemIconRect.width(), itemIconRect.height());
1860 }
1861 if (view)
1862 view->updateItemContainer(this);
1863}
1864
1865/*!
1866 Paints the item using the painter \a p and the color group \a cg.
1867 If you want the item to be drawn with a different font or color,
1868 reimplement this function, change the values of the color group or
1869 the painter's font, and then call the Q3IconViewItem::paintItem()
1870 with the changed values.
1871*/
1872
1873void Q3IconViewItem::paintItem(QPainter *p, const QColorGroup &cg)
1874{
1875 if (!view)
1876 return;
1877
1878 p->save();
1879
1880 if (isSelected()) {
1881 p->setPen(cg.highlightedText());
1882 } else {
1883 p->setPen(cg.text());
1884 }
1885
1886 calcTmpText();
1887
1888#ifndef QT_NO_PICTURE
1889 if (picture()) {
1890 QPicture *pic = picture();
1891 if (isSelected()) {
1892 p->fillRect(pixmapRect(false), QBrush(cg.highlight(), Qt::Dense4Pattern));
1893 }
1894 p->drawPicture(x()-pic->boundingRect().x(), y()-pic->boundingRect().y(), *pic);
1895 if (isSelected()) {
1896 p->fillRect(textRect(false), cg.highlight());
1897 p->setPen(QPen(cg.highlightedText()));
1898 } else if (view->d->itemTextBrush != QBrush(Qt::NoBrush))
1899 p->fillRect(textRect(false), view->d->itemTextBrush);
1900
1901 int align = view->itemTextPos() == Q3IconView::Bottom ? Qt::AlignHCenter : Qt::AlignAuto;
1902 if (view->d->wordWrapIconText)
1903 align |= Qt::WordBreak | Qt::BreakAnywhere;
1904 p->drawText(textRect(false), align, view->d->wordWrapIconText ? itemText : tmpText);
1905 p->restore();
1906 return;
1907 }
1908#endif
1909 bool textOnBottom = (view->itemTextPos() == Q3IconView::Bottom);
1910 int dim;
1911 if (textOnBottom)
1912 dim = (pixmap() ? pixmap() : unknown_icon)->width();
1913 else
1914 dim = (pixmap() ? pixmap() : unknown_icon)->height();
1915 if (isSelected()) {
1916 QPixmap *pix = pixmap() ? pixmap() : unknown_icon;
1917 if (pix && !pix->isNull()) {
1918 QPixmap *buffer = get_qiv_buffer_pixmap(pix->size());
1919 QBitmap mask = view->mask(pix);
1920
1921 QPainter p2(buffer);
1922 p2.fillRect(pix->rect(), Qt::white);
1923 p2.drawPixmap(0, 0, *pix);
1924 p2.end();
1925
1926 p2.begin(buffer);
1927 p2.fillRect(pix->rect(), QBrush(cg.highlight(), Qt::Dense4Pattern));
1928 p2.end();
1929 buffer->setMask(mask);
1930
1931 QRect cr = pix->rect();
1932 if (textOnBottom)
1933 p->drawPixmap(x() + (width() - dim) / 2, y(), *buffer, 0, 0,
1934 cr.width(), cr.height());
1935 else
1936 p->drawPixmap(x() , y() + (height() - dim) / 2, *buffer, 0, 0,
1937 cr.width(), cr.height());
1938 }
1939 } else {
1940 if (textOnBottom)
1941 p->drawPixmap(x() + (width() - dim) / 2, y(),
1942 *(pixmap() ? pixmap() : unknown_icon));
1943 else
1944 p->drawPixmap(x() , y() + (height() - dim) / 2,
1945 *(pixmap() ? pixmap() : unknown_icon));
1946 }
1947
1948 p->save();
1949 if (isSelected()) {
1950 p->fillRect(textRect(false), cg.highlight());
1951 p->setPen(QPen(cg.highlightedText()));
1952 } else if (view->d->itemTextBrush != QBrush(Qt::NoBrush))
1953 p->fillRect(textRect(false), view->d->itemTextBrush);
1954
1955 int align = Qt::AlignHCenter;
1956 if (view->d->wordWrapIconText)
1957 align |= Qt::WordBreak | Qt::BreakAnywhere;
1958 p->drawText(textRect(false), align,
1959 view->d->wordWrapIconText ? itemText : tmpText);
1960
1961 p->restore();
1962
1963 p->restore();
1964}
1965
1966/*!
1967 Paints the focus rectangle of the item using the painter \a p and
1968 the color group \a cg.
1969*/
1970
1971void Q3IconViewItem::paintFocus(QPainter *p, const QColorGroup &cg)
1972{
1973 if (!view)
1974 return;
1975
1976 QStyleOptionFocusRect opt;
1977 opt.rect = textRect(false);
1978 opt.palette = cg;
1979 if (isSelected()) {
1980 opt.state = QStyle::State_FocusAtBorder;
1981 opt.backgroundColor = cg.highlight();
1982 } else {
1983 opt.state = QStyle::State_None;
1984 opt.backgroundColor = cg.base();
1985 }
1986 view->style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p);
1987
1988 if (this != view->d->currentItem) {
1989 opt.rect = pixmapRect(false);
1990 opt.backgroundColor = cg.base();
1991 opt.state = QStyle::State_None;
1992 view->style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p);
1993 }
1994}
1995
1996#ifndef QT_NO_DRAGANDDROP
1997/*!
1998 \fn void Q3IconViewItem::dropped(QDropEvent *e, const Q3ValueList<Q3IconDragItem> &lst)
1999
2000 This function is called when something is dropped on the item. \a
2001 e provides all the information about the drop. If the drag object
2002 of the drop was a Q3IconDrag, \a lst contains the list of the
2003 dropped items. You can get the data by calling
2004 Q3IconDragItem::data() on each item. If the \a lst is empty, i.e.
2005 the drag was not a Q3IconDrag, you must decode the data in \a e and
2006 work with that.
2007
2008 The default implementation does nothing; subclasses may
2009 reimplement this function.
2010*/
2011
2012void Q3IconViewItem::dropped(QDropEvent *, const Q3ValueList<Q3IconDragItem> &)
2013{
2014}
2015#endif
2016
2017/*!
2018 This function is called when a drag enters the item's bounding
2019 rectangle.
2020
2021 The default implementation does nothing; subclasses may
2022 reimplement this function.
2023*/
2024
2025void Q3IconViewItem::dragEntered()
2026{
2027}
2028
2029/*!
2030 This function is called when a drag leaves the item's bounding
2031 rectangle.
2032
2033 The default implementation does nothing; subclasses may
2034 reimplement this function.
2035*/
2036
2037void Q3IconViewItem::dragLeft()
2038{
2039}
2040
2041/*!
2042 Sets the bounding rectangle of the whole item to \a r. This
2043 function is provided for subclasses which reimplement calcRect(),
2044 so that they can set the calculated rectangle. \e{Any other use is
2045 discouraged.}
2046
2047 \sa calcRect() textRect() setTextRect() pixmapRect() setPixmapRect()
2048*/
2049
2050void Q3IconViewItem::setItemRect(const QRect &r)
2051{
2052 itemRect = r;
2053 checkRect();
2054 if (view)
2055 view->updateItemContainer(this);
2056}
2057
2058/*!
2059 Sets the bounding rectangle of the item's text to \a r. This
2060 function is provided for subclasses which reimplement calcRect(),
2061 so that they can set the calculated rectangle. \e{Any other use is
2062 discouraged.}
2063
2064 \sa calcRect() textRect() setItemRect() setPixmapRect()
2065*/
2066
2067void Q3IconViewItem::setTextRect(const QRect &r)
2068{
2069 itemTextRect = r;
2070 if (view)
2071 view->updateItemContainer(this);
2072}
2073
2074/*!
2075 Sets the bounding rectangle of the item's icon to \a r. This
2076 function is provided for subclasses which reimplement calcRect(),
2077 so that they can set the calculated rectangle. \e{Any other use is
2078 discouraged.}
2079
2080 \sa calcRect() pixmapRect() setItemRect() setTextRect()
2081*/
2082
2083void Q3IconViewItem::setPixmapRect(const QRect &r)
2084{
2085 itemIconRect = r;
2086 if (view)
2087 view->updateItemContainer(this);
2088}
2089
2090/*!
2091 \internal
2092*/
2093
2094void Q3IconViewItem::calcTmpText()
2095{
2096 if (!view || view->d->wordWrapIconText || !wordWrapDirty)
2097 return;
2098 wordWrapDirty = false;
2099
2100 int w = iconView()->maxItemWidth() - (iconView()->itemTextPos() == Q3IconView::Bottom ? 0 :
2101 pixmapRect().width());
2102 if (view->d->fm->width(itemText) < w) {
2103 tmpText = itemText;
2104 return;
2105 }
2106
2107 tmpText = QLatin1String("...");
2108 int i = 0;
2109 while (view->d->fm->width(tmpText + itemText[i]) < w)
2110 tmpText += itemText[i++];
2111 tmpText.remove((uint)0, 3);
2112 tmpText += QLatin1String("...");
2113}
2114
2115/*! \internal */
2116
2117QString Q3IconViewItem::tempText() const
2118{
2119 return tmpText;
2120}
2121
2122void Q3IconViewItem::checkRect()
2123{
2124 int x = itemRect.x();
2125 int y = itemRect.y();
2126 int w = itemRect.width();
2127 int h = itemRect.height();
2128
2129 bool changed = false;
2130 if (x < 0) {
2131 x = 0;
2132 changed = true;
2133 }
2134 if (y < 0) {
2135 y = 0;
2136 changed = true;
2137 }
2138
2139 if (changed)
2140 itemRect.setRect(x, y, w, h);
2141}
2142
2143
2144/*!
2145 \class Q3IconView
2146 \brief The Q3IconView class provides an area with movable labelled icons.
2147
2148 \compat
2149
2150 A Q3IconView can display and manage a grid or other 2D layout of
2151 labelled icons. Each labelled icon is a Q3IconViewItem. Items
2152 (Q3IconViewItems) can be added or deleted at any time; items can be
2153 moved within the Q3IconView. Single or multiple items can be
2154 selected. Items can be renamed in-place. Q3IconView also supports
2155 \link #draganddrop drag and drop\endlink.
2156
2157 Each item contains a label string, a pixmap or picture (the icon
2158 itself) and optionally a sort key. The sort key is used for
2159 sorting the items and defaults to the label string. The label
2160 string can be displayed below or to the right of the icon (see \l
2161 ItemTextPos).
2162
2163 The simplest way to create a Q3IconView is to create a Q3IconView
2164 object and create some Q3IconViewItems with the Q3IconView as their
2165 parent, set the icon view's geometry and show it.
2166 For example:
2167 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 4
2168
2169 The Q3IconViewItem call passes a pointer to the Q3IconView we wish to
2170 populate, along with the label text and a QPixmap.
2171
2172 When an item is inserted the Q3IconView allocates a position for it.
2173 Existing items are rearranged if autoArrange() is true. The
2174 default arrangement is \l LeftToRight -- the Q3IconView fills up
2175 the \e left-most column from top to bottom, then moves one column
2176 \e right and fills that from top to bottom and so on. The
2177 arrangement can be modified with any of the following approaches:
2178 \list
2179 \i Call setArrangement(), e.g. with \l TopToBottom which will fill
2180 the \e top-most row from left to right, then moves one row \e down
2181 and fills that row from left to right and so on.
2182 \i Construct each Q3IconViewItem using a constructor which allows
2183 you to specify which item the new one is to follow.
2184 \i Call setSorting() or sort() to sort the items.
2185 \endlist
2186
2187 The spacing between items is set with setSpacing(). Items can be
2188 laid out using a fixed grid using setGridX() and setGridY(); by
2189 default the Q3IconView calculates a grid dynamically. The position
2190 of items' label text is set with setItemTextPos(). The text's
2191 background can be set with setItemTextBackground(). The maximum
2192 width of an item and of its text are set with setMaxItemWidth()
2193 and setMaxItemTextLength(). The label text will be word-wrapped if
2194 it is too long; this is controlled by setWordWrapIconText(). If
2195 the label text is truncated, the user can still see the entire
2196 text in a tool tip if they hover the mouse over the item. This is
2197 controlled with setShowToolTips().
2198
2199 Items which are \link Q3IconViewItem::isSelectable()
2200 selectable\endlink may be selected depending on the SelectionMode;
2201 the default is \l Single. Because Q3IconView offers multiple
2202 selection it must display keyboard focus and selection state
2203 separately. Therefore there are functions to set the selection
2204 state of an item (setSelected()) and to select which item displays
2205 keyboard focus (setCurrentItem()). When multiple items may be
2206 selected the icon view provides a rubberband, too.
2207
2208 When in-place renaming is enabled (it is disabled by default), the
2209 user may change the item's label. They do this by selecting the item
2210 (single clicking it or navigating to it with the arrow keys), then
2211 single clicking it (or pressing F2), and entering their text. If no
2212 key has been set with Q3IconViewItem::setKey() the new text will also
2213 serve as the key. (See Q3IconViewItem::setRenameEnabled().)
2214
2215 You can control whether users can move items themselves with
2216 setItemsMovable().
2217
2218 Because the internal structure used to store the icon view items is
2219 linear, no iterator class is needed to iterate over all the items.
2220 Instead we iterate by getting the first item from the \e{icon view}
2221 and then each subsequent (\l Q3IconViewItem::nextItem()) from each
2222 \e item in turn:
2223 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 5
2224 Q3IconView also provides currentItem(). You can search for an item
2225 using findItem() (searching by position or for label text) and
2226 with findFirstVisibleItem() and findLastVisibleItem(). The number
2227 of items is returned by count(). An item can be removed from an
2228 icon view using takeItem(); to delete an item use \c delete. All
2229 the items can be deleted with clear().
2230
2231 The Q3IconView emits a wide range of useful signals, including
2232 selectionChanged(), currentChanged(), clicked(), moved() and
2233 itemRenamed().
2234
2235 \target draganddrop
2236 \section1 Drag and Drop
2237
2238 Q3IconView supports the drag and drop of items within the Q3IconView
2239 itself. It also supports the drag and drop of items out of or into
2240 the Q3IconView and drag and drop onto items themselves. The drag and
2241 drop of items outside the Q3IconView can be achieved in a simple way
2242 with basic functionality, or in a more sophisticated way which
2243 provides more power and control.
2244
2245 The simple approach to dragging items out of the icon view is to
2246 subclass Q3IconView and reimplement Q3IconView::dragObject().
2247
2248 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 6
2249
2250 In this example we create a Q3TextDrag object, (derived from
2251 Q3DragObject), containing the item's label and return it as the drag
2252 object. We could just as easily have created a Q3ImageDrag from the
2253 item's pixmap and returned that instead.
2254
2255 Q3IconViews and their Q3IconViewItems can also be the targets of drag
2256 and drops. To make the Q3IconView itself able to accept drops connect
2257 to the dropped() signal. When a drop occurs this signal will be
2258 emitted with a QDragEvent and a QLinkedList of Q3IconDragItems. To
2259 make a Q3IconViewItem into a drop target subclass Q3IconViewItem and
2260 reimplement Q3IconViewItem::acceptDrop() and
2261 Q3IconViewItem::dropped().
2262
2263 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 7
2264
2265 If you want to use extended drag-and-drop or have drag shapes drawn
2266 you must take a more sophisticated approach.
2267
2268 The first part is starting drags -- you should use a Q3IconDrag (or a
2269 class derived from it) for the drag object. In dragObject() create the
2270 drag object, populate it with Q3IconDragItems and return it. Normally
2271 such a drag should offer each selected item's data. So in dragObject()
2272 you should iterate over all the items, and create a Q3IconDragItem for
2273 each selected item, and append these items with Q3IconDrag::append() to
2274 the Q3IconDrag object. You can use Q3IconDragItem::setData() to set the
2275 data of each item that should be dragged. If you want to offer the
2276 data in additional mime-types, it's best to use a class derived from
2277 Q3IconDrag, which implements additional encoding and decoding
2278 functions.
2279
2280 When a drag enters the icon view, there is little to do. Simply
2281 connect to the dropped() signal and reimplement
2282 Q3IconViewItem::acceptDrop() and Q3IconViewItem::dropped(). If you've
2283 used a Q3IconDrag (or a subclass of it) the second argument to the
2284 dropped signal contains a QLinkedList of Q3IconDragItems -- you can
2285 access their data by calling Q3IconDragItem::data() on each one.
2286
2287 For an example implementation of complex drag-and-drop look at the
2288 fileiconview example (qt/examples/fileiconview).
2289
2290 \sa Q3IconViewItem::setDragEnabled(), Q3IconViewItem::setDropEnabled(),
2291 Q3IconViewItem::acceptDrop(), Q3IconViewItem::dropped()
2292*/
2293
2294/*! \enum Q3IconView::ResizeMode
2295
2296 This enum type is used to tell Q3IconView how it should treat the
2297 positions of its icons when the widget is resized. The modes are:
2298
2299 \value Fixed The icons' positions are not changed.
2300 \value Adjust The icons' positions are adjusted to be within the
2301 new geometry, if possible.
2302*/
2303
2304/*!
2305 \enum Q3IconView::SelectionMode
2306
2307 This enumerated type is used by Q3IconView to indicate how it
2308 reacts to selection by the user. It has four values:
2309
2310 \value Single When the user selects an item, any already-selected
2311 item becomes unselected and the user cannot unselect the selected
2312 item. This means that the user can never clear the selection. (The
2313 application programmer can, using Q3IconView::clearSelection().)
2314
2315 \value Multi When the user selects an item, e.g. by navigating to
2316 it with the keyboard arrow keys or by clicking it, the selection
2317 status of that item is toggled and the other items are left alone.
2318
2319 \value Extended When the user selects an item the selection is
2320 cleared and the new item selected. However, if the user presses
2321 the Ctrl key when clicking on an item, the clicked item gets
2322 toggled and all other items are left untouched. If the user
2323 presses the Shift key while clicking on an item, all items between
2324 the current item and the clicked item get selected or unselected,
2325 depending on the state of the clicked item. Also, multiple items
2326 can be selected by dragging the mouse while the left mouse button
2327 stays pressed.
2328
2329 \value NoSelection Items cannot be selected.
2330
2331 To summarize: \c Single is a real single-selection icon view; \c
2332 Multi a real multi-selection icon view; \c Extended is an icon
2333 view in which users can select multiple items but usually want to
2334 select either just one or a range of contiguous items; and \c
2335 NoSelection mode is for an icon view where the user can look but
2336 not touch.
2337*/
2338
2339/*!
2340 \enum Q3IconView::Arrangement
2341
2342 This enum type determines in which direction the items flow when
2343 the view runs out of space.
2344
2345 \value LeftToRight Items which don't fit into the view go further
2346 down (you get a vertical scroll bar)
2347
2348 \value TopToBottom Items which don't fit into the view go further
2349 right (you get a horizontal scroll bar)
2350*/
2351
2352/*!
2353 \enum Q3IconView::ItemTextPos
2354
2355 This enum type specifies the position of the item text in relation
2356 to the icon.
2357
2358 \value Bottom The text is drawn below the icon.
2359 \value Right The text is drawn to the right of the icon.
2360*/
2361
2362/*!
2363 \fn void Q3IconView::dropped(QDropEvent *e, const Q3ValueList<Q3IconDragItem> &lst)
2364
2365 This signal is emitted when a drop event occurs in the viewport
2366 (but not on any icon) which the icon view itself can't handle.
2367
2368 \a e provides all the information about the drop. If the drag
2369 object of the drop was a Q3IconDrag, \a lst contains the list of
2370 the dropped items. You can get the data using
2371 Q3IconDragItem::data() on each item. If the \a lst is empty, i.e.
2372 the drag was not a Q3IconDrag, you have to decode the data in \a e
2373 and work with that.
2374
2375 Note Q3IconViewItems may be drop targets; if a drop event occurs on
2376 an item the item handles the drop.
2377*/
2378
2379/*!
2380 \fn void Q3IconView::moved()
2381
2382 This signal is emitted after successfully dropping one (or more)
2383 items of the icon view. If the items should be removed, it's best
2384 to do so in a slot connected to this signal.
2385*/
2386
2387/*!
2388 \fn void Q3IconView::doubleClicked(Q3IconViewItem * item)
2389
2390 This signal is emitted when the user double-clicks on \a item.
2391*/
2392
2393/*!
2394 \fn void Q3IconView::returnPressed (Q3IconViewItem * item)
2395
2396 This signal is emitted if the user presses the Return or Enter
2397 key. \a item is the currentItem() at the time of the keypress.
2398*/
2399
2400/*!
2401 \fn void Q3IconView::selectionChanged()
2402
2403 This signal is emitted when the selection has been changed. It's
2404 emitted in each selection mode.
2405*/
2406
2407/*!
2408 \fn void Q3IconView::selectionChanged(Q3IconViewItem *item)
2409 \overload
2410
2411 This signal is emitted when the selection changes. \a item is the
2412 newly selected item. This signal is emitted only in single
2413 selection mode.
2414*/
2415
2416/*!
2417 \fn void Q3IconView::currentChanged(Q3IconViewItem *item)
2418
2419 This signal is emitted when a new item becomes current. \a item is
2420 the new current item (or 0 if no item is now current).
2421
2422 \sa currentItem()
2423*/
2424
2425/*!
2426 \fn void Q3IconView::onItem(Q3IconViewItem *item)
2427
2428 This signal is emitted when the user moves the mouse cursor onto
2429 an \a item, similar to the QWidget::enterEvent() function.
2430*/
2431
2432// ### bug here - enter/leave event aren't considered. move the mouse
2433// out of the window and back in, to the same item.
2434
2435/*!
2436 \fn void Q3IconView::onViewport()
2437
2438 This signal is emitted when the user moves the mouse cursor from
2439 an item to an empty part of the icon view.
2440
2441 \sa onItem()
2442*/
2443
2444/*!
2445 \fn void Q3IconView::itemRenamed (Q3IconViewItem * item)
2446 \overload
2447
2448 This signal is emitted when \a item has been renamed, usually by
2449 in-place renaming.
2450
2451 \sa Q3IconViewItem::setRenameEnabled() Q3IconViewItem::rename()
2452*/
2453
2454/*!
2455 \fn void Q3IconView::itemRenamed (Q3IconViewItem * item, const QString &name)
2456
2457 This signal is emitted when \a item has been renamed to \a name,
2458 usually by in-place renaming.
2459
2460 \sa Q3IconViewItem::setRenameEnabled() Q3IconViewItem::rename()
2461*/
2462
2463/*!
2464 \fn void Q3IconView::rightButtonClicked (Q3IconViewItem * item, const QPoint & pos)
2465
2466 This signal is emitted when the user clicks the right mouse
2467 button. If \a item is non-null, the cursor is on \a item. If \a
2468 item is null, the mouse cursor isn't on any item.
2469
2470 \a pos is the position of the mouse cursor in the global
2471 coordinate system (QMouseEvent::globalPos()). (If the click's
2472 press and release differ by a pixel or two, \a pos is the
2473 position at release time.)
2474
2475 \sa rightButtonPressed() mouseButtonClicked() clicked()
2476*/
2477
2478/*!
2479 \fn void Q3IconView::contextMenuRequested(Q3IconViewItem *item, const QPoint & pos)
2480
2481 This signal is emitted when the user invokes a context menu with
2482 the right mouse button or with special system keys, with \a item
2483 being the item under the mouse cursor or the current item,
2484 respectively.
2485
2486 \a pos is the position for the context menu in the global
2487 coordinate system.
2488*/
2489
2490/*!
2491 \fn void Q3IconView::mouseButtonPressed(int button, Q3IconViewItem *item, const QPoint &pos)
2492
2493 This signal is emitted when the user presses mouse button \a
2494 button. If \a item is non-null, the cursor is on \a item. If \a
2495 item is null, the mouse cursor isn't on any item.
2496
2497 \a pos is the position of the mouse cursor in the global
2498 coordinate system (QMouseEvent::globalPos()).
2499
2500 \sa rightButtonClicked() mouseButtonClicked() pressed()
2501*/
2502
2503/*!
2504 \fn void Q3IconView::mouseButtonClicked (int button, Q3IconViewItem * item, const QPoint & pos)
2505
2506 This signal is emitted when the user clicks mouse button \a
2507 button. If \a item is non-null, the cursor is on \a item. If \a
2508 item is null, the mouse cursor isn't on any item.
2509
2510 \a pos is the position of the mouse cursor in the global
2511 coordinate system (QMouseEvent::globalPos()). (If the click's
2512 press and release differ by a pixel or two, \a pos is the
2513 position at release time.)
2514
2515 \sa mouseButtonPressed() rightButtonClicked() clicked()
2516*/
2517
2518/*!
2519 \fn void Q3IconView::clicked (Q3IconViewItem * item, const QPoint & pos)
2520 \overload
2521
2522 This signal is emitted when the user clicks any mouse button on an
2523 icon view item. \a item is a pointer to the item that has been
2524 clicked.
2525
2526 \a pos is the position of the mouse cursor in the global coordinate
2527 system (QMouseEvent::globalPos()). (If the click's press and release
2528 differ by a pixel or two, \a pos is the position at release time.)
2529
2530 \sa mouseButtonClicked() rightButtonClicked() pressed()
2531*/
2532
2533/*!
2534 \fn void Q3IconView::pressed (Q3IconViewItem * item, const QPoint & pos)
2535 \overload
2536
2537 This signal is emitted when the user presses any mouse button. If
2538 \a item is non-null, the cursor is on \a item. If \a item is null,
2539 the mouse cursor isn't on any item.
2540
2541 \a pos is the position of the mouse cursor in the global
2542 coordinate system (QMouseEvent::globalPos()). (If the click's
2543 press and release differ by a pixel or two, \a pos is the
2544 position at release time.)
2545
2546 \sa mouseButtonPressed() rightButtonPressed() clicked()
2547*/
2548
2549/*!
2550 \fn void Q3IconView::clicked (Q3IconViewItem * item)
2551
2552 This signal is emitted when the user clicks any mouse button. If
2553 \a item is non-null, the cursor is on \a item. If \a item is null,
2554 the mouse cursor isn't on any item.
2555
2556 \sa mouseButtonClicked() rightButtonClicked() pressed()
2557*/
2558
2559/*!
2560 \fn void Q3IconView::pressed (Q3IconViewItem * item)
2561
2562 This signal is emitted when the user presses any mouse button. If
2563 \a item is non-null, the cursor is on \a item. If \a item is null,
2564 the mouse cursor isn't on any item.
2565
2566 \sa mouseButtonPressed() rightButtonPressed() clicked()
2567*/
2568
2569/*!
2570 \fn void Q3IconView::rightButtonPressed(Q3IconViewItem * item, const QPoint & pos)
2571
2572 This signal is emitted when the user presses the right mouse
2573 button. If \a item is non-null, the cursor is on \a item. If \a
2574 item is null, the mouse cursor isn't on any item.
2575
2576 \a pos is the position of the mouse cursor in the global
2577 coordinate system (QMouseEvent::globalPos()).
2578*/
2579
2580/*!
2581 Constructs an empty icon view called \a name, with parent \a
2582 parent and using the widget flags \a f.
2583*/
2584
2585Q3IconView::Q3IconView(QWidget *parent, const char *name, Qt::WindowFlags f)
2586 : Q3ScrollView(parent, name, Qt::WStaticContents | Qt::WNoAutoErase | f)
2587{
2588 if (!unknown_icon) {
2589 unknown_icon = new QPixmap((const char **)unknown_xpm);
2590 qiv_pixmaps()->append(unknown_icon);
2591 }
2592
2593 d = new Q3IconViewPrivate;
2594 d->dragging = false;
2595 d->firstItem = 0;
2596 d->lastItem = 0;
2597 d->count = 0;
2598 d->mousePressed = false;
2599 d->selectionMode = Single;
2600 d->currentItem = 0;
2601 d->highlightedItem = 0;
2602 d->rubber = 0;
2603 d->scrollTimer = 0;
2604 d->startDragItem = 0;
2605 d->tmpCurrentItem = 0;
2606 d->rastX = d->rastY = -1;
2607 d->spacing = 5;
2608 d->cleared = false;
2609 d->arrangement = LeftToRight;
2610 d->resizeMode = Fixed;
2611 d->dropped = false;
2612 d->adjustTimer = new QTimer(this, "iconview adjust timer");
2613 d->isIconDrag = false;
2614 d->inMenuMode = false;
2615#ifndef QT_NO_DRAGANDDROP
2616 d->iconDragData.clear();
2617#endif
2618 d->numDragItems = 0;
2619 d->updateTimer = new QTimer(this, "iconview update timer");
2620 d->cachedW = d->cachedH = 0;
2621 d->maxItemWidth = 100;
2622 d->maxItemTextLength = 255;
2623 d->inputTimer = new QTimer(this, "iconview input timer");
2624 d->currInputString.clear();
2625 d->dirty = false;
2626 d->rearrangeEnabled = true;
2627 d->itemTextPos = Bottom;
2628 d->reorderItemsWhenInsert = true;
2629#ifndef QT_NO_CURSOR
2630 d->oldCursor = Qt::ArrowCursor;
2631#endif
2632 d->resortItemsWhenInsert = false;
2633 d->sortDirection = true;
2634 d->wordWrapIconText = true;
2635 d->cachedContentsX = d->cachedContentsY = -1;
2636 d->clearing = false;
2637 d->fullRedrawTimer = new QTimer(this, "iconview full redraw timer");
2638 d->itemTextBrush = Qt::NoBrush;
2639 d->drawAllBack = true;
2640 d->fm = new QFontMetrics(font());
2641 d->minLeftBearing = d->fm->minLeftBearing();
2642 d->minRightBearing = d->fm->minRightBearing();
2643 d->firstContainer = d->lastContainer = 0;
2644 d->containerUpdateLocked = false;
2645 d->firstSizeHint = false;
2646 d->selectAnchor = 0;
2647 d->renamingItem = 0;
2648 d->drawActiveSelection = true;
2649 d->drawDragShapes = false;
2650
2651 connect(d->adjustTimer, SIGNAL(timeout()),
2652 this, SLOT(adjustItems()));
2653 connect(d->updateTimer, SIGNAL(timeout()),
2654 this, SLOT(slotUpdate()));
2655 connect(d->fullRedrawTimer, SIGNAL(timeout()),
2656 this, SLOT(updateContents()));
2657 connect(this, SIGNAL(contentsMoving(int,int)),
2658 this, SLOT(movedContents(int,int)));
2659
2660 setAcceptDrops(true);
2661 viewport()->setAcceptDrops(true);
2662
2663 setMouseTracking(true);
2664 viewport()->setMouseTracking(true);
2665
2666 viewport()->setBackgroundRole(QPalette::Base);
2667 viewport()->setFocusProxy(this);
2668 viewport()->setFocusPolicy(Qt::WheelFocus);
2669 setFocusPolicy(Qt::WheelFocus);
2670
2671 d->showTips = true;
2672}
2673
2674/*!
2675 \reimp
2676*/
2677void Q3IconView::changeEvent(QEvent *ev)
2678{
2679 if(ev->type() == QEvent::StyleChange) {
2680 *d->fm = QFontMetrics(font());
2681 d->minLeftBearing = d->fm->minLeftBearing();
2682 d->minRightBearing = d->fm->minRightBearing();
2683
2684 Q3IconViewItem *item = d->firstItem;
2685 for (; item; item = item->next) {
2686 item->wordWrapDirty = true;
2687 item->calcRect();
2688 }
2689
2690#if !defined(Q_WS_X11)
2691 delete qiv_selection;
2692 qiv_selection = 0;
2693#endif
2694 } else if(ev->type() == QEvent::ActivationChange) {
2695 if (!isActiveWindow() && d->scrollTimer)
2696 d->scrollTimer->stop();
2697 if(isVisible() && !palette().isEqual(QPalette::Active, QPalette::Inactive))
2698 repaintSelectedItems();
2699 }
2700
2701 Q3ScrollView::changeEvent(ev);
2702
2703 if (ev->type() == QEvent::ApplicationFontChange || ev->type() == QEvent::FontChange) {
2704 *d->fm = QFontMetrics(font());
2705 d->minLeftBearing = d->fm->minLeftBearing();
2706 d->minRightBearing = d->fm->minRightBearing();
2707
2708 Q3IconViewItem *item = d->firstItem;
2709 for (; item; item = item->next) {
2710 item->wordWrapDirty = true;
2711 item->calcRect();
2712 }
2713 }
2714}
2715
2716/*!
2717 Destroys the icon view and deletes all items.
2718*/
2719
2720Q3IconView::~Q3IconView()
2721{
2722 Q3IconViewItem *tmp, *item = d->firstItem;
2723 d->clearing = true;
2724 Q3IconViewPrivate::ItemContainer *c = d->firstContainer, *tmpc;
2725 while (c) {
2726 tmpc = c->n;
2727 delete c;
2728 c = tmpc;
2729 }
2730 while (item) {
2731 tmp = item->next;
2732 delete item;
2733 item = tmp;
2734 }
2735 delete d->fm;
2736 d->fm = 0;
2737 delete d;
2738}
2739
2740/*!
2741 Inserts the icon view item \a item after \a after. If \a after is
2742 0, \a item is appended after the last item.
2743
2744 \e{You should never need to call this function.} Instead create
2745 Q3IconViewItem's and associate them with your icon view like this:
2746
2747 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 8
2748*/
2749
2750void Q3IconView::insertItem(Q3IconViewItem *item, Q3IconViewItem *after)
2751{
2752 if (!item)
2753 return;
2754
2755 if (d->firstItem == item || item->prev || item->next)
2756 return;
2757
2758 if (!item->view)
2759 item->view = this;
2760
2761 if (!d->firstItem) {
2762 d->firstItem = d->lastItem = item;
2763 item->prev = 0;
2764 item->next = 0;
2765 } else {
2766 if (!after || after == d->lastItem) {
2767 d->lastItem->next = item;
2768 item->prev = d->lastItem;
2769 item->next = 0;
2770 d->lastItem = item;
2771 } else {
2772 Q3IconViewItem *i = d->firstItem;
2773 while (i != after)
2774 i = i->next;
2775
2776 if (i) {
2777 Q3IconViewItem *next = i->next;
2778 item->next = next;
2779 item->prev = i;
2780 i->next = item;
2781 next->prev = item;
2782 }
2783 }
2784 }
2785
2786 if (isVisible()) {
2787 if (d->reorderItemsWhenInsert) {
2788 if (d->updateTimer->isActive())
2789 d->updateTimer->stop();
2790 d->fullRedrawTimer->stop();
2791 // #### uncomment this ASA insertInGrid uses cached values and is efficient
2792 //insertInGrid(item);
2793
2794 d->cachedW = qMax(d->cachedW, item->x() + item->width());
2795 d->cachedH= qMax(d->cachedH, item->y() + item->height());
2796
2797 d->updateTimer->start(0, true);
2798 } else {
2799 insertInGrid(item);
2800
2801 viewport()->update(item->x() - contentsX(),
2802 item->y() - contentsY(),
2803 item->width(), item->height());
2804 }
2805 } else if (!autoArrange()) {
2806 item->dirty = false;
2807 }
2808
2809 d->count++;
2810 d->dirty = true;
2811}
2812
2813/*!
2814 This slot is used for a slightly-delayed update.
2815
2816 The icon view is not redrawn immediately after inserting a new item
2817 but after a very small delay using a QTimer. This means that when
2818 many items are inserted in a loop the icon view is probably redrawn
2819 only once at the end of the loop. This makes the insertions both
2820 flicker-free and faster.
2821*/
2822
2823void Q3IconView::slotUpdate()
2824{
2825 d->updateTimer->stop();
2826 d->fullRedrawTimer->stop();
2827
2828 if (!d->firstItem || !d->lastItem)
2829 return;
2830
2831 // #### remove that ASA insertInGrid uses cached values and is efficient
2832 if (d->resortItemsWhenInsert)
2833 sort(d->sortDirection);
2834 else {
2835 int y = d->spacing;
2836 Q3IconViewItem *item = d->firstItem;
2837 int w = 0, h = 0;
2838 while (item) {
2839 bool changed;
2840 Q3IconViewItem *next = makeRowLayout(item, y, changed);
2841 if (!next || !next->next)
2842 break;
2843
2844 if(!QApplication::reverseLayout())
2845 item = next;
2846 w = qMax(w, item->x() + item->width());
2847 h = qMax(h, item->y() + item->height());
2848 item = next;
2849 if (d->arrangement == LeftToRight)
2850 h = qMax(h, y);
2851
2852 item = item->next;
2853 }
2854
2855 if (d->lastItem && d->arrangement == TopToBottom) {
2856 item = d->lastItem;
2857 int x = item->x();
2858 while (item && item->x() >= x) {
2859 w = qMax(w, item->x() + item->width());
2860 h = qMax(h, item->y() + item->height());
2861 item = item->prev;
2862 }
2863 }
2864
2865 w = qMax(qMax(d->cachedW, w), d->lastItem->x() + d->lastItem->width());
2866 h = qMax(qMax(d->cachedH, h), d->lastItem->y() + d->lastItem->height());
2867
2868 if (d->arrangement == TopToBottom)
2869 w += d->spacing;
2870 else
2871 h += d->spacing;
2872 viewport()->setUpdatesEnabled(false);
2873 resizeContents(w, h);
2874 viewport()->setUpdatesEnabled(true);
2875 viewport()->repaint();
2876 }
2877
2878 int cx = d->cachedContentsX == -1 ? contentsX() : d->cachedContentsX;
2879 int cy = d->cachedContentsY == -1 ? contentsY() : d->cachedContentsY;
2880
2881 if (cx != contentsX() || cy != contentsY())
2882 setContentsPos(cx, cy);
2883
2884 d->cachedContentsX = d->cachedContentsY = -1;
2885 d->cachedW = d->cachedH = 0;
2886}
2887
2888/*!
2889 Takes the icon view item \a item out of the icon view and causes
2890 an update of the screen display. The item is not deleted. You
2891 should normally not need to call this function because
2892 Q3IconViewItem::~Q3IconViewItem() calls it. The normal way to delete
2893 an item is to delete it.
2894*/
2895
2896void Q3IconView::takeItem(Q3IconViewItem *item)
2897{
2898 if (!item)
2899 return;
2900
2901 if (item->d->container1)
2902 item->d->container1->items.removeAll(item);
2903 if (item->d->container2)
2904 item->d->container2->items.removeAll(item);
2905 item->d->container2 = 0;
2906 item->d->container1 = 0;
2907
2908 bool block = signalsBlocked();
2909 blockSignals(d->clearing);
2910
2911 QRect r = item->rect();
2912
2913 if (d->currentItem == item) {
2914 if (item->prev) {
2915 d->currentItem = item->prev;
2916 emit currentChanged(d->currentItem);
2917 repaintItem(d->currentItem);
2918 } else if (item->next) {
2919 d->currentItem = item->next;
2920 emit currentChanged(d->currentItem);
2921 repaintItem(d->currentItem);
2922 } else {
2923 d->currentItem = 0;
2924 emit currentChanged(d->currentItem);
2925 }
2926 }
2927 if (item->isSelected()) {
2928 item->selected = false;
2929 emit selectionChanged();
2930 }
2931
2932 if (item == d->firstItem) {
2933 d->firstItem = d->firstItem->next;
2934 if (d->firstItem)
2935 d->firstItem->prev = 0;
2936 } else if (item == d->lastItem) {
2937 d->lastItem = d->lastItem->prev;
2938 if (d->lastItem)
2939 d->lastItem->next = 0;
2940 } else {
2941 Q3IconViewItem *i = item;
2942 if (i) {
2943 if (i->prev)
2944 i->prev->next = i->next;
2945 if (i->next)
2946 i->next->prev = i->prev;
2947 }
2948 }
2949
2950 if (d->selectAnchor == item)
2951 d->selectAnchor = d->currentItem;
2952
2953 if (!d->clearing)
2954 repaintContents(r.x(), r.y(), r.width(), r.height());
2955
2956 item->view = 0;
2957 item->prev = 0;
2958 item->next = 0;
2959 d->count--;
2960
2961 blockSignals(block);
2962}
2963
2964/*!
2965 Returns the index of \a item, or -1 if \a item doesn't exist in
2966 this icon view.
2967*/
2968
2969int Q3IconView::index(const Q3IconViewItem *item) const
2970{
2971 if (!item)
2972 return -1;
2973
2974 if (item == d->firstItem)
2975 return 0;
2976 else if (item == d->lastItem)
2977 return d->count - 1;
2978 else {
2979 Q3IconViewItem *i = d->firstItem;
2980 int j = 0;
2981 while (i && i != item) {
2982 i = i->next;
2983 ++j;
2984 }
2985
2986 return i ? j : -1;
2987 }
2988}
2989
2990/*!
2991 Returns a pointer to the first item of the icon view, or 0 if
2992 there are no items in the icon view.
2993
2994 \sa lastItem() currentItem()
2995*/
2996
2997Q3IconViewItem *Q3IconView::firstItem() const
2998{
2999 return d->firstItem;
3000}
3001
3002/*!
3003 Returns a pointer to the last item of the icon view, or 0 if there
3004 are no items in the icon view.
3005
3006 \sa firstItem() currentItem()
3007*/
3008
3009Q3IconViewItem *Q3IconView::lastItem() const
3010{
3011 return d->lastItem;
3012}
3013
3014/*!
3015 Returns a pointer to the current item of the icon view, or 0 if no
3016 item is current.
3017
3018 \sa setCurrentItem() firstItem() lastItem()
3019*/
3020
3021Q3IconViewItem *Q3IconView::currentItem() const
3022{
3023 return d->currentItem;
3024}
3025
3026/*!
3027 \reimp
3028*/
3029QVariant Q3IconView::inputMethodQuery(Qt::InputMethodQuery query) const
3030{
3031 if (query == Qt::ImMicroFocus) {
3032 return d->currentItem ? d->currentItem->rect() : QRect();
3033 }
3034 return QWidget::inputMethodQuery(query);
3035}
3036
3037/*!
3038 Makes \a item the new current item of the icon view.
3039*/
3040
3041void Q3IconView::setCurrentItem(Q3IconViewItem *item)
3042{
3043 if (!item || item == d->currentItem)
3044 return;
3045
3046 Q3IconViewItem *old = d->currentItem;
3047 d->currentItem = item;
3048 emit currentChanged(d->currentItem);
3049 if (d->selectionMode == Single) {
3050 bool changed = false;
3051 if (old && old->selected) {
3052 old->selected = false;
3053 changed = true;
3054 }
3055 if (item && !item->selected && item->isSelectable() && d->selectionMode != NoSelection) {
3056 item->selected = true;
3057 changed = true;
3058 emit selectionChanged(item);
3059 }
3060 if (changed)
3061 emit selectionChanged();
3062 }
3063
3064 if (old)
3065 repaintItem(old);
3066 repaintItem(d->currentItem);
3067}
3068
3069/*!
3070 Selects or unselects \a item depending on \a s, and may also
3071 unselect other items, depending on Q3IconView::selectionMode() and
3072 \a cb.
3073
3074 If \a s is false, \a item is unselected.
3075
3076 If \a s is true and Q3IconView::selectionMode() is \l Single, \a
3077 item is selected, and the item which was selected is unselected.
3078
3079 If \a s is true and Q3IconView::selectionMode() is \l Extended, \a
3080 item is selected. If \a cb is true, the selection state of the
3081 icon view's other items is left unchanged. If \a cb is false (the
3082 default) all other items are unselected.
3083
3084 If \a s is true and Q3IconView::selectionMode() is \l Multi \a item
3085 is selected.
3086
3087 Note that \a cb is used only if Q3IconView::selectionMode() is \l
3088 Extended. \a cb defaults to false.
3089
3090 All items whose selection status is changed repaint themselves.
3091*/
3092
3093void Q3IconView::setSelected(Q3IconViewItem *item, bool s, bool cb)
3094{
3095 if (!item)
3096 return;
3097 item->setSelected(s, cb);
3098}
3099
3100/*!
3101 \property Q3IconView::count
3102 \brief the number of items in the icon view
3103*/
3104
3105uint Q3IconView::count() const
3106{
3107 return d->count;
3108}
3109
3110/*!
3111 Performs autoscrolling when selecting multiple icons with the
3112 rubber band.
3113*/
3114
3115void Q3IconView::doAutoScroll()
3116{
3117 QRect oldRubber = QRect(*d->rubber);
3118
3119 QPoint vp = viewport()->mapFromGlobal(QCursor::pos());
3120 QPoint pos = viewportToContents(vp);
3121
3122 if (pos == d->rubber->bottomRight())
3123 return;
3124
3125 d->rubber->setRight(pos.x());
3126 d->rubber->setBottom(pos.y());
3127
3128 int minx = contentsWidth(), miny = contentsHeight();
3129 int maxx = 0, maxy = 0;
3130 bool changed = false;
3131 bool block = signalsBlocked();
3132
3133 QRect rr;
3134 QRegion region(0, 0, visibleWidth(), visibleHeight());
3135
3136 blockSignals(true);
3137 viewport()->setUpdatesEnabled(false);
3138 bool alreadyIntersected = false;
3139 QRect nr = d->rubber->normalized();
3140 QRect rubberUnion = nr.united(oldRubber.normalized());
3141 Q3IconViewPrivate::ItemContainer *c = d->firstContainer;
3142 for (; c; c = c->n) {
3143 if (c->rect.intersects(rubberUnion)) {
3144 alreadyIntersected = true;
3145 for (int i = 0; i < c->items.size(); ++i) {
3146 Q3IconViewItem *item = c->items.at(i);
3147 if (d->selectedItems.contains(item))
3148 continue;
3149 if (!item->intersects(nr)) {
3150 if (item->isSelected()) {
3151 item->setSelected(false);
3152 changed = true;
3153 rr = rr.united(item->rect());
3154 }
3155 } else if (item->intersects(nr)) {
3156 if (!item->isSelected() && item->isSelectable()) {
3157 item->setSelected(true, true);
3158 changed = true;
3159 rr = rr.united(item->rect());
3160 } else {
3161 region = region.subtracted(QRect(contentsToViewport(item->pos()),
3162 item->size()));
3163 }
3164
3165 minx = qMin(minx, item->x() - 1);
3166 miny = qMin(miny, item->y() - 1);
3167 maxx = qMax(maxx, item->x() + item->width() + 1);
3168 maxy = qMax(maxy, item->y() + item->height() + 1);
3169 }
3170 }
3171 } else {
3172 if (alreadyIntersected)
3173 break;
3174 }
3175 }
3176 viewport()->setUpdatesEnabled(true);
3177 blockSignals(block);
3178
3179 QRect r = *d->rubber;
3180 *d->rubber = oldRubber;
3181 d->dragging = false;
3182 *d->rubber = r;
3183 if (changed) {
3184 d->drawAllBack = false;
3185 d->clipRegion = region;
3186 repaintContents(rr);
3187 d->drawAllBack = true;
3188 }
3189 ensureVisible(pos.x(), pos.y());
3190 d->dragging = true;
3191
3192 if (changed) {
3193 emit selectionChanged();
3194 if (d->selectionMode == Single)
3195 emit selectionChanged(d->currentItem);
3196 }
3197
3198 if (!QRect(50, 50, viewport()->width()-100, viewport()->height()-100).contains(vp) &&
3199 !d->scrollTimer) {
3200 d->scrollTimer = new QTimer(this);
3201
3202 connect(d->scrollTimer, SIGNAL(timeout()),
3203 this, SLOT(doAutoScroll()));
3204 d->scrollTimer->start(100, false);
3205 } else if (QRect(50, 50, viewport()->width()-100, viewport()->height()-100).contains(vp) &&
3206 d->scrollTimer) {
3207 disconnect(d->scrollTimer, SIGNAL(timeout()),
3208 this, SLOT(doAutoScroll()));
3209 d->scrollTimer->stop();
3210 delete d->scrollTimer;
3211 d->scrollTimer = 0;
3212 }
3213
3214}
3215
3216/*!
3217 \reimp
3218*/
3219
3220void Q3IconView::drawContents(QPainter *p, int cx, int cy, int cw, int ch)
3221{
3222 if (d->dragging && d->rubber)
3223 drawRubber(p);
3224
3225 QRect r = QRect(cx, cy, cw, ch);
3226
3227 Q3IconViewPrivate::ItemContainer *c = d->firstContainer;
3228 QRegion remaining(QRect(cx, cy, cw, ch));
3229 bool alreadyIntersected = false;
3230 while (c) {
3231 if (c->rect.intersects(r)) {
3232 p->save();
3233 p->resetXForm();
3234 QRect r2 = c->rect;
3235 r2 = r2.intersected(r);
3236 QRect r3(contentsToViewport(QPoint(r2.x(), r2.y())), QSize(r2.width(), r2.height()));
3237 if (d->drawAllBack) {
3238 p->setClipRect(r3);
3239 } else {
3240 QRegion reg = d->clipRegion.intersected(r3);
3241 p->setClipRegion(reg);
3242 }
3243 drawBackground(p, r3);
3244 remaining = remaining.subtracted(r3);
3245 p->restore();
3246
3247 QPalette pal = palette();
3248 d->drawActiveSelection = hasFocus() || d->inMenuMode
3249 || !style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this);
3250 if (!d->drawActiveSelection)
3251 pal.setCurrentColorGroup(QPalette::Inactive);
3252
3253 // clip items to the container rect by default... this
3254 // prevents icons with alpha channels from being painted
3255 // twice when they are in 2 containers
3256 //
3257 // NOTE: the item could override this cliprect in its
3258 // paintItem() implementation, which makes this useless
3259 p->setClipRect(r2);
3260 for (int i = 0; i < c->items.size(); ++i) {
3261 Q3IconViewItem *item = c->items.at(i);
3262 if (item->rect().intersects(r) && !item->dirty) {
3263 p->save();
3264 p->setFont(font());
3265 item->paintItem(p, pal);
3266 p->restore();
3267 }
3268 }
3269 alreadyIntersected = true;
3270 } else {
3271 if (alreadyIntersected)
3272 break;
3273 }
3274 c = c->n;
3275 }
3276
3277 if (!remaining.isEmpty()) {
3278 p->save();
3279 p->resetXForm();
3280 if (d->drawAllBack) {
3281 p->setClipRegion(remaining);
3282 } else {
3283 remaining = d->clipRegion.intersected(remaining);
3284 p->setClipRegion(remaining);
3285 }
3286 drawBackground(p, remaining.boundingRect());
3287 p->restore();
3288 }
3289
3290 if ((hasFocus() || viewport()->hasFocus()) && d->currentItem &&
3291 d->currentItem->rect().intersects(r)) {
3292 d->currentItem->paintFocus(p, palette());
3293 }
3294
3295 if (d->dragging && d->rubber)
3296 drawRubber(p);
3297}
3298
3299/*!
3300 \overload
3301
3302 Arranges all the items in the grid specified by gridX() and gridY().
3303
3304 Even if sorting() is enabled, the items are not sorted by this
3305 function. If you want to sort or rearrange the items, use
3306 iconview->sort(iconview->sortDirection()).
3307
3308 If \a update is true (the default), the viewport is repainted as
3309 well.
3310
3311 \sa Q3IconView::setGridX(), Q3IconView::setGridY(), Q3IconView::sort()
3312*/
3313
3314void Q3IconView::arrangeItemsInGrid(bool update)
3315{
3316 if (!d->firstItem || !d->lastItem)
3317 return;
3318
3319 d->containerUpdateLocked = true;
3320
3321 int w = 0, h = 0, y = d->spacing;
3322
3323 Q3IconViewItem *item = d->firstItem;
3324 bool changedLayout = false;
3325 while (item) {
3326 bool changed;
3327 Q3IconViewItem *next = makeRowLayout(item, y, changed);
3328 changedLayout = changed || changedLayout;
3329 if(!QApplication::reverseLayout())
3330 item = next;
3331 w = qMax(w, item->x() + item->width());
3332 h = qMax(h, item->y() + item->height());
3333 item = next;
3334 if (d->arrangement == LeftToRight)
3335 h = qMax(h, y);
3336
3337 if (!item || !item->next)
3338 break;
3339
3340 item = item->next;
3341 }
3342
3343 if (d->lastItem && d->arrangement == TopToBottom) {
3344 item = d->lastItem;
3345 int x = item->x();
3346 while (item && item->x() >= x) {
3347 w = qMax(w, item->x() + item->width());
3348 h = qMax(h, item->y() + item->height());
3349 item = item->prev;
3350 }
3351 }
3352 d->containerUpdateLocked = false;
3353
3354 w = qMax(qMax(d->cachedW, w), d->lastItem->x() + d->lastItem->width());
3355 h = qMax(qMax(d->cachedH, h), d->lastItem->y() + d->lastItem->height());
3356
3357 if (d->arrangement == TopToBottom)
3358 w += d->spacing;
3359 else
3360 h += d->spacing;
3361
3362 bool ue = updatesEnabled();
3363 if (ue)
3364 viewport()->setUpdatesEnabled(false);
3365 int vw = visibleWidth();
3366 int vh = visibleHeight();
3367 resizeContents(w, h);
3368 bool doAgain = false;
3369 if (d->arrangement == LeftToRight)
3370 doAgain = visibleWidth() != vw;
3371 if (d->arrangement == TopToBottom)
3372 doAgain = visibleHeight() != vh;
3373 if (doAgain) // in the case that the visibleExtend changed because of the resizeContents (scroll bar show/hide), redo layout again
3374 arrangeItemsInGrid(false);
3375 if (ue)
3376 viewport()->setUpdatesEnabled(true);
3377 d->dirty = !isVisible();
3378 rebuildContainers();
3379 if (update && (!optimize_layout || changedLayout))
3380 repaintContents(contentsX(), contentsY(), viewport()->width(), viewport()->height());
3381}
3382
3383/*!
3384 This variant uses \a grid instead of (gridX(), gridY()). If \a
3385 grid is invalid (see QSize::isValid()), arrangeItemsInGrid()
3386 calculates a valid grid itself and uses that.
3387
3388 If \a update is true (the default) the viewport is repainted.
3389*/
3390
3391void Q3IconView::arrangeItemsInGrid(const QSize &grid, bool update)
3392{
3393 d->containerUpdateLocked = true;
3394 QSize grid_(grid);
3395 if (!grid_.isValid()) {
3396 int w = 0, h = 0;
3397 Q3IconViewItem *item = d->firstItem;
3398 for (; item; item = item->next) {
3399 w = qMax(w, item->width());
3400 h = qMax(h, item->height());
3401 }
3402
3403 grid_ = QSize(qMax(d->rastX + d->spacing, w),
3404 qMax(d->rastY + d->spacing, h));
3405 }
3406
3407 int w = 0, h = 0;
3408 Q3IconViewItem *item = d->firstItem;
3409 for (; item; item = item->next) {
3410 int nx = item->x() / grid_.width();
3411 int ny = item->y() / grid_.height();
3412 item->move(nx * grid_.width(),
3413 ny * grid_.height());
3414 w = qMax(w, item->x() + item->width());
3415 h = qMax(h, item->y() + item->height());
3416 item->dirty = false;
3417 }
3418 d->containerUpdateLocked = false;
3419
3420 resizeContents(w, h);
3421 rebuildContainers();
3422 if (update)
3423 repaintContents(contentsX(), contentsY(), viewport()->width(), viewport()->height());
3424}
3425
3426/*!
3427 \reimp
3428*/
3429
3430void Q3IconView::setContentsPos(int x, int y)
3431{
3432 if (d->updateTimer->isActive()) {
3433 d->cachedContentsX = x;
3434 d->cachedContentsY = y;
3435 } else {
3436 d->cachedContentsY = d->cachedContentsX = -1;
3437 Q3ScrollView::setContentsPos(x, y);
3438 }
3439}
3440
3441/*!
3442 \reimp
3443*/
3444
3445void Q3IconView::showEvent(QShowEvent *)
3446{
3447 if (d->dirty) {
3448 resizeContents(qMax(contentsWidth(), viewport()->width()),
3449 qMax(contentsHeight(), viewport()->height()));
3450 if (d->resortItemsWhenInsert)
3451 sort(d->sortDirection);
3452 if (autoArrange())
3453 arrangeItemsInGrid(false);
3454 }
3455 Q3ScrollView::show();
3456}
3457
3458/*!
3459 \property Q3IconView::selectionMode
3460 \brief the selection mode of the icon view
3461
3462 This can be \l Single (the default), \l Extended, \l Multi or \l
3463 NoSelection.
3464*/
3465
3466void Q3IconView::setSelectionMode(SelectionMode m)
3467{
3468 d->selectionMode = m;
3469}
3470
3471Q3IconView::SelectionMode Q3IconView::selectionMode() const
3472{
3473 return d->selectionMode;
3474}
3475
3476/*!
3477 Returns a pointer to the item that contains point \a pos, which is
3478 given in contents coordinates, or 0 if no item contains point \a
3479 pos.
3480*/
3481
3482Q3IconViewItem *Q3IconView::findItem(const QPoint &pos) const
3483{
3484 if (!d->firstItem)
3485 return 0;
3486
3487 Q3IconViewPrivate::ItemContainer *c = d->lastContainer;
3488 for (; c; c = c->p) {
3489 if (c->rect.contains(pos))
3490 for (int i = c->items.size()-1; i >= 0; --i)
3491 if (c->items.at(i)->contains(pos))
3492 return c->items.at(i);
3493 }
3494
3495 return 0;
3496}
3497
3498/*!
3499 \overload
3500
3501 Returns a pointer to the first item whose text begins with \a
3502 text, or 0 if no such item could be found. Use the \a compare flag
3503 to control the comparison behavior.
3504*/
3505
3506Q3IconViewItem *Q3IconView::findItem(const QString &text, ComparisonFlags compare) const
3507{
3508 if (!d->firstItem)
3509 return 0;
3510
3511 if (compare == CaseSensitive || compare == 0)
3512 compare |= ExactMatch;
3513
3514 QString itmtxt;
3515 QString comtxt = text;
3516 if (! (compare & CaseSensitive))
3517 comtxt = text.toLower();
3518
3519 Q3IconViewItem *item;
3520 if (d->currentItem)
3521 item = d->currentItem;
3522 else
3523 item = d->firstItem;
3524
3525 Q3IconViewItem *beginsWithItem = 0;
3526 Q3IconViewItem *endsWithItem = 0;
3527 Q3IconViewItem *containsItem = 0;
3528
3529 if (item) {
3530 for (; item; item = item->next) {
3531 if (!(compare & CaseSensitive))
3532 itmtxt = item->text().toLower();
3533 else
3534 itmtxt = item->text();
3535
3536 if ((compare & ExactMatch)==ExactMatch && itmtxt == comtxt)
3537 return item;
3538 if (compare & BeginsWith && !beginsWithItem && itmtxt.startsWith(comtxt))
3539 beginsWithItem = containsItem = item;
3540 if (compare & EndsWith && !endsWithItem && itmtxt.endsWith(comtxt))
3541 endsWithItem = containsItem = item;
3542 if ((compare & ExactMatch)==0 && !containsItem && itmtxt.contains(comtxt))
3543 containsItem = item;
3544 }
3545
3546 if (d->currentItem && d->firstItem) {
3547 item = d->firstItem;
3548 for (; item && item != d->currentItem; item = item->next) {
3549 if (!(compare & CaseSensitive))
3550 itmtxt = item->text().toLower();
3551 else
3552 itmtxt = item->text();
3553
3554 if ((compare & ExactMatch)==ExactMatch && itmtxt == comtxt)
3555 return item;
3556 if (compare & BeginsWith && !beginsWithItem && itmtxt.startsWith(comtxt))
3557 beginsWithItem = containsItem = item;
3558 if (compare & EndsWith && !endsWithItem && itmtxt.endsWith(comtxt))
3559 endsWithItem = containsItem = item;
3560 if ((compare & ExactMatch)==0 && !containsItem && itmtxt.contains(comtxt))
3561 containsItem = item;
3562 }
3563 }
3564 }
3565
3566 // Obey the priorities
3567 if (beginsWithItem)
3568 return beginsWithItem;
3569 else if (endsWithItem)
3570 return endsWithItem;
3571 else if (containsItem)
3572 return containsItem;
3573 return 0;
3574}
3575
3576/*!
3577 Unselects all the items.
3578*/
3579
3580void Q3IconView::clearSelection()
3581{
3582 selectAll(false);
3583}
3584
3585/*!
3586 In Multi and Extended modes, this function sets all items to be
3587 selected if \a select is true, and to be unselected if \a select
3588 is false.
3589
3590 In Single and NoSelection modes, this function only changes the
3591 selection status of currentItem().
3592*/
3593
3594void Q3IconView::selectAll(bool select)
3595{
3596 if (d->selectionMode == NoSelection)
3597 return;
3598
3599 if (d->selectionMode == Single) {
3600 if (d->currentItem)
3601 d->currentItem->setSelected(select);
3602 return;
3603 }
3604
3605 bool b = signalsBlocked();
3606 blockSignals(true);
3607 Q3IconViewItem *item = d->firstItem;
3608 Q3IconViewItem *i = d->currentItem;
3609 bool changed = false;
3610 bool ue = viewport()->updatesEnabled();
3611 if (ue)
3612 viewport()->setUpdatesEnabled(false);
3613 QRect rr;
3614 for (; item; item = item->next) {
3615 if (select != item->isSelected()) {
3616 item->setSelected(select, true);
3617 rr = rr.united(item->rect());
3618 changed = true;
3619 }
3620 }
3621 if (ue)
3622 viewport()->setUpdatesEnabled(true);
3623 // we call updateContents not repaintContents because of possible previous updateContents
3624 Q3ScrollView::updateContents(rr);
3625 QApplication::sendPostedEvents(viewport(), QEvent::Paint);
3626 if (i)
3627 setCurrentItem(i);
3628 blockSignals(b);
3629 if (changed) {
3630 emit selectionChanged();
3631 }
3632}
3633
3634/*!
3635 Inverts the selection. Works only in Multi and Extended selection
3636 mode.
3637*/
3638
3639void Q3IconView::invertSelection()
3640{
3641 if (d->selectionMode == Single ||
3642 d->selectionMode == NoSelection)
3643 return;
3644
3645 bool b = signalsBlocked();
3646 blockSignals(true);
3647 Q3IconViewItem *item = d->firstItem;
3648 for (; item; item = item->next)
3649 item->setSelected(!item->isSelected(), true);
3650 blockSignals(b);
3651 emit selectionChanged();
3652}
3653
3654/*!
3655 Repaints the \a item.
3656*/
3657
3658void Q3IconView::repaintItem(Q3IconViewItem *item)
3659{
3660 if (!item || item->dirty)
3661 return;
3662
3663 if (QRect(contentsX(), contentsY(), visibleWidth(), visibleHeight()).
3664 intersects(QRect(item->x() - 1, item->y() - 1, item->width() + 2, item->height() + 2)))
3665 repaintContents(item->x() - 1, item->y() - 1, item->width() + 2, item->height() + 2);
3666}
3667
3668/*!
3669 Repaints the selected items.
3670*/
3671void Q3IconView::repaintSelectedItems()
3672{
3673 if (selectionMode() == NoSelection)
3674 return;
3675
3676 if (selectionMode() == Single) {
3677 if (!currentItem() || !currentItem()->isSelected())
3678 return;
3679 QRect itemRect = currentItem()->rect(); //rect in contents coordinates
3680 itemRect.moveBy(-contentsX(), -contentsY());
3681 viewport()->update(itemRect);
3682 } else {
3683 // check if any selected items are visible
3684 Q3IconViewItem *item = firstItem();
3685 const QRect vr = QRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
3686
3687 while (item) {
3688 if (item->isSelected() && item->rect().intersects(vr))
3689 repaintItem(item);
3690 item = item->nextItem();
3691 }
3692 }
3693}
3694
3695/*!
3696 Makes sure that \a item is entirely visible. If necessary,
3697 ensureItemVisible() scrolls the icon view.
3698
3699 \sa ensureVisible()
3700*/
3701
3702void Q3IconView::ensureItemVisible(Q3IconViewItem *item)
3703{
3704 if (!item)
3705 return;
3706
3707 if ((d->updateTimer && d->updateTimer->isActive())
3708 || (d->fullRedrawTimer && d->fullRedrawTimer->isActive()))
3709 slotUpdate();
3710
3711 int w = item->width();
3712 int h = item->height();
3713 ensureVisible(item->x() + w / 2, item->y() + h / 2,
3714 w / 2 + 1, h / 2 + 1);
3715}
3716
3717/*!
3718 Finds the first item whose bounding rectangle overlaps \a r and
3719 returns a pointer to that item. \a r is given in content
3720 coordinates. Returns 0 if no item overlaps \a r.
3721
3722 If you want to find all items that touch \a r, you will need to
3723 use this function and nextItem() in a loop ending at
3724 findLastVisibleItem() and test Q3IconViewItem::rect() for each of
3725 these items.
3726
3727 \sa findLastVisibleItem() Q3IconViewItem::rect()
3728*/
3729
3730Q3IconViewItem* Q3IconView::findFirstVisibleItem(const QRect &r) const
3731{
3732 Q3IconViewPrivate::ItemContainer *c = d->firstContainer;
3733 Q3IconViewItem *i = 0;
3734 bool alreadyIntersected = false;
3735 for (; c; c = c->n) {
3736 if (c->rect.intersects(r)) {
3737 alreadyIntersected = true;
3738 for (int j = 0; j < c->items.size(); ++j) {
3739 Q3IconViewItem *item = c->items.at(j);
3740 if (r.intersects(item->rect())) {
3741 if (!i) {
3742 i = item;
3743 } else {
3744 QRect r2 = item->rect();
3745 QRect r3 = i->rect();
3746 if (r2.y() < r3.y())
3747 i = item;
3748 else if (r2.y() == r3.y() &&
3749 r2.x() < r3.x())
3750 i = item;
3751 }
3752 }
3753 }
3754 } else {
3755 if (alreadyIntersected)
3756 break;
3757 }
3758 }
3759
3760 return i;
3761}
3762
3763/*!
3764 Finds the last item whose bounding rectangle overlaps \a r and
3765 returns a pointer to that item. \a r is given in content
3766 coordinates. Returns 0 if no item overlaps \a r.
3767
3768 \sa findFirstVisibleItem()
3769*/
3770
3771Q3IconViewItem* Q3IconView::findLastVisibleItem(const QRect &r) const
3772{
3773 Q3IconViewPrivate::ItemContainer *c = d->firstContainer;
3774 Q3IconViewItem *i = 0;
3775 bool alreadyIntersected = false;
3776 for (; c; c = c->n) {
3777 if (c->rect.intersects(r)) {
3778 alreadyIntersected = true;
3779 for (int j = 0; j < c->items.size(); ++j) {
3780 Q3IconViewItem *item = c->items.at(j);
3781 if (r.intersects(item->rect())) {
3782 if (!i) {
3783 i = item;
3784 } else {
3785 QRect r2 = item->rect();
3786 QRect r3 = i->rect();
3787 if (r2.y() > r3.y())
3788 i = item;
3789 else if (r2.y() == r3.y() &&
3790 r2.x() > r3.x())
3791 i = item;
3792 }
3793 }
3794 }
3795 } else {
3796 if (alreadyIntersected)
3797 break;
3798 }
3799 }
3800
3801 return i;
3802}
3803
3804/*!
3805 Clears the icon view. All items are deleted.
3806*/
3807
3808void Q3IconView::clear()
3809{
3810 setContentsPos(0, 0);
3811 d->clearing = true;
3812 bool block = signalsBlocked();
3813 blockSignals(true);
3814 clearSelection();
3815 blockSignals(block);
3816 setContentsPos(0, 0);
3817 d->currentItem = 0;
3818
3819 if (!d->firstItem) {
3820 d->clearing = false;
3821 return;
3822 }
3823
3824 Q3IconViewItem *item = d->firstItem, *tmp;
3825 d->firstItem = 0;
3826 while (item) {
3827 tmp = item->next;
3828 delete item;
3829 item = tmp;
3830 }
3831 Q3IconViewPrivate::ItemContainer *c = d->firstContainer, *tmpc;
3832 while (c) {
3833 tmpc = c->n;
3834 delete c;
3835 c = tmpc;
3836 }
3837 d->firstContainer = d->lastContainer = 0;
3838
3839 d->count = 0;
3840 d->lastItem = 0;
3841 setCurrentItem(0);
3842 d->highlightedItem = 0;
3843 d->tmpCurrentItem = 0;
3844 d->drawDragShapes = false;
3845
3846 resizeContents(0, 0);
3847 // maybe we don't need this update, so delay it
3848 d->fullRedrawTimer->start(0, true);
3849
3850 d->cleared = true;
3851 d->clearing = false;
3852}
3853
3854/*!
3855 \property Q3IconView::gridX
3856 \brief the horizontal grid of the icon view
3857
3858 If the value is -1, (the default), Q3IconView computes suitable
3859 column widths based on the icon view's contents.
3860
3861 Note that setting a grid width overrides setMaxItemWidth().
3862*/
3863
3864void Q3IconView::setGridX(int rx)
3865{
3866 d->rastX = rx >= 0 ? rx : -1;
3867}
3868
3869/*!
3870 \property Q3IconView::gridY
3871 \brief the vertical grid of the icon view
3872
3873 If the value is -1, (the default), Q3IconView computes suitable
3874 column heights based on the icon view's contents.
3875*/
3876
3877void Q3IconView::setGridY(int ry)
3878{
3879 d->rastY = ry >= 0 ? ry : -1;
3880}
3881
3882int Q3IconView::gridX() const
3883{
3884 return d->rastX;
3885}
3886
3887int Q3IconView::gridY() const
3888{
3889 return d->rastY;
3890}
3891
3892/*!
3893 \property Q3IconView::spacing
3894 \brief the space in pixels between icon view items
3895
3896 The default is 5 pixels.
3897
3898 Negative values for spacing are illegal.
3899*/
3900
3901void Q3IconView::setSpacing(int sp)
3902{
3903 d->spacing = sp;
3904}
3905
3906int Q3IconView::spacing() const
3907{
3908 return d->spacing;
3909}
3910
3911/*!
3912 \property Q3IconView::itemTextPos
3913 \brief the position where the text of each item is drawn.
3914
3915 Valid values are \l Bottom or \l Right. The default is \l Bottom.
3916*/
3917
3918void Q3IconView::setItemTextPos(ItemTextPos pos)
3919{
3920 if (pos == d->itemTextPos || (pos != Bottom && pos != Right))
3921 return;
3922
3923 d->itemTextPos = pos;
3924
3925 Q3IconViewItem *item = d->firstItem;
3926 for (; item; item = item->next) {
3927 item->wordWrapDirty = true;
3928 item->calcRect();
3929 }
3930
3931 arrangeItemsInGrid(true);
3932}
3933
3934Q3IconView::ItemTextPos Q3IconView::itemTextPos() const
3935{
3936 return d->itemTextPos;
3937}
3938
3939/*!
3940 \property Q3IconView::itemTextBackground
3941 \brief the brush to use when drawing the background of an item's text.
3942
3943 By default this brush is set to Qt::NoBrush, meaning that only the
3944 normal icon view background is used.
3945*/
3946
3947void Q3IconView::setItemTextBackground(const QBrush &brush)
3948{
3949 d->itemTextBrush = brush;
3950}
3951
3952QBrush Q3IconView::itemTextBackground() const
3953{
3954 return d->itemTextBrush;
3955}
3956
3957/*!
3958 \property Q3IconView::arrangement
3959 \brief the arrangement mode of the icon view
3960
3961 This can be \l LeftToRight or \l TopToBottom. The default is \l
3962 LeftToRight.
3963*/
3964
3965void Q3IconView::setArrangement(Arrangement am)
3966{
3967 if (d->arrangement == am)
3968 return;
3969
3970 d->arrangement = am;
3971
3972 viewport()->setUpdatesEnabled(false);
3973 resizeContents(viewport()->width(), viewport()->height());
3974 viewport()->setUpdatesEnabled(true);
3975 arrangeItemsInGrid(true);
3976}
3977
3978Q3IconView::Arrangement Q3IconView::arrangement() const
3979{
3980 return d->arrangement;
3981}
3982
3983/*!
3984 \property Q3IconView::resizeMode
3985 \brief the resize mode of the icon view
3986
3987 This can be \l Fixed or \l Adjust. The default is \l Fixed.
3988 See \l ResizeMode.
3989*/
3990
3991void Q3IconView::setResizeMode(ResizeMode rm)
3992{
3993 if (d->resizeMode == rm)
3994 return;
3995
3996 d->resizeMode = rm;
3997}
3998
3999Q3IconView::ResizeMode Q3IconView::resizeMode() const
4000{
4001 return d->resizeMode;
4002}
4003
4004/*!
4005 \property Q3IconView::maxItemWidth
4006 \brief the maximum width that an item may have.
4007
4008 The default is 100 pixels.
4009
4010 Note that if the gridX() value is set Q3IconView will ignore
4011 this property.
4012*/
4013
4014void Q3IconView::setMaxItemWidth(int w)
4015{
4016 d->maxItemWidth = w;
4017}
4018
4019/*!
4020 \property Q3IconView::maxItemTextLength
4021 \brief the maximum length (in characters) that an item's text may have.
4022
4023 The default is 255 characters.
4024*/
4025
4026void Q3IconView::setMaxItemTextLength(int w)
4027{
4028 d->maxItemTextLength = w;
4029}
4030
4031int Q3IconView::maxItemWidth() const
4032{
4033 if (d->rastX != -1)
4034 return d->rastX - 2;
4035 else
4036 return d->maxItemWidth;
4037}
4038
4039int Q3IconView::maxItemTextLength() const
4040{
4041 return d->maxItemTextLength;
4042}
4043
4044/*!
4045 \property Q3IconView::itemsMovable
4046 \brief whether the user is allowed to move items around in the icon view
4047
4048 The default is true.
4049*/
4050
4051void Q3IconView::setItemsMovable(bool b)
4052{
4053 d->rearrangeEnabled = b;
4054}
4055
4056bool Q3IconView::itemsMovable() const
4057{
4058 return d->rearrangeEnabled;
4059}
4060
4061/*!
4062 \property Q3IconView::autoArrange
4063 \brief whether the icon view rearranges its items when a new item is inserted.
4064
4065 The default is true.
4066
4067 Note that if the icon view is not visible at the time of
4068 insertion, Q3IconView defers all position-related work until it is
4069 shown and then calls arrangeItemsInGrid().
4070*/
4071
4072void Q3IconView::setAutoArrange(bool b)
4073{
4074 d->reorderItemsWhenInsert = b;
4075}
4076
4077bool Q3IconView::autoArrange() const
4078{
4079 return d->reorderItemsWhenInsert;
4080}
4081
4082/*!
4083 If \a sort is true, this function sets the icon view to sort items
4084 when a new item is inserted. If \a sort is false, the icon view
4085 will not be sorted.
4086
4087 Note that autoArrange() must be true for sorting to take place.
4088
4089 If \a ascending is true (the default), items are sorted in
4090 ascending order. If \a ascending is false, items are sorted in
4091 descending order.
4092
4093 Q3IconViewItem::compare() is used to compare pairs of items. The
4094 sorting is based on the items' keys; these default to the items'
4095 text unless specifically set to something else.
4096
4097 \sa Q3IconView::setAutoArrange(), Q3IconView::autoArrange(),
4098 sortDirection(), sort(), Q3IconViewItem::setKey()
4099*/
4100
4101void Q3IconView::setSorting(bool sort, bool ascending)
4102{
4103 d->resortItemsWhenInsert = sort;
4104 d->sortDirection = ascending;
4105}
4106
4107/*!
4108 \property Q3IconView::sorting
4109 \brief whether the icon view sorts on insertion
4110
4111 The default is false, i.e. no sorting on insertion.
4112
4113 To set the sorting, use setSorting().
4114*/
4115
4116bool Q3IconView::sorting() const
4117{
4118 return d->resortItemsWhenInsert;
4119}
4120
4121/*!
4122 \property Q3IconView::sortDirection
4123 \brief whether the sort direction for inserting new items is ascending;
4124
4125 The default is true (i.e. ascending). This sort direction is only
4126 meaningful if both sorting() and autoArrange() are true.
4127
4128 To set the sort direction, use setSorting()
4129*/
4130
4131bool Q3IconView::sortDirection() const
4132{
4133 return d->sortDirection;
4134}
4135
4136/*!
4137 \property Q3IconView::wordWrapIconText
4138 \brief whether the item text will be word-wrapped if it is too long
4139
4140 The default is true.
4141
4142 If this property is false, icon text that is too long is
4143 truncated, and an ellipsis (...) appended to indicate that
4144 truncation has occurred. The full text can still be seen by the
4145 user if they hover the mouse because the full text is shown in a
4146 tooltip; see setShowToolTips().
4147*/
4148
4149void Q3IconView::setWordWrapIconText(bool b)
4150{
4151 if (d->wordWrapIconText == (uint)b)
4152 return;
4153
4154 d->wordWrapIconText = b;
4155 for (Q3IconViewItem *item = d->firstItem; item; item = item->next) {
4156 item->wordWrapDirty = true;
4157 item->calcRect();
4158 }
4159 arrangeItemsInGrid(true);
4160}
4161
4162bool Q3IconView::wordWrapIconText() const
4163{
4164 return d->wordWrapIconText;
4165}
4166
4167/*!
4168 \property Q3IconView::showToolTips
4169 \brief whether the icon view will display a tool tip with the complete text for any truncated item text
4170
4171 The default is true. Note that this has no effect if
4172 setWordWrapIconText() is true, as it is by default.
4173*/
4174
4175void Q3IconView::setShowToolTips(bool b)
4176{
4177 d->showTips = b;
4178}
4179
4180bool Q3IconView::showToolTips() const
4181{
4182 return d->showTips;
4183}
4184
4185/*!
4186 \reimp
4187*/
4188void Q3IconView::contentsMousePressEvent(QMouseEvent *e)
4189{
4190 contentsMousePressEventEx(e);
4191}
4192
4193void Q3IconView::contentsMousePressEventEx(QMouseEvent *e)
4194{
4195 if (d->rubber) {
4196 d->dragging = false;
4197 delete d->rubber;
4198 d->rubber = 0;
4199 viewport()->update();
4200
4201 if (d->scrollTimer) {
4202 disconnect(d->scrollTimer, SIGNAL(timeout()), this, SLOT(doAutoScroll()));
4203 d->scrollTimer->stop();
4204 delete d->scrollTimer;
4205 d->scrollTimer = 0;
4206 }
4207 }
4208
4209 d->dragStartPos = e->pos();
4210 Q3IconViewItem *item = findItem(e->pos());
4211 d->pressedItem = item;
4212
4213 if (item)
4214 d->selectAnchor = item;
4215
4216#ifndef QT_NO_TEXTEDIT
4217 if (d->renamingItem)
4218 d->renamingItem->renameItem();
4219#endif
4220
4221 if (!d->currentItem && !item && d->firstItem) {
4222 d->currentItem = d->firstItem;
4223 repaintItem(d->firstItem);
4224 }
4225
4226 if (item && item->dragEnabled())
4227 d->startDragItem = item;
4228 else
4229 d->startDragItem = 0;
4230
4231 if (e->button() == Qt::LeftButton && !(e->state() & Qt::ShiftButton) &&
4232 !(e->state() & Qt::ControlButton) && item && item->isSelected() &&
4233 item->textRect(false).contains(e->pos())) {
4234
4235 if (!item->renameEnabled()) {
4236 d->mousePressed = true;
4237#ifndef QT_NO_TEXTEDIT
4238 } else {
4239 ensureItemVisible(item);
4240 setCurrentItem(item);
4241 item->rename();
4242 goto emit_signals;
4243#endif
4244 }
4245 }
4246
4247 d->pressedSelected = item && item->isSelected();
4248
4249 if (item && item->isSelectable()) {
4250 if (d->selectionMode == Single)
4251 item->setSelected(true, e->state() & Qt::ControlButton);
4252 else if (d->selectionMode == Multi && !item->isSelected())
4253 item->setSelected(true, e->state() & Qt::ControlButton);
4254 else if (d->selectionMode == Extended) {
4255 if (e->state() & Qt::ShiftButton) {
4256 d->pressedSelected = false;
4257 bool block = signalsBlocked();
4258 blockSignals(true);
4259 viewport()->setUpdatesEnabled(false);
4260 QRect r;
4261 bool select = true;
4262 if (d->currentItem)
4263 r = QRect(qMin(d->currentItem->x(), item->x()),
4264 qMin(d->currentItem->y(), item->y()),
4265 0, 0);
4266 else
4267 r = QRect(0, 0, 0, 0);
4268 if (d->currentItem) {
4269 if (d->currentItem->x() < item->x())
4270 r.setWidth(item->x() - d->currentItem->x() + item->width());
4271 else
4272 r.setWidth(d->currentItem->x() - item->x() + d->currentItem->width());
4273 if (d->currentItem->y() < item->y())
4274 r.setHeight(item->y() - d->currentItem->y() + item->height());
4275 else
4276 r.setHeight(d->currentItem->y() - item->y() + d->currentItem->height());
4277 r = r.normalized();
4278 Q3IconViewPrivate::ItemContainer *c = d->firstContainer;
4279 bool alreadyIntersected = false;
4280 QRect redraw;
4281 for (; c; c = c->n) {
4282 if (c->rect.intersects(r)) {
4283 alreadyIntersected = true;
4284 for (int i = 0; i < c->items.size(); ++i) {
4285 Q3IconViewItem *item = c->items.at(i);
4286 if (r.intersects(item->rect())) {
4287 redraw = redraw.united(item->rect());
4288 item->setSelected(select, true);
4289 }
4290 }
4291 } else {
4292 if (alreadyIntersected)
4293 break;
4294 }
4295 }
4296 redraw = redraw.united(item->rect());
4297 viewport()->setUpdatesEnabled(true);
4298 repaintContents(redraw);
4299 }
4300 blockSignals(block);
4301 viewport()->setUpdatesEnabled(true);
4302 item->setSelected(select, true);
4303 emit selectionChanged();
4304 } else if (e->state() & Qt::ControlButton) {
4305 d->pressedSelected = false;
4306 item->setSelected(!item->isSelected(), e->state() & Qt::ControlButton);
4307 } else {
4308 item->setSelected(true, e->state() & Qt::ControlButton);
4309 }
4310 }
4311 } else if ((d->selectionMode != Single || e->button() == Qt::RightButton)
4312 && !(e->state() & Qt::ControlButton))
4313 selectAll(false);
4314
4315 setCurrentItem(item);
4316
4317 if (e->button() == Qt::LeftButton) {
4318 if (!item && (d->selectionMode == Multi ||
4319 d->selectionMode == Extended)) {
4320 d->tmpCurrentItem = d->currentItem;
4321 d->currentItem = 0;
4322 repaintItem(d->tmpCurrentItem);
4323 if (d->rubber)
4324 delete d->rubber;
4325 d->rubber = 0;
4326 d->rubber = new QRect(e->x(), e->y(), 0, 0);
4327 d->selectedItems.clear();
4328 if ((e->state() & Qt::ControlButton) == Qt::ControlButton) {
4329 for (Q3IconViewItem *i = firstItem(); i; i = i->nextItem())
4330 if (i->isSelected())
4331 d->selectedItems.insert(i, i);
4332 }
4333 }
4334
4335 d->mousePressed = true;
4336 }
4337
4338 emit_signals:
4339 if (!d->rubber) {
4340 emit mouseButtonPressed(e->button(), item, e->globalPos());
4341 emit pressed(item);
4342 emit pressed(item, e->globalPos());
4343
4344 if (e->button() == Qt::RightButton)
4345 emit rightButtonPressed(item, e->globalPos());
4346 }
4347}
4348
4349/*!
4350 \reimp
4351*/
4352
4353void Q3IconView::contentsContextMenuEvent(QContextMenuEvent *e)
4354{
4355 if (!receivers(SIGNAL(contextMenuRequested(Q3IconViewItem*,QPoint)))) {
4356 e->ignore();
4357 return;
4358 }
4359 if (e->reason() == QContextMenuEvent::Keyboard) {
4360 Q3IconViewItem *item = currentItem();
4361 QRect r = item ? item->rect() : QRect(0, 0, visibleWidth(), visibleHeight());
4362 emit contextMenuRequested(item, viewport()->mapToGlobal(contentsToViewport(r.center())));
4363 } else {
4364 d->mousePressed = false;
4365 Q3IconViewItem *item = findItem(e->pos());
4366 emit contextMenuRequested(item, e->globalPos());
4367 }
4368}
4369
4370/*!
4371 \reimp
4372*/
4373
4374void Q3IconView::contentsMouseReleaseEvent(QMouseEvent *e)
4375{
4376 Q3IconViewItem *item = findItem(e->pos());
4377 d->selectedItems.clear();
4378
4379 bool emitClicked = true;
4380 d->mousePressed = false;
4381 d->startDragItem = 0;
4382
4383 if (d->rubber) {
4384 d->dragging = false;
4385 viewport()->update();
4386
4387 if ((d->rubber->topLeft() - d->rubber->bottomRight()).manhattanLength() >
4388 QApplication::startDragDistance())
4389 emitClicked = false;
4390 delete d->rubber;
4391 d->rubber = 0;
4392 d->currentItem = d->tmpCurrentItem;
4393 d->tmpCurrentItem = 0;
4394 if (d->currentItem)
4395 repaintItem(d->currentItem);
4396 }
4397
4398 if (d->scrollTimer) {
4399 disconnect(d->scrollTimer, SIGNAL(timeout()), this, SLOT(doAutoScroll()));
4400 d->scrollTimer->stop();
4401 delete d->scrollTimer;
4402 d->scrollTimer = 0;
4403 }
4404
4405 if ((d->selectionMode == Extended || d->selectionMode == Multi) &&
4406 d->currentItem == d->pressedItem &&
4407 d->pressedSelected && d->currentItem) {
4408 if (d->selectionMode == Extended) {
4409 bool block = signalsBlocked();
4410 blockSignals(true);
4411 clearSelection();
4412 blockSignals(block);
4413 }
4414 if (d->currentItem->isSelectable()) {
4415 d->currentItem->selected = (d->selectionMode == Extended);
4416 repaintItem(d->currentItem);
4417 }
4418 emit selectionChanged();
4419 }
4420 d->pressedItem = 0;
4421
4422 if (emitClicked) {
4423 emit mouseButtonClicked(e->button(), item, e->globalPos());
4424 emit clicked(item);
4425 emit clicked(item, e->globalPos());
4426 if (e->button() == Qt::RightButton)
4427 emit rightButtonClicked(item, e->globalPos());
4428 }
4429}
4430
4431/*!
4432 \reimp
4433*/
4434
4435void Q3IconView::contentsMouseMoveEvent(QMouseEvent *e)
4436{
4437 Q3IconViewItem *item = findItem(e->pos());
4438 if (d->highlightedItem != item) {
4439 if (item)
4440 emit onItem(item);
4441 else
4442 emit onViewport();
4443 d->highlightedItem = item;
4444 }
4445
4446 if (d->mousePressed && e->state() == Qt::NoButton)
4447 d->mousePressed = false;
4448
4449 if (d->startDragItem)
4450 item = d->startDragItem;
4451
4452 if (d->mousePressed && d->startDragItem && item && item == d->currentItem &&
4453 (item->isSelected() || d->selectionMode == NoSelection) && item->dragEnabled()) {
4454 if ((d->dragStartPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) {
4455 d->mousePressed = false;
4456 d->cleared = false;
4457#ifndef QT_NO_DRAGANDDROP
4458 startDrag();
4459#endif
4460 if (d->tmpCurrentItem)
4461 repaintItem(d->tmpCurrentItem);
4462 }
4463 } else if (d->mousePressed && !d->currentItem && d->rubber) {
4464 doAutoScroll();
4465 }
4466}
4467
4468/*!
4469 \reimp
4470*/
4471
4472void Q3IconView::contentsMouseDoubleClickEvent(QMouseEvent *e)
4473{
4474 Q3IconViewItem *item = findItem(e->pos());
4475 if (item) {
4476 selectAll(false);
4477 item->setSelected(true, true);
4478 emit doubleClicked(item);
4479 }
4480}
4481
4482/*!
4483 \reimp
4484*/
4485
4486#ifndef QT_NO_DRAGANDDROP
4487void Q3IconView::contentsDragEnterEvent(QDragEnterEvent *e)
4488{
4489 d->dragging = true;
4490 d->drawDragShapes = true;
4491 d->tmpCurrentItem = 0;
4492 initDragEnter(e);
4493 d->oldDragPos = e->pos();
4494 d->oldDragAcceptAction = false;
4495 drawDragShapes(e->pos());
4496 d->dropped = false;
4497 e->accept();
4498}
4499
4500/*!
4501 \reimp
4502*/
4503
4504void Q3IconView::contentsDragMoveEvent(QDragMoveEvent *e)
4505{
4506 if (e->pos() == d->oldDragPos) {
4507 if (d->oldDragAcceptAction)
4508 e->acceptAction();
4509 else
4510 e->ignore();
4511 return;
4512 }
4513
4514 drawDragShapes(d->oldDragPos);
4515 d->dragging = false;
4516
4517 Q3IconViewItem *old = d->tmpCurrentItem;
4518 d->tmpCurrentItem = 0;
4519
4520 Q3IconViewItem *item = findItem(e->pos());
4521
4522 if (item) {
4523 if (old &&
4524 old->rect().contains(d->oldDragPos) &&
4525 !old->rect().contains(e->pos())) {
4526 old->dragLeft();
4527 repaintItem(old);
4528 }
4529 if (!item->rect().contains(d->oldDragPos))
4530 item->dragEntered();
4531 if (item->acceptDrop(e) || (item->isSelected() && e->source() == viewport())) {
4532 d->oldDragAcceptAction = true;
4533 e->acceptAction();
4534 } else {
4535 d->oldDragAcceptAction = false;
4536 e->ignore();
4537 }
4538
4539 d->tmpCurrentItem = item;
4540 viewport()->update();
4541 } else {
4542 e->acceptAction();
4543 d->oldDragAcceptAction = true;
4544 if (old) {
4545 old->dragLeft();
4546 repaintItem(old);
4547 }
4548 }
4549
4550 d->oldDragPos = e->pos();
4551 drawDragShapes(e->pos());
4552 d->dragging = true;
4553}
4554
4555/*!
4556 \reimp
4557*/
4558
4559void Q3IconView::contentsDragLeaveEvent(QDragLeaveEvent *)
4560{
4561 if (!d->dropped)
4562 drawDragShapes(d->oldDragPos);
4563 d->dragging = false;
4564
4565 if (d->tmpCurrentItem) {
4566 repaintItem(d->tmpCurrentItem);
4567 d->tmpCurrentItem->dragLeft();
4568 }
4569
4570 d->tmpCurrentItem = 0;
4571 d->isIconDrag = false;
4572 d->iconDragData.clear();
4573}
4574
4575/*!
4576 \reimp
4577*/
4578
4579void Q3IconView::contentsDropEvent(QDropEvent *e)
4580{
4581 d->dropped = true;
4582 d->dragging = false;
4583 drawDragShapes(d->oldDragPos);
4584
4585 if (d->tmpCurrentItem)
4586 repaintItem(d->tmpCurrentItem);
4587
4588 Q3IconViewItem *i = findItem(e->pos());
4589
4590 if ((!i || i->isSelected()) && e->source() == viewport() && d->currentItem && !d->cleared) {
4591 if (!d->rearrangeEnabled)
4592 return;
4593 QRect r = d->currentItem->rect();
4594
4595 d->currentItem->move(e->pos() - d->dragStart);
4596
4597 int w = d->currentItem->x() + d->currentItem->width() + 1;
4598 int h = d->currentItem->y() + d->currentItem->height() + 1;
4599
4600 repaintItem(d->currentItem);
4601 repaintContents(r.x(), r.y(), r.width(), r.height());
4602
4603 int dx = d->currentItem->x() - r.x();
4604 int dy = d->currentItem->y() - r.y();
4605
4606 Q3IconViewItem *item = d->firstItem;
4607 QRect rr;
4608 for (; item; item = item->next) {
4609 if (item->isSelected() && item != d->currentItem) {
4610 rr = rr.united(item->rect());
4611 item->moveBy(dx, dy);
4612 rr = rr.united(item->rect());
4613 }
4614 w = qMax(w, item->x() + item->width() + 1);
4615 h = qMax(h, item->y() + item->height() + 1);
4616 }
4617 repaintContents(rr);
4618 bool fullRepaint = false;
4619 if (w > contentsWidth() ||
4620 h > contentsHeight())
4621 fullRepaint = true;
4622
4623 int oldw = contentsWidth();
4624 int oldh = contentsHeight();
4625
4626 resizeContents(w, h);
4627
4628
4629 if (fullRepaint) {
4630 repaintContents(oldw, 0, contentsWidth() - oldw, contentsHeight());
4631 repaintContents(0, oldh, contentsWidth(), contentsHeight() - oldh);
4632 }
4633 e->acceptAction();
4634 } else if (!i && (e->source() != viewport() || d->cleared)) {
4635 QLinkedList<Q3IconDragItem> lst;
4636 if (Q3IconDrag::canDecode(e)) {
4637 QLinkedList<Q3IconDragDataItem> l;
4638 Q3IconDragPrivate::decode(e, l);
4639 QLinkedList<Q3IconDragDataItem>::Iterator it = l.begin();
4640 for (; it != l.end(); ++it)
4641 lst << (*it).data;
4642 }
4643 emit dropped(e, lst);
4644 } else if (i) {
4645 QLinkedList<Q3IconDragItem> lst;
4646 if (Q3IconDrag::canDecode(e)) {
4647 QLinkedList<Q3IconDragDataItem> l;
4648 Q3IconDragPrivate::decode(e, l);
4649 QLinkedList<Q3IconDragDataItem>::Iterator it = l.begin();
4650 for (; it != l.end(); ++it)
4651 lst << (*it).data;
4652 }
4653 i->dropped(e, lst);
4654 }
4655 d->isIconDrag = false;
4656}
4657#endif
4658
4659/*!
4660 \reimp
4661*/
4662
4663void Q3IconView::resizeEvent(QResizeEvent* e)
4664{
4665 Q3ScrollView::resizeEvent(e);
4666 if (d->resizeMode == Adjust) {
4667 optimize_layout = true;
4668 adjustItems();
4669 optimize_layout = false;
4670#if 0 // no need for timer delay anymore
4671 d->oldSize = e->oldSize();
4672 if (d->adjustTimer->isActive())
4673 d->adjustTimer->stop();
4674 d->adjustTimer->start(0, true);
4675#endif
4676 }
4677}
4678
4679/*!
4680 Adjusts the positions of the items to the geometry of the icon
4681 view.
4682*/
4683
4684void Q3IconView::adjustItems()
4685{
4686 d->adjustTimer->stop();
4687 if (d->resizeMode == Adjust)
4688 arrangeItemsInGrid(true);
4689}
4690
4691/*!
4692 \reimp
4693*/
4694
4695void Q3IconView::keyPressEvent(QKeyEvent *e)
4696{
4697 if (!d->firstItem)
4698 return;
4699
4700 if (!d->currentItem) {
4701 setCurrentItem(d->firstItem);
4702 if (d->selectionMode == Single)
4703 d->currentItem->setSelected(true, true);
4704 return;
4705 }
4706
4707 bool selectCurrent = true;
4708
4709 switch (e->key()) {
4710 case Qt::Key_Escape:
4711 e->ignore();
4712 break;
4713#ifndef QT_NO_TEXTEDIT
4714 case Qt::Key_F2: {
4715 if (d->currentItem->renameEnabled()) {
4716 d->currentItem->renameItem();
4717 d->currentItem->rename();
4718 return;
4719 }
4720 } break;
4721#endif
4722 case Qt::Key_Home: {
4723 d->currInputString.clear();
4724 if (!d->firstItem)
4725 break;
4726
4727 selectCurrent = false;
4728
4729 Q3IconViewItem *item = 0;
4730 Q3IconViewPrivate::ItemContainer *c = d->firstContainer;
4731 while (!item && c) {
4732 QList<Q3IconViewItem*> &list = c->items;
4733 for (int j = 0; j < list.size(); ++j) {
4734 Q3IconViewItem *i = list.at(j);
4735 if (!item) {
4736 item = i;
4737 } else {
4738 if (d->arrangement == LeftToRight) {
4739 // we use pixmap so the items textlength are ignored
4740 // find topmost, leftmost item
4741 if (i->pixmapRect(false).y() < item->pixmapRect(false).y() ||
4742 (i->pixmapRect(false).y() == item->pixmapRect(false).y() &&
4743 i->pixmapRect(false).x() < item->pixmapRect(false).x()))
4744 item = i;
4745 } else {
4746 // find leftmost, topmost item
4747 if (i->pixmapRect(false).x() < item->pixmapRect(false).x() ||
4748 (i->pixmapRect(false).x() == item->pixmapRect(false).x() &&
4749 i->pixmapRect(false).y() < item->pixmapRect(false).y()))
4750 item = i;
4751 }
4752 }
4753 }
4754 c = c->n;
4755 }
4756
4757 if (item) {
4758 Q3IconViewItem *old = d->currentItem;
4759 setCurrentItem(item);
4760 ensureItemVisible(item);
4761 handleItemChange(old, e->state() & Qt::ShiftButton,
4762 e->state() & Qt::ControlButton, true);
4763 }
4764 } break;
4765 case Qt::Key_End: {
4766 d->currInputString.clear();
4767 if (!d->lastItem)
4768 break;
4769
4770 selectCurrent = false;
4771
4772 Q3IconViewItem *item = 0;
4773 Q3IconViewPrivate::ItemContainer *c = d->lastContainer;
4774 while (!item && c) {
4775 QList<Q3IconViewItem*> &list = c->items;
4776 for (int j = 0; j < list.size(); ++j) {
4777 Q3IconViewItem *i = list.at(j);
4778 if (!item) {
4779 item = i;
4780 } else {
4781 if (d->arrangement == LeftToRight) {
4782 // find bottommost, rightmost item
4783 if (i->pixmapRect(false).bottom() > item->pixmapRect(false).bottom() ||
4784 (i->pixmapRect(false).bottom() == item->pixmapRect(false).bottom() &&
4785 i->pixmapRect(false).right() > item->pixmapRect(false).right()))
4786 item = i;
4787 } else {
4788 // find rightmost, bottommost item
4789 if (i->pixmapRect(false).right() > item->pixmapRect(false).right() ||
4790 (i->pixmapRect(false).right() == item->pixmapRect(false).right() &&
4791 i->pixmapRect(false).bottom() > item->pixmapRect(false).bottom()))
4792 item = i;
4793 }
4794 }
4795 }
4796 c = c->p;
4797 }
4798
4799 if (item) {
4800 Q3IconViewItem *old = d->currentItem;
4801 setCurrentItem(item);
4802 ensureItemVisible(item);
4803 handleItemChange(old, e->state() & Qt::ShiftButton,
4804 e->state() & Qt::ControlButton, true);
4805 }
4806 } break;
4807 case Qt::Key_Right: {
4808 d->currInputString.clear();
4809 Q3IconViewItem *item;
4810 selectCurrent = false;
4811 Direction dir = DirRight;
4812
4813 QRect r(0, d->currentItem->y(), contentsWidth(), d->currentItem->height());
4814 item = findItem(dir, d->currentItem->rect().center(), r);
4815
4816 // search the row below from the right
4817 while (!item && r.y() < contentsHeight()) {
4818 r.moveBy(0, d->currentItem->height());
4819 item = findItem(dir, QPoint(0, r.center().y()), r);
4820 }
4821
4822 if (item) {
4823 Q3IconViewItem *old = d->currentItem;
4824 setCurrentItem(item);
4825 ensureItemVisible(item);
4826 handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
4827 }
4828 } break;
4829 case Qt::Key_Left: {
4830 d->currInputString.clear();
4831 Q3IconViewItem *item;
4832 selectCurrent = false;
4833 Direction dir = DirLeft;
4834
4835 QRect r(0, d->currentItem->y(), contentsWidth(), d->currentItem->height());
4836 item = findItem(dir, d->currentItem->rect().center(), r);
4837
4838 // search the row above from the left
4839 while (!item && r.y() >= 0) {
4840 r.moveBy(0, - d->currentItem->height());
4841 item = findItem(dir, QPoint(contentsWidth(), r.center().y()), r);
4842 }
4843
4844 if (item) {
4845 Q3IconViewItem *old = d->currentItem;
4846 setCurrentItem(item);
4847 ensureItemVisible(item);
4848 handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
4849 }
4850 } break;
4851 case Qt::Key_Space: {
4852 d->currInputString.clear();
4853 if (d->selectionMode == Single)
4854 break;
4855
4856 d->currentItem->setSelected(!d->currentItem->isSelected(), true);
4857 } break;
4858 case Qt::Key_Enter: case Qt::Key_Return:
4859 d->currInputString.clear();
4860 emit returnPressed(d->currentItem);
4861 break;
4862 case Qt::Key_Down: {
4863 d->currInputString.clear();
4864 Q3IconViewItem *item;
4865 selectCurrent = false;
4866 Direction dir = DirDown;
4867
4868 QRect r(d->currentItem->x(), 0, d->currentItem->width(), contentsHeight());
4869 item = findItem(dir, d->currentItem->rect().center(), r);
4870
4871 // finding the closest item below and to the right
4872 while (!item && r.x() < contentsWidth()) {
4873 r.moveBy(r.width() , 0);
4874 item = findItem(dir, QPoint(r.center().x(), 0), r);
4875 }
4876
4877
4878 Q3IconViewItem *i = d->currentItem;
4879 setCurrentItem(item);
4880 item = i;
4881 handleItemChange(item, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
4882 } break;
4883 case Qt::Key_Up: {
4884 d->currInputString.clear();
4885 Q3IconViewItem *item;
4886 selectCurrent = false;
4887 Direction dir = DirUp;
4888
4889 QRect r(d->currentItem->x(), 0, d->currentItem->width(), contentsHeight());
4890 item = findItem(dir, d->currentItem->rect().center(), r);
4891
4892 // finding the closest item above and to the left
4893 while (!item && r.x() >= 0) {
4894 r.moveBy(- r.width(), 0);
4895 item = findItem(dir, QPoint(r.center().x(), contentsHeight()), r);
4896 }
4897
4898 Q3IconViewItem *i = d->currentItem;
4899 setCurrentItem(item);
4900 item = i;
4901 handleItemChange(item, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
4902 } break;
4903 case Qt::Key_Next: {
4904 d->currInputString.clear();
4905 selectCurrent = false;
4906 QRect r;
4907 if (d->arrangement == LeftToRight)
4908 r = QRect(0, d->currentItem->y() + visibleHeight(), contentsWidth(), visibleHeight());
4909 else
4910 r = QRect(d->currentItem->x() + visibleWidth(), 0, visibleWidth(), contentsHeight());
4911 Q3IconViewItem *item = d->currentItem;
4912 Q3IconViewItem *ni = findFirstVisibleItem(r );
4913 if (!ni) {
4914 if (d->arrangement == LeftToRight)
4915 r = QRect(0, d->currentItem->y() + d->currentItem->height(), contentsWidth(), contentsHeight());
4916 else
4917 r = QRect(d->currentItem->x() + d->currentItem->width(), 0, contentsWidth(), contentsHeight());
4918 ni = findLastVisibleItem(r );
4919 }
4920 if (ni) {
4921 setCurrentItem(ni);
4922 handleItemChange(item, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
4923 }
4924 } break;
4925 case Qt::Key_Prior: {
4926 d->currInputString.clear();
4927 selectCurrent = false;
4928 QRect r;
4929 if (d->arrangement == LeftToRight)
4930 r = QRect(0, d->currentItem->y() - visibleHeight(), contentsWidth(), visibleHeight());
4931 else
4932 r = QRect(d->currentItem->x() - visibleWidth(), 0, visibleWidth(), contentsHeight());
4933 Q3IconViewItem *item = d->currentItem;
4934 Q3IconViewItem *ni = findFirstVisibleItem(r );
4935 if (!ni) {
4936 if (d->arrangement == LeftToRight)
4937 r = QRect(0, 0, contentsWidth(), d->currentItem->y());
4938 else
4939 r = QRect(0, 0, d->currentItem->x(), contentsHeight());
4940 ni = findFirstVisibleItem(r );
4941 }
4942 if (ni) {
4943 setCurrentItem(ni);
4944 handleItemChange(item, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
4945 }
4946 } break;
4947 default:
4948 if (!e->text().isEmpty() && e->text()[0].isPrint()) {
4949 selectCurrent = false;
4950 Q3IconViewItem *i = d->currentItem;
4951 if (!i)
4952 i = d->firstItem;
4953 if (!d->inputTimer->isActive()) {
4954 d->currInputString = e->text();
4955 i = i->next;
4956 if (!i)
4957 i = d->firstItem;
4958 i = findItemByName(i);
4959 } else {
4960 d->inputTimer->stop();
4961 d->currInputString += e->text();
4962 i = findItemByName(i);
4963 if (!i) {
4964 d->currInputString = e->text();
4965 if (d->currentItem && d->currentItem->next)
4966 i = d->currentItem->next;
4967 else
4968 i = d->firstItem;
4969 i = findItemByName(i);
4970 }
4971 }
4972 if (i) {
4973 setCurrentItem(i);
4974 if (d->selectionMode == Extended) {
4975 bool changed = false;
4976 bool block = signalsBlocked();
4977 blockSignals(true);
4978 selectAll(false);
4979 blockSignals(block);
4980 if (!i->selected && i->isSelectable()) {
4981 changed = true;
4982 i->selected = true;
4983 repaintItem(i);
4984 }
4985 if (changed)
4986 emit selectionChanged();
4987 }
4988 }
4989 d->inputTimer->start(400, true);
4990 } else {
4991 selectCurrent = false;
4992 d->currInputString.clear();
4993 if (e->state() & Qt::ControlButton) {
4994 switch (e->key()) {
4995 case Qt::Key_A:
4996 selectAll(true);
4997 break;
4998 }
4999 }
5000 e->ignore();
5001 return;
5002 }
5003 }
5004
5005 if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
5006 d->selectAnchor = d->currentItem;
5007
5008 if (d->currentItem && !d->currentItem->isSelected() &&
5009 d->selectionMode == Single && selectCurrent) {
5010 d->currentItem->setSelected(true);
5011 }
5012
5013 ensureItemVisible(d->currentItem);
5014}
5015
5016/*
5017 Finds the closest item in the Direction \a dir relative from the point \a relativeTo
5018 which intersects with the searchRect.
5019
5020 The function chooses the closest item with its center in the \a searchRect.
5021*/
5022Q3IconViewItem* Q3IconView::findItem(Direction dir,
5023 const QPoint &relativeTo,
5024 const QRect &searchRect) const
5025{
5026 Q3IconViewItem *centerMatch = 0;
5027 int centerMatchML = 0;
5028
5029 // gets list of containers with potential items
5030 QList<Q3IconViewPrivate::ItemContainer * >* cList =
5031 d->findContainers(dir, relativeTo, searchRect);
5032
5033 for (int i = 0; i < cList->size() && !centerMatch; ++i) {
5034 QList<Q3IconViewItem *> &list = (cList->at(i))->items;
5035 for (int j = 0; j < list.size(); ++j) {
5036 Q3IconViewItem *item = list.at(j);
5037 if (neighbourItem(dir, relativeTo, item) &&
5038 searchRect.contains(item->rect().center()) && item != currentItem()) {
5039 int ml = (relativeTo - item->rect().center()).manhattanLength();
5040 if (centerMatch) {
5041 if (ml < centerMatchML) {
5042 centerMatch = item;
5043 centerMatchML = ml;
5044 }
5045 } else {
5046 centerMatch = item;
5047 centerMatchML = ml;
5048 }
5049 }
5050 }
5051 }
5052 return centerMatch;
5053}
5054
5055
5056/*
5057 Returns true if the items orientation compared to
5058 the point \a relativeTo is correct.
5059*/
5060bool Q3IconView::neighbourItem(Direction dir,
5061 const QPoint &relativeTo,
5062 const Q3IconViewItem *item) const
5063{
5064 switch (dir) {
5065 case DirUp:
5066 if (item->rect().center().y() < relativeTo.y())
5067 return true;
5068 break;
5069 case DirDown:
5070 if (item->rect().center().y() > relativeTo.y())
5071 return true;
5072 break;
5073 case DirLeft:
5074 if (item->rect().center().x() < relativeTo.x())
5075 return true;
5076 break;
5077 case DirRight:
5078 if (item->rect().center().x() > relativeTo.x())
5079 return true;
5080 break;
5081 default:
5082 // nothing
5083 break;
5084 }
5085 return false;
5086}
5087
5088/*!
5089 \reimp
5090*/
5091
5092void Q3IconView::focusInEvent(QFocusEvent *e)
5093{
5094 d->mousePressed = false;
5095 d->inMenuMode = false;
5096 if (d->currentItem) {
5097 repaintItem(d->currentItem);
5098 } else if (d->firstItem && e->reason() != Qt::MouseFocusReason) {
5099 d->currentItem = d->firstItem;
5100 emit currentChanged(d->currentItem);
5101 repaintItem(d->currentItem);
5102 }
5103
5104 if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this))
5105 repaintSelectedItems();
5106}
5107
5108/*!
5109 \reimp
5110*/
5111
5112void Q3IconView::focusOutEvent(QFocusEvent *e)
5113{
5114 if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this)) {
5115 d->inMenuMode =
5116 e->reason() == Qt::PopupFocusReason ||
5117 (qApp->focusWidget() && qApp->focusWidget()->inherits("QMenuBar"));
5118 if (!d->inMenuMode)
5119 repaintSelectedItems();
5120 }
5121 if (d->currentItem)
5122 repaintItem(d->currentItem);
5123}
5124
5125/*!
5126 Draws the rubber band using the painter \a p.
5127*/
5128
5129void Q3IconView::drawRubber(QPainter *p)
5130{
5131 if (!p || !d->rubber)
5132 return;
5133 QStyleOptionRubberBand opt;
5134 opt.rect = d->rubber->normalized();
5135 opt.shape = QRubberBand::Rectangle;
5136 opt.palette = palette();
5137 opt.state = QStyle::State_None;
5138 style()->drawControl(QStyle::CE_RubberBand, &opt, p, this);
5139}
5140
5141/*!
5142 Returns the Q3DragObject that should be used for drag-and-drop.
5143 This function is called by the icon view when starting a drag to
5144 get the dragobject that should be used for the drag. Subclasses
5145 may reimplement this.
5146
5147 \sa Q3IconDrag
5148*/
5149
5150#ifndef QT_NO_DRAGANDDROP
5151Q3DragObject *Q3IconView::dragObject()
5152{
5153 if (!d->currentItem)
5154 return 0;
5155
5156 QPoint orig = d->dragStartPos;
5157
5158 Q3IconDrag *drag = new Q3IconDrag(viewport());
5159 drag->setPixmap((d->currentItem->pixmap() ?
5160 *d->currentItem->pixmap() : QPixmap()), // ### QPicture
5161 QPoint(d->currentItem->pixmapRect().width() / 2,
5162 d->currentItem->pixmapRect().height() / 2));
5163
5164 if (d->selectionMode == NoSelection) {
5165 Q3IconViewItem *item = d->currentItem;
5166 drag->append(Q3IconDragItem(),
5167 QRect(item->pixmapRect(false).x() - orig.x(),
5168 item->pixmapRect(false).y() - orig.y(),
5169 item->pixmapRect().width(), item->pixmapRect().height()),
5170 QRect(item->textRect(false).x() - orig.x(),
5171 item->textRect(false).y() - orig.y(),
5172 item->textRect().width(), item->textRect().height()));
5173 } else {
5174 for (Q3IconViewItem *item = d->firstItem; item; item = item->next) {
5175 if (item->isSelected()) {
5176 drag->append(Q3IconDragItem(),
5177 QRect(item->pixmapRect(false).x() - orig.x(),
5178 item->pixmapRect(false).y() - orig.y(),
5179 item->pixmapRect().width(), item->pixmapRect().height()),
5180 QRect(item->textRect(false).x() - orig.x(),
5181 item->textRect(false).y() - orig.y(),
5182 item->textRect().width(), item->textRect().height()));
5183 }
5184 }
5185 }
5186
5187 return drag;
5188}
5189
5190/*!
5191 Starts a drag.
5192*/
5193
5194void Q3IconView::startDrag()
5195{
5196 if (!d->startDragItem)
5197 return;
5198
5199 QPoint orig = d->dragStartPos;
5200 d->dragStart = QPoint(orig.x() - d->startDragItem->x(),
5201 orig.y() - d->startDragItem->y());
5202 d->startDragItem = 0;
5203 d->mousePressed = false;
5204 d->pressedItem = 0;
5205 d->pressedSelected = 0;
5206
5207 Q3DragObject *drag = dragObject();
5208 if (!drag)
5209 return;
5210
5211 if (drag->drag())
5212 if (drag->target() != viewport())
5213 emit moved();
5214}
5215
5216#endif
5217
5218/*!
5219 Inserts the Q3IconViewItem \a item in the icon view's grid. \e{You
5220 should never need to call this function.} Instead, insert
5221 Q3IconViewItems by creating them with a pointer to the Q3IconView
5222 that they are to be inserted into.
5223*/
5224
5225void Q3IconView::insertInGrid(Q3IconViewItem *item)
5226{
5227 if (!item)
5228 return;
5229
5230 if (d->reorderItemsWhenInsert) {
5231 // #### make this efficient - but it's not too dramatic
5232 int y = d->spacing;
5233
5234 item->dirty = false;
5235 if (item == d->firstItem) {
5236 bool dummy;
5237 makeRowLayout(item, y, dummy);
5238 return;
5239 }
5240
5241 Q3IconViewItem *begin = rowBegin(item);
5242 y = begin->y();
5243 while (begin) {
5244 bool dummy;
5245 begin = makeRowLayout(begin, y, dummy);
5246
5247 if (!begin || !begin->next)
5248 break;
5249
5250 begin = begin->next;
5251 }
5252 item->dirty = false;
5253 } else {
5254 QRegion r(QRect(0, 0, qMax(contentsWidth(), visibleWidth()),
5255 qMax(contentsHeight(), visibleHeight())));
5256
5257 int y = -1;
5258 for (Q3IconViewItem *i = d->firstItem; i; i = i->next) {
5259 r = r.subtracted(i->rect());
5260 y = qMax(y, i->y() + i->height());
5261 }
5262
5263 QVector<QRect> rects = r.rects();
5264 bool foundPlace = false;
5265 for (int j = 0; j < rects.size(); ++j) {
5266 const QRect rect = rects.at(j);
5267 if (rect.width() >= item->width() &&
5268 rect.height() >= item->height()) {
5269 int sx = 0, sy = 0;
5270 if (rect.width() >= item->width() + d->spacing)
5271 sx = d->spacing;
5272 if (rect.height() >= item->height() + d->spacing)
5273 sy = d->spacing;
5274 item->move(rect.x() + sx, rect.y() + sy);
5275 foundPlace = true;
5276 break;
5277 }
5278 }
5279
5280 if (!foundPlace)
5281 item->move(d->spacing, y + d->spacing);
5282
5283 resizeContents(qMax(contentsWidth(), item->x() + item->width()),
5284 qMax(contentsHeight(), item->y() + item->height()));
5285 item->dirty = false;
5286 }
5287}
5288
5289/*!
5290 Emits a signal to indicate selection changes. \a i is the
5291 Q3IconViewItem that was selected or de-selected.
5292
5293 \e{You should never need to call this function.}
5294*/
5295
5296void Q3IconView::emitSelectionChanged(Q3IconViewItem *i)
5297{
5298 emit selectionChanged();
5299 if (d->selectionMode == Single)
5300 emit selectionChanged(i ? i : d->currentItem);
5301}
5302
5303/*!
5304 \internal
5305*/
5306
5307void Q3IconView::emitRenamed(Q3IconViewItem *item)
5308{
5309 if (!item)
5310 return;
5311
5312 emit itemRenamed(item, item->text());
5313 emit itemRenamed(item);
5314}
5315
5316/*!
5317 If a drag enters the icon view the shapes of the objects which the
5318 drag contains are drawn, usnig \a pos as origin.
5319*/
5320
5321void Q3IconView::drawDragShapes(const QPoint &pos)
5322{
5323#ifndef QT_NO_DRAGANDDROP
5324 if (pos == QPoint(-1, -1))
5325 return;
5326
5327 if (!d->drawDragShapes) {
5328 d->drawDragShapes = true;
5329 return;
5330 }
5331
5332 d->dragPos = pos;
5333 viewport()->update();
5334#endif
5335}
5336
5337/*!
5338 When a drag enters the icon view, this function is called to
5339 initialize it. Initializing in this context means getting
5340 information about the drag, for example so that the icon view
5341 knows enough about the drag to be able to draw drag shapes for the
5342 drag data (e.g. shapes of icons which are dragged), etc.
5343*/
5344
5345#ifndef QT_NO_DRAGANDDROP
5346void Q3IconView::initDragEnter(QDropEvent *e)
5347{
5348 if (Q3IconDrag::canDecode(e)) {
5349 Q3IconDragPrivate::decode(e, d->iconDragData);
5350 d->isIconDrag = true;
5351 } else if (Q3UriDrag::canDecode(e)) {
5352 Q3StrList lst;
5353 Q3UriDrag::decode(e, lst);
5354 d->numDragItems = lst.count();
5355 } else {
5356 d->numDragItems = 0;
5357 }
5358
5359}
5360#endif
5361
5362/*!
5363 This function is called to draw the rectangle \a r of the
5364 background using the painter \a p.
5365
5366 The default implementation fills \a r with the viewport's
5367 backgroundBrush(). Subclasses can reimplement this to draw custom
5368 backgrounds.
5369
5370 \sa drawContents()
5371*/
5372
5373void Q3IconView::drawBackground(QPainter *p, const QRect &r)
5374{
5375 p->fillRect(r, viewport()->backgroundBrush());
5376}
5377
5378/*!
5379 \reimp
5380*/
5381
5382bool Q3IconView::eventFilter(QObject * o, QEvent * e)
5383{
5384 if (o == viewport()) {
5385 switch(e->type()) {
5386 case QEvent::FocusIn:
5387 focusInEvent((QFocusEvent*)e);
5388 return true;
5389 case QEvent::FocusOut:
5390 focusOutEvent((QFocusEvent*)e);
5391 return true;
5392 case QEvent::Enter:
5393 enterEvent(e);
5394 return true;
5395 case QEvent::Paint:
5396 if (o == viewport()) {
5397 viewportPaintEvent((QPaintEvent*)e);
5398 QPainter p(viewport());
5399 if (d->dragging) {
5400 if (!d->rubber && d->drawDragShapes) {
5401 p.setPen(QPen(Qt::color0));
5402 QStyleOptionFocusRect opt;
5403 opt.palette = palette();
5404 opt.state = QStyle::State_KeyboardFocusChange;
5405 opt.backgroundColor = palette().base().color();
5406 if (d->isIconDrag) {
5407#ifndef QT_NO_DRAGANDDROP
5408 d->dragPos = contentsToViewport(d->dragPos);
5409 QLinkedList<Q3IconDragDataItem>::Iterator it = d->iconDragData.begin();
5410 for (; it != d->iconDragData.end(); ++it) {
5411 QRect ir = (*it).item.pixmapRect();
5412 QRect tr = (*it).item.textRect();
5413 tr.moveBy(d->dragPos.x(), d->dragPos.y());
5414 ir.moveBy(d->dragPos.x(), d->dragPos.y());
5415 if (!ir.intersects(QRect(0, 0, visibleWidth(), visibleHeight())))
5416 continue;
5417 opt.rect = ir;
5418 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, &p, this);
5419 opt.rect = tr;
5420 p.drawRect(tr);
5421 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, &p, this);
5422 }
5423#endif
5424 } else if (d->numDragItems > 0) {
5425 for (int i = 0; i < d->numDragItems; ++i) {
5426 opt.rect.setRect(d->dragPos.x() + i * 40, d->dragPos.y(), 35, 35);
5427 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, &p, this);
5428 }
5429
5430 }
5431 p.end();
5432 }
5433 } else {
5434 p.translate(-contentsX(), -contentsY());
5435 drawRubber(&p);
5436 }
5437 }
5438 return true;
5439#ifndef QT_NO_TOOLTIP
5440 case QHelpEvent::ToolTip:
5441 {
5442 if (wordWrapIconText() || !showToolTips())
5443 return false;
5444
5445 QHelpEvent *he = static_cast<QHelpEvent *>(e);
5446 Q3IconViewItem *item = findItem(viewportToContents(he->pos()));
5447 if (!item || item->tmpText == item->itemText) {
5448 QToolTip::showText(he->globalPos(), QString(), viewport());
5449 return true;
5450 }
5451
5452 QToolTip::showText(he->globalPos(), item->itemText, viewport());
5453 return true;
5454 }
5455#endif
5456 default:
5457 // nothing
5458 break;
5459 }
5460 }
5461
5462 return Q3ScrollView::eventFilter(o, e);
5463}
5464
5465
5466/*!
5467 \reimp
5468*/
5469
5470QSize Q3IconView::minimumSizeHint() const
5471{
5472 return Q3ScrollView::minimumSizeHint();
5473}
5474
5475/*!
5476 \internal
5477 Finds the next item after the start item beginning
5478 with \a text.
5479*/
5480
5481Q3IconViewItem* Q3IconView::findItemByName(Q3IconViewItem *start)
5482{
5483 if (!start)
5484 return 0;
5485 QString match = d->currInputString.toLower();
5486 if (match.length() < 1)
5487 return start;
5488 QString curText;
5489 Q3IconViewItem *i = start;
5490 do {
5491 curText = i->text().toLower();
5492 if (curText.startsWith(match))
5493 return i;
5494 i = i->next;
5495 if (!i)
5496 i = d->firstItem;
5497 } while (i != start);
5498 return 0;
5499}
5500
5501/*!
5502 Lays out a row of icons (if Arrangement == \l TopToBottom this is
5503 a column). Starts laying out with the item \a begin. \a y is the
5504 starting coordinate. Returns the last item of the row (column) and
5505 sets the new starting coordinate to \a y. The \a changed parameter
5506 is used internally.
5507
5508 \warning This function may be made private in a future version of
5509 Qt. We do not recommend calling it.
5510*/
5511
5512Q3IconViewItem *Q3IconView::makeRowLayout(Q3IconViewItem *begin, int &y, bool &changed)
5513{
5514 Q3IconViewItem *end = 0;
5515
5516 bool reverse = QApplication::reverseLayout();
5517 changed = false;
5518
5519 if (d->arrangement == LeftToRight) {
5520
5521 if (d->rastX == -1) {
5522 // first calculate the row height
5523 int h = 0;
5524 int x = 0;
5525 int ih = 0;
5526 Q3IconViewItem *item = begin;
5527 for (;;) {
5528 x += d->spacing + item->width();
5529 if (x > visibleWidth() && item != begin) {
5530 item = item->prev;
5531 break;
5532 }
5533 h = qMax(h, item->height());
5534 ih = qMax(ih, item->pixmapRect().height());
5535 Q3IconViewItem *old = item;
5536 item = item->next;
5537 if (!item) {
5538 item = old;
5539 break;
5540 }
5541 }
5542 end = item;
5543
5544 if (d->rastY != -1)
5545 h = qMax(h, d->rastY);
5546
5547 // now move the items
5548 item = begin;
5549 for (;;) {
5550 item->dirty = false;
5551 int x;
5552 if (item == begin) {
5553 if (reverse)
5554 x = visibleWidth() - d->spacing - item->width();
5555 else
5556 x = d->spacing;
5557 } else {
5558 if (reverse)
5559 x = item->prev->x() - item->width() - d->spacing;
5560 else
5561 x = item->prev->x() + item->prev->width() + d->spacing;
5562 }
5563 changed = item->move(x, y + ih - item->pixmapRect().height()) || changed;
5564 if (y + h < item->y() + item->height())
5565 h = qMax(h, ih + item->textRect().height());
5566 if (item == end)
5567 break;
5568 item = item->next;
5569 }
5570 y += h + d->spacing;
5571 } else {
5572 // first calculate the row height
5573 int h = begin->height();
5574 int x = d->spacing;
5575 int ih = begin->pixmapRect().height();
5576 Q3IconViewItem *item = begin;
5577 int i = 0;
5578 int sp = 0;
5579 for (;;) {
5580 int r = calcGridNum(item->width(), d->rastX);
5581 if (item == begin) {
5582 i += r;
5583 sp += r;
5584 x = d->spacing + d->rastX * r;
5585 } else {
5586 sp += r;
5587 i += r;
5588 x = i * d->rastX + sp * d->spacing;
5589 }
5590 if (x > visibleWidth() && item != begin) {
5591 item = item->prev;
5592 break;
5593 }
5594 h = qMax(h, item->height());
5595 ih = qMax(ih, item->pixmapRect().height());
5596 Q3IconViewItem *old = item;
5597 item = item->next;
5598 if (!item) {
5599 item = old;
5600 break;
5601 }
5602 }
5603 end = item;
5604
5605 if (d->rastY != -1)
5606 h = qMax(h, d->rastY);
5607
5608 // now move the items
5609 item = begin;
5610 i = 0;
5611 sp = 0;
5612 for (;;) {
5613 item->dirty = false;
5614 int r = calcGridNum(item->width(), d->rastX);
5615 if (item == begin) {
5616 if (d->itemTextPos == Bottom)
5617 changed = item->move(d->spacing + (r * d->rastX - item->width()) / 2,
5618 y + ih - item->pixmapRect().height()) || changed;
5619 else
5620 changed = item->move(d->spacing, y + ih - item->pixmapRect().height()) || changed;
5621 i += r;
5622 sp += r;
5623 } else {
5624 sp += r;
5625 int x = i * d->rastX + sp * d->spacing;
5626 if (d->itemTextPos == Bottom)
5627 changed = item->move(x + (r * d->rastX - item->width()) / 2,
5628 y + ih - item->pixmapRect().height()) || changed;
5629 else
5630 changed = item->move(x, y + ih - item->pixmapRect().height()) || changed;
5631 i += r;
5632 }
5633 if (y + h < item->y() + item->height())
5634 h = qMax(h, ih + item->textRect().height());
5635 if (item == end)
5636 break;
5637 item = item->next;
5638 }
5639 y += h + d->spacing;
5640 }
5641
5642
5643 } else { // -------------------------------- SOUTH ------------------------------
5644
5645 int x = y;
5646
5647 {
5648 int w = 0;
5649 int y = 0;
5650 Q3IconViewItem *item = begin;
5651 for (;;) {
5652 y += d->spacing + item->height();
5653 if (y > visibleHeight() && item != begin) {
5654 item = item->prev;
5655 break;
5656 }
5657 w = qMax(w, item->width());
5658 Q3IconViewItem *old = item;
5659 item = item->next;
5660 if (!item) {
5661 item = old;
5662 break;
5663 }
5664 }
5665 end = item;
5666
5667 if (d->rastX != -1)
5668 w = qMax(w, d->rastX);
5669
5670 // now move the items
5671 item = begin;
5672 for (;;) {
5673 item->dirty = false;
5674 if (d->itemTextPos == Bottom) {
5675 if (item == begin)
5676 changed = item->move(x + (w - item->width()) / 2, d->spacing) || changed;
5677 else
5678 changed = item->move(x + (w - item->width()) / 2,
5679 item->prev->y() + item->prev->height() + d->spacing) || changed;
5680 } else {
5681 if (item == begin)
5682 changed = item->move(x, d->spacing) || changed;
5683 else
5684 changed = item->move(x, item->prev->y() + item->prev->height() + d->spacing) || changed;
5685 }
5686 if (item == end)
5687 break;
5688 item = item->next;
5689 }
5690 x += w + d->spacing;
5691 }
5692
5693 y = x;
5694 }
5695
5696 return end;
5697}
5698
5699/*!
5700 \internal
5701 Calculates how many cells an item of width \a w needs in a grid with of
5702 \a x and returns the result.
5703*/
5704
5705int Q3IconView::calcGridNum(int w, int x) const
5706{
5707 float r = (float)w / (float)x;
5708 if ((w / x) * x != w)
5709 r += 1.0;
5710 return (int)r;
5711}
5712
5713/*!
5714 \internal
5715 Returns the first item of the row which contains \a item.
5716*/
5717
5718Q3IconViewItem *Q3IconView::rowBegin(Q3IconViewItem *) const
5719{
5720 // #### todo
5721 return d->firstItem;
5722}
5723
5724/*!
5725 Sorts and rearranges all the items in the icon view. If \a
5726 ascending is true, the items are sorted in increasing order,
5727 otherwise they are sorted in decreasing order.
5728
5729 Q3IconViewItem::compare() is used to compare pairs of items. The
5730 sorting is based on the items' keys; these default to the items'
5731 text unless specifically set to something else.
5732
5733 Note that this function sets the sort order to \a ascending.
5734
5735 \sa Q3IconViewItem::key(), Q3IconViewItem::setKey(),
5736 Q3IconViewItem::compare(), Q3IconView::setSorting(),
5737 Q3IconView::sortDirection()
5738*/
5739
5740void Q3IconView::sort(bool ascending)
5741{
5742 if (count() == 0)
5743 return;
5744
5745 d->sortDirection = ascending;
5746 Q3IconViewPrivate::SortableItem *items = new Q3IconViewPrivate::SortableItem[count()];
5747
5748 Q3IconViewItem *item = d->firstItem;
5749 int i = 0;
5750 for (; item; item = item->next)
5751 items[i++].item = item;
5752
5753 qsort(items, count(), sizeof(Q3IconViewPrivate::SortableItem), cmpIconViewItems);
5754
5755 Q3IconViewItem *prev = 0;
5756 item = 0;
5757 if (ascending) {
5758 for (i = 0; i < (int)count(); ++i) {
5759 item = items[i].item;
5760 if (item) {
5761 item->prev = prev;
5762 if (item->prev)
5763 item->prev->next = item;
5764 item->next = 0;
5765 }
5766 if (i == 0)
5767 d->firstItem = item;
5768 if (i == (int)count() - 1)
5769 d->lastItem = item;
5770 prev = item;
5771 }
5772 } else {
5773 for (i = (int)count() - 1; i >= 0 ; --i) {
5774 item = items[i].item;
5775 if (item) {
5776 item->prev = prev;
5777 if (item->prev)
5778 item->prev->next = item;
5779 item->next = 0;
5780 }
5781 if (i == (int)count() - 1)
5782 d->firstItem = item;
5783 if (i == 0)
5784 d->lastItem = item;
5785 prev = item;
5786 }
5787 }
5788
5789 delete [] items;
5790
5791 arrangeItemsInGrid(true);
5792}
5793
5794/*!
5795 \reimp
5796*/
5797
5798QSize Q3IconView::sizeHint() const
5799{
5800 ensurePolished();
5801
5802 if (!d->firstItem)
5803 return Q3ScrollView::sizeHint();
5804
5805 if (d->dirty && d->firstSizeHint) {
5806 ((Q3IconView*)this)->resizeContents(qMax(400, contentsWidth()),
5807 qMax(400, contentsHeight()));
5808 if (autoArrange())
5809 ((Q3IconView*)this)->arrangeItemsInGrid(false);
5810 d->firstSizeHint = false;
5811 }
5812
5813 d->dirty = true;
5814 const QScrollBar *sb = verticalScrollBar();
5815 QStyleOptionSlider opt;
5816 opt.init(sb);
5817 opt.orientation = sb->orientation();
5818 int extra = style()->pixelMetric(QStyle::PM_ScrollBarExtent, &opt, sb) + 2 * frameWidth();
5819 QSize s(qMin(400, contentsWidth() + extra),
5820 qMin(400, contentsHeight() + extra));
5821 return s;
5822}
5823
5824/*!
5825 \internal
5826*/
5827
5828void Q3IconView::updateContents()
5829{
5830 viewport()->update();
5831}
5832
5833/*!
5834 \reimp
5835*/
5836
5837void Q3IconView::enterEvent(QEvent *e)
5838{
5839 Q3ScrollView::enterEvent(e);
5840 emit onViewport();
5841}
5842
5843/*!
5844 \internal
5845 This function is always called when the geometry of an item changes.
5846 This function moves the item into the correct area in the internal
5847 data structure.
5848*/
5849
5850void Q3IconView::updateItemContainer(Q3IconViewItem *item)
5851{
5852 if (!item || d->containerUpdateLocked || (!isVisible() && autoArrange()))
5853 return;
5854
5855 if (item->d->container1 && d->firstContainer) {
5856 //Special-case to check if we can use removeLast otherwise use removeAll (slower)
5857 if (item->d->container1->items.last() == item)
5858 item->d->container1->items.removeLast();
5859 else
5860 item->d->container1->items.removeAll(item);
5861 }
5862 item->d->container1 = 0;
5863 if (item->d->container2 && d->firstContainer) {
5864 //Special-case to check if we can use removeLast otherwise use removeAll (slower)
5865 if (item->d->container2->items.last() == item)
5866 item->d->container2->items.removeLast();
5867 else
5868 item->d->container2->items.removeAll(item);
5869 }
5870 item->d->container2 = 0;
5871
5872 Q3IconViewPrivate::ItemContainer *c = d->firstContainer;
5873 if (!c) {
5874 appendItemContainer();
5875 c = d->firstContainer;
5876 }
5877
5878 const QRect irect = item->rect();
5879 bool contains = false;
5880 for (;;) {
5881 if (c->rect.intersects(irect)) {
5882 contains = c->rect.contains(irect);
5883 break;
5884 }
5885
5886 c = c->n;
5887 if (!c) {
5888 appendItemContainer();
5889 c = d->lastContainer;
5890 }
5891 }
5892
5893 if (!c) {
5894 qWarning("Q3IconViewItem::updateItemContainer(): No fitting container found!");
5895 return;
5896 }
5897
5898 c->items.append(item);
5899 item->d->container1 = c;
5900
5901 if (!contains) {
5902 c = c->n;
5903 if (!c) {
5904 appendItemContainer();
5905 c = d->lastContainer;
5906 }
5907 c->items.append(item);
5908 item->d->container2 = c;
5909 }
5910 if (contentsWidth() < irect.right() || contentsHeight() < irect.bottom())
5911 resizeContents(qMax(contentsWidth(), irect.right()), qMax(contentsHeight(), irect.bottom()));
5912}
5913
5914/*!
5915 \internal
5916 Appends a new rect area to the internal data structure of the items.
5917*/
5918
5919void Q3IconView::appendItemContainer()
5920{
5921 QSize s;
5922 // #### We have to find out which value is best here
5923 if (d->arrangement == LeftToRight)
5924 s = QSize(INT_MAX - 1, RECT_EXTENSION);
5925 else
5926 s = QSize(RECT_EXTENSION, INT_MAX - 1);
5927
5928 if (!d->firstContainer) {
5929 d->firstContainer = new Q3IconViewPrivate::ItemContainer(0, 0, QRect(QPoint(0, 0), s));
5930 d->lastContainer = d->firstContainer;
5931 } else {
5932 if (d->arrangement == LeftToRight)
5933 d->lastContainer = new Q3IconViewPrivate::ItemContainer(
5934 d->lastContainer, 0, QRect(d->lastContainer->rect.bottomLeft(), s));
5935 else
5936 d->lastContainer = new Q3IconViewPrivate::ItemContainer(
5937 d->lastContainer, 0, QRect(d->lastContainer->rect.topRight(), s));
5938 }
5939}
5940
5941/*! \internal
5942
5943 Rebuilds the whole internal data structure. This is done when it's
5944 likely that most/all items change their geometry (e.g. in
5945 arrangeItemsInGrid()), because calling this is then more efficient
5946 than calling updateItemContainer() for each item.
5947*/
5948
5949void Q3IconView::rebuildContainers()
5950{
5951 Q3IconViewPrivate::ItemContainer *c = d->firstContainer, *tmpc;
5952 while (c) {
5953 tmpc = c->n;
5954 delete c;
5955 c = tmpc;
5956 }
5957 d->firstContainer = d->lastContainer = 0;
5958
5959 Q3IconViewItem *item = d->firstItem;
5960 appendItemContainer();
5961 c = d->lastContainer;
5962 while (item) {
5963 if (c->rect.contains(item->rect())) {
5964 item->d->container1 = c;
5965 item->d->container2 = 0;
5966 c->items.append(item);
5967 item = item->next;
5968 } else if (c->rect.intersects(item->rect())) {
5969 item->d->container1 = c;
5970 c->items.append(item);
5971 c = c->n;
5972 if (!c) {
5973 appendItemContainer();
5974 c = d->lastContainer;
5975 }
5976 c->items.append(item);
5977 item->d->container2 = c;
5978 item = item->next;
5979 c = c->p;
5980 } else {
5981 if (d->arrangement == LeftToRight) {
5982 if (item->y() < c->rect.y() && c->p) {
5983 c = c->p;
5984 continue;
5985 }
5986 } else {
5987 if (item->x() < c->rect.x() && c->p) {
5988 c = c->p;
5989 continue;
5990 }
5991 }
5992
5993 c = c->n;
5994 if (!c) {
5995 appendItemContainer();
5996 c = d->lastContainer;
5997 }
5998 }
5999 }
6000}
6001
6002/*!
6003 \internal
6004*/
6005
6006void Q3IconView::movedContents(int, int)
6007{
6008 if (d->drawDragShapes) {
6009 drawDragShapes(d->oldDragPos);
6010 d->oldDragPos = QPoint(-1, -1);
6011 }
6012}
6013
6014void Q3IconView::handleItemChange(Q3IconViewItem *old, bool shift,
6015 bool control, bool homeend)
6016{
6017 if (d->selectionMode == Single) {
6018 bool block = signalsBlocked();
6019 blockSignals(true);
6020 if (old)
6021 old->setSelected(false);
6022 blockSignals(block);
6023 d->currentItem->setSelected(true, true);
6024 } else if (d->selectionMode == Extended) {
6025 if (shift) {
6026 if (!d->selectAnchor) {
6027 if (old && !old->selected && old->isSelectable()) {
6028 old->selected = true;
6029 repaintItem(old);
6030 }
6031 d->currentItem->setSelected(true, true);
6032 } else {
6033 Q3IconViewItem *from = d->selectAnchor, *to = d->currentItem;
6034 if (!from || !to)
6035 return;
6036
6037 // checking if it's downwards and if we span rows
6038 bool downwards = false;
6039 bool spanning = false;
6040 if (d->arrangement == LeftToRight) {
6041 if (from->rect().center().y() < to->rect().center().y())
6042 downwards = true;
6043 } else {
6044 if (from->rect().center().x() < to->rect().center().x())
6045 downwards = true;
6046 }
6047
6048 QRect fr = from->rect();
6049 QRect tr = to->rect();
6050 if (d->arrangement == LeftToRight) {
6051 fr.moveTopLeft(QPoint(tr.x(), fr.y()));
6052 if (!tr.intersects(fr))
6053 spanning = true;
6054 } else {
6055 fr.moveTopLeft(QPoint(fr.x(), tr.y()));
6056 if (!tr.intersects(fr))
6057 spanning = true;
6058 }
6059
6060
6061 // finding the rectangles
6062 QRect topRect, bottomRect, midRect;
6063 if (!spanning) {
6064 midRect = from->rect().united(to->rect());
6065 } else {
6066 if (downwards) {
6067 topRect = from->rect();
6068 bottomRect = to->rect();
6069 } else {
6070 topRect = to->rect();
6071 bottomRect = from->rect();
6072 }
6073 if (d->arrangement == LeftToRight) {
6074 topRect.setRight(contentsWidth());
6075 bottomRect.setLeft(0);
6076 midRect.setRect(0, topRect.bottom(),
6077 contentsWidth(),
6078 bottomRect.top() - topRect.bottom());
6079 } else {
6080 topRect.setBottom(contentsHeight());
6081 bottomRect.setTop(0);
6082 midRect.setRect(topRect.right(),
6083 0,
6084 bottomRect.left() - topRect.right(),
6085 contentsHeight());
6086 }
6087 }
6088
6089 // finding contained items and selecting them
6090 Q3IconViewItem *item = 0;
6091 bool changed = false;
6092 bool midValid = midRect.isValid();
6093 bool topValid = topRect.isValid();
6094 bool bottomValid = bottomRect.isValid();
6095 QRect selectedRect, unselectedRect;
6096 for (item = d->firstItem; item; item = item->next) {
6097 bool contained = false;
6098 QPoint itemCenter = item->rect().center();
6099 if (midValid && midRect.contains(itemCenter))
6100 contained = true;
6101 if (!contained && topValid && topRect.contains(itemCenter))
6102 contained = true;
6103 if (!contained && bottomValid && bottomRect.contains(itemCenter))
6104 contained = true;
6105
6106 if (contained) {
6107 if (!item->selected && item->isSelectable()) {
6108 changed = true;
6109 item->selected = true;
6110 selectedRect = selectedRect.united(item->rect());
6111 }
6112 } else if (item->selected && !control) {
6113 item->selected = false;
6114 unselectedRect = unselectedRect.united(item->rect());
6115 changed = true;
6116 }
6117 }
6118
6119 QRect viewRect(contentsX(), contentsY(),
6120 visibleWidth(), visibleHeight());
6121
6122 if (viewRect.intersects(selectedRect)) {
6123 if (homeend)
6124 Q3ScrollView::updateContents(viewRect.intersected(selectedRect));
6125 else
6126 repaintContents(viewRect.intersected(selectedRect));
6127 }
6128 if (viewRect.intersects(unselectedRect)) {
6129 if (homeend)
6130 Q3ScrollView::updateContents(viewRect.intersected(unselectedRect));
6131 else
6132 repaintContents(viewRect.intersected(unselectedRect));
6133 }
6134
6135 if (changed)
6136 emit selectionChanged();
6137 }
6138 } else if (!control) {
6139 blockSignals(true);
6140 selectAll(false);
6141 blockSignals(false);
6142 d->currentItem->setSelected(true, true);
6143 }
6144 } else {
6145 if (shift)
6146 d->currentItem->setSelected(!d->currentItem->isSelected(), true);
6147 }
6148}
6149
6150QBitmap Q3IconView::mask(QPixmap *pix) const
6151{
6152 QBitmap m;
6153 if (d->maskCache.find(QString::number(pix->serialNumber()), m))
6154 return m;
6155 if (pix->hasAlphaChannel())
6156 m = pix->mask();
6157 else
6158 m = pix->createHeuristicMask();
6159 d->maskCache.insert(QString::number(pix->serialNumber()), m);
6160 return m;
6161}
6162
6163/*!
6164 Returns true if an iconview item is being renamed; otherwise
6165 returns false.
6166*/
6167
6168bool Q3IconView::isRenaming() const
6169{
6170#ifndef QT_NO_TEXTEDIT
6171 return d->renamingItem && d->renamingItem->renameBox;
6172#else
6173 return false;
6174#endif
6175}
6176
6177/*!
6178 \enum Q3IconView::StringComparisonMode
6179
6180 This enum type is used to set the string comparison mode when
6181 searching for an item. We'll refer to the string being searched
6182 as the 'target' string.
6183
6184 \value CaseSensitive The strings must match case sensitively.
6185 \value ExactMatch The target and search strings must match exactly.
6186 \value BeginsWith The target string begins with the search string.
6187 \value EndsWith The target string ends with the search string.
6188 \value Contains The target string contains the search string.
6189
6190 If you OR these flags together (excluding \c CaseSensitive), the
6191 search criteria be applied in the following order: \c ExactMatch,
6192 \c BeginsWith, \c EndsWith, \c Contains.
6193
6194 Matching is case-insensitive unless \c CaseSensitive is set. \c
6195 CaseSensitive can be OR-ed with any combination of the other
6196 flags.
6197
6198 \sa ComparisonFlags
6199*/
6200
6201/*!
6202 \typedef Q3IconView::ComparisonFlags
6203
6204 This typedef is used in Q3IconView's API for values that are OR'd
6205 combinations of \l StringComparisonMode values.
6206
6207 \sa StringComparisonMode
6208*/
6209
6210QT_END_NAMESPACE
6211
6212#endif // QT_NO_ICONVIEW
Note: See TracBrowser for help on using the repository browser.