source: branches/4.5.1/src/qt3support/itemviews/q3iconview.cpp

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

qt3support: Added QT_NO_DRAGANDDROP to Q3IconView [vendor bug].

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