summaryrefslogtreecommitdiffstats
path: root/src/qt3support/itemviews/q3iconview.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2009-03-23 10:18:55 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2009-03-23 10:18:55 +0100
commite5fcad302d86d316390c6b0f62759a067313e8a9 (patch)
treec2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/qt3support/itemviews/q3iconview.cpp
Long live Qt 4.5!
Diffstat (limited to 'src/qt3support/itemviews/q3iconview.cpp')
-rw-r--r--src/qt3support/itemviews/q3iconview.cpp6203
1 files changed, 6203 insertions, 0 deletions
diff --git a/src/qt3support/itemviews/q3iconview.cpp b/src/qt3support/itemviews/q3iconview.cpp
new file mode 100644
index 0000000000..d1a9c1e8e0
--- /dev/null
+++ b/src/qt3support/itemviews/q3iconview.cpp
@@ -0,0 +1,6203 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglobal.h"
+#if defined(Q_CC_BOR)
+// needed for qsort() because of a std namespace problem on Borland
+#include "qplatformdefs.h"
+#endif
+
+#include "q3iconview.h"
+
+#ifndef QT_NO_ICONVIEW
+
+#include "private/q3richtext_p.h"
+#include "q3textedit.h"
+#include "qapplication.h"
+#include "qbitmap.h"
+#include "qbrush.h"
+#include "q3cleanuphandler.h"
+#include "qcursor.h"
+#include "qevent.h"
+#include "qfontmetrics.h"
+#include "qhash.h"
+#include "qimage.h"
+#include "qmime.h"
+#include "qpainter.h"
+#include "qpalette.h"
+#include "qpen.h"
+#include "qpixmapcache.h"
+#include "qstringlist.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qtimer.h"
+#include "qtooltip.h"
+#include "q3strlist.h"
+
+#include <limits.h>
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+#define RECT_EXTENSION 300
+
+static const char * const unknown_xpm[] = {
+ "32 32 11 1",
+ "c c #ffffff",
+ "g c #c0c0c0",
+ "a c #c0ffc0",
+ "h c #a0a0a4",
+ "d c #585858",
+ "f c #303030",
+ "i c #400000",
+ "b c #00c000",
+ "e c #000000",
+ "# c #000000",
+ ". c None",
+ "...###..........................",
+ "...#aa##........................",
+ ".###baaa##......................",
+ ".#cde#baaa##....................",
+ ".#cccdeebaaa##..##f.............",
+ ".#cccccdeebaaa##aaa##...........",
+ ".#cccccccdeebaaaaaaaa##.........",
+ ".#cccccccccdeebaaaaaaa#.........",
+ ".#cccccgcgghhebbbbaaaaa#........",
+ ".#ccccccgcgggdebbbbbbaa#........",
+ ".#cccgcgcgcgghdeebiebbba#.......",
+ ".#ccccgcggggggghdeddeeba#.......",
+ ".#cgcgcgcggggggggghghdebb#......",
+ ".#ccgcggggggggghghghghd#b#......",
+ ".#cgcgcggggggggghghghhd#b#......",
+ ".#gcggggggggghghghhhhhd#b#......",
+ ".#cgcggggggggghghghhhhd#b#......",
+ ".#ggggggggghghghhhhhhhdib#......",
+ ".#gggggggggghghghhhhhhd#b#......",
+ ".#hhggggghghghhhhhhhhhd#b#......",
+ ".#ddhhgggghghghhhhhhhhd#b#......",
+ "..##ddhhghghhhhhhhhhhhdeb#......",
+ "....##ddhhhghhhhhhhhhhd#b#......",
+ "......##ddhhhhhhhhhhhhd#b#......",
+ "........##ddhhhhhhhhhhd#b#......",
+ "..........##ddhhhhhhhhd#b#......",
+ "............##ddhhhhhhd#b###....",
+ "..............##ddhhhhd#b#####..",
+ "................##ddhhd#b######.",
+ "..................##dddeb#####..",
+ "....................##d#b###....",
+ "......................####......"};
+
+static QPixmap *unknown_icon = 0;
+static QPixmap *qiv_buffer_pixmap = 0;
+#if !defined(Q_WS_X11)
+static QPixmap *qiv_selection = 0;
+#endif
+static bool optimize_layout = false;
+
+static Q3CleanupHandler<QPixmap> qiv_cleanup_pixmap;
+
+
+static QPixmap *get_qiv_buffer_pixmap(const QSize &s)
+{
+ if (!qiv_buffer_pixmap) {
+ qiv_buffer_pixmap = new QPixmap(s);
+ qiv_cleanup_pixmap.add(&qiv_buffer_pixmap);
+ return qiv_buffer_pixmap;
+ }
+
+ qiv_buffer_pixmap->resize(s);
+ return qiv_buffer_pixmap;
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+class Q_COMPAT_EXPORT Q3IconDragData
+{
+public:
+ Q3IconDragData();
+ Q3IconDragData(const QRect &ir, const QRect &tr);
+
+ QRect pixmapRect() const;
+ QRect textRect() const;
+
+ void setPixmapRect(const QRect &r);
+ void setTextRect(const QRect &r);
+
+ QRect iconRect_, textRect_;
+ QString key_;
+
+ bool operator==(const Q3IconDragData &i) const;
+};
+
+class Q_COMPAT_EXPORT Q3IconDragDataItem
+{
+public:
+ Q3IconDragDataItem() {}
+ Q3IconDragDataItem(const Q3IconDragItem &i1, const Q3IconDragData &i2) : data(i1), item(i2) {}
+ Q3IconDragItem data;
+ Q3IconDragData item;
+ bool operator== (const Q3IconDragDataItem&) const;
+};
+
+class Q3IconDragPrivate
+{
+public:
+ QLinkedList<Q3IconDragDataItem> items;
+ static bool decode(QMimeSource* e, QLinkedList<Q3IconDragDataItem> &lst);
+};
+
+#endif
+
+class Q3IconViewPrivate
+{
+public:
+ Q3IconViewItem *firstItem, *lastItem;
+ uint count;
+ Q3IconView::SelectionMode selectionMode;
+ Q3IconViewItem *currentItem, *tmpCurrentItem, *highlightedItem,
+ *startDragItem, *pressedItem, *selectAnchor, *renamingItem;
+ QRect *rubber;
+ QTimer *scrollTimer, *adjustTimer, *updateTimer, *inputTimer,
+ *fullRedrawTimer;
+ int rastX, rastY, spacing;
+ int dragItems;
+ QPoint oldDragPos;
+ Q3IconView::Arrangement arrangement;
+ Q3IconView::ResizeMode resizeMode;
+ QSize oldSize;
+#ifndef QT_NO_DRAGANDDROP
+ QLinkedList<Q3IconDragDataItem> iconDragData;
+#endif
+ int numDragItems, cachedW, cachedH;
+ int maxItemWidth, maxItemTextLength;
+ QPoint dragStart;
+ QString currInputString;
+ Q3IconView::ItemTextPos itemTextPos;
+#ifndef QT_NO_CURSOR
+ QCursor oldCursor;
+#endif
+ int cachedContentsX, cachedContentsY;
+ QBrush itemTextBrush;
+ QRegion clipRegion;
+ QPoint dragStartPos;
+ QFontMetrics *fm;
+ int minLeftBearing, minRightBearing;
+
+ uint mousePressed : 1;
+ uint cleared : 1;
+ uint dropped : 1;
+ uint clearing : 1;
+ uint oldDragAcceptAction : 1;
+ uint isIconDrag : 1;
+ uint drawDragShapes : 1;
+ uint dirty : 1;
+ uint rearrangeEnabled : 1;
+ uint reorderItemsWhenInsert : 1;
+ uint drawAllBack : 1;
+ uint resortItemsWhenInsert : 1;
+ uint sortDirection : 1;
+ uint wordWrapIconText : 1;
+ uint containerUpdateLocked : 1;
+ uint firstSizeHint : 1;
+ uint showTips : 1;
+ uint pressedSelected : 1;
+ uint dragging : 1;
+ uint drawActiveSelection : 1;
+ uint inMenuMode : 1;
+
+ QPoint dragPos;
+ QPixmapCache maskCache;
+ QHash<Q3IconViewItem *, Q3IconViewItem *> selectedItems;
+
+ struct ItemContainer {
+ ItemContainer(ItemContainer *pr, ItemContainer *nx, const QRect &r)
+ : p(pr), n(nx), rect(r)
+ {
+ if (p)
+ p->n = this;
+ if (n)
+ n->p = this;
+ }
+ ItemContainer *p, *n;
+ QRect rect;
+ QList<Q3IconViewItem*> items;
+ } *firstContainer, *lastContainer;
+
+ struct SortableItem {
+ Q3IconViewItem *item;
+ };
+
+public:
+
+ /* finds the containers that intersect with \a searchRect in the direction \a dir relative to \a relativeTo */
+ QList<ItemContainer* >* findContainers(
+ Q3IconView:: Direction dir,
+ const QPoint &relativeTo,
+ const QRect &searchRect) const;
+ // friend int cmpIconViewItems(const void *n1, const void *n2);
+};
+
+
+QList<Q3IconViewPrivate::ItemContainer *>* Q3IconViewPrivate::findContainers(
+ Q3IconView:: Direction dir,
+ const QPoint &relativeTo,
+ const QRect &searchRect) const
+{
+
+ QList<Q3IconViewPrivate::ItemContainer *>* list =
+ new QList<Q3IconViewPrivate::ItemContainer*>();
+
+ if (arrangement == Q3IconView::LeftToRight) {
+ if (dir == Q3IconView::DirLeft || dir == Q3IconView::DirRight) {
+ ItemContainer *c = firstContainer;
+ for (; c; c = c->n)
+ if (c->rect.intersects(searchRect))
+ list->append(c);
+ } else {
+ if (dir == Q3IconView::DirDown) {
+ ItemContainer *c = firstContainer;
+ for (; c; c = c->n)
+ if (c->rect.intersects(searchRect) &&
+ c->rect.bottom() >= relativeTo.y())
+ list->append(c);
+ } else {
+ ItemContainer *c = lastContainer;
+ for (; c; c = c->p)
+ if (c->rect.intersects(searchRect) &&
+ c->rect.top() <= relativeTo.y())
+ list->append(c);
+ }
+ }
+ } else {
+ if (dir == Q3IconView::DirUp || dir == Q3IconView::DirDown) {
+ ItemContainer *c = firstContainer;
+ for (; c; c = c->n)
+ if (c->rect.intersects(searchRect))
+ list->append(c);
+ } else {
+ if (dir == Q3IconView::DirRight) {
+ ItemContainer *c = firstContainer;
+ for (; c; c = c->n)
+ if (c->rect.intersects(searchRect) &&
+ c->rect.right() >= relativeTo.x())
+ list->append(c);
+ } else {
+ ItemContainer *c = lastContainer;
+ for (; c; c = c->p)
+ if (c->rect.intersects(searchRect) &&
+ c->rect.left() <= relativeTo.x())
+ list->append(c);
+ }
+ }
+ }
+ return list;
+}
+
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+#ifdef Q_OS_WINCE
+static int _cdecl cmpIconViewItems(const void *n1, const void *n2)
+#else
+static int cmpIconViewItems(const void *n1, const void *n2)
+#endif
+{
+ if (!n1 || !n2)
+ return 0;
+
+ Q3IconViewPrivate::SortableItem *i1 = (Q3IconViewPrivate::SortableItem *)n1;
+ Q3IconViewPrivate::SortableItem *i2 = (Q3IconViewPrivate::SortableItem *)n2;
+
+ return i1->item->compare(i2->item);
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+class Q3IconViewItemPrivate
+{
+public:
+ Q3IconViewPrivate::ItemContainer *container1, *container2;
+};
+
+#ifndef QT_NO_TEXTEDIT
+
+class Q3IconViewItemLineEdit : public Q3TextEdit
+{
+ friend class Q3IconViewItem;
+
+public:
+ Q3IconViewItemLineEdit(const QString &text, QWidget *parent, Q3IconViewItem *theItem, const char* name=0);
+
+protected:
+ void keyPressEvent(QKeyEvent *e);
+ void focusOutEvent(QFocusEvent *e);
+
+protected:
+ Q3IconViewItem *item;
+ QString startText;
+
+private:
+ Q_DISABLE_COPY(Q3IconViewItemLineEdit)
+};
+
+Q3IconViewItemLineEdit::Q3IconViewItemLineEdit(const QString &text, QWidget *parent,
+ Q3IconViewItem *theItem, const char *name)
+ : Q3TextEdit(parent, name), item(theItem), startText(text)
+{
+ setFrameStyle(QFrame::Plain | QFrame::Box);
+ setLineWidth(1);
+
+ setHScrollBarMode(AlwaysOff);
+ setVScrollBarMode(AlwaysOff);
+
+ setWordWrap(WidgetWidth);
+ setWrapColumnOrWidth(item->iconView()->maxItemWidth() -
+ (item->iconView()->itemTextPos() == Q3IconView::Bottom ?
+ 0 : item->pixmapRect().width()));
+ document()->formatter()->setAllowBreakInWords(true);
+ resize(200, 200); // ### some size, there should be a forceReformat()
+ setTextFormat(Qt::PlainText);
+ setText(text);
+ setAlignment(Qt::AlignCenter);
+
+ resize(wrapColumnOrWidth() + 2, heightForWidth(wrapColumnOrWidth()) + 2);
+}
+
+void Q3IconViewItemLineEdit::keyPressEvent(QKeyEvent *e)
+{
+ if (e->key() == Qt::Key_Escape) {
+ item->Q3IconViewItem::setText(startText);
+ item->cancelRenameItem();
+ } else if (e->key() == Qt::Key_Enter ||
+ e->key() == Qt::Key_Return) {
+ item->renameItem();
+ } else {
+ Q3TextEdit::keyPressEvent(e);
+ sync();
+ resize(width(), document()->height() + 2);
+
+ }
+}
+
+void Q3IconViewItemLineEdit::focusOutEvent(QFocusEvent *e)
+{
+ Q_UNUSED(e) // I need this to get rid of a Borland warning
+ if (e->reason() != Qt::PopupFocusReason)
+ item->cancelRenameItem();
+}
+#endif
+
+#ifndef QT_NO_DRAGANDDROP
+
+
+/*!
+ \class Q3IconDragItem
+ \brief The Q3IconDragItem class encapsulates a drag item.
+ \compat
+
+ The Q3IconDrag class uses a list of Q3IconDragItems to support drag
+ and drop operations.
+
+ In practice a Q3IconDragItem object (or an object of a class derived
+ from Q3IconDragItem) is created for each icon view item which is
+ dragged. Each of these Q3IconDragItems is stored in a Q3IconDrag
+ object.
+
+ See Q3IconView::dragObject() for more information.
+*/
+
+/*!
+ Constructs a Q3IconDragItem with no data.
+*/
+
+Q3IconDragItem::Q3IconDragItem()
+{
+ ba = "no data";
+}
+
+/*!
+ Destructor.
+*/
+
+Q3IconDragItem::~Q3IconDragItem()
+{
+}
+
+/*!
+ Returns the data contained in the Q3IconDragItem.
+*/
+
+QByteArray Q3IconDragItem::data() const
+{
+ return ba;
+}
+
+/*!
+ Sets the data for the Q3IconDragItem to the data stored in the
+ QByteArray \a d.
+*/
+
+void Q3IconDragItem::setData(const QByteArray &d)
+{
+ ba = d;
+}
+
+/*!
+ \internal
+*/
+
+bool Q3IconDragItem::operator==(const Q3IconDragItem &i) const
+{
+ return ba == i.ba;
+}
+
+/*!
+ \reimp
+*/
+
+bool Q3IconDragDataItem::operator==(const Q3IconDragDataItem &i) const
+{
+ return (i.item == item &&
+ i.data == data);
+}
+
+/*!
+ \reimp
+*/
+
+bool Q3IconDragData::operator==(const Q3IconDragData &i) const
+{
+ return key_ == i.key_;
+}
+
+
+/*!
+ \class Q3IconDrag
+ \brief The Q3IconDrag class supports drag and drop operations
+ within a Q3IconView.
+
+ \compat
+
+ A Q3IconDrag object is used to maintain information about the
+ positions of dragged items and the data associated with them.
+ Q3IconViews are able to use this information to paint the dragged
+ items in the correct positions. Internally, Q3IconDrag stores the
+ data associated with drag items in Q3IconDragItem objects.
+
+ If you want to use the extended drag and drop functionality of
+ Q3IconView, create a Q3IconDrag object in a reimplementation of
+ Q3IconView::dragObject(). Then create a Q3IconDragItem for each item
+ which should be dragged, set the data it represents with
+ Q3IconDragItem::setData(), and add each Q3IconDragItem to the drag
+ object using append().
+
+ The data in Q3IconDragItems is stored in a QByteArray and is
+ mime-typed (see QMimeSource and the
+ \link http://doc.trolltech.com/dnd.html Drag and Drop\endlink
+ overview). If you want to use your own mime-types derive a class
+ from Q3IconDrag and reimplement format(), encodedData() and
+ canDecode().
+
+ The fileiconview example program demonstrates the use of the
+ Q3IconDrag class including subclassing and reimplementing
+ dragObject(), format(), encodedData() and canDecode().
+
+ \sa QMimeSource::format()
+*/
+
+/*!
+ Constructs a drag object called \a name, which is a child of \a
+ dragSource.
+
+ Note that the drag object will be deleted when \a dragSource is deleted.
+*/
+
+Q3IconDrag::Q3IconDrag(QWidget * dragSource, const char* name)
+ : Q3DragObject(dragSource, name)
+{
+ d = new Q3IconDragPrivate;
+}
+
+/*!
+ Destructor.
+*/
+
+Q3IconDrag::~Q3IconDrag()
+{
+ delete d;
+}
+
+/*!
+ Append the Q3IconDragItem, \a i, to the Q3IconDrag object's list of
+ items. You must also supply the geometry of the pixmap, \a pr, and
+ the textual caption, \a tr.
+
+ \sa Q3IconDragItem
+*/
+
+void Q3IconDrag::append(const Q3IconDragItem &i, const QRect &pr, const QRect &tr)
+{
+ d->items.append(Q3IconDragDataItem(i, Q3IconDragData(pr, tr)));
+}
+
+/*!
+ \reimp
+*/
+
+const char* Q3IconDrag::format(int i) const
+{
+ if (i == 0)
+ return "application/x-qiconlist";
+ return 0;
+}
+
+/*!
+ Returns the encoded data of the drag object if \a mime is
+ application/x-qiconlist.
+*/
+
+QByteArray Q3IconDrag::encodedData(const char* mime) const
+{
+ if (d->items.size() <= 0 || QString::fromLatin1(mime) !=
+ QString::fromLatin1("application/x-qiconlist"))
+ return QByteArray();
+
+ QLinkedList<Q3IconDragDataItem>::ConstIterator it = d->items.begin();
+ QString s;
+ for (; it != d->items.end(); ++it) {
+ QString k(QLatin1String("%1$@@$%2$@@$%3$@@$%4$@@$%5$@@$%6$@@$%7$@@$%8$@@$"));
+ k = k.arg((*it).item.pixmapRect().x()).arg(
+ (*it).item.pixmapRect().y()).arg((*it).item.pixmapRect().width()).
+ arg((*it).item.pixmapRect().height()).arg(
+ (*it).item.textRect().x()).arg((*it).item.textRect().y()).
+ arg((*it).item.textRect().width()).arg(
+ (*it).item.textRect().height());
+ k += QString(QLatin1String((*it).data.data())) + QLatin1String("$@@$");
+ s += k;
+ }
+
+ QByteArray a;
+ a.resize(s.length() + 1);
+ memcpy(a.data(), s.latin1(), a.size());
+ return a;
+}
+
+/*!
+ Returns true if \a e can be decoded by the Q3IconDrag, otherwise
+ return false.
+*/
+
+bool Q3IconDrag::canDecode(QMimeSource* e)
+{
+ if (e->provides("application/x-qiconlist"))
+ return true;
+ return false;
+}
+
+/*!
+ Decodes the data which is stored (encoded) in \a e and, if
+ successful, fills the \a list of icon drag items with the decoded
+ data. Returns true if there was some data, false otherwise.
+*/
+
+bool Q3IconDragPrivate::decode(QMimeSource* e, QLinkedList<Q3IconDragDataItem> &lst)
+{
+ QByteArray ba = e->encodedData("application/x-qiconlist");
+ if (ba.size()) {
+ lst.clear();
+ // #### unicode clean????
+ QString s = QString::fromLatin1(ba);
+ Q3IconDragDataItem item;
+ QRect ir, tr;
+ QStringList l = QStringList::split(QLatin1String("$@@$"), s);
+
+ int i = 0;
+ QStringList::Iterator it = l.begin();
+ for (; it != l.end(); ++it) {
+ if (i == 0) {
+ ir.setX((*it).toInt());
+ } else if (i == 1) {
+ ir.setY((*it).toInt());
+ } else if (i == 2) {
+ ir.setWidth((*it).toInt());
+ } else if (i == 3) {
+ ir.setHeight((*it).toInt());
+ } else if (i == 4) {
+ tr.setX((*it).toInt());
+ } else if (i == 5) {
+ tr.setY((*it).toInt());
+ } else if (i == 6) {
+ tr.setWidth((*it).toInt());
+ } else if (i == 7) {
+ tr.setHeight((*it).toInt());
+ } else if (i == 8) {
+ QByteArray d;
+ d.resize((*it).length());
+ memcpy(d.data(), (*it).latin1(), (*it).length());
+ item.item.setPixmapRect(ir);
+ item.item.setTextRect(tr);
+ item.data.setData(d);
+ lst.append(item);
+ }
+ ++i;
+ if (i > 8)
+ i = 0;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+Q3IconDragData::Q3IconDragData()
+ : iconRect_(), textRect_()
+{
+}
+
+Q3IconDragData::Q3IconDragData(const QRect &ir, const QRect &tr)
+ : iconRect_(ir), textRect_(tr)
+{
+}
+
+QRect Q3IconDragData::textRect() const
+{
+ return textRect_;
+}
+
+QRect Q3IconDragData::pixmapRect() const
+{
+ return iconRect_;
+}
+
+void Q3IconDragData::setPixmapRect(const QRect &r)
+{
+ iconRect_ = r;
+}
+
+void Q3IconDragData::setTextRect(const QRect &r)
+{
+ textRect_ = r;
+}
+
+#endif
+
+
+/*!
+ \class Q3IconViewItem
+ \brief The Q3IconViewItem class provides a single item in a Q3IconView.
+
+ \compat
+
+ A Q3IconViewItem contains an icon, a string and optionally a sort
+ key, and can display itself in a Q3IconView.
+
+ The simplest way to create a Q3IconViewItem and insert it into a
+ Q3IconView is to construct the item passing the constructor a
+ pointer to the icon view, a string and an icon:
+
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 0
+
+ By default the text of an icon view item may not be edited by the
+ user but calling setRenameEnabled(true) will allow the user to
+ perform in-place editing of the item's text.
+
+ When the icon view is deleted all items in it are deleted
+ automatically.
+
+ The Q3IconView::firstItem() and Q3IconViewItem::nextItem() functions
+ provide a means of iterating over all the items in a Q3IconView:
+
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 1
+
+ The item's icon view is available from iconView(), and its
+ position in the icon view from index().
+
+ The item's selection status is available from isSelected() and is
+ set and controlled by setSelected() and isSelectable().
+
+ The text and icon can be set with setText() and setPixmap() and
+ retrieved with text() and pixmap(). The item's sort key defaults
+ to text() but may be set with setKey() and retrieved with key().
+ The comparison function, compare() uses key().
+
+ Items may be repositioned with move() and moveBy(). An item's
+ geometry is available from rect(), x(), y(), width(), height(),
+ size(), pos(), textRect() and pixmapRect(). You can also test
+ against the position of a point with contains() and intersects().
+
+ To remove an item from an icon view, just delete the item. The
+ Q3IconViewItem destructor removes it cleanly from its icon view.
+
+ Because the icon view is designed to use drag-and-drop, the icon
+ view item also has functions for drag-and-drop which may be
+ reimplemented.
+
+ The class is designed to be very similar to Q3ListView and Q3ListBox
+ in use, both via instantiation and subclassing.
+*/
+
+/*!
+ Constructs a Q3IconViewItem and inserts it into icon view \a parent
+ with no text and a default icon.
+*/
+
+Q3IconViewItem::Q3IconViewItem(Q3IconView *parent)
+ : view(parent), itemText(), itemIcon(unknown_icon)
+{
+ init();
+}
+
+/*!
+ Constructs a Q3IconViewItem and inserts it into the icon view \a
+ parent with no text and a default icon, after the icon view item
+ \a after.
+*/
+
+Q3IconViewItem::Q3IconViewItem(Q3IconView *parent, Q3IconViewItem *after)
+ : view(parent), itemText(), itemIcon(unknown_icon),
+ prev(0), next(0)
+{
+ init(after);
+}
+
+/*!
+ Constructs an icon view item and inserts it into the icon view \a
+ parent using \a text as the text and a default icon.
+*/
+
+Q3IconViewItem::Q3IconViewItem(Q3IconView *parent, const QString &text)
+ : view(parent), itemText(text), itemIcon(unknown_icon)
+{
+ init(0);
+}
+
+/*!
+ Constructs an icon view item and inserts it into the icon view \a
+ parent using \a text as the text and a default icon, after the
+ icon view item \a after.
+*/
+
+Q3IconViewItem::Q3IconViewItem(Q3IconView *parent, Q3IconViewItem *after,
+ const QString &text)
+ : view(parent), itemText(text), itemIcon(unknown_icon)
+{
+ init(after);
+}
+
+/*!
+ Constructs an icon view item and inserts it into the icon view \a
+ parent using \a text as the text and \a icon as the icon.
+*/
+
+Q3IconViewItem::Q3IconViewItem(Q3IconView *parent, const QString &text,
+ const QPixmap &icon)
+ : view(parent),
+ itemText(text), itemIcon(new QPixmap(icon))
+{
+ init(0);
+}
+
+
+/*!
+ Constructs an icon view item and inserts it into the icon view \a
+ parent using \a text as the text and \a icon as the icon, after
+ the icon view item \a after.
+*/
+
+Q3IconViewItem::Q3IconViewItem(Q3IconView *parent, Q3IconViewItem *after,
+ const QString &text, const QPixmap &icon)
+ : view(parent), itemText(text), itemIcon(new QPixmap(icon))
+{
+ init(after);
+}
+
+/*!
+ Constructs an icon view item and inserts it into the icon view \a
+ parent using \a text as the text and \a picture as the icon.
+*/
+
+#ifndef QT_NO_PICTURE
+Q3IconViewItem::Q3IconViewItem(Q3IconView *parent, const QString &text,
+ const QPicture &picture)
+ : view(parent), itemText(text), itemIcon(0)
+{
+ init(0, new QPicture(picture));
+}
+
+/*!
+ Constructs an icon view item and inserts it into the icon view \a
+ parent using \a text as the text and \a picture as the icon, after
+ the icon view item \a after.
+*/
+
+Q3IconViewItem::Q3IconViewItem(Q3IconView *parent, Q3IconViewItem *after,
+ const QString &text, const QPicture &picture)
+ : view(parent), itemText(text), itemIcon(0)
+{
+ init(after, new QPicture(picture));
+}
+#endif
+
+/*!
+ This private function initializes the icon view item and inserts it
+ into the icon view.
+*/
+
+void Q3IconViewItem::init(Q3IconViewItem *after
+#ifndef QT_NO_PICTURE
+ , QPicture *pic
+#endif
+ )
+{
+ d = new Q3IconViewItemPrivate;
+ d->container1 = 0;
+ d->container2 = 0;
+ prev = next = 0;
+ allow_rename = false;
+ allow_drag = true;
+ allow_drop = true;
+ selected = false;
+ selectable = true;
+#ifndef QT_NO_TEXTEDIT
+ renameBox = 0;
+#endif
+#ifndef QT_NO_PICTURE
+ itemPic = pic;
+#endif
+ if (view) {
+ itemKey = itemText;
+ dirty = true;
+ wordWrapDirty = true;
+ itemRect = QRect(-1, -1, 0, 0);
+ calcRect();
+ view->insertItem(this, after);
+ }
+}
+
+/*!
+ Destroys the icon view item and tells the parent icon view that
+ the item has been destroyed.
+*/
+
+Q3IconViewItem::~Q3IconViewItem()
+{
+#ifndef QT_NO_TEXTEDIT
+ removeRenameBox();
+#endif
+ if (view && !view->d->clearing)
+ view->takeItem(this);
+ view = 0;
+ if (itemIcon && itemIcon->serialNumber() != unknown_icon->serialNumber())
+ delete itemIcon;
+#ifndef QT_NO_PICTURE
+ delete itemPic;
+#endif
+ delete d;
+}
+
+int Q3IconViewItem::RTTI = 0;
+
+/*!
+ Returns 0.
+
+ Make your derived classes return their own values for rtti(), so
+ that you can distinguish between icon view item types. You should
+ use values greater than 1000, preferably a large random number, to
+ allow for extensions to this class.
+*/
+
+int Q3IconViewItem::rtti() const
+{
+ return RTTI;
+}
+
+
+/*!
+ Sets \a text as the text of the icon view item. This function
+ might be a no-op if you reimplement text().
+
+ \sa text()
+*/
+
+void Q3IconViewItem::setText(const QString &text)
+{
+ if (text == itemText)
+ return;
+
+ wordWrapDirty = true;
+ itemText = text;
+ if (itemKey.isEmpty())
+ itemKey = itemText;
+
+ QRect oR = rect();
+ calcRect();
+ oR = oR.united(rect());
+
+ if (view) {
+ if (QRect(view->contentsX(), view->contentsY(),
+ view->visibleWidth(), view->visibleHeight()).
+ intersects(oR))
+ view->repaintContents(oR.x() - 1, oR.y() - 1, oR.width() + 2, oR.height() + 2);
+ }
+}
+
+/*!
+ Sets \a k as the sort key of the icon view item. By default
+ text() is used for sorting.
+
+ \sa compare()
+*/
+
+void Q3IconViewItem::setKey(const QString &k)
+{
+ if (k == itemKey)
+ return;
+
+ itemKey = k;
+}
+
+/*!
+ Sets \a icon as the item's icon in the icon view. This function
+ might be a no-op if you reimplement pixmap().
+
+ \sa pixmap()
+*/
+
+void Q3IconViewItem::setPixmap(const QPixmap &icon)
+{
+ if (itemIcon && itemIcon == unknown_icon)
+ itemIcon = 0;
+
+ if (itemIcon)
+ *itemIcon = icon;
+ else
+ itemIcon = new QPixmap(icon);
+ QRect oR = rect();
+ calcRect();
+ oR = oR.united(rect());
+
+ if (view) {
+ if (QRect(view->contentsX(), view->contentsY(),
+ view->visibleWidth(), view->visibleHeight()).
+ intersects(oR))
+ view->repaintContents(oR.x() - 1, oR.y() - 1, oR.width() + 2, oR.height() + 2);
+ }
+}
+
+/*!
+ Sets \a icon as the item's icon in the icon view. This function
+ might be a no-op if you reimplement picture().
+
+ \sa picture()
+*/
+
+#ifndef QT_NO_PICTURE
+void Q3IconViewItem::setPicture(const QPicture &icon)
+{
+ // clear assigned pixmap if any
+ if (itemIcon) {
+ if (itemIcon == unknown_icon) {
+ itemIcon = 0;
+ } else {
+ delete itemIcon;
+ itemIcon = 0;
+ }
+ }
+ if (itemPic)
+ delete itemPic;
+ itemPic = new QPicture(icon);
+
+ QRect oR = rect();
+ calcRect();
+ oR = oR.united(rect());
+
+ if (view) {
+ if (QRect(view->contentsX(), view->contentsY(),
+ view->visibleWidth(), view->visibleHeight()).
+ intersects(oR))
+ view->repaintContents(oR.x() - 1, oR.y() - 1, oR.width() + 2, oR.height() + 2);
+ }
+}
+#endif
+
+/*!
+ \overload
+
+ Sets \a text as the text of the icon view item. If \a recalc is
+ true, the icon view's layout is recalculated. If \a redraw is true
+ (the default), the icon view is repainted.
+
+ \sa text()
+*/
+
+void Q3IconViewItem::setText(const QString &text, bool recalc, bool redraw)
+{
+ if (text == itemText)
+ return;
+
+ wordWrapDirty = true;
+ itemText = text;
+
+ if (recalc)
+ calcRect();
+ if (redraw)
+ repaint();
+}
+
+/*!
+ \overload
+
+ Sets \a icon as the item's icon in the icon view. If \a recalc is
+ true, the icon view's layout is recalculated. If \a redraw is true
+ (the default), the icon view is repainted.
+
+ \sa pixmap()
+*/
+
+void Q3IconViewItem::setPixmap(const QPixmap &icon, bool recalc, bool redraw)
+{
+ if (itemIcon && itemIcon == unknown_icon)
+ itemIcon = 0;
+
+ if (itemIcon)
+ *itemIcon = icon;
+ else
+ itemIcon = new QPixmap(icon);
+
+ if (redraw) {
+ if (recalc) {
+ QRect oR = rect();
+ calcRect();
+ oR = oR.united(rect());
+
+ if (view) {
+ if (QRect(view->contentsX(), view->contentsY(),
+ view->visibleWidth(), view->visibleHeight()).
+ intersects(oR))
+ view->repaintContents(oR.x() - 1, oR.y() - 1, oR.width() + 2, oR.height() + 2);
+ }
+ } else {
+ repaint();
+ }
+ } else if (recalc) {
+ calcRect();
+ }
+}
+
+/*!
+ If \a allow is true, the user can rename the icon view item by
+ clicking on the text (or pressing F2) while the item is selected
+ (in-place renaming). If \a allow is false, in-place renaming is
+ not possible.
+*/
+
+void Q3IconViewItem::setRenameEnabled(bool allow)
+{
+ allow_rename = (uint)allow;
+}
+
+/*!
+ If \a allow is true, the icon view permits the user to drag the
+ icon view item either to another position within the icon view or
+ to somewhere outside of it. If \a allow is false, the item cannot
+ be dragged.
+*/
+
+void Q3IconViewItem::setDragEnabled(bool allow)
+{
+ allow_drag = (uint)allow;
+}
+
+/*!
+ If \a allow is true, the icon view lets the user drop something on
+ this icon view item.
+*/
+
+void Q3IconViewItem::setDropEnabled(bool allow)
+{
+ allow_drop = (uint)allow;
+}
+
+/*!
+ Returns the text of the icon view item. Normally you set the text
+ of the item with setText(), but sometimes it's inconvenient to
+ call setText() for every item; so you can subclass Q3IconViewItem,
+ reimplement this function, and return the text of the item. If you
+ do this, you must call calcRect() manually each time the text
+ (and therefore its size) changes.
+
+ \sa setText()
+*/
+
+QString Q3IconViewItem::text() const
+{
+ return itemText;
+}
+
+/*!
+ Returns the key of the icon view item or text() if no key has been
+ explicitly set.
+
+ \sa setKey(), compare()
+*/
+
+QString Q3IconViewItem::key() const
+{
+ return itemKey;
+}
+
+/*!
+ Returns the icon of the icon view item if it is a pixmap, or 0 if
+ it is a picture. In the latter case use picture() instead.
+ Normally you set the pixmap of the item with setPixmap(), but
+ sometimes it's inconvenient to call setPixmap() for every item. So
+ you can subclass Q3IconViewItem, reimplement this function and
+ return a pointer to the item's pixmap. If you do this, you \e must
+ call calcRect() manually each time the size of this pixmap
+ changes.
+
+ \sa setPixmap()
+*/
+
+QPixmap *Q3IconViewItem::pixmap() const
+{
+ return itemIcon;
+}
+
+/*!
+ Returns the icon of the icon view item if it is a picture, or 0 if
+ it is a pixmap. In the latter case use pixmap() instead. Normally
+ you set the picture of the item with setPicture(), but sometimes
+ it's inconvenient to call setPicture() for every item. So you can
+ subclass Q3IconViewItem, reimplement this function and return a
+ pointer to the item's picture. If you do this, you \e must call
+ calcRect() manually each time the size of this picture changes.
+
+ \sa setPicture()
+*/
+
+#ifndef QT_NO_PICTURE
+QPicture *Q3IconViewItem::picture() const
+{
+ return itemPic;
+}
+#endif
+
+/*!
+ Returns true if the item can be renamed by the user with in-place
+ renaming; otherwise returns false.
+
+ \sa setRenameEnabled()
+*/
+
+bool Q3IconViewItem::renameEnabled() const
+{
+ return (bool)allow_rename;
+}
+
+/*!
+ Returns true if the user is allowed to drag the icon view item;
+ otherwise returns false.
+
+ \sa setDragEnabled()
+*/
+
+bool Q3IconViewItem::dragEnabled() const
+{
+ return (bool)allow_drag;
+}
+
+/*!
+ Returns true if the user is allowed to drop something onto the
+ item; otherwise returns false.
+
+ \sa setDropEnabled()
+*/
+
+bool Q3IconViewItem::dropEnabled() const
+{
+ return (bool)allow_drop;
+}
+
+/*!
+ Returns a pointer to this item's icon view parent.
+*/
+
+Q3IconView *Q3IconViewItem::iconView() const
+{
+ return view;
+}
+
+/*!
+ Returns a pointer to the previous item, or 0 if this is the first
+ item in the icon view.
+
+ \sa nextItem() Q3IconView::firstItem()
+*/
+
+Q3IconViewItem *Q3IconViewItem::prevItem() const
+{
+ return prev;
+}
+
+/*!
+ Returns a pointer to the next item, or 0 if this is the last item
+ in the icon view.
+
+ To find the first item use Q3IconView::firstItem().
+
+ Example:
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 2
+
+ \sa prevItem()
+*/
+
+Q3IconViewItem *Q3IconViewItem::nextItem() const
+{
+ return next;
+}
+
+/*!
+ Returns the index of this item in the icon view, or -1 if an error
+ occurred.
+*/
+
+int Q3IconViewItem::index() const
+{
+ if (view)
+ return view->index(this);
+
+ return -1;
+}
+
+
+
+/*!
+ \overload
+
+ This variant is equivalent to calling the other variant with \e cb
+ set to false.
+*/
+
+void Q3IconViewItem::setSelected(bool s)
+{
+ setSelected(s, false);
+}
+
+/*!
+ Selects or unselects the item, depending on \a s; it may also
+ unselect other items, depending on Q3IconView::selectionMode() and
+ \a cb.
+
+ If \a s is false, the item is unselected.
+
+ If \a s is true and Q3IconView::selectionMode() is
+ Q3IconView::Single, the item is selected and the item previously
+ selected is unselected.
+
+ If \a s is true and Q3IconView::selectionMode() is
+ Q3IconView::Extended, the item is selected. If \a cb is true, the
+ selection state of the other items is left unchanged. If \a cb is
+ false (the default) all other items are unselected.
+
+ If \a s is true and Q3IconView::selectionMode() is
+ Q3IconView::Multi, the item is selected.
+
+ Note that \a cb is used only if Q3IconView::selectionMode() is
+ Q3IconView::Extended; cb defaults to false.
+
+ All items whose selection status changes repaint themselves.
+*/
+
+void Q3IconViewItem::setSelected(bool s, bool cb)
+{
+ if (!view)
+ return;
+ if (view->selectionMode() != Q3IconView::NoSelection &&
+ selectable && s != (bool)selected) {
+
+ if (view->d->selectionMode == Q3IconView::Single && this != view->d->currentItem) {
+ Q3IconViewItem *o = view->d->currentItem;
+ if (o && o->selected)
+ o->selected = false;
+ view->d->currentItem = this;
+ if (o)
+ o->repaint();
+ emit view->currentChanged(this);
+ }
+
+ if (!s) {
+ selected = false;
+ } else {
+ if (view->d->selectionMode == Q3IconView::Single && view->d->currentItem) {
+ view->d->currentItem->selected = false;
+ }
+ if ((view->d->selectionMode == Q3IconView::Extended && !cb) ||
+ view->d->selectionMode == Q3IconView::Single) {
+ bool b = view->signalsBlocked();
+ view->blockSignals(true);
+ view->selectAll(false);
+ view->blockSignals(b);
+ }
+ selected = s;
+ }
+
+ repaint();
+ if (!view->signalsBlocked()) {
+ bool emitIt = view->d->selectionMode == Q3IconView::Single && s;
+ Q3IconView *v = view;
+ emit v->selectionChanged();
+ if (emitIt)
+ emit v->selectionChanged(this);
+ }
+ }
+}
+
+/*!
+ Sets this item to be selectable if \a enable is true (the default)
+ or unselectable if \a enable is false.
+
+ The user is unable to select a non-selectable item using either
+ the keyboard or the mouse. (The application programmer can select
+ an item in code regardless of this setting.)
+
+ \sa isSelectable()
+*/
+
+void Q3IconViewItem::setSelectable(bool enable)
+{
+ selectable = (uint)enable;
+}
+
+/*!
+ Returns true if the item is selected; otherwise returns false.
+
+ \sa setSelected()
+*/
+
+bool Q3IconViewItem::isSelected() const
+{
+ return (bool)selected;
+}
+
+/*!
+ Returns true if the item is selectable; otherwise returns false.
+
+ \sa setSelectable()
+*/
+
+bool Q3IconViewItem::isSelectable() const
+{
+ return (bool)selectable;
+}
+
+/*!
+ Repaints the item.
+*/
+
+void Q3IconViewItem::repaint()
+{
+ if (view)
+ view->repaintItem(this);
+}
+
+/*!
+ Moves the item to position (\a x, \a y) in the icon view (these
+ are contents coordinates). Returns true if the item is moved.
+ Returns false if the item is already at the specified position.
+*/
+
+bool Q3IconViewItem::move(int x, int y)
+{
+ if (x == this->x() && y == this->y())
+ return false;
+ itemRect.setRect(x, y, itemRect.width(), itemRect.height());
+ checkRect();
+ if (view)
+ view->updateItemContainer(this);
+ return true;
+}
+
+/*!
+ Moves the item \a dx pixels in the x-direction and \a dy pixels in
+ the y-direction.
+*/
+
+void Q3IconViewItem::moveBy(int dx, int dy)
+{
+ itemRect.moveBy(dx, dy);
+ checkRect();
+ if (view)
+ view->updateItemContainer(this);
+}
+
+/*!
+ \overload
+
+ Moves the item to the point \a pnt.
+*/
+
+bool Q3IconViewItem::move(const QPoint &pnt)
+{
+ return move(pnt.x(), pnt.y());
+}
+
+/*!
+ \overload
+
+ Moves the item by the x, y values in point \a pnt.
+*/
+
+void Q3IconViewItem::moveBy(const QPoint &pnt)
+{
+ moveBy(pnt.x(), pnt.y());
+}
+
+/*!
+ Returns the bounding rectangle of the item (in contents
+ coordinates).
+*/
+
+QRect Q3IconViewItem::rect() const
+{
+ return itemRect;
+}
+
+/*!
+ Returns the x-coordinate of the item (in contents coordinates).
+*/
+
+int Q3IconViewItem::x() const
+{
+ return itemRect.x();
+}
+
+/*!
+ Returns the y-coordinate of the item (in contents coordinates).
+*/
+
+int Q3IconViewItem::y() const
+{
+ return itemRect.y();
+}
+
+/*!
+ Returns the width of the item.
+*/
+
+int Q3IconViewItem::width() const
+{
+ return qMax(itemRect.width(), QApplication::globalStrut().width());
+}
+
+/*!
+ Returns the height of the item.
+*/
+
+int Q3IconViewItem::height() const
+{
+ return qMax(itemRect.height(), QApplication::globalStrut().height());
+}
+
+/*!
+ Returns the size of the item.
+*/
+
+QSize Q3IconViewItem::size() const
+{
+ return QSize(itemRect.width(), itemRect.height());
+}
+
+/*!
+ Returns the position of the item (in contents coordinates).
+*/
+
+QPoint Q3IconViewItem::pos() const
+{
+ return QPoint(itemRect.x(), itemRect.y());
+}
+
+/*!
+ Returns the bounding rectangle of the item's text.
+
+ If \a relative is true, (the default), the returned rectangle is
+ relative to the origin of the item's rectangle. If \a relative is
+ false, the returned rectangle is relative to the origin of the
+ icon view's contents coordinate system.
+*/
+
+QRect Q3IconViewItem::textRect(bool relative) const
+{
+ if (relative)
+ return itemTextRect;
+ else
+ return QRect(x() + itemTextRect.x(), y() + itemTextRect.y(), itemTextRect.width(), itemTextRect.height());
+}
+
+/*!
+ Returns the bounding rectangle of the item's icon.
+
+ If \a relative is true, (the default), the rectangle is relative to
+ the origin of the item's rectangle. If \a relative is false, the
+ returned rectangle is relative to the origin of the icon view's
+ contents coordinate system.
+*/
+
+QRect Q3IconViewItem::pixmapRect(bool relative) const
+{
+ if (relative)
+ return itemIconRect;
+ else
+ return QRect(x() + itemIconRect.x(), y() + itemIconRect.y(), itemIconRect.width(), itemIconRect.height());
+}
+
+/*!
+ Returns true if the item contains the point \a pnt (in contents
+ coordinates); otherwise returns false.
+*/
+
+bool Q3IconViewItem::contains(const QPoint& pnt) const
+{
+ QRect textArea = textRect(false);
+ QRect pixmapArea = pixmapRect(false);
+ if (iconView()->itemTextPos() == Q3IconView::Bottom)
+ textArea.setTop(pixmapArea.bottom());
+ else
+ textArea.setLeft(pixmapArea.right());
+ return textArea.contains(pnt) || pixmapArea.contains(pnt);
+}
+
+/*!
+ Returns true if the item intersects the rectangle \a r (in
+ contents coordinates); otherwise returns false.
+*/
+
+bool Q3IconViewItem::intersects(const QRect& r) const
+{
+ return (textRect(false).intersects(r) ||
+ pixmapRect(false).intersects(r));
+}
+
+/*!
+ \fn bool Q3IconViewItem::acceptDrop(const QMimeSource *mime) const
+
+ Returns true if you can drop things with a QMimeSource of \a mime
+ onto this item; otherwise returns false.
+
+ The default implementation always returns false. You must subclass
+ Q3IconViewItem and reimplement acceptDrop() to accept drops.
+*/
+
+bool Q3IconViewItem::acceptDrop(const QMimeSource *) const
+{
+ return false;
+}
+
+#ifndef QT_NO_TEXTEDIT
+/*!
+ Starts in-place renaming of an icon, if allowed.
+
+ This function sets up the icon view so that the user can edit the
+ item text, and then returns. When the user is done, setText() will
+ be called and Q3IconView::itemRenamed() will be emitted (unless the
+ user canceled, e.g. by pressing the Escape key).
+
+ \sa setRenameEnabled()
+*/
+
+void Q3IconViewItem::rename()
+{
+ if (!view)
+ return;
+ if (renameBox)
+ removeRenameBox();
+ oldRect = rect();
+ renameBox = new Q3IconViewItemLineEdit(itemText, view->viewport(), this, "qt_renamebox");
+ iconView()->ensureItemVisible(this);
+ QRect tr(textRect(false));
+ view->addChild(renameBox, tr.x() + (tr.width() / 2 - renameBox->width() / 2), tr.y() - 3);
+ renameBox->selectAll();
+ view->viewport()->setFocusProxy(renameBox);
+ renameBox->setFocus();
+ renameBox->show();
+ Q_ASSERT(view->d->renamingItem == 0L);
+ view->d->renamingItem = this;
+}
+#endif
+
+/*!
+ Compares this icon view item to \a i. Returns -1 if this item is
+ less than \a i, 0 if they are equal, and 1 if this icon view item
+ is greater than \a i.
+
+ The default implementation compares the item keys (key()) using
+ QString::localeAwareCompare(). A reimplementation may use
+ different values and a different comparison function. Here is a
+ reimplementation that uses plain Unicode comparison:
+
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 3
+
+ \sa key() QString::localeAwareCompare() QString::compare()
+*/
+
+int Q3IconViewItem::compare(Q3IconViewItem *i) const
+{
+ return key().localeAwareCompare(i->key());
+}
+
+#ifndef QT_NO_TEXTEDIT
+/*!
+ This private function is called when the user pressed Return during
+ in-place renaming.
+*/
+
+void Q3IconViewItem::renameItem()
+{
+ if (!renameBox || !view)
+ return;
+
+ if (!view->d->wordWrapIconText) {
+ wordWrapDirty = true;
+ calcRect();
+ }
+ QRect r = itemRect;
+ setText(renameBox->text());
+ view->repaintContents(oldRect.x() - 1, oldRect.y() - 1, oldRect.width() + 2, oldRect.height() + 2);
+ view->repaintContents(r.x() - 1, r.y() - 1, r.width() + 2, r.height() + 2);
+ removeRenameBox();
+
+ view->emitRenamed(this);
+}
+
+/*!
+ Cancels in-place renaming.
+*/
+
+void Q3IconViewItem::cancelRenameItem()
+{
+ if (!view)
+ return;
+
+ QRect r = itemRect;
+ calcRect();
+ view->repaintContents(oldRect.x() - 1, oldRect.y() - 1, oldRect.width() + 2, oldRect.height() + 2);
+ view->repaintContents(r.x() - 1, r.y() - 1, r.width() + 2, r.height() + 2);
+
+ if (!renameBox)
+ return;
+
+ removeRenameBox();
+}
+
+/*!
+ Removes the editbox that is used for in-place renaming.
+*/
+
+void Q3IconViewItem::removeRenameBox()
+{
+ if (!renameBox || !view)
+ return;
+
+ bool resetFocus = view->viewport()->focusProxy() == renameBox;
+ renameBox->hide();
+ renameBox->deleteLater();
+ renameBox = 0;
+ if (resetFocus) {
+ view->viewport()->setFocusProxy(view);
+ view->setFocus();
+ }
+ Q_ASSERT(view->d->renamingItem == this);
+ view->d->renamingItem = 0L;
+}
+#endif
+
+/*!
+ This virtual function is responsible for calculating the
+ rectangles returned by rect(), textRect() and pixmapRect().
+ setRect(), setTextRect() and setPixmapRect() are provided mainly
+ for reimplementations of this function.
+
+ \a text_ is an internal parameter which defaults to an empty
+ string.
+*/
+
+void Q3IconViewItem::calcRect(const QString &text_)
+{
+ if (!view) // #####
+ return;
+
+ wordWrapDirty = true;
+ int pw = 0;
+ int ph = 0;
+
+#ifndef QT_NO_PICTURE
+ if (picture()) {
+ QRect br = picture()->boundingRect();
+ pw = br.width() + 2;
+ ph = br.height() + 2;
+ } else
+#endif
+ {
+ pw = (pixmap() ? pixmap() : unknown_icon)->width() + 2;
+ ph = (pixmap() ? pixmap() : unknown_icon)->height() + 2;
+ }
+
+ itemIconRect.setWidth(pw);
+ itemIconRect.setHeight(ph);
+
+ calcTmpText();
+
+ QString t = text_;
+ if (t.isEmpty()) {
+ if (view->d->wordWrapIconText)
+ t = itemText;
+ else
+ t = tmpText;
+ }
+
+ int tw = 0;
+ int th = 0;
+ // ##### TODO: fix font bearings!
+ QRect r;
+ if (view->d->wordWrapIconText) {
+ r = QRect(view->d->fm->boundingRect(0, 0, iconView()->maxItemWidth() -
+ (iconView()->itemTextPos() == Q3IconView::Bottom ? 0 :
+ pixmapRect().width()),
+ 0xFFFFFFFF, Qt::AlignHCenter | Qt::WordBreak | Qt::BreakAnywhere, t));
+ r.setWidth(r.width() + 4);
+ } else {
+ r = QRect(0, 0, view->d->fm->width(t), view->d->fm->height());
+ r.setWidth(r.width() + 4);
+ }
+
+ if (r.width() > iconView()->maxItemWidth() -
+ (iconView()->itemTextPos() == Q3IconView::Bottom ? 0 :
+ pixmapRect().width()))
+ r.setWidth(iconView()->maxItemWidth() - (iconView()->itemTextPos() == Q3IconView::Bottom ? 0 :
+ pixmapRect().width()));
+
+ tw = r.width();
+ th = r.height();
+ if (tw < view->d->fm->width(QLatin1String("X")))
+ tw = view->d->fm->width(QLatin1String("X"));
+
+ itemTextRect.setWidth(tw);
+ itemTextRect.setHeight(th);
+
+ int w = 0;
+ int h = 0;
+ if (view->itemTextPos() == Q3IconView::Bottom) {
+ w = qMax(itemTextRect.width(), itemIconRect.width());
+ h = itemTextRect.height() + itemIconRect.height() + 1;
+
+ itemRect.setWidth(w);
+ itemRect.setHeight(h);
+
+ itemTextRect = QRect((width() - itemTextRect.width()) / 2, height() - itemTextRect.height(),
+ itemTextRect.width(), itemTextRect.height());
+ itemIconRect = QRect((width() - itemIconRect.width()) / 2, 0,
+ itemIconRect.width(), itemIconRect.height());
+ } else {
+ h = qMax(itemTextRect.height(), itemIconRect.height());
+ w = itemTextRect.width() + itemIconRect.width() + 1;
+
+ itemRect.setWidth(w);
+ itemRect.setHeight(h);
+
+ itemTextRect = QRect(width() - itemTextRect.width(), (height() - itemTextRect.height()) / 2,
+ itemTextRect.width(), itemTextRect.height());
+ itemIconRect = QRect(0, (height() - itemIconRect.height()) / 2,
+ itemIconRect.width(), itemIconRect.height());
+ }
+ if (view)
+ view->updateItemContainer(this);
+}
+
+/*!
+ Paints the item using the painter \a p and the color group \a cg.
+ If you want the item to be drawn with a different font or color,
+ reimplement this function, change the values of the color group or
+ the painter's font, and then call the Q3IconViewItem::paintItem()
+ with the changed values.
+*/
+
+void Q3IconViewItem::paintItem(QPainter *p, const QColorGroup &cg)
+{
+ if (!view)
+ return;
+
+ p->save();
+
+ if (isSelected()) {
+ p->setPen(cg.highlightedText());
+ } else {
+ p->setPen(cg.text());
+ }
+
+ calcTmpText();
+
+#ifndef QT_NO_PICTURE
+ if (picture()) {
+ QPicture *pic = picture();
+ if (isSelected()) {
+ p->fillRect(pixmapRect(false), QBrush(cg.highlight(), Qt::Dense4Pattern));
+ }
+ p->drawPicture(x()-pic->boundingRect().x(), y()-pic->boundingRect().y(), *pic);
+ if (isSelected()) {
+ p->fillRect(textRect(false), cg.highlight());
+ p->setPen(QPen(cg.highlightedText()));
+ } else if (view->d->itemTextBrush != QBrush(Qt::NoBrush))
+ p->fillRect(textRect(false), view->d->itemTextBrush);
+
+ int align = view->itemTextPos() == Q3IconView::Bottom ? Qt::AlignHCenter : Qt::AlignAuto;
+ if (view->d->wordWrapIconText)
+ align |= Qt::WordBreak | Qt::BreakAnywhere;
+ p->drawText(textRect(false), align, view->d->wordWrapIconText ? itemText : tmpText);
+ p->restore();
+ return;
+ }
+#endif
+ bool textOnBottom = (view->itemTextPos() == Q3IconView::Bottom);
+ int dim;
+ if (textOnBottom)
+ dim = (pixmap() ? pixmap() : unknown_icon)->width();
+ else
+ dim = (pixmap() ? pixmap() : unknown_icon)->height();
+ if (isSelected()) {
+ QPixmap *pix = pixmap() ? pixmap() : unknown_icon;
+ if (pix && !pix->isNull()) {
+ QPixmap *buffer = get_qiv_buffer_pixmap(pix->size());
+ QBitmap mask = view->mask(pix);
+
+ QPainter p2(buffer);
+ p2.fillRect(pix->rect(), Qt::white);
+ p2.drawPixmap(0, 0, *pix);
+ p2.end();
+
+ p2.begin(buffer);
+ p2.fillRect(pix->rect(), QBrush(cg.highlight(), Qt::Dense4Pattern));
+ p2.end();
+ buffer->setMask(mask);
+
+ QRect cr = pix->rect();
+ if (textOnBottom)
+ p->drawPixmap(x() + (width() - dim) / 2, y(), *buffer, 0, 0,
+ cr.width(), cr.height());
+ else
+ p->drawPixmap(x() , y() + (height() - dim) / 2, *buffer, 0, 0,
+ cr.width(), cr.height());
+ }
+ } else {
+ if (textOnBottom)
+ p->drawPixmap(x() + (width() - dim) / 2, y(),
+ *(pixmap() ? pixmap() : unknown_icon));
+ else
+ p->drawPixmap(x() , y() + (height() - dim) / 2,
+ *(pixmap() ? pixmap() : unknown_icon));
+ }
+
+ p->save();
+ if (isSelected()) {
+ p->fillRect(textRect(false), cg.highlight());
+ p->setPen(QPen(cg.highlightedText()));
+ } else if (view->d->itemTextBrush != QBrush(Qt::NoBrush))
+ p->fillRect(textRect(false), view->d->itemTextBrush);
+
+ int align = Qt::AlignHCenter;
+ if (view->d->wordWrapIconText)
+ align |= Qt::WordBreak | Qt::BreakAnywhere;
+ p->drawText(textRect(false), align,
+ view->d->wordWrapIconText ? itemText : tmpText);
+
+ p->restore();
+
+ p->restore();
+}
+
+/*!
+ Paints the focus rectangle of the item using the painter \a p and
+ the color group \a cg.
+*/
+
+void Q3IconViewItem::paintFocus(QPainter *p, const QColorGroup &cg)
+{
+ if (!view)
+ return;
+
+ QStyleOptionFocusRect opt;
+ opt.rect = textRect(false);
+ opt.palette = cg;
+ if (isSelected()) {
+ opt.state = QStyle::State_FocusAtBorder;
+ opt.backgroundColor = cg.highlight();
+ } else {
+ opt.state = QStyle::State_None;
+ opt.backgroundColor = cg.base();
+ }
+ view->style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p);
+
+ if (this != view->d->currentItem) {
+ opt.rect = pixmapRect(false);
+ opt.backgroundColor = cg.base();
+ opt.state = QStyle::State_None;
+ view->style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p);
+ }
+}
+
+#ifndef QT_NO_DRAGANDDROP
+/*!
+ \fn void Q3IconViewItem::dropped(QDropEvent *e, const Q3ValueList<Q3IconDragItem> &lst)
+
+ This function is called when something is dropped on the item. \a
+ e provides all the information about the drop. If the drag object
+ of the drop was a Q3IconDrag, \a lst contains the list of the
+ dropped items. You can get the data by calling
+ Q3IconDragItem::data() on each item. If the \a lst is empty, i.e.
+ the drag was not a Q3IconDrag, you must decode the data in \a e and
+ work with that.
+
+ The default implementation does nothing; subclasses may
+ reimplement this function.
+*/
+
+void Q3IconViewItem::dropped(QDropEvent *, const Q3ValueList<Q3IconDragItem> &)
+{
+}
+#endif
+
+/*!
+ This function is called when a drag enters the item's bounding
+ rectangle.
+
+ The default implementation does nothing; subclasses may
+ reimplement this function.
+*/
+
+void Q3IconViewItem::dragEntered()
+{
+}
+
+/*!
+ This function is called when a drag leaves the item's bounding
+ rectangle.
+
+ The default implementation does nothing; subclasses may
+ reimplement this function.
+*/
+
+void Q3IconViewItem::dragLeft()
+{
+}
+
+/*!
+ Sets the bounding rectangle of the whole item to \a r. This
+ function is provided for subclasses which reimplement calcRect(),
+ so that they can set the calculated rectangle. \e{Any other use is
+ discouraged.}
+
+ \sa calcRect() textRect() setTextRect() pixmapRect() setPixmapRect()
+*/
+
+void Q3IconViewItem::setItemRect(const QRect &r)
+{
+ itemRect = r;
+ checkRect();
+ if (view)
+ view->updateItemContainer(this);
+}
+
+/*!
+ Sets the bounding rectangle of the item's text to \a r. This
+ function is provided for subclasses which reimplement calcRect(),
+ so that they can set the calculated rectangle. \e{Any other use is
+ discouraged.}
+
+ \sa calcRect() textRect() setItemRect() setPixmapRect()
+*/
+
+void Q3IconViewItem::setTextRect(const QRect &r)
+{
+ itemTextRect = r;
+ if (view)
+ view->updateItemContainer(this);
+}
+
+/*!
+ Sets the bounding rectangle of the item's icon to \a r. This
+ function is provided for subclasses which reimplement calcRect(),
+ so that they can set the calculated rectangle. \e{Any other use is
+ discouraged.}
+
+ \sa calcRect() pixmapRect() setItemRect() setTextRect()
+*/
+
+void Q3IconViewItem::setPixmapRect(const QRect &r)
+{
+ itemIconRect = r;
+ if (view)
+ view->updateItemContainer(this);
+}
+
+/*!
+ \internal
+*/
+
+void Q3IconViewItem::calcTmpText()
+{
+ if (!view || view->d->wordWrapIconText || !wordWrapDirty)
+ return;
+ wordWrapDirty = false;
+
+ int w = iconView()->maxItemWidth() - (iconView()->itemTextPos() == Q3IconView::Bottom ? 0 :
+ pixmapRect().width());
+ if (view->d->fm->width(itemText) < w) {
+ tmpText = itemText;
+ return;
+ }
+
+ tmpText = QLatin1String("...");
+ int i = 0;
+ while (view->d->fm->width(tmpText + itemText[i]) < w)
+ tmpText += itemText[i++];
+ tmpText.remove((uint)0, 3);
+ tmpText += QLatin1String("...");
+}
+
+/*! \internal */
+
+QString Q3IconViewItem::tempText() const
+{
+ return tmpText;
+}
+
+void Q3IconViewItem::checkRect()
+{
+ int x = itemRect.x();
+ int y = itemRect.y();
+ int w = itemRect.width();
+ int h = itemRect.height();
+
+ bool changed = false;
+ if (x < 0) {
+ x = 0;
+ changed = true;
+ }
+ if (y < 0) {
+ y = 0;
+ changed = true;
+ }
+
+ if (changed)
+ itemRect.setRect(x, y, w, h);
+}
+
+
+/*!
+ \class Q3IconView
+ \brief The Q3IconView class provides an area with movable labelled icons.
+
+ \compat
+
+ A Q3IconView can display and manage a grid or other 2D layout of
+ labelled icons. Each labelled icon is a Q3IconViewItem. Items
+ (Q3IconViewItems) can be added or deleted at any time; items can be
+ moved within the Q3IconView. Single or multiple items can be
+ selected. Items can be renamed in-place. Q3IconView also supports
+ \link #draganddrop drag and drop\endlink.
+
+ Each item contains a label string, a pixmap or picture (the icon
+ itself) and optionally a sort key. The sort key is used for
+ sorting the items and defaults to the label string. The label
+ string can be displayed below or to the right of the icon (see \l
+ ItemTextPos).
+
+ The simplest way to create a Q3IconView is to create a Q3IconView
+ object and create some Q3IconViewItems with the Q3IconView as their
+ parent, set the icon view's geometry and show it.
+ For example:
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 4
+
+ The Q3IconViewItem call passes a pointer to the Q3IconView we wish to
+ populate, along with the label text and a QPixmap.
+
+ When an item is inserted the Q3IconView allocates a position for it.
+ Existing items are rearranged if autoArrange() is true. The
+ default arrangement is \l LeftToRight -- the Q3IconView fills up
+ the \e left-most column from top to bottom, then moves one column
+ \e right and fills that from top to bottom and so on. The
+ arrangement can be modified with any of the following approaches:
+ \list
+ \i Call setArrangement(), e.g. with \l TopToBottom which will fill
+ the \e top-most row from left to right, then moves one row \e down
+ and fills that row from left to right and so on.
+ \i Construct each Q3IconViewItem using a constructor which allows
+ you to specify which item the new one is to follow.
+ \i Call setSorting() or sort() to sort the items.
+ \endlist
+
+ The spacing between items is set with setSpacing(). Items can be
+ laid out using a fixed grid using setGridX() and setGridY(); by
+ default the Q3IconView calculates a grid dynamically. The position
+ of items' label text is set with setItemTextPos(). The text's
+ background can be set with setItemTextBackground(). The maximum
+ width of an item and of its text are set with setMaxItemWidth()
+ and setMaxItemTextLength(). The label text will be word-wrapped if
+ it is too long; this is controlled by setWordWrapIconText(). If
+ the label text is truncated, the user can still see the entire
+ text in a tool tip if they hover the mouse over the item. This is
+ controlled with setShowToolTips().
+
+ Items which are \link Q3IconViewItem::isSelectable()
+ selectable\endlink may be selected depending on the SelectionMode;
+ the default is \l Single. Because Q3IconView offers multiple
+ selection it must display keyboard focus and selection state
+ separately. Therefore there are functions to set the selection
+ state of an item (setSelected()) and to select which item displays
+ keyboard focus (setCurrentItem()). When multiple items may be
+ selected the icon view provides a rubberband, too.
+
+ When in-place renaming is enabled (it is disabled by default), the
+ user may change the item's label. They do this by selecting the item
+ (single clicking it or navigating to it with the arrow keys), then
+ single clicking it (or pressing F2), and entering their text. If no
+ key has been set with Q3IconViewItem::setKey() the new text will also
+ serve as the key. (See Q3IconViewItem::setRenameEnabled().)
+
+ You can control whether users can move items themselves with
+ setItemsMovable().
+
+ Because the internal structure used to store the icon view items is
+ linear, no iterator class is needed to iterate over all the items.
+ Instead we iterate by getting the first item from the \e{icon view}
+ and then each subsequent (\l Q3IconViewItem::nextItem()) from each
+ \e item in turn:
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 5
+ Q3IconView also provides currentItem(). You can search for an item
+ using findItem() (searching by position or for label text) and
+ with findFirstVisibleItem() and findLastVisibleItem(). The number
+ of items is returned by count(). An item can be removed from an
+ icon view using takeItem(); to delete an item use \c delete. All
+ the items can be deleted with clear().
+
+ The Q3IconView emits a wide range of useful signals, including
+ selectionChanged(), currentChanged(), clicked(), moved() and
+ itemRenamed().
+
+ \target draganddrop
+ \section1 Drag and Drop
+
+ Q3IconView supports the drag and drop of items within the Q3IconView
+ itself. It also supports the drag and drop of items out of or into
+ the Q3IconView and drag and drop onto items themselves. The drag and
+ drop of items outside the Q3IconView can be achieved in a simple way
+ with basic functionality, or in a more sophisticated way which
+ provides more power and control.
+
+ The simple approach to dragging items out of the icon view is to
+ subclass Q3IconView and reimplement Q3IconView::dragObject().
+
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 6
+
+ In this example we create a Q3TextDrag object, (derived from
+ Q3DragObject), containing the item's label and return it as the drag
+ object. We could just as easily have created a Q3ImageDrag from the
+ item's pixmap and returned that instead.
+
+ Q3IconViews and their Q3IconViewItems can also be the targets of drag
+ and drops. To make the Q3IconView itself able to accept drops connect
+ to the dropped() signal. When a drop occurs this signal will be
+ emitted with a QDragEvent and a QLinkedList of Q3IconDragItems. To
+ make a Q3IconViewItem into a drop target subclass Q3IconViewItem and
+ reimplement Q3IconViewItem::acceptDrop() and
+ Q3IconViewItem::dropped().
+
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 7
+
+ If you want to use extended drag-and-drop or have drag shapes drawn
+ you must take a more sophisticated approach.
+
+ The first part is starting drags -- you should use a Q3IconDrag (or a
+ class derived from it) for the drag object. In dragObject() create the
+ drag object, populate it with Q3IconDragItems and return it. Normally
+ such a drag should offer each selected item's data. So in dragObject()
+ you should iterate over all the items, and create a Q3IconDragItem for
+ each selected item, and append these items with Q3IconDrag::append() to
+ the Q3IconDrag object. You can use Q3IconDragItem::setData() to set the
+ data of each item that should be dragged. If you want to offer the
+ data in additional mime-types, it's best to use a class derived from
+ Q3IconDrag, which implements additional encoding and decoding
+ functions.
+
+ When a drag enters the icon view, there is little to do. Simply
+ connect to the dropped() signal and reimplement
+ Q3IconViewItem::acceptDrop() and Q3IconViewItem::dropped(). If you've
+ used a Q3IconDrag (or a subclass of it) the second argument to the
+ dropped signal contains a QLinkedList of Q3IconDragItems -- you can
+ access their data by calling Q3IconDragItem::data() on each one.
+
+ For an example implementation of complex drag-and-drop look at the
+ fileiconview example (qt/examples/fileiconview).
+
+ \sa Q3IconViewItem::setDragEnabled(), Q3IconViewItem::setDropEnabled(),
+ Q3IconViewItem::acceptDrop(), Q3IconViewItem::dropped()
+*/
+
+/*! \enum Q3IconView::ResizeMode
+
+ This enum type is used to tell Q3IconView how it should treat the
+ positions of its icons when the widget is resized. The modes are:
+
+ \value Fixed The icons' positions are not changed.
+ \value Adjust The icons' positions are adjusted to be within the
+ new geometry, if possible.
+*/
+
+/*!
+ \enum Q3IconView::SelectionMode
+
+ This enumerated type is used by Q3IconView to indicate how it
+ reacts to selection by the user. It has four values:
+
+ \value Single When the user selects an item, any already-selected
+ item becomes unselected and the user cannot unselect the selected
+ item. This means that the user can never clear the selection. (The
+ application programmer can, using Q3IconView::clearSelection().)
+
+ \value Multi When the user selects an item, e.g. by navigating to
+ it with the keyboard arrow keys or by clicking it, the selection
+ status of that item is toggled and the other items are left alone.
+
+ \value Extended When the user selects an item the selection is
+ cleared and the new item selected. However, if the user presses
+ the Ctrl key when clicking on an item, the clicked item gets
+ toggled and all other items are left untouched. If the user
+ presses the Shift key while clicking on an item, all items between
+ the current item and the clicked item get selected or unselected,
+ depending on the state of the clicked item. Also, multiple items
+ can be selected by dragging the mouse while the left mouse button
+ stays pressed.
+
+ \value NoSelection Items cannot be selected.
+
+ To summarize: \c Single is a real single-selection icon view; \c
+ Multi a real multi-selection icon view; \c Extended is an icon
+ view in which users can select multiple items but usually want to
+ select either just one or a range of contiguous items; and \c
+ NoSelection mode is for an icon view where the user can look but
+ not touch.
+*/
+
+/*!
+ \enum Q3IconView::Arrangement
+
+ This enum type determines in which direction the items flow when
+ the view runs out of space.
+
+ \value LeftToRight Items which don't fit into the view go further
+ down (you get a vertical scroll bar)
+
+ \value TopToBottom Items which don't fit into the view go further
+ right (you get a horizontal scroll bar)
+*/
+
+/*!
+ \enum Q3IconView::ItemTextPos
+
+ This enum type specifies the position of the item text in relation
+ to the icon.
+
+ \value Bottom The text is drawn below the icon.
+ \value Right The text is drawn to the right of the icon.
+*/
+
+/*!
+ \fn void Q3IconView::dropped(QDropEvent *e, const Q3ValueList<Q3IconDragItem> &lst)
+
+ This signal is emitted when a drop event occurs in the viewport
+ (but not on any icon) which the icon view itself can't handle.
+
+ \a e provides all the information about the drop. If the drag
+ object of the drop was a Q3IconDrag, \a lst contains the list of
+ the dropped items. You can get the data using
+ Q3IconDragItem::data() on each item. If the \a lst is empty, i.e.
+ the drag was not a Q3IconDrag, you have to decode the data in \a e
+ and work with that.
+
+ Note Q3IconViewItems may be drop targets; if a drop event occurs on
+ an item the item handles the drop.
+*/
+
+/*!
+ \fn void Q3IconView::moved()
+
+ This signal is emitted after successfully dropping one (or more)
+ items of the icon view. If the items should be removed, it's best
+ to do so in a slot connected to this signal.
+*/
+
+/*!
+ \fn void Q3IconView::doubleClicked(Q3IconViewItem * item)
+
+ This signal is emitted when the user double-clicks on \a item.
+*/
+
+/*!
+ \fn void Q3IconView::returnPressed (Q3IconViewItem * item)
+
+ This signal is emitted if the user presses the Return or Enter
+ key. \a item is the currentItem() at the time of the keypress.
+*/
+
+/*!
+ \fn void Q3IconView::selectionChanged()
+
+ This signal is emitted when the selection has been changed. It's
+ emitted in each selection mode.
+*/
+
+/*!
+ \fn void Q3IconView::selectionChanged(Q3IconViewItem *item)
+ \overload
+
+ This signal is emitted when the selection changes. \a item is the
+ newly selected item. This signal is emitted only in single
+ selection mode.
+*/
+
+/*!
+ \fn void Q3IconView::currentChanged(Q3IconViewItem *item)
+
+ This signal is emitted when a new item becomes current. \a item is
+ the new current item (or 0 if no item is now current).
+
+ \sa currentItem()
+*/
+
+/*!
+ \fn void Q3IconView::onItem(Q3IconViewItem *item)
+
+ This signal is emitted when the user moves the mouse cursor onto
+ an \a item, similar to the QWidget::enterEvent() function.
+*/
+
+// ### bug here - enter/leave event aren't considered. move the mouse
+// out of the window and back in, to the same item.
+
+/*!
+ \fn void Q3IconView::onViewport()
+
+ This signal is emitted when the user moves the mouse cursor from
+ an item to an empty part of the icon view.
+
+ \sa onItem()
+*/
+
+/*!
+ \fn void Q3IconView::itemRenamed (Q3IconViewItem * item)
+ \overload
+
+ This signal is emitted when \a item has been renamed, usually by
+ in-place renaming.
+
+ \sa Q3IconViewItem::setRenameEnabled() Q3IconViewItem::rename()
+*/
+
+/*!
+ \fn void Q3IconView::itemRenamed (Q3IconViewItem * item, const QString &name)
+
+ This signal is emitted when \a item has been renamed to \a name,
+ usually by in-place renaming.
+
+ \sa Q3IconViewItem::setRenameEnabled() Q3IconViewItem::rename()
+*/
+
+/*!
+ \fn void Q3IconView::rightButtonClicked (Q3IconViewItem * item, const QPoint & pos)
+
+ This signal is emitted when the user clicks the right mouse
+ button. If \a item is non-null, the cursor is on \a item. If \a
+ item is null, the mouse cursor isn't on any item.
+
+ \a pos is the position of the mouse cursor in the global
+ coordinate system (QMouseEvent::globalPos()). (If the click's
+ press and release differ by a pixel or two, \a pos is the
+ position at release time.)
+
+ \sa rightButtonPressed() mouseButtonClicked() clicked()
+*/
+
+/*!
+ \fn void Q3IconView::contextMenuRequested(Q3IconViewItem *item, const QPoint & pos)
+
+ This signal is emitted when the user invokes a context menu with
+ the right mouse button or with special system keys, with \a item
+ being the item under the mouse cursor or the current item,
+ respectively.
+
+ \a pos is the position for the context menu in the global
+ coordinate system.
+*/
+
+/*!
+ \fn void Q3IconView::mouseButtonPressed(int button, Q3IconViewItem *item, const QPoint &pos)
+
+ This signal is emitted when the user presses mouse button \a
+ button. If \a item is non-null, the cursor is on \a item. If \a
+ item is null, the mouse cursor isn't on any item.
+
+ \a pos is the position of the mouse cursor in the global
+ coordinate system (QMouseEvent::globalPos()).
+
+ \sa rightButtonClicked() mouseButtonClicked() pressed()
+*/
+
+/*!
+ \fn void Q3IconView::mouseButtonClicked (int button, Q3IconViewItem * item, const QPoint & pos)
+
+ This signal is emitted when the user clicks mouse button \a
+ button. If \a item is non-null, the cursor is on \a item. If \a
+ item is null, the mouse cursor isn't on any item.
+
+ \a pos is the position of the mouse cursor in the global
+ coordinate system (QMouseEvent::globalPos()). (If the click's
+ press and release differ by a pixel or two, \a pos is the
+ position at release time.)
+
+ \sa mouseButtonPressed() rightButtonClicked() clicked()
+*/
+
+/*!
+ \fn void Q3IconView::clicked (Q3IconViewItem * item, const QPoint & pos)
+ \overload
+
+ This signal is emitted when the user clicks any mouse button on an
+ icon view item. \a item is a pointer to the item that has been
+ clicked.
+
+ \a pos is the position of the mouse cursor in the global coordinate
+ system (QMouseEvent::globalPos()). (If the click's press and release
+ differ by a pixel or two, \a pos is the position at release time.)
+
+ \sa mouseButtonClicked() rightButtonClicked() pressed()
+*/
+
+/*!
+ \fn void Q3IconView::pressed (Q3IconViewItem * item, const QPoint & pos)
+ \overload
+
+ This signal is emitted when the user presses any mouse button. If
+ \a item is non-null, the cursor is on \a item. If \a item is null,
+ the mouse cursor isn't on any item.
+
+ \a pos is the position of the mouse cursor in the global
+ coordinate system (QMouseEvent::globalPos()). (If the click's
+ press and release differ by a pixel or two, \a pos is the
+ position at release time.)
+
+ \sa mouseButtonPressed() rightButtonPressed() clicked()
+*/
+
+/*!
+ \fn void Q3IconView::clicked (Q3IconViewItem * item)
+
+ This signal is emitted when the user clicks any mouse button. If
+ \a item is non-null, the cursor is on \a item. If \a item is null,
+ the mouse cursor isn't on any item.
+
+ \sa mouseButtonClicked() rightButtonClicked() pressed()
+*/
+
+/*!
+ \fn void Q3IconView::pressed (Q3IconViewItem * item)
+
+ This signal is emitted when the user presses any mouse button. If
+ \a item is non-null, the cursor is on \a item. If \a item is null,
+ the mouse cursor isn't on any item.
+
+ \sa mouseButtonPressed() rightButtonPressed() clicked()
+*/
+
+/*!
+ \fn void Q3IconView::rightButtonPressed(Q3IconViewItem * item, const QPoint & pos)
+
+ This signal is emitted when the user presses the right mouse
+ button. If \a item is non-null, the cursor is on \a item. If \a
+ item is null, the mouse cursor isn't on any item.
+
+ \a pos is the position of the mouse cursor in the global
+ coordinate system (QMouseEvent::globalPos()).
+*/
+
+/*!
+ Constructs an empty icon view called \a name, with parent \a
+ parent and using the widget flags \a f.
+*/
+
+Q3IconView::Q3IconView(QWidget *parent, const char *name, Qt::WindowFlags f)
+ : Q3ScrollView(parent, name, Qt::WStaticContents | Qt::WNoAutoErase | f)
+{
+ if (!unknown_icon) {
+ unknown_icon = new QPixmap((const char **)unknown_xpm);
+ qiv_cleanup_pixmap.add(&unknown_icon);
+ }
+
+ d = new Q3IconViewPrivate;
+ d->dragging = false;
+ d->firstItem = 0;
+ d->lastItem = 0;
+ d->count = 0;
+ d->mousePressed = false;
+ d->selectionMode = Single;
+ d->currentItem = 0;
+ d->highlightedItem = 0;
+ d->rubber = 0;
+ d->scrollTimer = 0;
+ d->startDragItem = 0;
+ d->tmpCurrentItem = 0;
+ d->rastX = d->rastY = -1;
+ d->spacing = 5;
+ d->cleared = false;
+ d->arrangement = LeftToRight;
+ d->resizeMode = Fixed;
+ d->dropped = false;
+ d->adjustTimer = new QTimer(this, "iconview adjust timer");
+ d->isIconDrag = false;
+ d->inMenuMode = false;
+#ifndef QT_NO_DRAGANDDROP
+ d->iconDragData.clear();
+#endif
+ d->numDragItems = 0;
+ d->updateTimer = new QTimer(this, "iconview update timer");
+ d->cachedW = d->cachedH = 0;
+ d->maxItemWidth = 100;
+ d->maxItemTextLength = 255;
+ d->inputTimer = new QTimer(this, "iconview input timer");
+ d->currInputString.clear();
+ d->dirty = false;
+ d->rearrangeEnabled = true;
+ d->itemTextPos = Bottom;
+ d->reorderItemsWhenInsert = true;
+#ifndef QT_NO_CURSOR
+ d->oldCursor = Qt::ArrowCursor;
+#endif
+ d->resortItemsWhenInsert = false;
+ d->sortDirection = true;
+ d->wordWrapIconText = true;
+ d->cachedContentsX = d->cachedContentsY = -1;
+ d->clearing = false;
+ d->fullRedrawTimer = new QTimer(this, "iconview full redraw timer");
+ d->itemTextBrush = Qt::NoBrush;
+ d->drawAllBack = true;
+ d->fm = new QFontMetrics(font());
+ d->minLeftBearing = d->fm->minLeftBearing();
+ d->minRightBearing = d->fm->minRightBearing();
+ d->firstContainer = d->lastContainer = 0;
+ d->containerUpdateLocked = false;
+ d->firstSizeHint = false;
+ d->selectAnchor = 0;
+ d->renamingItem = 0;
+ d->drawActiveSelection = true;
+ d->drawDragShapes = false;
+
+ connect(d->adjustTimer, SIGNAL(timeout()),
+ this, SLOT(adjustItems()));
+ connect(d->updateTimer, SIGNAL(timeout()),
+ this, SLOT(slotUpdate()));
+ connect(d->fullRedrawTimer, SIGNAL(timeout()),
+ this, SLOT(updateContents()));
+ connect(this, SIGNAL(contentsMoving(int,int)),
+ this, SLOT(movedContents(int,int)));
+
+ setAcceptDrops(true);
+ viewport()->setAcceptDrops(true);
+
+ setMouseTracking(true);
+ viewport()->setMouseTracking(true);
+
+ viewport()->setBackgroundRole(QPalette::Base);
+ viewport()->setFocusProxy(this);
+ viewport()->setFocusPolicy(Qt::WheelFocus);
+ setFocusPolicy(Qt::WheelFocus);
+
+ d->showTips = true;
+}
+
+/*!
+ \reimp
+*/
+void Q3IconView::changeEvent(QEvent *ev)
+{
+ if(ev->type() == QEvent::StyleChange) {
+ *d->fm = QFontMetrics(font());
+ d->minLeftBearing = d->fm->minLeftBearing();
+ d->minRightBearing = d->fm->minRightBearing();
+
+ Q3IconViewItem *item = d->firstItem;
+ for (; item; item = item->next) {
+ item->wordWrapDirty = true;
+ item->calcRect();
+ }
+
+#if !defined(Q_WS_X11)
+ delete qiv_selection;
+ qiv_selection = 0;
+#endif
+ } else if(ev->type() == QEvent::ActivationChange) {
+ if (!isActiveWindow() && d->scrollTimer)
+ d->scrollTimer->stop();
+ if(isVisible() && !palette().isEqual(QPalette::Active, QPalette::Inactive))
+ repaintSelectedItems();
+ }
+
+ Q3ScrollView::changeEvent(ev);
+
+ if (ev->type() == QEvent::ApplicationFontChange || ev->type() == QEvent::FontChange) {
+ *d->fm = QFontMetrics(font());
+ d->minLeftBearing = d->fm->minLeftBearing();
+ d->minRightBearing = d->fm->minRightBearing();
+
+ Q3IconViewItem *item = d->firstItem;
+ for (; item; item = item->next) {
+ item->wordWrapDirty = true;
+ item->calcRect();
+ }
+ }
+}
+
+/*!
+ Destroys the icon view and deletes all items.
+*/
+
+Q3IconView::~Q3IconView()
+{
+ Q3IconViewItem *tmp, *item = d->firstItem;
+ d->clearing = true;
+ Q3IconViewPrivate::ItemContainer *c = d->firstContainer, *tmpc;
+ while (c) {
+ tmpc = c->n;
+ delete c;
+ c = tmpc;
+ }
+ while (item) {
+ tmp = item->next;
+ delete item;
+ item = tmp;
+ }
+ delete d->fm;
+ d->fm = 0;
+ delete d;
+}
+
+/*!
+ Inserts the icon view item \a item after \a after. If \a after is
+ 0, \a item is appended after the last item.
+
+ \e{You should never need to call this function.} Instead create
+ Q3IconViewItem's and associate them with your icon view like this:
+
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3iconview.cpp 8
+*/
+
+void Q3IconView::insertItem(Q3IconViewItem *item, Q3IconViewItem *after)
+{
+ if (!item)
+ return;
+
+ if (d->firstItem == item || item->prev || item->next)
+ return;
+
+ if (!item->view)
+ item->view = this;
+
+ if (!d->firstItem) {
+ d->firstItem = d->lastItem = item;
+ item->prev = 0;
+ item->next = 0;
+ } else {
+ if (!after || after == d->lastItem) {
+ d->lastItem->next = item;
+ item->prev = d->lastItem;
+ item->next = 0;
+ d->lastItem = item;
+ } else {
+ Q3IconViewItem *i = d->firstItem;
+ while (i != after)
+ i = i->next;
+
+ if (i) {
+ Q3IconViewItem *next = i->next;
+ item->next = next;
+ item->prev = i;
+ i->next = item;
+ next->prev = item;
+ }
+ }
+ }
+
+ if (isVisible()) {
+ if (d->reorderItemsWhenInsert) {
+ if (d->updateTimer->isActive())
+ d->updateTimer->stop();
+ d->fullRedrawTimer->stop();
+ // #### uncomment this ASA insertInGrid uses cached values and is efficient
+ //insertInGrid(item);
+
+ d->cachedW = qMax(d->cachedW, item->x() + item->width());
+ d->cachedH= qMax(d->cachedH, item->y() + item->height());
+
+ d->updateTimer->start(0, true);
+ } else {
+ insertInGrid(item);
+
+ viewport()->update(item->x() - contentsX(),
+ item->y() - contentsY(),
+ item->width(), item->height());
+ }
+ } else if (!autoArrange()) {
+ item->dirty = false;
+ }
+
+ d->count++;
+ d->dirty = true;
+}
+
+/*!
+ This slot is used for a slightly-delayed update.
+
+ The icon view is not redrawn immediately after inserting a new item
+ but after a very small delay using a QTimer. This means that when
+ many items are inserted in a loop the icon view is probably redrawn
+ only once at the end of the loop. This makes the insertions both
+ flicker-free and faster.
+*/
+
+void Q3IconView::slotUpdate()
+{
+ d->updateTimer->stop();
+ d->fullRedrawTimer->stop();
+
+ if (!d->firstItem || !d->lastItem)
+ return;
+
+ // #### remove that ASA insertInGrid uses cached values and is efficient
+ if (d->resortItemsWhenInsert)
+ sort(d->sortDirection);
+ else {
+ int y = d->spacing;
+ Q3IconViewItem *item = d->firstItem;
+ int w = 0, h = 0;
+ while (item) {
+ bool changed;
+ Q3IconViewItem *next = makeRowLayout(item, y, changed);
+ if (!next || !next->next)
+ break;
+
+ if(!QApplication::reverseLayout())
+ item = next;
+ w = qMax(w, item->x() + item->width());
+ h = qMax(h, item->y() + item->height());
+ item = next;
+ if (d->arrangement == LeftToRight)
+ h = qMax(h, y);
+
+ item = item->next;
+ }
+
+ if (d->lastItem && d->arrangement == TopToBottom) {
+ item = d->lastItem;
+ int x = item->x();
+ while (item && item->x() >= x) {
+ w = qMax(w, item->x() + item->width());
+ h = qMax(h, item->y() + item->height());
+ item = item->prev;
+ }
+ }
+
+ w = qMax(qMax(d->cachedW, w), d->lastItem->x() + d->lastItem->width());
+ h = qMax(qMax(d->cachedH, h), d->lastItem->y() + d->lastItem->height());
+
+ if (d->arrangement == TopToBottom)
+ w += d->spacing;
+ else
+ h += d->spacing;
+ viewport()->setUpdatesEnabled(false);
+ resizeContents(w, h);
+ viewport()->setUpdatesEnabled(true);
+ viewport()->repaint();
+ }
+
+ int cx = d->cachedContentsX == -1 ? contentsX() : d->cachedContentsX;
+ int cy = d->cachedContentsY == -1 ? contentsY() : d->cachedContentsY;
+
+ if (cx != contentsX() || cy != contentsY())
+ setContentsPos(cx, cy);
+
+ d->cachedContentsX = d->cachedContentsY = -1;
+ d->cachedW = d->cachedH = 0;
+}
+
+/*!
+ Takes the icon view item \a item out of the icon view and causes
+ an update of the screen display. The item is not deleted. You
+ should normally not need to call this function because
+ Q3IconViewItem::~Q3IconViewItem() calls it. The normal way to delete
+ an item is to delete it.
+*/
+
+void Q3IconView::takeItem(Q3IconViewItem *item)
+{
+ if (!item)
+ return;
+
+ if (item->d->container1)
+ item->d->container1->items.removeAll(item);
+ if (item->d->container2)
+ item->d->container2->items.removeAll(item);
+ item->d->container2 = 0;
+ item->d->container1 = 0;
+
+ bool block = signalsBlocked();
+ blockSignals(d->clearing);
+
+ QRect r = item->rect();
+
+ if (d->currentItem == item) {
+ if (item->prev) {
+ d->currentItem = item->prev;
+ emit currentChanged(d->currentItem);
+ repaintItem(d->currentItem);
+ } else if (item->next) {
+ d->currentItem = item->next;
+ emit currentChanged(d->currentItem);
+ repaintItem(d->currentItem);
+ } else {
+ d->currentItem = 0;
+ emit currentChanged(d->currentItem);
+ }
+ }
+ if (item->isSelected()) {
+ item->selected = false;
+ emit selectionChanged();
+ }
+
+ if (item == d->firstItem) {
+ d->firstItem = d->firstItem->next;
+ if (d->firstItem)
+ d->firstItem->prev = 0;
+ } else if (item == d->lastItem) {
+ d->lastItem = d->lastItem->prev;
+ if (d->lastItem)
+ d->lastItem->next = 0;
+ } else {
+ Q3IconViewItem *i = item;
+ if (i) {
+ if (i->prev)
+ i->prev->next = i->next;
+ if (i->next)
+ i->next->prev = i->prev;
+ }
+ }
+
+ if (d->selectAnchor == item)
+ d->selectAnchor = d->currentItem;
+
+ if (!d->clearing)
+ repaintContents(r.x(), r.y(), r.width(), r.height());
+
+ item->view = 0;
+ item->prev = 0;
+ item->next = 0;
+ d->count--;
+
+ blockSignals(block);
+}
+
+/*!
+ Returns the index of \a item, or -1 if \a item doesn't exist in
+ this icon view.
+*/
+
+int Q3IconView::index(const Q3IconViewItem *item) const
+{
+ if (!item)
+ return -1;
+
+ if (item == d->firstItem)
+ return 0;
+ else if (item == d->lastItem)
+ return d->count - 1;
+ else {
+ Q3IconViewItem *i = d->firstItem;
+ int j = 0;
+ while (i && i != item) {
+ i = i->next;
+ ++j;
+ }
+
+ return i ? j : -1;
+ }
+}
+
+/*!
+ Returns a pointer to the first item of the icon view, or 0 if
+ there are no items in the icon view.
+
+ \sa lastItem() currentItem()
+*/
+
+Q3IconViewItem *Q3IconView::firstItem() const
+{
+ return d->firstItem;
+}
+
+/*!
+ Returns a pointer to the last item of the icon view, or 0 if there
+ are no items in the icon view.
+
+ \sa firstItem() currentItem()
+*/
+
+Q3IconViewItem *Q3IconView::lastItem() const
+{
+ return d->lastItem;
+}
+
+/*!
+ Returns a pointer to the current item of the icon view, or 0 if no
+ item is current.
+
+ \sa setCurrentItem() firstItem() lastItem()
+*/
+
+Q3IconViewItem *Q3IconView::currentItem() const
+{
+ return d->currentItem;
+}
+
+/*!
+ \reimp
+*/
+QVariant Q3IconView::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ if (query == Qt::ImMicroFocus) {
+ return d->currentItem ? d->currentItem->rect() : QRect();
+ }
+ return QWidget::inputMethodQuery(query);
+}
+
+/*!
+ Makes \a item the new current item of the icon view.
+*/
+
+void Q3IconView::setCurrentItem(Q3IconViewItem *item)
+{
+ if (!item || item == d->currentItem)
+ return;
+
+ Q3IconViewItem *old = d->currentItem;
+ d->currentItem = item;
+ emit currentChanged(d->currentItem);
+ if (d->selectionMode == Single) {
+ bool changed = false;
+ if (old && old->selected) {
+ old->selected = false;
+ changed = true;
+ }
+ if (item && !item->selected && item->isSelectable() && d->selectionMode != NoSelection) {
+ item->selected = true;
+ changed = true;
+ emit selectionChanged(item);
+ }
+ if (changed)
+ emit selectionChanged();
+ }
+
+ if (old)
+ repaintItem(old);
+ repaintItem(d->currentItem);
+}
+
+/*!
+ Selects or unselects \a item depending on \a s, and may also
+ unselect other items, depending on Q3IconView::selectionMode() and
+ \a cb.
+
+ If \a s is false, \a item is unselected.
+
+ If \a s is true and Q3IconView::selectionMode() is \l Single, \a
+ item is selected, and the item which was selected is unselected.
+
+ If \a s is true and Q3IconView::selectionMode() is \l Extended, \a
+ item is selected. If \a cb is true, the selection state of the
+ icon view's other items is left unchanged. If \a cb is false (the
+ default) all other items are unselected.
+
+ If \a s is true and Q3IconView::selectionMode() is \l Multi \a item
+ is selected.
+
+ Note that \a cb is used only if Q3IconView::selectionMode() is \l
+ Extended. \a cb defaults to false.
+
+ All items whose selection status is changed repaint themselves.
+*/
+
+void Q3IconView::setSelected(Q3IconViewItem *item, bool s, bool cb)
+{
+ if (!item)
+ return;
+ item->setSelected(s, cb);
+}
+
+/*!
+ \property Q3IconView::count
+ \brief the number of items in the icon view
+*/
+
+uint Q3IconView::count() const
+{
+ return d->count;
+}
+
+/*!
+ Performs autoscrolling when selecting multiple icons with the
+ rubber band.
+*/
+
+void Q3IconView::doAutoScroll()
+{
+ QRect oldRubber = QRect(*d->rubber);
+
+ QPoint vp = viewport()->mapFromGlobal(QCursor::pos());
+ QPoint pos = viewportToContents(vp);
+
+ if (pos == d->rubber->bottomRight())
+ return;
+
+ d->rubber->setRight(pos.x());
+ d->rubber->setBottom(pos.y());
+
+ int minx = contentsWidth(), miny = contentsHeight();
+ int maxx = 0, maxy = 0;
+ bool changed = false;
+ bool block = signalsBlocked();
+
+ QRect rr;
+ QRegion region(0, 0, visibleWidth(), visibleHeight());
+
+ blockSignals(true);
+ viewport()->setUpdatesEnabled(false);
+ bool alreadyIntersected = false;
+ QRect nr = d->rubber->normalized();
+ QRect rubberUnion = nr.united(oldRubber.normalized());
+ Q3IconViewPrivate::ItemContainer *c = d->firstContainer;
+ for (; c; c = c->n) {
+ if (c->rect.intersects(rubberUnion)) {
+ alreadyIntersected = true;
+ for (int i = 0; i < c->items.size(); ++i) {
+ Q3IconViewItem *item = c->items.at(i);
+ if (d->selectedItems.contains(item))
+ continue;
+ if (!item->intersects(nr)) {
+ if (item->isSelected()) {
+ item->setSelected(false);
+ changed = true;
+ rr = rr.united(item->rect());
+ }
+ } else if (item->intersects(nr)) {
+ if (!item->isSelected() && item->isSelectable()) {
+ item->setSelected(true, true);
+ changed = true;
+ rr = rr.united(item->rect());
+ } else {
+ region = region.subtracted(QRect(contentsToViewport(item->pos()),
+ item->size()));
+ }
+
+ minx = qMin(minx, item->x() - 1);
+ miny = qMin(miny, item->y() - 1);
+ maxx = qMax(maxx, item->x() + item->width() + 1);
+ maxy = qMax(maxy, item->y() + item->height() + 1);
+ }
+ }
+ } else {
+ if (alreadyIntersected)
+ break;
+ }
+ }
+ viewport()->setUpdatesEnabled(true);
+ blockSignals(block);
+
+ QRect r = *d->rubber;
+ *d->rubber = oldRubber;
+ d->dragging = false;
+ *d->rubber = r;
+ if (changed) {
+ d->drawAllBack = false;
+ d->clipRegion = region;
+ repaintContents(rr);
+ d->drawAllBack = true;
+ }
+ ensureVisible(pos.x(), pos.y());
+ d->dragging = true;
+
+ if (changed) {
+ emit selectionChanged();
+ if (d->selectionMode == Single)
+ emit selectionChanged(d->currentItem);
+ }
+
+ if (!QRect(50, 50, viewport()->width()-100, viewport()->height()-100).contains(vp) &&
+ !d->scrollTimer) {
+ d->scrollTimer = new QTimer(this);
+
+ connect(d->scrollTimer, SIGNAL(timeout()),
+ this, SLOT(doAutoScroll()));
+ d->scrollTimer->start(100, false);
+ } else if (QRect(50, 50, viewport()->width()-100, viewport()->height()-100).contains(vp) &&
+ d->scrollTimer) {
+ disconnect(d->scrollTimer, SIGNAL(timeout()),
+ this, SLOT(doAutoScroll()));
+ d->scrollTimer->stop();
+ delete d->scrollTimer;
+ d->scrollTimer = 0;
+ }
+
+}
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::drawContents(QPainter *p, int cx, int cy, int cw, int ch)
+{
+ if (d->dragging && d->rubber)
+ drawRubber(p);
+
+ QRect r = QRect(cx, cy, cw, ch);
+
+ Q3IconViewPrivate::ItemContainer *c = d->firstContainer;
+ QRegion remaining(QRect(cx, cy, cw, ch));
+ bool alreadyIntersected = false;
+ while (c) {
+ if (c->rect.intersects(r)) {
+ p->save();
+ p->resetXForm();
+ QRect r2 = c->rect;
+ r2 = r2.intersected(r);
+ QRect r3(contentsToViewport(QPoint(r2.x(), r2.y())), QSize(r2.width(), r2.height()));
+ if (d->drawAllBack) {
+ p->setClipRect(r3);
+ } else {
+ QRegion reg = d->clipRegion.intersected(r3);
+ p->setClipRegion(reg);
+ }
+ drawBackground(p, r3);
+ remaining = remaining.subtracted(r3);
+ p->restore();
+
+ QPalette pal = palette();
+ d->drawActiveSelection = hasFocus() || d->inMenuMode
+ || !style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this);
+ if (!d->drawActiveSelection)
+ pal.setCurrentColorGroup(QPalette::Inactive);
+
+ // clip items to the container rect by default... this
+ // prevents icons with alpha channels from being painted
+ // twice when they are in 2 containers
+ //
+ // NOTE: the item could override this cliprect in its
+ // paintItem() implementation, which makes this useless
+ p->setClipRect(r2);
+ for (int i = 0; i < c->items.size(); ++i) {
+ Q3IconViewItem *item = c->items.at(i);
+ if (item->rect().intersects(r) && !item->dirty) {
+ p->save();
+ p->setFont(font());
+ item->paintItem(p, pal);
+ p->restore();
+ }
+ }
+ alreadyIntersected = true;
+ } else {
+ if (alreadyIntersected)
+ break;
+ }
+ c = c->n;
+ }
+
+ if (!remaining.isEmpty()) {
+ p->save();
+ p->resetXForm();
+ if (d->drawAllBack) {
+ p->setClipRegion(remaining);
+ } else {
+ remaining = d->clipRegion.intersected(remaining);
+ p->setClipRegion(remaining);
+ }
+ drawBackground(p, remaining.boundingRect());
+ p->restore();
+ }
+
+ if ((hasFocus() || viewport()->hasFocus()) && d->currentItem &&
+ d->currentItem->rect().intersects(r)) {
+ d->currentItem->paintFocus(p, palette());
+ }
+
+ if (d->dragging && d->rubber)
+ drawRubber(p);
+}
+
+/*!
+ \overload
+
+ Arranges all the items in the grid specified by gridX() and gridY().
+
+ Even if sorting() is enabled, the items are not sorted by this
+ function. If you want to sort or rearrange the items, use
+ iconview->sort(iconview->sortDirection()).
+
+ If \a update is true (the default), the viewport is repainted as
+ well.
+
+ \sa Q3IconView::setGridX(), Q3IconView::setGridY(), Q3IconView::sort()
+*/
+
+void Q3IconView::arrangeItemsInGrid(bool update)
+{
+ if (!d->firstItem || !d->lastItem)
+ return;
+
+ d->containerUpdateLocked = true;
+
+ int w = 0, h = 0, y = d->spacing;
+
+ Q3IconViewItem *item = d->firstItem;
+ bool changedLayout = false;
+ while (item) {
+ bool changed;
+ Q3IconViewItem *next = makeRowLayout(item, y, changed);
+ changedLayout = changed || changedLayout;
+ if(!QApplication::reverseLayout())
+ item = next;
+ w = qMax(w, item->x() + item->width());
+ h = qMax(h, item->y() + item->height());
+ item = next;
+ if (d->arrangement == LeftToRight)
+ h = qMax(h, y);
+
+ if (!item || !item->next)
+ break;
+
+ item = item->next;
+ }
+
+ if (d->lastItem && d->arrangement == TopToBottom) {
+ item = d->lastItem;
+ int x = item->x();
+ while (item && item->x() >= x) {
+ w = qMax(w, item->x() + item->width());
+ h = qMax(h, item->y() + item->height());
+ item = item->prev;
+ }
+ }
+ d->containerUpdateLocked = false;
+
+ w = qMax(qMax(d->cachedW, w), d->lastItem->x() + d->lastItem->width());
+ h = qMax(qMax(d->cachedH, h), d->lastItem->y() + d->lastItem->height());
+
+ if (d->arrangement == TopToBottom)
+ w += d->spacing;
+ else
+ h += d->spacing;
+
+ bool ue = updatesEnabled();
+ if (ue)
+ viewport()->setUpdatesEnabled(false);
+ int vw = visibleWidth();
+ int vh = visibleHeight();
+ resizeContents(w, h);
+ bool doAgain = false;
+ if (d->arrangement == LeftToRight)
+ doAgain = visibleWidth() != vw;
+ if (d->arrangement == TopToBottom)
+ doAgain = visibleHeight() != vh;
+ if (doAgain) // in the case that the visibleExtend changed because of the resizeContents (scroll bar show/hide), redo layout again
+ arrangeItemsInGrid(false);
+ if (ue)
+ viewport()->setUpdatesEnabled(true);
+ d->dirty = !isVisible();
+ rebuildContainers();
+ if (update && (!optimize_layout || changedLayout))
+ repaintContents(contentsX(), contentsY(), viewport()->width(), viewport()->height());
+}
+
+/*!
+ This variant uses \a grid instead of (gridX(), gridY()). If \a
+ grid is invalid (see QSize::isValid()), arrangeItemsInGrid()
+ calculates a valid grid itself and uses that.
+
+ If \a update is true (the default) the viewport is repainted.
+*/
+
+void Q3IconView::arrangeItemsInGrid(const QSize &grid, bool update)
+{
+ d->containerUpdateLocked = true;
+ QSize grid_(grid);
+ if (!grid_.isValid()) {
+ int w = 0, h = 0;
+ Q3IconViewItem *item = d->firstItem;
+ for (; item; item = item->next) {
+ w = qMax(w, item->width());
+ h = qMax(h, item->height());
+ }
+
+ grid_ = QSize(qMax(d->rastX + d->spacing, w),
+ qMax(d->rastY + d->spacing, h));
+ }
+
+ int w = 0, h = 0;
+ Q3IconViewItem *item = d->firstItem;
+ for (; item; item = item->next) {
+ int nx = item->x() / grid_.width();
+ int ny = item->y() / grid_.height();
+ item->move(nx * grid_.width(),
+ ny * grid_.height());
+ w = qMax(w, item->x() + item->width());
+ h = qMax(h, item->y() + item->height());
+ item->dirty = false;
+ }
+ d->containerUpdateLocked = false;
+
+ resizeContents(w, h);
+ rebuildContainers();
+ if (update)
+ repaintContents(contentsX(), contentsY(), viewport()->width(), viewport()->height());
+}
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::setContentsPos(int x, int y)
+{
+ if (d->updateTimer->isActive()) {
+ d->cachedContentsX = x;
+ d->cachedContentsY = y;
+ } else {
+ d->cachedContentsY = d->cachedContentsX = -1;
+ Q3ScrollView::setContentsPos(x, y);
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::showEvent(QShowEvent *)
+{
+ if (d->dirty) {
+ resizeContents(qMax(contentsWidth(), viewport()->width()),
+ qMax(contentsHeight(), viewport()->height()));
+ if (d->resortItemsWhenInsert)
+ sort(d->sortDirection);
+ if (autoArrange())
+ arrangeItemsInGrid(false);
+ }
+ Q3ScrollView::show();
+}
+
+/*!
+ \property Q3IconView::selectionMode
+ \brief the selection mode of the icon view
+
+ This can be \l Single (the default), \l Extended, \l Multi or \l
+ NoSelection.
+*/
+
+void Q3IconView::setSelectionMode(SelectionMode m)
+{
+ d->selectionMode = m;
+}
+
+Q3IconView::SelectionMode Q3IconView::selectionMode() const
+{
+ return d->selectionMode;
+}
+
+/*!
+ Returns a pointer to the item that contains point \a pos, which is
+ given in contents coordinates, or 0 if no item contains point \a
+ pos.
+*/
+
+Q3IconViewItem *Q3IconView::findItem(const QPoint &pos) const
+{
+ if (!d->firstItem)
+ return 0;
+
+ Q3IconViewPrivate::ItemContainer *c = d->lastContainer;
+ for (; c; c = c->p) {
+ if (c->rect.contains(pos))
+ for (int i = c->items.size()-1; i >= 0; --i)
+ if (c->items.at(i)->contains(pos))
+ return c->items.at(i);
+ }
+
+ return 0;
+}
+
+/*!
+ \overload
+
+ Returns a pointer to the first item whose text begins with \a
+ text, or 0 if no such item could be found. Use the \a compare flag
+ to control the comparison behavior.
+*/
+
+Q3IconViewItem *Q3IconView::findItem(const QString &text, ComparisonFlags compare) const
+{
+ if (!d->firstItem)
+ return 0;
+
+ if (compare == CaseSensitive || compare == 0)
+ compare |= ExactMatch;
+
+ QString itmtxt;
+ QString comtxt = text;
+ if (! (compare & CaseSensitive))
+ comtxt = text.toLower();
+
+ Q3IconViewItem *item;
+ if (d->currentItem)
+ item = d->currentItem;
+ else
+ item = d->firstItem;
+
+ Q3IconViewItem *beginsWithItem = 0;
+ Q3IconViewItem *endsWithItem = 0;
+ Q3IconViewItem *containsItem = 0;
+
+ if (item) {
+ for (; item; item = item->next) {
+ if (!(compare & CaseSensitive))
+ itmtxt = item->text().toLower();
+ else
+ itmtxt = item->text();
+
+ if ((compare & ExactMatch)==ExactMatch && itmtxt == comtxt)
+ return item;
+ if (compare & BeginsWith && !beginsWithItem && itmtxt.startsWith(comtxt))
+ beginsWithItem = containsItem = item;
+ if (compare & EndsWith && !endsWithItem && itmtxt.endsWith(comtxt))
+ endsWithItem = containsItem = item;
+ if ((compare & ExactMatch)==0 && !containsItem && itmtxt.contains(comtxt))
+ containsItem = item;
+ }
+
+ if (d->currentItem && d->firstItem) {
+ item = d->firstItem;
+ for (; item && item != d->currentItem; item = item->next) {
+ if (!(compare & CaseSensitive))
+ itmtxt = item->text().toLower();
+ else
+ itmtxt = item->text();
+
+ if ((compare & ExactMatch)==ExactMatch && itmtxt == comtxt)
+ return item;
+ if (compare & BeginsWith && !beginsWithItem && itmtxt.startsWith(comtxt))
+ beginsWithItem = containsItem = item;
+ if (compare & EndsWith && !endsWithItem && itmtxt.endsWith(comtxt))
+ endsWithItem = containsItem = item;
+ if ((compare & ExactMatch)==0 && !containsItem && itmtxt.contains(comtxt))
+ containsItem = item;
+ }
+ }
+ }
+
+ // Obey the priorities
+ if (beginsWithItem)
+ return beginsWithItem;
+ else if (endsWithItem)
+ return endsWithItem;
+ else if (containsItem)
+ return containsItem;
+ return 0;
+}
+
+/*!
+ Unselects all the items.
+*/
+
+void Q3IconView::clearSelection()
+{
+ selectAll(false);
+}
+
+/*!
+ In Multi and Extended modes, this function sets all items to be
+ selected if \a select is true, and to be unselected if \a select
+ is false.
+
+ In Single and NoSelection modes, this function only changes the
+ selection status of currentItem().
+*/
+
+void Q3IconView::selectAll(bool select)
+{
+ if (d->selectionMode == NoSelection)
+ return;
+
+ if (d->selectionMode == Single) {
+ if (d->currentItem)
+ d->currentItem->setSelected(select);
+ return;
+ }
+
+ bool b = signalsBlocked();
+ blockSignals(true);
+ Q3IconViewItem *item = d->firstItem;
+ Q3IconViewItem *i = d->currentItem;
+ bool changed = false;
+ bool ue = viewport()->updatesEnabled();
+ if (ue)
+ viewport()->setUpdatesEnabled(false);
+ QRect rr;
+ for (; item; item = item->next) {
+ if (select != item->isSelected()) {
+ item->setSelected(select, true);
+ rr = rr.united(item->rect());
+ changed = true;
+ }
+ }
+ if (ue)
+ viewport()->setUpdatesEnabled(true);
+ // we call updateContents not repaintContents because of possible previous updateContents
+ Q3ScrollView::updateContents(rr);
+ QApplication::sendPostedEvents(viewport(), QEvent::Paint);
+ if (i)
+ setCurrentItem(i);
+ blockSignals(b);
+ if (changed) {
+ emit selectionChanged();
+ }
+}
+
+/*!
+ Inverts the selection. Works only in Multi and Extended selection
+ mode.
+*/
+
+void Q3IconView::invertSelection()
+{
+ if (d->selectionMode == Single ||
+ d->selectionMode == NoSelection)
+ return;
+
+ bool b = signalsBlocked();
+ blockSignals(true);
+ Q3IconViewItem *item = d->firstItem;
+ for (; item; item = item->next)
+ item->setSelected(!item->isSelected(), true);
+ blockSignals(b);
+ emit selectionChanged();
+}
+
+/*!
+ Repaints the \a item.
+*/
+
+void Q3IconView::repaintItem(Q3IconViewItem *item)
+{
+ if (!item || item->dirty)
+ return;
+
+ if (QRect(contentsX(), contentsY(), visibleWidth(), visibleHeight()).
+ intersects(QRect(item->x() - 1, item->y() - 1, item->width() + 2, item->height() + 2)))
+ repaintContents(item->x() - 1, item->y() - 1, item->width() + 2, item->height() + 2);
+}
+
+/*!
+ Repaints the selected items.
+*/
+void Q3IconView::repaintSelectedItems()
+{
+ if (selectionMode() == NoSelection)
+ return;
+
+ if (selectionMode() == Single) {
+ if (!currentItem() || !currentItem()->isSelected())
+ return;
+ QRect itemRect = currentItem()->rect(); //rect in contents coordinates
+ itemRect.moveBy(-contentsX(), -contentsY());
+ viewport()->update(itemRect);
+ } else {
+ // check if any selected items are visible
+ Q3IconViewItem *item = firstItem();
+ const QRect vr = QRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
+
+ while (item) {
+ if (item->isSelected() && item->rect().intersects(vr))
+ repaintItem(item);
+ item = item->nextItem();
+ }
+ }
+}
+
+/*!
+ Makes sure that \a item is entirely visible. If necessary,
+ ensureItemVisible() scrolls the icon view.
+
+ \sa ensureVisible()
+*/
+
+void Q3IconView::ensureItemVisible(Q3IconViewItem *item)
+{
+ if (!item)
+ return;
+
+ if ((d->updateTimer && d->updateTimer->isActive())
+ || (d->fullRedrawTimer && d->fullRedrawTimer->isActive()))
+ slotUpdate();
+
+ int w = item->width();
+ int h = item->height();
+ ensureVisible(item->x() + w / 2, item->y() + h / 2,
+ w / 2 + 1, h / 2 + 1);
+}
+
+/*!
+ Finds the first item whose bounding rectangle overlaps \a r and
+ returns a pointer to that item. \a r is given in content
+ coordinates. Returns 0 if no item overlaps \a r.
+
+ If you want to find all items that touch \a r, you will need to
+ use this function and nextItem() in a loop ending at
+ findLastVisibleItem() and test Q3IconViewItem::rect() for each of
+ these items.
+
+ \sa findLastVisibleItem() Q3IconViewItem::rect()
+*/
+
+Q3IconViewItem* Q3IconView::findFirstVisibleItem(const QRect &r) const
+{
+ Q3IconViewPrivate::ItemContainer *c = d->firstContainer;
+ Q3IconViewItem *i = 0;
+ bool alreadyIntersected = false;
+ for (; c; c = c->n) {
+ if (c->rect.intersects(r)) {
+ alreadyIntersected = true;
+ for (int j = 0; j < c->items.size(); ++j) {
+ Q3IconViewItem *item = c->items.at(j);
+ if (r.intersects(item->rect())) {
+ if (!i) {
+ i = item;
+ } else {
+ QRect r2 = item->rect();
+ QRect r3 = i->rect();
+ if (r2.y() < r3.y())
+ i = item;
+ else if (r2.y() == r3.y() &&
+ r2.x() < r3.x())
+ i = item;
+ }
+ }
+ }
+ } else {
+ if (alreadyIntersected)
+ break;
+ }
+ }
+
+ return i;
+}
+
+/*!
+ Finds the last item whose bounding rectangle overlaps \a r and
+ returns a pointer to that item. \a r is given in content
+ coordinates. Returns 0 if no item overlaps \a r.
+
+ \sa findFirstVisibleItem()
+*/
+
+Q3IconViewItem* Q3IconView::findLastVisibleItem(const QRect &r) const
+{
+ Q3IconViewPrivate::ItemContainer *c = d->firstContainer;
+ Q3IconViewItem *i = 0;
+ bool alreadyIntersected = false;
+ for (; c; c = c->n) {
+ if (c->rect.intersects(r)) {
+ alreadyIntersected = true;
+ for (int j = 0; j < c->items.size(); ++j) {
+ Q3IconViewItem *item = c->items.at(j);
+ if (r.intersects(item->rect())) {
+ if (!i) {
+ i = item;
+ } else {
+ QRect r2 = item->rect();
+ QRect r3 = i->rect();
+ if (r2.y() > r3.y())
+ i = item;
+ else if (r2.y() == r3.y() &&
+ r2.x() > r3.x())
+ i = item;
+ }
+ }
+ }
+ } else {
+ if (alreadyIntersected)
+ break;
+ }
+ }
+
+ return i;
+}
+
+/*!
+ Clears the icon view. All items are deleted.
+*/
+
+void Q3IconView::clear()
+{
+ setContentsPos(0, 0);
+ d->clearing = true;
+ bool block = signalsBlocked();
+ blockSignals(true);
+ clearSelection();
+ blockSignals(block);
+ setContentsPos(0, 0);
+ d->currentItem = 0;
+
+ if (!d->firstItem) {
+ d->clearing = false;
+ return;
+ }
+
+ Q3IconViewItem *item = d->firstItem, *tmp;
+ d->firstItem = 0;
+ while (item) {
+ tmp = item->next;
+ delete item;
+ item = tmp;
+ }
+ Q3IconViewPrivate::ItemContainer *c = d->firstContainer, *tmpc;
+ while (c) {
+ tmpc = c->n;
+ delete c;
+ c = tmpc;
+ }
+ d->firstContainer = d->lastContainer = 0;
+
+ d->count = 0;
+ d->lastItem = 0;
+ setCurrentItem(0);
+ d->highlightedItem = 0;
+ d->tmpCurrentItem = 0;
+ d->drawDragShapes = false;
+
+ resizeContents(0, 0);
+ // maybe we don't need this update, so delay it
+ d->fullRedrawTimer->start(0, true);
+
+ d->cleared = true;
+ d->clearing = false;
+}
+
+/*!
+ \property Q3IconView::gridX
+ \brief the horizontal grid of the icon view
+
+ If the value is -1, (the default), Q3IconView computes suitable
+ column widths based on the icon view's contents.
+
+ Note that setting a grid width overrides setMaxItemWidth().
+*/
+
+void Q3IconView::setGridX(int rx)
+{
+ d->rastX = rx >= 0 ? rx : -1;
+}
+
+/*!
+ \property Q3IconView::gridY
+ \brief the vertical grid of the icon view
+
+ If the value is -1, (the default), Q3IconView computes suitable
+ column heights based on the icon view's contents.
+*/
+
+void Q3IconView::setGridY(int ry)
+{
+ d->rastY = ry >= 0 ? ry : -1;
+}
+
+int Q3IconView::gridX() const
+{
+ return d->rastX;
+}
+
+int Q3IconView::gridY() const
+{
+ return d->rastY;
+}
+
+/*!
+ \property Q3IconView::spacing
+ \brief the space in pixels between icon view items
+
+ The default is 5 pixels.
+
+ Negative values for spacing are illegal.
+*/
+
+void Q3IconView::setSpacing(int sp)
+{
+ d->spacing = sp;
+}
+
+int Q3IconView::spacing() const
+{
+ return d->spacing;
+}
+
+/*!
+ \property Q3IconView::itemTextPos
+ \brief the position where the text of each item is drawn.
+
+ Valid values are \l Bottom or \l Right. The default is \l Bottom.
+*/
+
+void Q3IconView::setItemTextPos(ItemTextPos pos)
+{
+ if (pos == d->itemTextPos || (pos != Bottom && pos != Right))
+ return;
+
+ d->itemTextPos = pos;
+
+ Q3IconViewItem *item = d->firstItem;
+ for (; item; item = item->next) {
+ item->wordWrapDirty = true;
+ item->calcRect();
+ }
+
+ arrangeItemsInGrid(true);
+}
+
+Q3IconView::ItemTextPos Q3IconView::itemTextPos() const
+{
+ return d->itemTextPos;
+}
+
+/*!
+ \property Q3IconView::itemTextBackground
+ \brief the brush to use when drawing the background of an item's text.
+
+ By default this brush is set to Qt::NoBrush, meaning that only the
+ normal icon view background is used.
+*/
+
+void Q3IconView::setItemTextBackground(const QBrush &brush)
+{
+ d->itemTextBrush = brush;
+}
+
+QBrush Q3IconView::itemTextBackground() const
+{
+ return d->itemTextBrush;
+}
+
+/*!
+ \property Q3IconView::arrangement
+ \brief the arrangement mode of the icon view
+
+ This can be \l LeftToRight or \l TopToBottom. The default is \l
+ LeftToRight.
+*/
+
+void Q3IconView::setArrangement(Arrangement am)
+{
+ if (d->arrangement == am)
+ return;
+
+ d->arrangement = am;
+
+ viewport()->setUpdatesEnabled(false);
+ resizeContents(viewport()->width(), viewport()->height());
+ viewport()->setUpdatesEnabled(true);
+ arrangeItemsInGrid(true);
+}
+
+Q3IconView::Arrangement Q3IconView::arrangement() const
+{
+ return d->arrangement;
+}
+
+/*!
+ \property Q3IconView::resizeMode
+ \brief the resize mode of the icon view
+
+ This can be \l Fixed or \l Adjust. The default is \l Fixed.
+ See \l ResizeMode.
+*/
+
+void Q3IconView::setResizeMode(ResizeMode rm)
+{
+ if (d->resizeMode == rm)
+ return;
+
+ d->resizeMode = rm;
+}
+
+Q3IconView::ResizeMode Q3IconView::resizeMode() const
+{
+ return d->resizeMode;
+}
+
+/*!
+ \property Q3IconView::maxItemWidth
+ \brief the maximum width that an item may have.
+
+ The default is 100 pixels.
+
+ Note that if the gridX() value is set Q3IconView will ignore
+ this property.
+*/
+
+void Q3IconView::setMaxItemWidth(int w)
+{
+ d->maxItemWidth = w;
+}
+
+/*!
+ \property Q3IconView::maxItemTextLength
+ \brief the maximum length (in characters) that an item's text may have.
+
+ The default is 255 characters.
+*/
+
+void Q3IconView::setMaxItemTextLength(int w)
+{
+ d->maxItemTextLength = w;
+}
+
+int Q3IconView::maxItemWidth() const
+{
+ if (d->rastX != -1)
+ return d->rastX - 2;
+ else
+ return d->maxItemWidth;
+}
+
+int Q3IconView::maxItemTextLength() const
+{
+ return d->maxItemTextLength;
+}
+
+/*!
+ \property Q3IconView::itemsMovable
+ \brief whether the user is allowed to move items around in the icon view
+
+ The default is true.
+*/
+
+void Q3IconView::setItemsMovable(bool b)
+{
+ d->rearrangeEnabled = b;
+}
+
+bool Q3IconView::itemsMovable() const
+{
+ return d->rearrangeEnabled;
+}
+
+/*!
+ \property Q3IconView::autoArrange
+ \brief whether the icon view rearranges its items when a new item is inserted.
+
+ The default is true.
+
+ Note that if the icon view is not visible at the time of
+ insertion, Q3IconView defers all position-related work until it is
+ shown and then calls arrangeItemsInGrid().
+*/
+
+void Q3IconView::setAutoArrange(bool b)
+{
+ d->reorderItemsWhenInsert = b;
+}
+
+bool Q3IconView::autoArrange() const
+{
+ return d->reorderItemsWhenInsert;
+}
+
+/*!
+ If \a sort is true, this function sets the icon view to sort items
+ when a new item is inserted. If \a sort is false, the icon view
+ will not be sorted.
+
+ Note that autoArrange() must be true for sorting to take place.
+
+ If \a ascending is true (the default), items are sorted in
+ ascending order. If \a ascending is false, items are sorted in
+ descending order.
+
+ Q3IconViewItem::compare() is used to compare pairs of items. The
+ sorting is based on the items' keys; these default to the items'
+ text unless specifically set to something else.
+
+ \sa Q3IconView::setAutoArrange(), Q3IconView::autoArrange(),
+ sortDirection(), sort(), Q3IconViewItem::setKey()
+*/
+
+void Q3IconView::setSorting(bool sort, bool ascending)
+{
+ d->resortItemsWhenInsert = sort;
+ d->sortDirection = ascending;
+}
+
+/*!
+ \property Q3IconView::sorting
+ \brief whether the icon view sorts on insertion
+
+ The default is false, i.e. no sorting on insertion.
+
+ To set the sorting, use setSorting().
+*/
+
+bool Q3IconView::sorting() const
+{
+ return d->resortItemsWhenInsert;
+}
+
+/*!
+ \property Q3IconView::sortDirection
+ \brief whether the sort direction for inserting new items is ascending;
+
+ The default is true (i.e. ascending). This sort direction is only
+ meaningful if both sorting() and autoArrange() are true.
+
+ To set the sort direction, use setSorting()
+*/
+
+bool Q3IconView::sortDirection() const
+{
+ return d->sortDirection;
+}
+
+/*!
+ \property Q3IconView::wordWrapIconText
+ \brief whether the item text will be word-wrapped if it is too long
+
+ The default is true.
+
+ If this property is false, icon text that is too long is
+ truncated, and an ellipsis (...) appended to indicate that
+ truncation has occurred. The full text can still be seen by the
+ user if they hover the mouse because the full text is shown in a
+ tooltip; see setShowToolTips().
+*/
+
+void Q3IconView::setWordWrapIconText(bool b)
+{
+ if (d->wordWrapIconText == (uint)b)
+ return;
+
+ d->wordWrapIconText = b;
+ for (Q3IconViewItem *item = d->firstItem; item; item = item->next) {
+ item->wordWrapDirty = true;
+ item->calcRect();
+ }
+ arrangeItemsInGrid(true);
+}
+
+bool Q3IconView::wordWrapIconText() const
+{
+ return d->wordWrapIconText;
+}
+
+/*!
+ \property Q3IconView::showToolTips
+ \brief whether the icon view will display a tool tip with the complete text for any truncated item text
+
+ The default is true. Note that this has no effect if
+ setWordWrapIconText() is true, as it is by default.
+*/
+
+void Q3IconView::setShowToolTips(bool b)
+{
+ d->showTips = b;
+}
+
+bool Q3IconView::showToolTips() const
+{
+ return d->showTips;
+}
+
+/*!
+ \reimp
+*/
+void Q3IconView::contentsMousePressEvent(QMouseEvent *e)
+{
+ contentsMousePressEventEx(e);
+}
+
+void Q3IconView::contentsMousePressEventEx(QMouseEvent *e)
+{
+ if (d->rubber) {
+ d->dragging = false;
+ delete d->rubber;
+ d->rubber = 0;
+ viewport()->update();
+
+ if (d->scrollTimer) {
+ disconnect(d->scrollTimer, SIGNAL(timeout()), this, SLOT(doAutoScroll()));
+ d->scrollTimer->stop();
+ delete d->scrollTimer;
+ d->scrollTimer = 0;
+ }
+ }
+
+ d->dragStartPos = e->pos();
+ Q3IconViewItem *item = findItem(e->pos());
+ d->pressedItem = item;
+
+ if (item)
+ d->selectAnchor = item;
+
+#ifndef QT_NO_TEXTEDIT
+ if (d->renamingItem)
+ d->renamingItem->renameItem();
+#endif
+
+ if (!d->currentItem && !item && d->firstItem) {
+ d->currentItem = d->firstItem;
+ repaintItem(d->firstItem);
+ }
+
+ if (item && item->dragEnabled())
+ d->startDragItem = item;
+ else
+ d->startDragItem = 0;
+
+ if (e->button() == Qt::LeftButton && !(e->state() & Qt::ShiftButton) &&
+ !(e->state() & Qt::ControlButton) && item && item->isSelected() &&
+ item->textRect(false).contains(e->pos())) {
+
+ if (!item->renameEnabled()) {
+ d->mousePressed = true;
+#ifndef QT_NO_TEXTEDIT
+ } else {
+ ensureItemVisible(item);
+ setCurrentItem(item);
+ item->rename();
+ goto emit_signals;
+#endif
+ }
+ }
+
+ d->pressedSelected = item && item->isSelected();
+
+ if (item && item->isSelectable()) {
+ if (d->selectionMode == Single)
+ item->setSelected(true, e->state() & Qt::ControlButton);
+ else if (d->selectionMode == Multi && !item->isSelected())
+ item->setSelected(true, e->state() & Qt::ControlButton);
+ else if (d->selectionMode == Extended) {
+ if (e->state() & Qt::ShiftButton) {
+ d->pressedSelected = false;
+ bool block = signalsBlocked();
+ blockSignals(true);
+ viewport()->setUpdatesEnabled(false);
+ QRect r;
+ bool select = true;
+ if (d->currentItem)
+ r = QRect(qMin(d->currentItem->x(), item->x()),
+ qMin(d->currentItem->y(), item->y()),
+ 0, 0);
+ else
+ r = QRect(0, 0, 0, 0);
+ if (d->currentItem) {
+ if (d->currentItem->x() < item->x())
+ r.setWidth(item->x() - d->currentItem->x() + item->width());
+ else
+ r.setWidth(d->currentItem->x() - item->x() + d->currentItem->width());
+ if (d->currentItem->y() < item->y())
+ r.setHeight(item->y() - d->currentItem->y() + item->height());
+ else
+ r.setHeight(d->currentItem->y() - item->y() + d->currentItem->height());
+ r = r.normalized();
+ Q3IconViewPrivate::ItemContainer *c = d->firstContainer;
+ bool alreadyIntersected = false;
+ QRect redraw;
+ for (; c; c = c->n) {
+ if (c->rect.intersects(r)) {
+ alreadyIntersected = true;
+ for (int i = 0; i < c->items.size(); ++i) {
+ Q3IconViewItem *item = c->items.at(i);
+ if (r.intersects(item->rect())) {
+ redraw = redraw.united(item->rect());
+ item->setSelected(select, true);
+ }
+ }
+ } else {
+ if (alreadyIntersected)
+ break;
+ }
+ }
+ redraw = redraw.united(item->rect());
+ viewport()->setUpdatesEnabled(true);
+ repaintContents(redraw);
+ }
+ blockSignals(block);
+ viewport()->setUpdatesEnabled(true);
+ item->setSelected(select, true);
+ emit selectionChanged();
+ } else if (e->state() & Qt::ControlButton) {
+ d->pressedSelected = false;
+ item->setSelected(!item->isSelected(), e->state() & Qt::ControlButton);
+ } else {
+ item->setSelected(true, e->state() & Qt::ControlButton);
+ }
+ }
+ } else if ((d->selectionMode != Single || e->button() == Qt::RightButton)
+ && !(e->state() & Qt::ControlButton))
+ selectAll(false);
+
+ setCurrentItem(item);
+
+ if (e->button() == Qt::LeftButton) {
+ if (!item && (d->selectionMode == Multi ||
+ d->selectionMode == Extended)) {
+ d->tmpCurrentItem = d->currentItem;
+ d->currentItem = 0;
+ repaintItem(d->tmpCurrentItem);
+ if (d->rubber)
+ delete d->rubber;
+ d->rubber = 0;
+ d->rubber = new QRect(e->x(), e->y(), 0, 0);
+ d->selectedItems.clear();
+ if ((e->state() & Qt::ControlButton) == Qt::ControlButton) {
+ for (Q3IconViewItem *i = firstItem(); i; i = i->nextItem())
+ if (i->isSelected())
+ d->selectedItems.insert(i, i);
+ }
+ }
+
+ d->mousePressed = true;
+ }
+
+ emit_signals:
+ if (!d->rubber) {
+ emit mouseButtonPressed(e->button(), item, e->globalPos());
+ emit pressed(item);
+ emit pressed(item, e->globalPos());
+
+ if (e->button() == Qt::RightButton)
+ emit rightButtonPressed(item, e->globalPos());
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::contentsContextMenuEvent(QContextMenuEvent *e)
+{
+ if (!receivers(SIGNAL(contextMenuRequested(Q3IconViewItem*,QPoint)))) {
+ e->ignore();
+ return;
+ }
+ if (e->reason() == QContextMenuEvent::Keyboard) {
+ Q3IconViewItem *item = currentItem();
+ QRect r = item ? item->rect() : QRect(0, 0, visibleWidth(), visibleHeight());
+ emit contextMenuRequested(item, viewport()->mapToGlobal(contentsToViewport(r.center())));
+ } else {
+ d->mousePressed = false;
+ Q3IconViewItem *item = findItem(e->pos());
+ emit contextMenuRequested(item, e->globalPos());
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::contentsMouseReleaseEvent(QMouseEvent *e)
+{
+ Q3IconViewItem *item = findItem(e->pos());
+ d->selectedItems.clear();
+
+ bool emitClicked = true;
+ d->mousePressed = false;
+ d->startDragItem = 0;
+
+ if (d->rubber) {
+ d->dragging = false;
+ viewport()->update();
+
+ if ((d->rubber->topLeft() - d->rubber->bottomRight()).manhattanLength() >
+ QApplication::startDragDistance())
+ emitClicked = false;
+ delete d->rubber;
+ d->rubber = 0;
+ d->currentItem = d->tmpCurrentItem;
+ d->tmpCurrentItem = 0;
+ if (d->currentItem)
+ repaintItem(d->currentItem);
+ }
+
+ if (d->scrollTimer) {
+ disconnect(d->scrollTimer, SIGNAL(timeout()), this, SLOT(doAutoScroll()));
+ d->scrollTimer->stop();
+ delete d->scrollTimer;
+ d->scrollTimer = 0;
+ }
+
+ if ((d->selectionMode == Extended || d->selectionMode == Multi) &&
+ d->currentItem == d->pressedItem &&
+ d->pressedSelected && d->currentItem) {
+ if (d->selectionMode == Extended) {
+ bool block = signalsBlocked();
+ blockSignals(true);
+ clearSelection();
+ blockSignals(block);
+ }
+ if (d->currentItem->isSelectable()) {
+ d->currentItem->selected = (d->selectionMode == Extended);
+ repaintItem(d->currentItem);
+ }
+ emit selectionChanged();
+ }
+ d->pressedItem = 0;
+
+ if (emitClicked) {
+ emit mouseButtonClicked(e->button(), item, e->globalPos());
+ emit clicked(item);
+ emit clicked(item, e->globalPos());
+ if (e->button() == Qt::RightButton)
+ emit rightButtonClicked(item, e->globalPos());
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::contentsMouseMoveEvent(QMouseEvent *e)
+{
+ Q3IconViewItem *item = findItem(e->pos());
+ if (d->highlightedItem != item) {
+ if (item)
+ emit onItem(item);
+ else
+ emit onViewport();
+ d->highlightedItem = item;
+ }
+
+ if (d->mousePressed && e->state() == Qt::NoButton)
+ d->mousePressed = false;
+
+ if (d->startDragItem)
+ item = d->startDragItem;
+
+ if (d->mousePressed && d->startDragItem && item && item == d->currentItem &&
+ (item->isSelected() || d->selectionMode == NoSelection) && item->dragEnabled()) {
+ if ((d->dragStartPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) {
+ d->mousePressed = false;
+ d->cleared = false;
+#ifndef QT_NO_DRAGANDDROP
+ startDrag();
+#endif
+ if (d->tmpCurrentItem)
+ repaintItem(d->tmpCurrentItem);
+ }
+ } else if (d->mousePressed && !d->currentItem && d->rubber) {
+ doAutoScroll();
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::contentsMouseDoubleClickEvent(QMouseEvent *e)
+{
+ Q3IconViewItem *item = findItem(e->pos());
+ if (item) {
+ selectAll(false);
+ item->setSelected(true, true);
+ emit doubleClicked(item);
+ }
+}
+
+/*!
+ \reimp
+*/
+
+#ifndef QT_NO_DRAGANDDROP
+void Q3IconView::contentsDragEnterEvent(QDragEnterEvent *e)
+{
+ d->dragging = true;
+ d->drawDragShapes = true;
+ d->tmpCurrentItem = 0;
+ initDragEnter(e);
+ d->oldDragPos = e->pos();
+ d->oldDragAcceptAction = false;
+ drawDragShapes(e->pos());
+ d->dropped = false;
+ e->accept();
+}
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::contentsDragMoveEvent(QDragMoveEvent *e)
+{
+ if (e->pos() == d->oldDragPos) {
+ if (d->oldDragAcceptAction)
+ e->acceptAction();
+ else
+ e->ignore();
+ return;
+ }
+
+ drawDragShapes(d->oldDragPos);
+ d->dragging = false;
+
+ Q3IconViewItem *old = d->tmpCurrentItem;
+ d->tmpCurrentItem = 0;
+
+ Q3IconViewItem *item = findItem(e->pos());
+
+ if (item) {
+ if (old &&
+ old->rect().contains(d->oldDragPos) &&
+ !old->rect().contains(e->pos())) {
+ old->dragLeft();
+ repaintItem(old);
+ }
+ if (!item->rect().contains(d->oldDragPos))
+ item->dragEntered();
+ if (item->acceptDrop(e) || (item->isSelected() && e->source() == viewport())) {
+ d->oldDragAcceptAction = true;
+ e->acceptAction();
+ } else {
+ d->oldDragAcceptAction = false;
+ e->ignore();
+ }
+
+ d->tmpCurrentItem = item;
+ viewport()->update();
+ } else {
+ e->acceptAction();
+ d->oldDragAcceptAction = true;
+ if (old) {
+ old->dragLeft();
+ repaintItem(old);
+ }
+ }
+
+ d->oldDragPos = e->pos();
+ drawDragShapes(e->pos());
+ d->dragging = true;
+}
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::contentsDragLeaveEvent(QDragLeaveEvent *)
+{
+ if (!d->dropped)
+ drawDragShapes(d->oldDragPos);
+ d->dragging = false;
+
+ if (d->tmpCurrentItem) {
+ repaintItem(d->tmpCurrentItem);
+ d->tmpCurrentItem->dragLeft();
+ }
+
+ d->tmpCurrentItem = 0;
+ d->isIconDrag = false;
+ d->iconDragData.clear();
+}
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::contentsDropEvent(QDropEvent *e)
+{
+ d->dropped = true;
+ d->dragging = false;
+ drawDragShapes(d->oldDragPos);
+
+ if (d->tmpCurrentItem)
+ repaintItem(d->tmpCurrentItem);
+
+ Q3IconViewItem *i = findItem(e->pos());
+
+ if ((!i || i->isSelected()) && e->source() == viewport() && d->currentItem && !d->cleared) {
+ if (!d->rearrangeEnabled)
+ return;
+ QRect r = d->currentItem->rect();
+
+ d->currentItem->move(e->pos() - d->dragStart);
+
+ int w = d->currentItem->x() + d->currentItem->width() + 1;
+ int h = d->currentItem->y() + d->currentItem->height() + 1;
+
+ repaintItem(d->currentItem);
+ repaintContents(r.x(), r.y(), r.width(), r.height());
+
+ int dx = d->currentItem->x() - r.x();
+ int dy = d->currentItem->y() - r.y();
+
+ Q3IconViewItem *item = d->firstItem;
+ QRect rr;
+ for (; item; item = item->next) {
+ if (item->isSelected() && item != d->currentItem) {
+ rr = rr.united(item->rect());
+ item->moveBy(dx, dy);
+ rr = rr.united(item->rect());
+ }
+ w = qMax(w, item->x() + item->width() + 1);
+ h = qMax(h, item->y() + item->height() + 1);
+ }
+ repaintContents(rr);
+ bool fullRepaint = false;
+ if (w > contentsWidth() ||
+ h > contentsHeight())
+ fullRepaint = true;
+
+ int oldw = contentsWidth();
+ int oldh = contentsHeight();
+
+ resizeContents(w, h);
+
+
+ if (fullRepaint) {
+ repaintContents(oldw, 0, contentsWidth() - oldw, contentsHeight());
+ repaintContents(0, oldh, contentsWidth(), contentsHeight() - oldh);
+ }
+ e->acceptAction();
+ } else if (!i && (e->source() != viewport() || d->cleared)) {
+ QLinkedList<Q3IconDragItem> lst;
+ if (Q3IconDrag::canDecode(e)) {
+ QLinkedList<Q3IconDragDataItem> l;
+ Q3IconDragPrivate::decode(e, l);
+ QLinkedList<Q3IconDragDataItem>::Iterator it = l.begin();
+ for (; it != l.end(); ++it)
+ lst << (*it).data;
+ }
+ emit dropped(e, lst);
+ } else if (i) {
+ QLinkedList<Q3IconDragItem> lst;
+ if (Q3IconDrag::canDecode(e)) {
+ QLinkedList<Q3IconDragDataItem> l;
+ Q3IconDragPrivate::decode(e, l);
+ QLinkedList<Q3IconDragDataItem>::Iterator it = l.begin();
+ for (; it != l.end(); ++it)
+ lst << (*it).data;
+ }
+ i->dropped(e, lst);
+ }
+ d->isIconDrag = false;
+}
+#endif
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::resizeEvent(QResizeEvent* e)
+{
+ Q3ScrollView::resizeEvent(e);
+ if (d->resizeMode == Adjust) {
+ optimize_layout = true;
+ adjustItems();
+ optimize_layout = false;
+#if 0 // no need for timer delay anymore
+ d->oldSize = e->oldSize();
+ if (d->adjustTimer->isActive())
+ d->adjustTimer->stop();
+ d->adjustTimer->start(0, true);
+#endif
+ }
+}
+
+/*!
+ Adjusts the positions of the items to the geometry of the icon
+ view.
+*/
+
+void Q3IconView::adjustItems()
+{
+ d->adjustTimer->stop();
+ if (d->resizeMode == Adjust)
+ arrangeItemsInGrid(true);
+}
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::keyPressEvent(QKeyEvent *e)
+{
+ if (!d->firstItem)
+ return;
+
+ if (!d->currentItem) {
+ setCurrentItem(d->firstItem);
+ if (d->selectionMode == Single)
+ d->currentItem->setSelected(true, true);
+ return;
+ }
+
+ bool selectCurrent = true;
+
+ switch (e->key()) {
+ case Qt::Key_Escape:
+ e->ignore();
+ break;
+#ifndef QT_NO_TEXTEDIT
+ case Qt::Key_F2: {
+ if (d->currentItem->renameEnabled()) {
+ d->currentItem->renameItem();
+ d->currentItem->rename();
+ return;
+ }
+ } break;
+#endif
+ case Qt::Key_Home: {
+ d->currInputString.clear();
+ if (!d->firstItem)
+ break;
+
+ selectCurrent = false;
+
+ Q3IconViewItem *item = 0;
+ Q3IconViewPrivate::ItemContainer *c = d->firstContainer;
+ while (!item && c) {
+ QList<Q3IconViewItem*> &list = c->items;
+ for (int j = 0; j < list.size(); ++j) {
+ Q3IconViewItem *i = list.at(j);
+ if (!item) {
+ item = i;
+ } else {
+ if (d->arrangement == LeftToRight) {
+ // we use pixmap so the items textlength are ignored
+ // find topmost, leftmost item
+ if (i->pixmapRect(false).y() < item->pixmapRect(false).y() ||
+ (i->pixmapRect(false).y() == item->pixmapRect(false).y() &&
+ i->pixmapRect(false).x() < item->pixmapRect(false).x()))
+ item = i;
+ } else {
+ // find leftmost, topmost item
+ if (i->pixmapRect(false).x() < item->pixmapRect(false).x() ||
+ (i->pixmapRect(false).x() == item->pixmapRect(false).x() &&
+ i->pixmapRect(false).y() < item->pixmapRect(false).y()))
+ item = i;
+ }
+ }
+ }
+ c = c->n;
+ }
+
+ if (item) {
+ Q3IconViewItem *old = d->currentItem;
+ setCurrentItem(item);
+ ensureItemVisible(item);
+ handleItemChange(old, e->state() & Qt::ShiftButton,
+ e->state() & Qt::ControlButton, true);
+ }
+ } break;
+ case Qt::Key_End: {
+ d->currInputString.clear();
+ if (!d->lastItem)
+ break;
+
+ selectCurrent = false;
+
+ Q3IconViewItem *item = 0;
+ Q3IconViewPrivate::ItemContainer *c = d->lastContainer;
+ while (!item && c) {
+ QList<Q3IconViewItem*> &list = c->items;
+ for (int j = 0; j < list.size(); ++j) {
+ Q3IconViewItem *i = list.at(j);
+ if (!item) {
+ item = i;
+ } else {
+ if (d->arrangement == LeftToRight) {
+ // find bottommost, rightmost item
+ if (i->pixmapRect(false).bottom() > item->pixmapRect(false).bottom() ||
+ (i->pixmapRect(false).bottom() == item->pixmapRect(false).bottom() &&
+ i->pixmapRect(false).right() > item->pixmapRect(false).right()))
+ item = i;
+ } else {
+ // find rightmost, bottommost item
+ if (i->pixmapRect(false).right() > item->pixmapRect(false).right() ||
+ (i->pixmapRect(false).right() == item->pixmapRect(false).right() &&
+ i->pixmapRect(false).bottom() > item->pixmapRect(false).bottom()))
+ item = i;
+ }
+ }
+ }
+ c = c->p;
+ }
+
+ if (item) {
+ Q3IconViewItem *old = d->currentItem;
+ setCurrentItem(item);
+ ensureItemVisible(item);
+ handleItemChange(old, e->state() & Qt::ShiftButton,
+ e->state() & Qt::ControlButton, true);
+ }
+ } break;
+ case Qt::Key_Right: {
+ d->currInputString.clear();
+ Q3IconViewItem *item;
+ selectCurrent = false;
+ Direction dir = DirRight;
+
+ QRect r(0, d->currentItem->y(), contentsWidth(), d->currentItem->height());
+ item = findItem(dir, d->currentItem->rect().center(), r);
+
+ // search the row below from the right
+ while (!item && r.y() < contentsHeight()) {
+ r.moveBy(0, d->currentItem->height());
+ item = findItem(dir, QPoint(0, r.center().y()), r);
+ }
+
+ if (item) {
+ Q3IconViewItem *old = d->currentItem;
+ setCurrentItem(item);
+ ensureItemVisible(item);
+ handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ }
+ } break;
+ case Qt::Key_Left: {
+ d->currInputString.clear();
+ Q3IconViewItem *item;
+ selectCurrent = false;
+ Direction dir = DirLeft;
+
+ QRect r(0, d->currentItem->y(), contentsWidth(), d->currentItem->height());
+ item = findItem(dir, d->currentItem->rect().center(), r);
+
+ // search the row above from the left
+ while (!item && r.y() >= 0) {
+ r.moveBy(0, - d->currentItem->height());
+ item = findItem(dir, QPoint(contentsWidth(), r.center().y()), r);
+ }
+
+ if (item) {
+ Q3IconViewItem *old = d->currentItem;
+ setCurrentItem(item);
+ ensureItemVisible(item);
+ handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ }
+ } break;
+ case Qt::Key_Space: {
+ d->currInputString.clear();
+ if (d->selectionMode == Single)
+ break;
+
+ d->currentItem->setSelected(!d->currentItem->isSelected(), true);
+ } break;
+ case Qt::Key_Enter: case Qt::Key_Return:
+ d->currInputString.clear();
+ emit returnPressed(d->currentItem);
+ break;
+ case Qt::Key_Down: {
+ d->currInputString.clear();
+ Q3IconViewItem *item;
+ selectCurrent = false;
+ Direction dir = DirDown;
+
+ QRect r(d->currentItem->x(), 0, d->currentItem->width(), contentsHeight());
+ item = findItem(dir, d->currentItem->rect().center(), r);
+
+ // finding the closest item below and to the right
+ while (!item && r.x() < contentsWidth()) {
+ r.moveBy(r.width() , 0);
+ item = findItem(dir, QPoint(r.center().x(), 0), r);
+ }
+
+
+ Q3IconViewItem *i = d->currentItem;
+ setCurrentItem(item);
+ item = i;
+ handleItemChange(item, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ } break;
+ case Qt::Key_Up: {
+ d->currInputString.clear();
+ Q3IconViewItem *item;
+ selectCurrent = false;
+ Direction dir = DirUp;
+
+ QRect r(d->currentItem->x(), 0, d->currentItem->width(), contentsHeight());
+ item = findItem(dir, d->currentItem->rect().center(), r);
+
+ // finding the closest item above and to the left
+ while (!item && r.x() >= 0) {
+ r.moveBy(- r.width(), 0);
+ item = findItem(dir, QPoint(r.center().x(), contentsHeight()), r);
+ }
+
+ Q3IconViewItem *i = d->currentItem;
+ setCurrentItem(item);
+ item = i;
+ handleItemChange(item, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ } break;
+ case Qt::Key_Next: {
+ d->currInputString.clear();
+ selectCurrent = false;
+ QRect r;
+ if (d->arrangement == LeftToRight)
+ r = QRect(0, d->currentItem->y() + visibleHeight(), contentsWidth(), visibleHeight());
+ else
+ r = QRect(d->currentItem->x() + visibleWidth(), 0, visibleWidth(), contentsHeight());
+ Q3IconViewItem *item = d->currentItem;
+ Q3IconViewItem *ni = findFirstVisibleItem(r );
+ if (!ni) {
+ if (d->arrangement == LeftToRight)
+ r = QRect(0, d->currentItem->y() + d->currentItem->height(), contentsWidth(), contentsHeight());
+ else
+ r = QRect(d->currentItem->x() + d->currentItem->width(), 0, contentsWidth(), contentsHeight());
+ ni = findLastVisibleItem(r );
+ }
+ if (ni) {
+ setCurrentItem(ni);
+ handleItemChange(item, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ }
+ } break;
+ case Qt::Key_Prior: {
+ d->currInputString.clear();
+ selectCurrent = false;
+ QRect r;
+ if (d->arrangement == LeftToRight)
+ r = QRect(0, d->currentItem->y() - visibleHeight(), contentsWidth(), visibleHeight());
+ else
+ r = QRect(d->currentItem->x() - visibleWidth(), 0, visibleWidth(), contentsHeight());
+ Q3IconViewItem *item = d->currentItem;
+ Q3IconViewItem *ni = findFirstVisibleItem(r );
+ if (!ni) {
+ if (d->arrangement == LeftToRight)
+ r = QRect(0, 0, contentsWidth(), d->currentItem->y());
+ else
+ r = QRect(0, 0, d->currentItem->x(), contentsHeight());
+ ni = findFirstVisibleItem(r );
+ }
+ if (ni) {
+ setCurrentItem(ni);
+ handleItemChange(item, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ }
+ } break;
+ default:
+ if (!e->text().isEmpty() && e->text()[0].isPrint()) {
+ selectCurrent = false;
+ Q3IconViewItem *i = d->currentItem;
+ if (!i)
+ i = d->firstItem;
+ if (!d->inputTimer->isActive()) {
+ d->currInputString = e->text();
+ i = i->next;
+ if (!i)
+ i = d->firstItem;
+ i = findItemByName(i);
+ } else {
+ d->inputTimer->stop();
+ d->currInputString += e->text();
+ i = findItemByName(i);
+ if (!i) {
+ d->currInputString = e->text();
+ if (d->currentItem && d->currentItem->next)
+ i = d->currentItem->next;
+ else
+ i = d->firstItem;
+ i = findItemByName(i);
+ }
+ }
+ if (i) {
+ setCurrentItem(i);
+ if (d->selectionMode == Extended) {
+ bool changed = false;
+ bool block = signalsBlocked();
+ blockSignals(true);
+ selectAll(false);
+ blockSignals(block);
+ if (!i->selected && i->isSelectable()) {
+ changed = true;
+ i->selected = true;
+ repaintItem(i);
+ }
+ if (changed)
+ emit selectionChanged();
+ }
+ }
+ d->inputTimer->start(400, true);
+ } else {
+ selectCurrent = false;
+ d->currInputString.clear();
+ if (e->state() & Qt::ControlButton) {
+ switch (e->key()) {
+ case Qt::Key_A:
+ selectAll(true);
+ break;
+ }
+ }
+ e->ignore();
+ return;
+ }
+ }
+
+ if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
+ d->selectAnchor = d->currentItem;
+
+ if (d->currentItem && !d->currentItem->isSelected() &&
+ d->selectionMode == Single && selectCurrent) {
+ d->currentItem->setSelected(true);
+ }
+
+ ensureItemVisible(d->currentItem);
+}
+
+/*
+ Finds the closest item in the Direction \a dir relative from the point \a relativeTo
+ which intersects with the searchRect.
+
+ The function chooses the closest item with its center in the \a searchRect.
+*/
+Q3IconViewItem* Q3IconView::findItem(Direction dir,
+ const QPoint &relativeTo,
+ const QRect &searchRect) const
+{
+ Q3IconViewItem *centerMatch = 0;
+ int centerMatchML = 0;
+
+ // gets list of containers with potential items
+ QList<Q3IconViewPrivate::ItemContainer * >* cList =
+ d->findContainers(dir, relativeTo, searchRect);
+
+ for (int i = 0; i < cList->size() && !centerMatch; ++i) {
+ QList<Q3IconViewItem *> &list = (cList->at(i))->items;
+ for (int j = 0; j < list.size(); ++j) {
+ Q3IconViewItem *item = list.at(j);
+ if (neighbourItem(dir, relativeTo, item) &&
+ searchRect.contains(item->rect().center()) && item != currentItem()) {
+ int ml = (relativeTo - item->rect().center()).manhattanLength();
+ if (centerMatch) {
+ if (ml < centerMatchML) {
+ centerMatch = item;
+ centerMatchML = ml;
+ }
+ } else {
+ centerMatch = item;
+ centerMatchML = ml;
+ }
+ }
+ }
+ }
+ return centerMatch;
+}
+
+
+/*
+ Returns true if the items orientation compared to
+ the point \a relativeTo is correct.
+*/
+bool Q3IconView::neighbourItem(Direction dir,
+ const QPoint &relativeTo,
+ const Q3IconViewItem *item) const
+{
+ switch (dir) {
+ case DirUp:
+ if (item->rect().center().y() < relativeTo.y())
+ return true;
+ break;
+ case DirDown:
+ if (item->rect().center().y() > relativeTo.y())
+ return true;
+ break;
+ case DirLeft:
+ if (item->rect().center().x() < relativeTo.x())
+ return true;
+ break;
+ case DirRight:
+ if (item->rect().center().x() > relativeTo.x())
+ return true;
+ break;
+ default:
+ // nothing
+ break;
+ }
+ return false;
+}
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::focusInEvent(QFocusEvent *e)
+{
+ d->mousePressed = false;
+ d->inMenuMode = false;
+ if (d->currentItem) {
+ repaintItem(d->currentItem);
+ } else if (d->firstItem && e->reason() != Qt::MouseFocusReason) {
+ d->currentItem = d->firstItem;
+ emit currentChanged(d->currentItem);
+ repaintItem(d->currentItem);
+ }
+
+ if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this))
+ repaintSelectedItems();
+}
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::focusOutEvent(QFocusEvent *e)
+{
+ if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this)) {
+ d->inMenuMode =
+ e->reason() == Qt::PopupFocusReason ||
+ (qApp->focusWidget() && qApp->focusWidget()->inherits("QMenuBar"));
+ if (!d->inMenuMode)
+ repaintSelectedItems();
+ }
+ if (d->currentItem)
+ repaintItem(d->currentItem);
+}
+
+/*!
+ Draws the rubber band using the painter \a p.
+*/
+
+void Q3IconView::drawRubber(QPainter *p)
+{
+ if (!p || !d->rubber)
+ return;
+ QStyleOptionRubberBand opt;
+ opt.rect = d->rubber->normalized();
+ opt.shape = QRubberBand::Rectangle;
+ opt.palette = palette();
+ opt.state = QStyle::State_None;
+ style()->drawControl(QStyle::CE_RubberBand, &opt, p, this);
+}
+
+/*!
+ Returns the Q3DragObject that should be used for drag-and-drop.
+ This function is called by the icon view when starting a drag to
+ get the dragobject that should be used for the drag. Subclasses
+ may reimplement this.
+
+ \sa Q3IconDrag
+*/
+
+#ifndef QT_NO_DRAGANDDROP
+Q3DragObject *Q3IconView::dragObject()
+{
+ if (!d->currentItem)
+ return 0;
+
+ QPoint orig = d->dragStartPos;
+
+ Q3IconDrag *drag = new Q3IconDrag(viewport());
+ drag->setPixmap((d->currentItem->pixmap() ?
+ *d->currentItem->pixmap() : QPixmap()), // ### QPicture
+ QPoint(d->currentItem->pixmapRect().width() / 2,
+ d->currentItem->pixmapRect().height() / 2));
+
+ if (d->selectionMode == NoSelection) {
+ Q3IconViewItem *item = d->currentItem;
+ drag->append(Q3IconDragItem(),
+ QRect(item->pixmapRect(false).x() - orig.x(),
+ item->pixmapRect(false).y() - orig.y(),
+ item->pixmapRect().width(), item->pixmapRect().height()),
+ QRect(item->textRect(false).x() - orig.x(),
+ item->textRect(false).y() - orig.y(),
+ item->textRect().width(), item->textRect().height()));
+ } else {
+ for (Q3IconViewItem *item = d->firstItem; item; item = item->next) {
+ if (item->isSelected()) {
+ drag->append(Q3IconDragItem(),
+ QRect(item->pixmapRect(false).x() - orig.x(),
+ item->pixmapRect(false).y() - orig.y(),
+ item->pixmapRect().width(), item->pixmapRect().height()),
+ QRect(item->textRect(false).x() - orig.x(),
+ item->textRect(false).y() - orig.y(),
+ item->textRect().width(), item->textRect().height()));
+ }
+ }
+ }
+
+ return drag;
+}
+
+/*!
+ Starts a drag.
+*/
+
+void Q3IconView::startDrag()
+{
+ if (!d->startDragItem)
+ return;
+
+ QPoint orig = d->dragStartPos;
+ d->dragStart = QPoint(orig.x() - d->startDragItem->x(),
+ orig.y() - d->startDragItem->y());
+ d->startDragItem = 0;
+ d->mousePressed = false;
+ d->pressedItem = 0;
+ d->pressedSelected = 0;
+
+ Q3DragObject *drag = dragObject();
+ if (!drag)
+ return;
+
+ if (drag->drag())
+ if (drag->target() != viewport())
+ emit moved();
+}
+
+#endif
+
+/*!
+ Inserts the Q3IconViewItem \a item in the icon view's grid. \e{You
+ should never need to call this function.} Instead, insert
+ Q3IconViewItems by creating them with a pointer to the Q3IconView
+ that they are to be inserted into.
+*/
+
+void Q3IconView::insertInGrid(Q3IconViewItem *item)
+{
+ if (!item)
+ return;
+
+ if (d->reorderItemsWhenInsert) {
+ // #### make this efficient - but it's not too dramatic
+ int y = d->spacing;
+
+ item->dirty = false;
+ if (item == d->firstItem) {
+ bool dummy;
+ makeRowLayout(item, y, dummy);
+ return;
+ }
+
+ Q3IconViewItem *begin = rowBegin(item);
+ y = begin->y();
+ while (begin) {
+ bool dummy;
+ begin = makeRowLayout(begin, y, dummy);
+
+ if (!begin || !begin->next)
+ break;
+
+ begin = begin->next;
+ }
+ item->dirty = false;
+ } else {
+ QRegion r(QRect(0, 0, qMax(contentsWidth(), visibleWidth()),
+ qMax(contentsHeight(), visibleHeight())));
+
+ int y = -1;
+ for (Q3IconViewItem *i = d->firstItem; i; i = i->next) {
+ r = r.subtracted(i->rect());
+ y = qMax(y, i->y() + i->height());
+ }
+
+ QVector<QRect> rects = r.rects();
+ bool foundPlace = false;
+ for (int j = 0; j < rects.size(); ++j) {
+ const QRect rect = rects.at(j);
+ if (rect.width() >= item->width() &&
+ rect.height() >= item->height()) {
+ int sx = 0, sy = 0;
+ if (rect.width() >= item->width() + d->spacing)
+ sx = d->spacing;
+ if (rect.height() >= item->height() + d->spacing)
+ sy = d->spacing;
+ item->move(rect.x() + sx, rect.y() + sy);
+ foundPlace = true;
+ break;
+ }
+ }
+
+ if (!foundPlace)
+ item->move(d->spacing, y + d->spacing);
+
+ resizeContents(qMax(contentsWidth(), item->x() + item->width()),
+ qMax(contentsHeight(), item->y() + item->height()));
+ item->dirty = false;
+ }
+}
+
+/*!
+ Emits a signal to indicate selection changes. \a i is the
+ Q3IconViewItem that was selected or de-selected.
+
+ \e{You should never need to call this function.}
+*/
+
+void Q3IconView::emitSelectionChanged(Q3IconViewItem *i)
+{
+ emit selectionChanged();
+ if (d->selectionMode == Single)
+ emit selectionChanged(i ? i : d->currentItem);
+}
+
+/*!
+ \internal
+*/
+
+void Q3IconView::emitRenamed(Q3IconViewItem *item)
+{
+ if (!item)
+ return;
+
+ emit itemRenamed(item, item->text());
+ emit itemRenamed(item);
+}
+
+/*!
+ If a drag enters the icon view the shapes of the objects which the
+ drag contains are drawn, usnig \a pos as origin.
+*/
+
+void Q3IconView::drawDragShapes(const QPoint &pos)
+{
+#ifndef QT_NO_DRAGANDDROP
+ if (pos == QPoint(-1, -1))
+ return;
+
+ if (!d->drawDragShapes) {
+ d->drawDragShapes = true;
+ return;
+ }
+
+ d->dragPos = pos;
+ viewport()->update();
+#endif
+}
+
+/*!
+ When a drag enters the icon view, this function is called to
+ initialize it. Initializing in this context means getting
+ information about the drag, for example so that the icon view
+ knows enough about the drag to be able to draw drag shapes for the
+ drag data (e.g. shapes of icons which are dragged), etc.
+*/
+
+#ifndef QT_NO_DRAGANDDROP
+void Q3IconView::initDragEnter(QDropEvent *e)
+{
+ if (Q3IconDrag::canDecode(e)) {
+ Q3IconDragPrivate::decode(e, d->iconDragData);
+ d->isIconDrag = true;
+ } else if (Q3UriDrag::canDecode(e)) {
+ Q3StrList lst;
+ Q3UriDrag::decode(e, lst);
+ d->numDragItems = lst.count();
+ } else {
+ d->numDragItems = 0;
+ }
+
+}
+#endif
+
+/*!
+ This function is called to draw the rectangle \a r of the
+ background using the painter \a p.
+
+ The default implementation fills \a r with the viewport's
+ backgroundBrush(). Subclasses can reimplement this to draw custom
+ backgrounds.
+
+ \sa drawContents()
+*/
+
+void Q3IconView::drawBackground(QPainter *p, const QRect &r)
+{
+ p->fillRect(r, viewport()->backgroundBrush());
+}
+
+/*!
+ \reimp
+*/
+
+bool Q3IconView::eventFilter(QObject * o, QEvent * e)
+{
+ if (o == viewport()) {
+ switch(e->type()) {
+ case QEvent::FocusIn:
+ focusInEvent((QFocusEvent*)e);
+ return true;
+ case QEvent::FocusOut:
+ focusOutEvent((QFocusEvent*)e);
+ return true;
+ case QEvent::Enter:
+ enterEvent(e);
+ return true;
+ case QEvent::Paint:
+ if (o == viewport()) {
+ viewportPaintEvent((QPaintEvent*)e);
+ QPainter p(viewport());
+ if (d->dragging) {
+ if (!d->rubber && d->drawDragShapes) {
+ p.setPen(QPen(Qt::color0));
+ QStyleOptionFocusRect opt;
+ opt.palette = palette();
+ opt.state = QStyle::State_KeyboardFocusChange;
+ opt.backgroundColor = palette().base().color();
+ if (d->isIconDrag) {
+ d->dragPos = contentsToViewport(d->dragPos);
+ QLinkedList<Q3IconDragDataItem>::Iterator it = d->iconDragData.begin();
+ for (; it != d->iconDragData.end(); ++it) {
+ QRect ir = (*it).item.pixmapRect();
+ QRect tr = (*it).item.textRect();
+ tr.moveBy(d->dragPos.x(), d->dragPos.y());
+ ir.moveBy(d->dragPos.x(), d->dragPos.y());
+ if (!ir.intersects(QRect(0, 0, visibleWidth(), visibleHeight())))
+ continue;
+ opt.rect = ir;
+ style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, &p, this);
+ opt.rect = tr;
+ p.drawRect(tr);
+ style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, &p, this);
+ }
+ } else if (d->numDragItems > 0) {
+ for (int i = 0; i < d->numDragItems; ++i) {
+ opt.rect.setRect(d->dragPos.x() + i * 40, d->dragPos.y(), 35, 35);
+ style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, &p, this);
+ }
+
+ }
+ p.end();
+ }
+ } else {
+ p.translate(-contentsX(), -contentsY());
+ drawRubber(&p);
+ }
+ }
+ return true;
+#ifndef QT_NO_TOOLTIP
+ case QHelpEvent::ToolTip:
+ {
+ if (wordWrapIconText() || !showToolTips())
+ return false;
+
+ QHelpEvent *he = static_cast<QHelpEvent *>(e);
+ Q3IconViewItem *item = findItem(viewportToContents(he->pos()));
+ if (!item || item->tmpText == item->itemText) {
+ QToolTip::showText(he->globalPos(), QString(), viewport());
+ return true;
+ }
+
+ QToolTip::showText(he->globalPos(), item->itemText, viewport());
+ return true;
+ }
+#endif
+ default:
+ // nothing
+ break;
+ }
+ }
+
+ return Q3ScrollView::eventFilter(o, e);
+}
+
+
+/*!
+ \reimp
+*/
+
+QSize Q3IconView::minimumSizeHint() const
+{
+ return Q3ScrollView::minimumSizeHint();
+}
+
+/*!
+ \internal
+ Finds the next item after the start item beginning
+ with \a text.
+*/
+
+Q3IconViewItem* Q3IconView::findItemByName(Q3IconViewItem *start)
+{
+ if (!start)
+ return 0;
+ QString match = d->currInputString.toLower();
+ if (match.length() < 1)
+ return start;
+ QString curText;
+ Q3IconViewItem *i = start;
+ do {
+ curText = i->text().toLower();
+ if (curText.startsWith(match))
+ return i;
+ i = i->next;
+ if (!i)
+ i = d->firstItem;
+ } while (i != start);
+ return 0;
+}
+
+/*!
+ Lays out a row of icons (if Arrangement == \l TopToBottom this is
+ a column). Starts laying out with the item \a begin. \a y is the
+ starting coordinate. Returns the last item of the row (column) and
+ sets the new starting coordinate to \a y. The \a changed parameter
+ is used internally.
+
+ \warning This function may be made private in a future version of
+ Qt. We do not recommend calling it.
+*/
+
+Q3IconViewItem *Q3IconView::makeRowLayout(Q3IconViewItem *begin, int &y, bool &changed)
+{
+ Q3IconViewItem *end = 0;
+
+ bool reverse = QApplication::reverseLayout();
+ changed = false;
+
+ if (d->arrangement == LeftToRight) {
+
+ if (d->rastX == -1) {
+ // first calculate the row height
+ int h = 0;
+ int x = 0;
+ int ih = 0;
+ Q3IconViewItem *item = begin;
+ for (;;) {
+ x += d->spacing + item->width();
+ if (x > visibleWidth() && item != begin) {
+ item = item->prev;
+ break;
+ }
+ h = qMax(h, item->height());
+ ih = qMax(ih, item->pixmapRect().height());
+ Q3IconViewItem *old = item;
+ item = item->next;
+ if (!item) {
+ item = old;
+ break;
+ }
+ }
+ end = item;
+
+ if (d->rastY != -1)
+ h = qMax(h, d->rastY);
+
+ // now move the items
+ item = begin;
+ for (;;) {
+ item->dirty = false;
+ int x;
+ if (item == begin) {
+ if (reverse)
+ x = visibleWidth() - d->spacing - item->width();
+ else
+ x = d->spacing;
+ } else {
+ if (reverse)
+ x = item->prev->x() - item->width() - d->spacing;
+ else
+ x = item->prev->x() + item->prev->width() + d->spacing;
+ }
+ changed = item->move(x, y + ih - item->pixmapRect().height()) || changed;
+ if (y + h < item->y() + item->height())
+ h = qMax(h, ih + item->textRect().height());
+ if (item == end)
+ break;
+ item = item->next;
+ }
+ y += h + d->spacing;
+ } else {
+ // first calculate the row height
+ int h = begin->height();
+ int x = d->spacing;
+ int ih = begin->pixmapRect().height();
+ Q3IconViewItem *item = begin;
+ int i = 0;
+ int sp = 0;
+ for (;;) {
+ int r = calcGridNum(item->width(), d->rastX);
+ if (item == begin) {
+ i += r;
+ sp += r;
+ x = d->spacing + d->rastX * r;
+ } else {
+ sp += r;
+ i += r;
+ x = i * d->rastX + sp * d->spacing;
+ }
+ if (x > visibleWidth() && item != begin) {
+ item = item->prev;
+ break;
+ }
+ h = qMax(h, item->height());
+ ih = qMax(ih, item->pixmapRect().height());
+ Q3IconViewItem *old = item;
+ item = item->next;
+ if (!item) {
+ item = old;
+ break;
+ }
+ }
+ end = item;
+
+ if (d->rastY != -1)
+ h = qMax(h, d->rastY);
+
+ // now move the items
+ item = begin;
+ i = 0;
+ sp = 0;
+ for (;;) {
+ item->dirty = false;
+ int r = calcGridNum(item->width(), d->rastX);
+ if (item == begin) {
+ if (d->itemTextPos == Bottom)
+ changed = item->move(d->spacing + (r * d->rastX - item->width()) / 2,
+ y + ih - item->pixmapRect().height()) || changed;
+ else
+ changed = item->move(d->spacing, y + ih - item->pixmapRect().height()) || changed;
+ i += r;
+ sp += r;
+ } else {
+ sp += r;
+ int x = i * d->rastX + sp * d->spacing;
+ if (d->itemTextPos == Bottom)
+ changed = item->move(x + (r * d->rastX - item->width()) / 2,
+ y + ih - item->pixmapRect().height()) || changed;
+ else
+ changed = item->move(x, y + ih - item->pixmapRect().height()) || changed;
+ i += r;
+ }
+ if (y + h < item->y() + item->height())
+ h = qMax(h, ih + item->textRect().height());
+ if (item == end)
+ break;
+ item = item->next;
+ }
+ y += h + d->spacing;
+ }
+
+
+ } else { // -------------------------------- SOUTH ------------------------------
+
+ int x = y;
+
+ {
+ int w = 0;
+ int y = 0;
+ Q3IconViewItem *item = begin;
+ for (;;) {
+ y += d->spacing + item->height();
+ if (y > visibleHeight() && item != begin) {
+ item = item->prev;
+ break;
+ }
+ w = qMax(w, item->width());
+ Q3IconViewItem *old = item;
+ item = item->next;
+ if (!item) {
+ item = old;
+ break;
+ }
+ }
+ end = item;
+
+ if (d->rastX != -1)
+ w = qMax(w, d->rastX);
+
+ // now move the items
+ item = begin;
+ for (;;) {
+ item->dirty = false;
+ if (d->itemTextPos == Bottom) {
+ if (item == begin)
+ changed = item->move(x + (w - item->width()) / 2, d->spacing) || changed;
+ else
+ changed = item->move(x + (w - item->width()) / 2,
+ item->prev->y() + item->prev->height() + d->spacing) || changed;
+ } else {
+ if (item == begin)
+ changed = item->move(x, d->spacing) || changed;
+ else
+ changed = item->move(x, item->prev->y() + item->prev->height() + d->spacing) || changed;
+ }
+ if (item == end)
+ break;
+ item = item->next;
+ }
+ x += w + d->spacing;
+ }
+
+ y = x;
+ }
+
+ return end;
+}
+
+/*!
+ \internal
+ Calculates how many cells an item of width \a w needs in a grid with of
+ \a x and returns the result.
+*/
+
+int Q3IconView::calcGridNum(int w, int x) const
+{
+ float r = (float)w / (float)x;
+ if ((w / x) * x != w)
+ r += 1.0;
+ return (int)r;
+}
+
+/*!
+ \internal
+ Returns the first item of the row which contains \a item.
+*/
+
+Q3IconViewItem *Q3IconView::rowBegin(Q3IconViewItem *) const
+{
+ // #### todo
+ return d->firstItem;
+}
+
+/*!
+ Sorts and rearranges all the items in the icon view. If \a
+ ascending is true, the items are sorted in increasing order,
+ otherwise they are sorted in decreasing order.
+
+ Q3IconViewItem::compare() is used to compare pairs of items. The
+ sorting is based on the items' keys; these default to the items'
+ text unless specifically set to something else.
+
+ Note that this function sets the sort order to \a ascending.
+
+ \sa Q3IconViewItem::key(), Q3IconViewItem::setKey(),
+ Q3IconViewItem::compare(), Q3IconView::setSorting(),
+ Q3IconView::sortDirection()
+*/
+
+void Q3IconView::sort(bool ascending)
+{
+ if (count() == 0)
+ return;
+
+ d->sortDirection = ascending;
+ Q3IconViewPrivate::SortableItem *items = new Q3IconViewPrivate::SortableItem[count()];
+
+ Q3IconViewItem *item = d->firstItem;
+ int i = 0;
+ for (; item; item = item->next)
+ items[i++].item = item;
+
+ qsort(items, count(), sizeof(Q3IconViewPrivate::SortableItem), cmpIconViewItems);
+
+ Q3IconViewItem *prev = 0;
+ item = 0;
+ if (ascending) {
+ for (i = 0; i < (int)count(); ++i) {
+ item = items[i].item;
+ if (item) {
+ item->prev = prev;
+ if (item->prev)
+ item->prev->next = item;
+ item->next = 0;
+ }
+ if (i == 0)
+ d->firstItem = item;
+ if (i == (int)count() - 1)
+ d->lastItem = item;
+ prev = item;
+ }
+ } else {
+ for (i = (int)count() - 1; i >= 0 ; --i) {
+ item = items[i].item;
+ if (item) {
+ item->prev = prev;
+ if (item->prev)
+ item->prev->next = item;
+ item->next = 0;
+ }
+ if (i == (int)count() - 1)
+ d->firstItem = item;
+ if (i == 0)
+ d->lastItem = item;
+ prev = item;
+ }
+ }
+
+ delete [] items;
+
+ arrangeItemsInGrid(true);
+}
+
+/*!
+ \reimp
+*/
+
+QSize Q3IconView::sizeHint() const
+{
+ ensurePolished();
+
+ if (!d->firstItem)
+ return Q3ScrollView::sizeHint();
+
+ if (d->dirty && d->firstSizeHint) {
+ ((Q3IconView*)this)->resizeContents(qMax(400, contentsWidth()),
+ qMax(400, contentsHeight()));
+ if (autoArrange())
+ ((Q3IconView*)this)->arrangeItemsInGrid(false);
+ d->firstSizeHint = false;
+ }
+
+ d->dirty = true;
+ const QScrollBar *sb = verticalScrollBar();
+ QStyleOptionSlider opt;
+ opt.init(sb);
+ opt.orientation = sb->orientation();
+ int extra = style()->pixelMetric(QStyle::PM_ScrollBarExtent, &opt, sb) + 2 * frameWidth();
+ QSize s(qMin(400, contentsWidth() + extra),
+ qMin(400, contentsHeight() + extra));
+ return s;
+}
+
+/*!
+ \internal
+*/
+
+void Q3IconView::updateContents()
+{
+ viewport()->update();
+}
+
+/*!
+ \reimp
+*/
+
+void Q3IconView::enterEvent(QEvent *e)
+{
+ Q3ScrollView::enterEvent(e);
+ emit onViewport();
+}
+
+/*!
+ \internal
+ This function is always called when the geometry of an item changes.
+ This function moves the item into the correct area in the internal
+ data structure.
+*/
+
+void Q3IconView::updateItemContainer(Q3IconViewItem *item)
+{
+ if (!item || d->containerUpdateLocked || (!isVisible() && autoArrange()))
+ return;
+
+ if (item->d->container1 && d->firstContainer) {
+ //Special-case to check if we can use removeLast otherwise use removeAll (slower)
+ if (item->d->container1->items.last() == item)
+ item->d->container1->items.removeLast();
+ else
+ item->d->container1->items.removeAll(item);
+ }
+ item->d->container1 = 0;
+ if (item->d->container2 && d->firstContainer) {
+ //Special-case to check if we can use removeLast otherwise use removeAll (slower)
+ if (item->d->container2->items.last() == item)
+ item->d->container2->items.removeLast();
+ else
+ item->d->container2->items.removeAll(item);
+ }
+ item->d->container2 = 0;
+
+ Q3IconViewPrivate::ItemContainer *c = d->firstContainer;
+ if (!c) {
+ appendItemContainer();
+ c = d->firstContainer;
+ }
+
+ const QRect irect = item->rect();
+ bool contains = false;
+ for (;;) {
+ if (c->rect.intersects(irect)) {
+ contains = c->rect.contains(irect);
+ break;
+ }
+
+ c = c->n;
+ if (!c) {
+ appendItemContainer();
+ c = d->lastContainer;
+ }
+ }
+
+ if (!c) {
+ qWarning("Q3IconViewItem::updateItemContainer(): No fitting container found!");
+ return;
+ }
+
+ c->items.append(item);
+ item->d->container1 = c;
+
+ if (!contains) {
+ c = c->n;
+ if (!c) {
+ appendItemContainer();
+ c = d->lastContainer;
+ }
+ c->items.append(item);
+ item->d->container2 = c;
+ }
+ if (contentsWidth() < irect.right() || contentsHeight() < irect.bottom())
+ resizeContents(qMax(contentsWidth(), irect.right()), qMax(contentsHeight(), irect.bottom()));
+}
+
+/*!
+ \internal
+ Appends a new rect area to the internal data structure of the items.
+*/
+
+void Q3IconView::appendItemContainer()
+{
+ QSize s;
+ // #### We have to find out which value is best here
+ if (d->arrangement == LeftToRight)
+ s = QSize(INT_MAX - 1, RECT_EXTENSION);
+ else
+ s = QSize(RECT_EXTENSION, INT_MAX - 1);
+
+ if (!d->firstContainer) {
+ d->firstContainer = new Q3IconViewPrivate::ItemContainer(0, 0, QRect(QPoint(0, 0), s));
+ d->lastContainer = d->firstContainer;
+ } else {
+ if (d->arrangement == LeftToRight)
+ d->lastContainer = new Q3IconViewPrivate::ItemContainer(
+ d->lastContainer, 0, QRect(d->lastContainer->rect.bottomLeft(), s));
+ else
+ d->lastContainer = new Q3IconViewPrivate::ItemContainer(
+ d->lastContainer, 0, QRect(d->lastContainer->rect.topRight(), s));
+ }
+}
+
+/*! \internal
+
+ Rebuilds the whole internal data structure. This is done when it's
+ likely that most/all items change their geometry (e.g. in
+ arrangeItemsInGrid()), because calling this is then more efficient
+ than calling updateItemContainer() for each item.
+*/
+
+void Q3IconView::rebuildContainers()
+{
+ Q3IconViewPrivate::ItemContainer *c = d->firstContainer, *tmpc;
+ while (c) {
+ tmpc = c->n;
+ delete c;
+ c = tmpc;
+ }
+ d->firstContainer = d->lastContainer = 0;
+
+ Q3IconViewItem *item = d->firstItem;
+ appendItemContainer();
+ c = d->lastContainer;
+ while (item) {
+ if (c->rect.contains(item->rect())) {
+ item->d->container1 = c;
+ item->d->container2 = 0;
+ c->items.append(item);
+ item = item->next;
+ } else if (c->rect.intersects(item->rect())) {
+ item->d->container1 = c;
+ c->items.append(item);
+ c = c->n;
+ if (!c) {
+ appendItemContainer();
+ c = d->lastContainer;
+ }
+ c->items.append(item);
+ item->d->container2 = c;
+ item = item->next;
+ c = c->p;
+ } else {
+ if (d->arrangement == LeftToRight) {
+ if (item->y() < c->rect.y() && c->p) {
+ c = c->p;
+ continue;
+ }
+ } else {
+ if (item->x() < c->rect.x() && c->p) {
+ c = c->p;
+ continue;
+ }
+ }
+
+ c = c->n;
+ if (!c) {
+ appendItemContainer();
+ c = d->lastContainer;
+ }
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+
+void Q3IconView::movedContents(int, int)
+{
+ if (d->drawDragShapes) {
+ drawDragShapes(d->oldDragPos);
+ d->oldDragPos = QPoint(-1, -1);
+ }
+}
+
+void Q3IconView::handleItemChange(Q3IconViewItem *old, bool shift,
+ bool control, bool homeend)
+{
+ if (d->selectionMode == Single) {
+ bool block = signalsBlocked();
+ blockSignals(true);
+ if (old)
+ old->setSelected(false);
+ blockSignals(block);
+ d->currentItem->setSelected(true, true);
+ } else if (d->selectionMode == Extended) {
+ if (shift) {
+ if (!d->selectAnchor) {
+ if (old && !old->selected && old->isSelectable()) {
+ old->selected = true;
+ repaintItem(old);
+ }
+ d->currentItem->setSelected(true, true);
+ } else {
+ Q3IconViewItem *from = d->selectAnchor, *to = d->currentItem;
+ if (!from || !to)
+ return;
+
+ // checking if it's downwards and if we span rows
+ bool downwards = false;
+ bool spanning = false;
+ if (d->arrangement == LeftToRight) {
+ if (from->rect().center().y() < to->rect().center().y())
+ downwards = true;
+ } else {
+ if (from->rect().center().x() < to->rect().center().x())
+ downwards = true;
+ }
+
+ QRect fr = from->rect();
+ QRect tr = to->rect();
+ if (d->arrangement == LeftToRight) {
+ fr.moveTopLeft(QPoint(tr.x(), fr.y()));
+ if (!tr.intersects(fr))
+ spanning = true;
+ } else {
+ fr.moveTopLeft(QPoint(fr.x(), tr.y()));
+ if (!tr.intersects(fr))
+ spanning = true;
+ }
+
+
+ // finding the rectangles
+ QRect topRect, bottomRect, midRect;
+ if (!spanning) {
+ midRect = from->rect().united(to->rect());
+ } else {
+ if (downwards) {
+ topRect = from->rect();
+ bottomRect = to->rect();
+ } else {
+ topRect = to->rect();
+ bottomRect = from->rect();
+ }
+ if (d->arrangement == LeftToRight) {
+ topRect.setRight(contentsWidth());
+ bottomRect.setLeft(0);
+ midRect.setRect(0, topRect.bottom(),
+ contentsWidth(),
+ bottomRect.top() - topRect.bottom());
+ } else {
+ topRect.setBottom(contentsHeight());
+ bottomRect.setTop(0);
+ midRect.setRect(topRect.right(),
+ 0,
+ bottomRect.left() - topRect.right(),
+ contentsHeight());
+ }
+ }
+
+ // finding contained items and selecting them
+ Q3IconViewItem *item = 0;
+ bool changed = false;
+ bool midValid = midRect.isValid();
+ bool topValid = topRect.isValid();
+ bool bottomValid = bottomRect.isValid();
+ QRect selectedRect, unselectedRect;
+ for (item = d->firstItem; item; item = item->next) {
+ bool contained = false;
+ QPoint itemCenter = item->rect().center();
+ if (midValid && midRect.contains(itemCenter))
+ contained = true;
+ if (!contained && topValid && topRect.contains(itemCenter))
+ contained = true;
+ if (!contained && bottomValid && bottomRect.contains(itemCenter))
+ contained = true;
+
+ if (contained) {
+ if (!item->selected && item->isSelectable()) {
+ changed = true;
+ item->selected = true;
+ selectedRect = selectedRect.united(item->rect());
+ }
+ } else if (item->selected && !control) {
+ item->selected = false;
+ unselectedRect = unselectedRect.united(item->rect());
+ changed = true;
+ }
+ }
+
+ QRect viewRect(contentsX(), contentsY(),
+ visibleWidth(), visibleHeight());
+
+ if (viewRect.intersects(selectedRect)) {
+ if (homeend)
+ Q3ScrollView::updateContents(viewRect.intersected(selectedRect));
+ else
+ repaintContents(viewRect.intersected(selectedRect));
+ }
+ if (viewRect.intersects(unselectedRect)) {
+ if (homeend)
+ Q3ScrollView::updateContents(viewRect.intersected(unselectedRect));
+ else
+ repaintContents(viewRect.intersected(unselectedRect));
+ }
+
+ if (changed)
+ emit selectionChanged();
+ }
+ } else if (!control) {
+ blockSignals(true);
+ selectAll(false);
+ blockSignals(false);
+ d->currentItem->setSelected(true, true);
+ }
+ } else {
+ if (shift)
+ d->currentItem->setSelected(!d->currentItem->isSelected(), true);
+ }
+}
+
+QBitmap Q3IconView::mask(QPixmap *pix) const
+{
+ QBitmap m;
+ if (d->maskCache.find(QString::number(pix->serialNumber()), m))
+ return m;
+ if (pix->hasAlphaChannel())
+ m = pix->mask();
+ else
+ m = pix->createHeuristicMask();
+ d->maskCache.insert(QString::number(pix->serialNumber()), m);
+ return m;
+}
+
+/*!
+ Returns true if an iconview item is being renamed; otherwise
+ returns false.
+*/
+
+bool Q3IconView::isRenaming() const
+{
+#ifndef QT_NO_TEXTEDIT
+ return d->renamingItem && d->renamingItem->renameBox;
+#else
+ return false;
+#endif
+}
+
+/*!
+ \enum Q3IconView::StringComparisonMode
+
+ This enum type is used to set the string comparison mode when
+ searching for an item. We'll refer to the string being searched
+ as the 'target' string.
+
+ \value CaseSensitive The strings must match case sensitively.
+ \value ExactMatch The target and search strings must match exactly.
+ \value BeginsWith The target string begins with the search string.
+ \value EndsWith The target string ends with the search string.
+ \value Contains The target string contains the search string.
+
+ If you OR these flags together (excluding \c CaseSensitive), the
+ search criteria be applied in the following order: \c ExactMatch,
+ \c BeginsWith, \c EndsWith, \c Contains.
+
+ Matching is case-insensitive unless \c CaseSensitive is set. \c
+ CaseSensitive can be OR-ed with any combination of the other
+ flags.
+
+ \sa ComparisonFlags
+*/
+
+/*!
+ \typedef Q3IconView::ComparisonFlags
+
+ This typedef is used in Q3IconView's API for values that are OR'd
+ combinations of \l StringComparisonMode values.
+
+ \sa StringComparisonMode
+*/
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_ICONVIEW