source: trunk/src/iconview/qiconview.cpp@ 168

Last change on this file since 168 was 160, checked in by dmik, 19 years ago

Imported table and iconview modules and a bunch of dependent examples from the official release 3.3.1 from Trolltech.

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