summaryrefslogtreecommitdiffstats
path: root/src/qt3support/itemviews/q3listview.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/q3listview.cpp
Long live Qt 4.5!
Diffstat (limited to 'src/qt3support/itemviews/q3listview.cpp')
-rw-r--r--src/qt3support/itemviews/q3listview.cpp7949
1 files changed, 7949 insertions, 0 deletions
diff --git a/src/qt3support/itemviews/q3listview.cpp b/src/qt3support/itemviews/q3listview.cpp
new file mode 100644
index 0000000000..1effdaa9f2
--- /dev/null
+++ b/src/qt3support/itemviews/q3listview.cpp
@@ -0,0 +1,7949 @@
+/****************************************************************************
+**
+** 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 <qplatformdefs.h>
+#include "q3listview.h"
+#ifndef QT_NO_LISTVIEW
+#include "q3tl.h"
+#include "qapplication.h"
+#include "qbitmap.h"
+#include "q3cleanuphandler.h"
+#include "qcursor.h"
+#include "qdatetime.h"
+#include "q3dragobject.h"
+#include "qevent.h"
+#include "qhash.h"
+#include "q3header.h"
+#include "qicon.h"
+#include "qlineedit.h"
+#include "qpainter.h"
+#include "qpixmapcache.h"
+#include "qstack.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qtimer.h"
+#include "qtooltip.h"
+#include "qdebug.h"
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+const int Unsorted = 16383;
+
+static Q3CleanupHandler<QBitmap> qlv_cleanup_bitmap;
+
+
+struct Q3ListViewPrivate
+{
+ // classes that are here to avoid polluting the global name space
+
+ // the magical hidden mother of all items
+ class Root: public Q3ListViewItem {
+ public:
+ Root(Q3ListView * parent);
+
+ void setHeight(int);
+ void invalidateHeight();
+ void setup();
+ Q3ListView * theListView() const;
+
+ Q3ListView * lv;
+ };
+
+ // to remember what's on screen
+ class DrawableItem {
+ public:
+ DrawableItem() {}
+ DrawableItem(int level, int ypos, Q3ListViewItem * item)
+ : l(level), y(ypos), i(item) {};
+ int l;
+ int y;
+ Q3ListViewItem * i;
+ };
+
+ // for sorting
+ class SortableItem {
+ public:
+ /*
+ We could be smarter and keep a pointer to the Q3ListView
+ item instead of numCols, col and asc. This would then allow
+ us to use the physical ordering of columns rather than the
+ logical. Microsoft uses the logical ordering, so there is
+ some virtue in doing so, although it prevents the user from
+ choosing the secondary key.
+ */
+ Q3ListViewItem * item;
+ int numCols;
+ int col;
+ bool asc;
+
+ int cmp(const SortableItem& i) const {
+ int diff = item->compare(i.item, col, asc);
+ if (diff == 0 && numCols != 1) {
+ for (int j = 0; j < numCols; j++) {
+ if (j != col) {
+ diff = item->compare(i.item, j, asc);
+ if (diff != 0)
+ break;
+ }
+ }
+ }
+ return diff;
+ }
+ bool operator<(const SortableItem& i) const { return cmp(i) < 0; }
+ bool operator<=(const SortableItem& i) const { return cmp(i) <= 0; }
+ bool operator>(const SortableItem& i) const { return cmp(i) > 0; }
+ };
+
+ class ItemColumnInfo {
+ public:
+ ItemColumnInfo(): pm(0), next(0), truncated(false), dirty(false), allow_rename(false), width(0) {}
+ ~ItemColumnInfo() { delete pm; delete next; }
+ QString text, tmpText;
+ QPixmap * pm;
+ ItemColumnInfo * next;
+ uint truncated : 1;
+ uint dirty : 1;
+ uint allow_rename : 1;
+ int width;
+ };
+
+ class ViewColumnInfo {
+ public:
+ ViewColumnInfo(): align(Qt::AlignAuto), sortable(true), next(0) {}
+ ~ViewColumnInfo() { delete next; }
+ int align;
+ bool sortable;
+ ViewColumnInfo * next;
+ };
+
+ // private variables used in Q3ListView
+ ViewColumnInfo * vci;
+ Q3Header * h;
+ Root * r;
+ uint rootIsExpandable : 1;
+ int margin;
+
+ Q3ListViewItem * focusItem, *highlighted, *oldFocusItem;
+
+ QTimer * timer;
+ QTimer * dirtyItemTimer;
+ QTimer * visibleTimer;
+ int levelWidth;
+
+ // the list of drawables, and the range drawables covers entirely
+ // (it may also include a few items above topPixel)
+ QList<DrawableItem> drawables;
+ int topPixel;
+ int bottomPixel;
+
+ QList<const Q3ListViewItem *> dirtyItems;
+
+ Q3ListView::SelectionMode selectionMode;
+
+ // Per-column structure for information not in the Q3Header
+ struct Column {
+ Q3ListView::WidthMode wmode;
+ };
+ QVector<Column> column;
+
+ // suggested height for the items
+ int fontMetricsHeight;
+ int minLeftBearing, minRightBearing;
+ int ellipsisWidth;
+
+ // currently typed prefix for the keyboard interface, and the time
+ // of the last key-press
+ QString currentPrefix;
+ QTime currentPrefixTime;
+
+ // holds a list of iterators
+ QList<Q3ListViewItemIterator *> iterators;
+ Q3ListViewItem *pressedItem, *selectAnchor;
+
+ QTimer *scrollTimer;
+ QTimer *renameTimer;
+ QTimer *autoopenTimer;
+
+ // sort column and order #### may need to move to Q3Header [subclass]
+ int sortcolumn;
+ bool ascending :1;
+ bool sortIndicator :1;
+ // whether to select or deselect during this mouse press.
+ bool allColumnsShowFocus :1;
+ bool select :1;
+
+ // true if the widget should take notice of mouseReleaseEvent
+ bool buttonDown :1;
+ // true if the widget should ignore a double-click
+ bool ignoreDoubleClick :1;
+
+ bool clearing :1;
+ bool pressedSelected :1;
+ bool pressedEmptyArea :1;
+
+ bool toolTips :1;
+ bool fullRepaintOnComlumnChange:1;
+ bool updateHeader :1;
+
+ bool startEdit : 1;
+ bool ignoreEditAfterFocus : 1;
+ bool inMenuMode :1;
+
+ Q3ListView::RenameAction defRenameAction;
+
+ Q3ListViewItem *startDragItem;
+ QPoint dragStartPos;
+ int pressedColumn;
+ Q3ListView::ResizeMode resizeMode;
+};
+
+Q_DECLARE_TYPEINFO(Q3ListViewPrivate::DrawableItem, Q_PRIMITIVE_TYPE);
+
+// these should probably be in Q3ListViewPrivate, for future thread safety
+static bool activatedByClick;
+static QPoint activatedP;
+
+#ifndef QT_NO_ACCESSIBILITY
+static int indexOfItem(Q3ListViewItem *item)
+{
+ if (!QAccessible::isActive())
+ return 0;
+
+ static Q3ListViewItem *lastItem = 0;
+ static int lastIndex = 0;
+
+ if (!item || !item->listView())
+ return 0;
+
+ if (item == lastItem)
+ return lastIndex;
+
+ lastItem = item;
+ int index = 1;
+
+ Q3ListViewItemIterator it(item->listView());
+ while (it.current()) {
+ if (it.current() == item) {
+ lastIndex = index;
+ return index;
+ }
+ ++it;
+ ++index;
+ }
+ lastIndex = 0;
+ return 0;
+}
+#endif
+
+/*!
+ Creates a string with ... like "Trollte..." or "...olltech", depending on the alignment.
+*/
+static QString qEllipsisText(const QString &org, const QFontMetrics &fm, int width, int align)
+{
+ int ellWidth = fm.width(QLatin1String("..."));
+ QString text = QString::fromLatin1("");
+ int i = 0;
+ int len = org.length();
+ int offset = (align & Qt::AlignRight) ? (len-1) - i : i;
+ while (i < len && fm.width(text + org[offset]) + ellWidth < width) {
+ if (align & Qt::AlignRight)
+ text.prepend(org[offset]);
+ else
+ text += org[offset];
+ offset = (align & Qt::AlignRight) ? (len-1) - ++i : ++i;
+ }
+ if (text.isEmpty())
+ text = (align & Qt::AlignRight) ? org.right(1) : text = org.left(1);
+ if (align & Qt::AlignRight)
+ text.prepend(QLatin1String("..."));
+ else
+ text += QLatin1String("...");
+ return text;
+}
+
+/*!
+ \class Q3ListViewItem
+ \brief The Q3ListViewItem class implements a list view item.
+
+ \compat
+
+ A list view item is a multi-column object capable of displaying
+ itself in a Q3ListView.
+
+ The easiest way to use Q3ListViewItem is to construct one with a
+ few constant strings, and either a Q3ListView or another
+ Q3ListViewItem as parent.
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 0
+ We've discarded the pointers to the items since we can still access
+ them via their parent \e listView. By default, Q3ListView sorts its
+ items; this can be switched off with Q3ListView::setSorting(-1).
+
+ The parent must be another Q3ListViewItem or a Q3ListView. If the
+ parent is a Q3ListView, the item becomes a top-level item within
+ that Q3ListView. If the parent is another Q3ListViewItem, the item
+ becomes a child of that list view item.
+
+ If you keep the pointer, you can set or change the texts using
+ setText(), add pixmaps using setPixmap(), change its mode using
+ setSelectable(), setSelected(), setOpen() and setExpandable().
+ You'll also be able to change its height using setHeight(), and
+ traverse its sub-items. You don't have to keep the pointer since
+ you can get a pointer to any Q3ListViewItem in a Q3ListView using
+ Q3ListView::selectedItem(), Q3ListView::currentItem(),
+ Q3ListView::firstChild(), Q3ListView::lastItem() and
+ Q3ListView::findItem().
+
+ If you call \c delete on a list view item, it will be deleted as
+ expected, and as usual for \l{QObject}s, if it has any child items
+ (to any depth), all these will be deleted too.
+
+ \l{Q3CheckListItem}s are list view items that have a checkbox or
+ radio button and can be used in place of plain Q3ListViewItems.
+
+ You can traverse the tree as if it were a doubly-linked list using
+ itemAbove() and itemBelow(); they return pointers to the items
+ directly above and below this item on the screen (even if none of
+ them are actually visible at the moment).
+
+ Here's how to traverse all of an item's children (but not its
+ children's children, etc.):
+ Example:
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 1
+
+ If you want to iterate over every item, to any level of depth use
+ an iterator. To iterate over the entire tree, initialize the
+ iterator with the list view itself; to iterate over an item's
+ children (and children's children to any depth), initialize the
+ iterator with the item:
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 2
+
+ Note that the order of the children will change when the sorting
+ order changes and is undefined if the items are not visible. You
+ can, however, call enforceSortOrder() at any time; Q3ListView will
+ always call it before it needs to show an item.
+
+ Many programs will need to reimplement Q3ListViewItem. The most
+ commonly reimplemented functions are:
+ \table
+ \header \i Function \i Description
+ \row \i \l text()
+ \i Returns the text in a column. Many subclasses will compute
+ this on the fly.
+ \row \i \l key()
+ \i Used for sorting. The default key() simply calls
+ text(), but judicious use of key() can give you fine
+ control over sorting; for example, QFileDialog
+ reimplements key() to sort by date.
+ \row \i \l setup()
+ \i Called before showing the item and whenever the list
+ view's font changes, for example.
+ \row \i \l activate()
+ \i Called whenever the user clicks on the item or presses
+ Space when the item is the current item.
+ \endtable
+
+ Some subclasses call setExpandable(true) even when they have no
+ children, and populate themselves when setup() or setOpen(true) is
+ called. The \c dirview/dirview.cpp example program uses this
+ technique to start up quickly: The files and subdirectories in a
+ directory aren't inserted into the tree until they're actually
+ needed.
+
+ \img qlistviewitems.png List View Items
+
+ \sa Q3CheckListItem Q3ListView
+*/
+
+/*!
+ \fn int Q3CheckListItem::rtti() const
+
+ Returns 1.
+
+ Make your derived classes return their own values for rtti(), and
+ you can distinguish between list view items. You should use values
+ greater than 1000, to allow for extensions to this class.
+*/
+
+/*!
+ Constructs a new top-level list view item in the Q3ListView \a
+ parent.
+*/
+
+Q3ListViewItem::Q3ListViewItem(Q3ListView * parent)
+{
+ init();
+ parent->insertItem(this);
+}
+
+
+/*!
+ Constructs a new list view item that is a child of \a parent and
+ first in the parent's list of children.
+*/
+
+Q3ListViewItem::Q3ListViewItem(Q3ListViewItem * parent)
+{
+ init();
+ parent->insertItem(this);
+}
+
+
+
+
+/*!
+ Constructs an empty list view item that is a child of \a parent
+ and is after item \a after in the parent's list of children. Since
+ \a parent is a Q3ListView the item will be a top-level item.
+*/
+
+Q3ListViewItem::Q3ListViewItem(Q3ListView * parent, Q3ListViewItem * after)
+{
+ init();
+ parent->insertItem(this);
+ moveToJustAfter(after);
+}
+
+
+/*!
+ Constructs an empty list view item that is a child of \a parent
+ and is after item \a after in the parent's list of children.
+*/
+
+Q3ListViewItem::Q3ListViewItem(Q3ListViewItem * parent, Q3ListViewItem * after)
+{
+ init();
+ parent->insertItem(this);
+ moveToJustAfter(after);
+}
+
+
+
+/*!
+ Constructs a new top-level list view item in the Q3ListView \a
+ parent, with up to eight constant strings, \a label1, \a label2, \a
+ label3, \a label4, \a label5, \a label6, \a label7 and \a label8
+ defining its columns' contents.
+
+ \sa setText()
+*/
+
+Q3ListViewItem::Q3ListViewItem(Q3ListView * parent,
+ const QString &label1,
+ const QString &label2,
+ const QString &label3,
+ const QString &label4,
+ const QString &label5,
+ const QString &label6,
+ const QString &label7,
+ const QString &label8)
+{
+ init();
+ parent->insertItem(this);
+
+ setText(0, label1);
+ setText(1, label2);
+ setText(2, label3);
+ setText(3, label4);
+ setText(4, label5);
+ setText(5, label6);
+ setText(6, label7);
+ setText(7, label8);
+}
+
+
+/*!
+ Constructs a new list view item as a child of the Q3ListViewItem \a
+ parent with up to eight constant strings, \a label1, \a label2, \a
+ label3, \a label4, \a label5, \a label6, \a label7 and \a label8
+ as columns' contents.
+
+ \sa setText()
+*/
+
+Q3ListViewItem::Q3ListViewItem(Q3ListViewItem * parent,
+ const QString &label1,
+ const QString &label2,
+ const QString &label3,
+ const QString &label4,
+ const QString &label5,
+ const QString &label6,
+ const QString &label7,
+ const QString &label8)
+{
+ init();
+ parent->insertItem(this);
+
+ setText(0, label1);
+ setText(1, label2);
+ setText(2, label3);
+ setText(3, label4);
+ setText(4, label5);
+ setText(5, label6);
+ setText(6, label7);
+ setText(7, label8);
+}
+
+/*!
+ Constructs a new list view item in the Q3ListView \a parent that is
+ included after item \a after and that has up to eight column
+ texts, \a label1, \a label2, \a label3, \a label4, \a label5, \a
+ label6, \a label7 and\a label8.
+
+ Note that the order is changed according to Q3ListViewItem::key()
+ unless the list view's sorting is disabled using
+ Q3ListView::setSorting(-1).
+
+ \sa setText()
+*/
+
+Q3ListViewItem::Q3ListViewItem(Q3ListView * parent, Q3ListViewItem * after,
+ const QString &label1,
+ const QString &label2,
+ const QString &label3,
+ const QString &label4,
+ const QString &label5,
+ const QString &label6,
+ const QString &label7,
+ const QString &label8)
+{
+ init();
+ parent->insertItem(this);
+ moveToJustAfter(after);
+
+ setText(0, label1);
+ setText(1, label2);
+ setText(2, label3);
+ setText(3, label4);
+ setText(4, label5);
+ setText(5, label6);
+ setText(6, label7);
+ setText(7, label8);
+}
+
+
+/*!
+ Constructs a new list view item as a child of the Q3ListViewItem \a
+ parent. It is inserted after item \a after and may contain up to
+ eight strings, \a label1, \a label2, \a label3, \a label4, \a
+ label5, \a label6, \a label7 and \a label8 as column entries.
+
+ Note that the order is changed according to Q3ListViewItem::key()
+ unless the list view's sorting is disabled using
+ Q3ListView::setSorting(-1).
+
+ \sa setText()
+*/
+
+Q3ListViewItem::Q3ListViewItem(Q3ListViewItem * parent, Q3ListViewItem * after,
+ const QString &label1,
+ const QString &label2,
+ const QString &label3,
+ const QString &label4,
+ const QString &label5,
+ const QString &label6,
+ const QString &label7,
+ const QString &label8)
+{
+ init();
+ parent->insertItem(this);
+ moveToJustAfter(after);
+
+ setText(0, label1);
+ setText(1, label2);
+ setText(2, label3);
+ setText(3, label4);
+ setText(4, label5);
+ setText(5, label6);
+ setText(6, label7);
+ setText(7, label8);
+}
+
+/*!
+ Sorts all this item's child items using the current sorting
+ configuration (sort column and direction).
+
+ \sa enforceSortOrder()
+*/
+
+void Q3ListViewItem::sort()
+{
+ if (!listView())
+ return;
+ lsc = Unsorted;
+ enforceSortOrder();
+ listView()->triggerUpdate();
+}
+
+/*!
+ Returns 0.
+
+ Make your derived classes return their own values for rtti(), so
+ that you can distinguish between different kinds of list view
+ items. You should use values greater than 1000 to allow for
+ extensions to this class.
+*/
+
+int Q3ListViewItem::rtti() const
+{
+ return RTTI;
+}
+
+/*
+ Performs the initializations that's common to the constructors.
+*/
+
+void Q3ListViewItem::init()
+{
+ ownHeight = 0;
+ maybeTotalHeight = -1;
+ open = false;
+
+ nChildren = 0;
+ parentItem = 0;
+ siblingItem = childItem = 0;
+
+ columns = 0;
+
+ selected = 0;
+ selectable = true;
+
+ lsc = Unsorted;
+ lso = true; // unsorted in ascending order :)
+ configured = false;
+ expandable = false;
+ selectable = true;
+ is_root = false;
+ allow_drag = false;
+ allow_drop = false;
+ visible = true;
+ renameBox = 0;
+ enabled = true;
+ mlenabled = false;
+}
+
+/*!
+ If \a b is true, the item is made visible; otherwise it is hidden.
+
+ If the item is not visible, itemAbove() and itemBelow() will never
+ return this item, although you still can reach it by using e.g.
+ Q3ListViewItemIterator.
+*/
+
+void Q3ListViewItem::setVisible(bool b)
+{
+ if (b == (bool)visible)
+ return;
+ Q3ListView *lv = listView();
+ if (!lv)
+ return;
+ if (b && parent() && !parent()->isVisible())
+ return;
+ visible = b;
+ configured = false;
+ setHeight(0);
+ invalidateHeight();
+ if (parent())
+ parent()->invalidateHeight();
+ else
+ lv->d->r->invalidateHeight();
+ for (Q3ListViewItem *i = childItem; i; i = i->siblingItem)
+ i->setVisible(b);
+ if (lv)
+ lv->triggerUpdate();
+}
+
+/*!
+ Returns true if the item is visible; otherwise returns false.
+
+ \sa setVisible()
+*/
+
+bool Q3ListViewItem::isVisible() const
+{
+ return (bool)visible;
+}
+
+/*!
+ If \a b is true, this item can be in-place renamed in the column
+ \a col by the user; otherwise it cannot be renamed in-place.
+*/
+
+void Q3ListViewItem::setRenameEnabled(int col, bool b)
+{
+ Q3ListViewPrivate::ItemColumnInfo * l = (Q3ListViewPrivate::ItemColumnInfo*)columns;
+ if (!l) {
+ l = new Q3ListViewPrivate::ItemColumnInfo;
+ columns = (void*)l;
+ }
+ for(int c = 0; c < col; c++) {
+ if (!l->next)
+ l->next = new Q3ListViewPrivate::ItemColumnInfo;
+ l = l->next;
+ }
+
+ if (!l)
+ return;
+ l->allow_rename = b;
+}
+
+/*!
+ Returns true if this item can be in-place renamed in column \a
+ col; otherwise returns false.
+*/
+
+bool Q3ListViewItem::renameEnabled(int col) const
+{
+ Q3ListViewPrivate::ItemColumnInfo * l = (Q3ListViewPrivate::ItemColumnInfo*)columns;
+ if (!l)
+ return false;
+
+ while(col && l) {
+ l = l->next;
+ col--;
+ }
+
+ if (!l)
+ return false;
+ return (bool)l->allow_rename;
+}
+
+/*!
+ If \a b is true the item is enabled; otherwise it is disabled.
+ Disabled items are drawn differently (e.g. grayed-out) and are not
+ accessible by the user.
+*/
+
+void Q3ListViewItem::setEnabled(bool b)
+{
+ if ((bool)enabled == b)
+ return;
+ enabled = b;
+ if (!enabled)
+ selected = false;
+ Q3ListView *lv = listView();
+ if (lv) {
+ lv->triggerUpdate();
+
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(lv->viewport(), indexOfItem(this), QAccessible::StateChanged);
+#endif
+ }
+}
+
+/*!
+ Returns true if this item is enabled; otherwise returns false.
+
+ \sa setEnabled()
+*/
+
+bool Q3ListViewItem::isEnabled() const
+{
+ return (bool)enabled;
+}
+
+/*!
+ If in-place renaming of this item is enabled (see
+ renameEnabled()), this function starts renaming the item in column
+ \a col, by creating and initializing an edit box.
+*/
+
+void Q3ListViewItem::startRename(int col)
+{
+ if (!renameEnabled(col))
+ return;
+ if (renameBox)
+ cancelRename(col);
+ Q3ListView *lv = listView();
+ if (!lv)
+ return;
+
+ if (lv->d->renameTimer)
+ lv->d->renameTimer->stop();
+
+ lv->ensureItemVisible(this);
+
+ if (lv->d->timer->isActive()) {
+ // make sure that pending calculations get finished
+ lv->d->timer->stop();
+ lv->updateContents();
+ }
+
+ if (lv->currentItem() && lv->currentItem()->renameBox) {
+ if (lv->d->defRenameAction == Q3ListView::Reject)
+ lv->currentItem()->cancelRename(lv->currentItem()->renameCol);
+ else
+ lv->currentItem()->okRename(lv->currentItem()->renameCol);
+ }
+
+ if (this != lv->currentItem())
+ lv->setCurrentItem(this);
+
+ QRect r = lv->itemRect(this);
+ r = QRect(lv->viewportToContents(r.topLeft()), r.size());
+ r.setLeft(lv->header()->sectionPos(col));
+ r.setWidth(qMin(lv->header()->sectionSize(col) - 1,
+ lv->contentsX() + lv->visibleWidth() - r.left()));
+ if (col == 0)
+ r.setLeft(r.left() + lv->itemMargin() + (depth() + (lv->rootIsDecorated() ? 1 : 0)) * lv->treeStepSize() - 1);
+ if (pixmap(col))
+ r.setLeft(r.left() + pixmap(col)->width());
+ if (r.x() - lv->contentsX() < 0) {
+ lv->scrollBy(r.x() - lv->contentsX(), 0);
+ r.setX(lv->contentsX());
+ } else if ((lv->contentsX() + lv->visibleWidth()) < (r.x() + r.width())) {
+ lv->scrollBy((r.x() + r.width()) - (lv->contentsX() + lv->visibleWidth()), 0);
+ }
+ if (r.width() > lv->visibleWidth())
+ r.setWidth(lv->visibleWidth());
+ renameBox = new QLineEdit(lv->viewport(), "qt_renamebox");
+ renameBox->setFrame(false);
+ renameBox->setText(text(col));
+ renameBox->selectAll();
+ renameBox->installEventFilter(lv);
+ lv->addChild(renameBox, r.x(), r.y());
+ renameBox->resize(r.size());
+ lv->viewport()->setFocusProxy(renameBox);
+ renameBox->setFocus();
+ renameBox->show();
+ renameCol = col;
+}
+
+/*!
+ This function removes the rename box.
+*/
+
+void Q3ListViewItem::removeRenameBox()
+{
+ // Sanity, it should be checked by the functions calling this first anyway
+ Q3ListView *lv = listView();
+ if (!lv || !renameBox)
+ return;
+ const bool resetFocus = lv->viewport()->focusProxy() == renameBox;
+ delete renameBox;
+ renameBox = 0;
+ if (resetFocus) {
+ lv->viewport()->setFocusProxy(lv);
+ lv->setFocus();
+ }
+}
+
+/*!
+ This function is called if the user presses Enter during in-place
+ renaming of the item in column \a col.
+
+ \sa cancelRename()
+*/
+
+void Q3ListViewItem::okRename(int col)
+{
+ Q3ListView *lv = listView();
+ if (!lv || !renameBox)
+ return;
+ setText(col, renameBox->text());
+ removeRenameBox();
+
+ // we set the parent lsc to Unsorted if that column is the sorted one
+ if (parent() && (int)parent()->lsc == col)
+ parent()->lsc = Unsorted;
+
+ emit lv->itemRenamed(this, col);
+ emit lv->itemRenamed(this, col, text(col));
+}
+
+/*!
+ This function is called if the user cancels in-place renaming of
+ this item in column \a col (e.g. by pressing Esc).
+
+ \sa okRename()
+*/
+
+void Q3ListViewItem::cancelRename(int)
+{
+ Q3ListView *lv = listView();
+ if (!lv || !renameBox)
+ return;
+ removeRenameBox();
+}
+
+/*!
+ Destroys the item, deleting all its children and freeing up all
+ allocated resources.
+*/
+
+Q3ListViewItem::~Q3ListViewItem()
+{
+ if (renameBox) {
+ delete renameBox;
+ renameBox = 0;
+ }
+
+ Q3ListView *lv = listView();
+
+ if (lv) {
+ if (lv->d->oldFocusItem == this)
+ lv->d->oldFocusItem = 0;
+ if (lv->d->focusItem == this)
+ lv->d->focusItem = 0;
+ if (lv->d->highlighted == this)
+ lv->d->highlighted = 0;
+ if (lv->d->pressedItem == this)
+ lv->d->pressedItem = 0;
+ if (lv->d->selectAnchor == this)
+ lv->d->selectAnchor = 0;
+ for (int j = 0; j < lv->d->iterators.size(); ++j) {
+ Q3ListViewItemIterator *i = lv->d->iterators.at(j);
+ if (i->current() == this)
+ i->currentRemoved();
+ }
+ }
+
+ if (parentItem)
+ parentItem->takeItem(this);
+ Q3ListViewItem * i = childItem;
+ childItem = 0;
+ while (i) {
+ i->parentItem = 0;
+ Q3ListViewItem * n = i->siblingItem;
+ delete i;
+ i = n;
+ }
+ delete (Q3ListViewPrivate::ItemColumnInfo *)columns;
+}
+
+
+/*!
+ If \a b is true each of the item's columns may contain multiple
+ lines of text; otherwise each of them may only contain a single
+ line.
+*/
+
+void Q3ListViewItem::setMultiLinesEnabled(bool b)
+{
+ mlenabled = b;
+}
+
+/*!
+ Returns true if the item can display multiple lines of text in its
+ columns; otherwise returns false.
+*/
+
+bool Q3ListViewItem::multiLinesEnabled() const
+{
+ return mlenabled;
+}
+
+/*!
+ If \a allow is true, the list view starts a drag (see
+ Q3ListView::dragObject()) when the user presses and moves the mouse
+ on this item.
+*/
+
+
+void Q3ListViewItem::setDragEnabled(bool allow)
+{
+ allow_drag = (uint)allow;
+}
+
+/*!
+ If \a allow is true, the list view accepts drops onto the item;
+ otherwise drops are not allowed.
+*/
+
+void Q3ListViewItem::setDropEnabled(bool allow)
+{
+ allow_drop = (uint)allow;
+}
+
+/*!
+ Returns true if this item can be dragged; otherwise returns false.
+
+ \sa setDragEnabled()
+*/
+
+bool Q3ListViewItem::dragEnabled() const
+{
+ return (bool)allow_drag;
+}
+
+/*!
+ Returns true if this item accepts drops; otherwise returns false.
+
+ \sa setDropEnabled(), acceptDrop()
+*/
+
+bool Q3ListViewItem::dropEnabled() const
+{
+ return (bool)allow_drop;
+}
+
+/*!
+ Returns true if the item can accept drops of type QMimeSource \a
+ mime; otherwise returns false.
+
+ The default implementation does nothing and returns false. A
+ subclass must reimplement this to accept drops.
+*/
+
+bool Q3ListViewItem::acceptDrop(const QMimeSource *) const
+{
+ return false;
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*!
+ This function is called when something was dropped on the item. \a e
+ contains all the information about the drop.
+
+ The default implementation does nothing, subclasses may need to
+ reimplement this function.
+*/
+
+void Q3ListViewItem::dropped(QDropEvent *e)
+{
+ Q_UNUSED(e);
+}
+
+#endif
+
+/*!
+ This function is called when a drag enters the item's bounding
+ rectangle.
+
+ The default implementation does nothing, subclasses may need to
+ reimplement this function.
+*/
+
+void Q3ListViewItem::dragEntered()
+{
+}
+
+/*!
+ This function is called when a drag leaves the item's bounding
+ rectangle.
+
+ The default implementation does nothing, subclasses may need to
+ reimplement this function.
+*/
+
+void Q3ListViewItem::dragLeft()
+{
+}
+
+/*!
+ Inserts \a newChild into this list view item's list of children.
+ You should not need to call this function; it is called
+ automatically by the constructor of \a newChild.
+
+ \warning If you are using \c Single selection mode, then you
+ should only insert unselected items.
+*/
+
+void Q3ListViewItem::insertItem(Q3ListViewItem * newChild)
+{
+ Q3ListView *lv = listView();
+ if (lv && lv->currentItem() && lv->currentItem()->renameBox) {
+ if (lv->d->defRenameAction == Q3ListView::Reject)
+ lv->currentItem()->cancelRename(lv->currentItem()->renameCol);
+ else
+ lv->currentItem()->okRename(lv->currentItem()->renameCol);
+ }
+
+ if (!newChild || newChild->parentItem == this)
+ return;
+ if (newChild->parentItem)
+ newChild->parentItem->takeItem(newChild);
+ if (open)
+ invalidateHeight();
+ newChild->siblingItem = childItem;
+ childItem = newChild;
+ nChildren++;
+ newChild->parentItem = this;
+ lsc = Unsorted;
+ newChild->ownHeight = 0;
+ newChild->configured = false;
+
+ if (lv && !lv->d->focusItem) {
+ lv->d->focusItem = lv->firstChild();
+ lv->d->selectAnchor = lv->d->focusItem;
+ lv->repaintItem(lv->d->focusItem);
+ }
+}
+
+
+/*!
+ \fn void Q3ListViewItem::removeItem(Q3ListViewItem *item)
+
+ Removes the given \a item. Use takeItem() instead.
+*/
+
+
+/*!
+ Removes \a item from this object's list of children and causes an
+ update of the screen display. The item is not deleted. You should
+ not normally need to call this function because
+ Q3ListViewItem::~Q3ListViewItem() calls it.
+
+ The normal way to delete an item is to use \c delete.
+
+ If you need to move an item from one place in the hierarchy to
+ another you can use takeItem() to remove the item from the list
+ view and then insertItem() to put the item back in its new
+ position.
+
+ If a taken item is part of a selection in \c Single selection
+ mode, it is unselected and selectionChanged() is emitted. If a
+ taken item is part of a selection in \c Multi or \c Extended
+ selection mode, it remains selected.
+
+ \warning This function leaves \a item and its children in a state
+ where most member functions are unsafe. Only a few functions work
+ correctly on an item in this state, most notably insertItem(). The
+ functions that work on taken items are explicitly documented as
+ such.
+
+ \sa Q3ListViewItem::insertItem()
+*/
+
+void Q3ListViewItem::takeItem(Q3ListViewItem * item)
+{
+ if (!item)
+ return;
+
+ Q3ListView *lv = listView();
+ if (lv && lv->currentItem() && lv->currentItem()->renameBox) {
+ if (lv->d->defRenameAction == Q3ListView::Reject)
+ lv->currentItem()->cancelRename(lv->currentItem()->renameCol);
+ else
+ lv->currentItem()->okRename(lv->currentItem()->renameCol);
+ }
+ bool emit_changed = false;
+ if (lv && !lv->d->clearing) {
+ if (lv->d->oldFocusItem == this)
+ lv->d->oldFocusItem = 0;
+
+ for (int j = 0; j < lv->d->iterators.size(); ++j) {
+ Q3ListViewItemIterator *i = lv->d->iterators.at(j);
+ if (i->current() == item)
+ i->currentRemoved();
+ }
+
+ invalidateHeight();
+
+ if (lv->d && !lv->d->drawables.isEmpty())
+ lv->d->drawables.clear();
+
+ if (!lv->d->dirtyItems.isEmpty()) {
+ if (item->childItem) {
+ lv->d->dirtyItems.clear();
+ lv->d->dirtyItemTimer->stop();
+ lv->triggerUpdate();
+ } else {
+ lv->d->dirtyItems.removeAll(item);
+ }
+ }
+
+ if (lv->d->focusItem) {
+ const Q3ListViewItem * c = lv->d->focusItem;
+ while(c && c != item)
+ c = c->parentItem;
+ if (c == item) {
+ if (lv->selectedItem()) {
+ // for Single, setSelected(false) when selectedItem() is taken
+ lv->selectedItem()->setSelected(false);
+ // we don't emit selectionChanged(0)
+ emit lv->selectionChanged();
+ }
+ if (item->nextSibling())
+ lv->d->focusItem = item->nextSibling();
+ else if (item->itemAbove())
+ lv->d->focusItem = item->itemAbove();
+ else
+ lv->d->focusItem = 0;
+ emit_changed = true;
+ }
+ }
+
+ // reset anchors etc. if they are set to this or any child
+ // items
+ const Q3ListViewItem *ptr = lv->d->selectAnchor;
+ while (ptr && ptr != item)
+ ptr = ptr->parentItem;
+ if (ptr == item)
+ lv->d->selectAnchor = lv->d->focusItem;
+
+ ptr = lv->d->startDragItem;
+ while (ptr && ptr != item)
+ ptr = ptr->parentItem;
+ if (ptr == item)
+ lv->d->startDragItem = 0;
+
+ ptr = lv->d->pressedItem;
+ while (ptr && ptr != item)
+ ptr = ptr->parentItem;
+ if (ptr == item)
+ lv->d->pressedItem = 0;
+
+ ptr = lv->d->highlighted;
+ while (ptr && ptr != item)
+ ptr = ptr->parentItem;
+ if (ptr == item)
+ lv->d->highlighted = 0;
+ }
+
+ nChildren--;
+
+ Q3ListViewItem ** nextChild = &childItem;
+ while(nextChild && *nextChild && item != *nextChild)
+ nextChild = &((*nextChild)->siblingItem);
+
+ if (nextChild && item == *nextChild)
+ *nextChild = (*nextChild)->siblingItem;
+ item->parentItem = 0;
+ item->siblingItem = 0;
+ item->ownHeight = 0;
+ item->maybeTotalHeight = -1;
+ item->configured = false;
+
+ if (emit_changed) {
+ emit lv->currentChanged(lv->d->focusItem);
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(lv->viewport(), 0, QAccessible::Focus);
+#endif
+ }
+}
+
+
+/*!
+ \fn QString Q3ListViewItem::key(int column, bool ascending) const
+
+ Returns a key that can be used for sorting by column \a column.
+ The default implementation returns text(). Derived classes may
+ also incorporate the order indicated by \a ascending into this
+ key, although this is not recommended.
+
+ If you want to sort on non-alphabetical data, e.g. dates, numbers,
+ etc., it is more efficient to reimplement compare().
+
+ \sa compare(), sortChildItems()
+*/
+
+QString Q3ListViewItem::key(int column, bool) const
+{
+ return text(column);
+}
+
+
+/*!
+ Compares this list view item to \a i using the column \a col in \a
+ ascending order. Returns \< 0 if this item is less than \a i, 0 if
+ they are equal and \> 0 if this item is greater than \a i.
+
+ This function is used for sorting.
+
+ The default implementation compares the item keys (key()) using
+ QString::localeAwareCompare(). A reimplementation can 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_q3listview.cpp 3
+ We don't recommend using \a ascending so your code can safely
+ ignore it.
+
+ \sa key() QString::localeAwareCompare() QString::compare()
+*/
+
+int Q3ListViewItem::compare(Q3ListViewItem *i, int col, bool ascending) const
+{
+ return key(col, ascending).localeAwareCompare(i->key(col, ascending));
+}
+
+/*!
+ Sorts this item's children using column \a column. This is done in
+ ascending order if \a ascending is true and in descending order if
+ \a ascending is false.
+
+ Asks some of the children to sort their children. (Q3ListView and
+ Q3ListViewItem ensure that all on-screen objects are properly
+ sorted but may avoid or defer sorting other objects in order to be
+ more responsive.)
+
+ \sa key() compare()
+*/
+
+void Q3ListViewItem::sortChildItems(int column, bool ascending)
+{
+ // we try HARD not to sort. if we're already sorted, don't.
+ if (column == (int)lsc && ascending == (bool)lso)
+ return;
+
+ if (column < 0)
+ return;
+
+ lsc = column;
+ lso = ascending;
+
+ const int nColumns = (listView() ? listView()->columns() : 0);
+
+ // and don't sort if we already have the right sorting order
+ if (column > nColumns || childItem == 0 || childItem->siblingItem == 0)
+ return;
+
+ // make an array for qHeapSort()
+ Q3ListViewPrivate::SortableItem * siblings
+ = new Q3ListViewPrivate::SortableItem[nChildren];
+ Q3ListViewItem * s = childItem;
+ int i = 0;
+ while (s && i < nChildren) {
+ siblings[i].numCols = nColumns;
+ siblings[i].col = column;
+ siblings[i].asc = ascending;
+ siblings[i].item = s;
+ s = s->siblingItem;
+ i++;
+ }
+
+ // and sort it.
+ qHeapSort(siblings, siblings + nChildren);
+
+ // build the linked list of siblings, in the appropriate
+ // direction, and finally set this->childItem to the new top
+ // child.
+ if (ascending) {
+ for(i = 0; i < nChildren - 1; i++)
+ siblings[i].item->siblingItem = siblings[i+1].item;
+ siblings[nChildren-1].item->siblingItem = 0;
+ childItem = siblings[0].item;
+ } else {
+ for(i = nChildren - 1; i > 0; i--)
+ siblings[i].item->siblingItem = siblings[i-1].item;
+ siblings[0].item->siblingItem = 0;
+ childItem = siblings[nChildren-1].item;
+ }
+ for (i = 0; i < nChildren; i++) {
+ if (siblings[i].item->isOpen())
+ siblings[i].item->sort();
+ }
+ delete[] siblings;
+}
+
+
+/*!
+ Sets this item's height to \a height pixels. This implicitly
+ changes totalHeight(), too.
+
+ Note that a font change causes this height to be overwritten
+ unless you reimplement setup().
+
+ For best results in Windows style we suggest using an even number
+ of pixels.
+
+ \sa height() totalHeight() isOpen()
+*/
+
+void Q3ListViewItem::setHeight(int height)
+{
+ if (ownHeight != height) {
+ if (visible)
+ ownHeight = height;
+ else
+ ownHeight = 0;
+ invalidateHeight();
+ }
+}
+
+
+/*!
+ Invalidates the cached total height of this item, including all
+ open children.
+
+ \sa setHeight() height() totalHeight()
+*/
+
+void Q3ListViewItem::invalidateHeight()
+{
+ if (maybeTotalHeight < 0)
+ return;
+ maybeTotalHeight = -1;
+ if (parentItem && parentItem->isOpen())
+ parentItem->invalidateHeight();
+}
+
+
+/*!
+ Opens or closes an item, i.e. shows or hides an item's children.
+
+ If \a o is true all child items are shown initially. The user can
+ hide them by clicking the \bold{-} icon to the left of the item.
+ If \a o is false, the children of this item are initially hidden.
+ The user can show them by clicking the \bold{+} icon to the left
+ of the item.
+
+ \sa height() totalHeight() isOpen()
+*/
+
+void Q3ListViewItem::setOpen(bool o)
+{
+ if (o == (bool)open || !enabled)
+ return;
+ open = o;
+
+ // If no children to show simply emit signals and return
+ if (!nChildren) {
+ Q3ListView *lv = listView();
+ if (lv && this != lv->d->r) {
+ if (o)
+ emit lv->expanded(this);
+ else
+ emit lv->collapsed(this);
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(lv->viewport(), indexOfItem(this), QAccessible::StateChanged);
+#endif
+ }
+ return;
+ }
+ invalidateHeight();
+
+ if (!configured) {
+ Q3ListViewItem * l = this;
+ QStack<Q3ListViewItem *> s;
+ while(l) {
+ if (l->open && l->childItem) {
+ s.push(l->childItem);
+ } else if (l->childItem) {
+ // first invisible child is unconfigured
+ Q3ListViewItem * c = l->childItem;
+ while(c) {
+ c->configured = false;
+ c = c->siblingItem;
+ }
+ }
+ l->configured = true;
+ l->setup();
+ l = (l == this) ? 0 : l->siblingItem;
+ if (!l && !s.isEmpty())
+ l = s.pop();
+ }
+ }
+
+ Q3ListView *lv = listView();
+
+ if (open && lv)
+ enforceSortOrder();
+
+ if (isVisible() && lv && lv->d && !lv->d->drawables.isEmpty())
+ lv->buildDrawableList();
+
+ if (lv && this != lv->d->r) {
+ if (o)
+ emit lv->expanded(this);
+ else
+ emit lv->collapsed(this);
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(lv->viewport(), indexOfItem(this), QAccessible::StateChanged);
+#endif
+ }
+}
+
+
+/*!
+ This virtual function is called before the first time Q3ListView
+ needs to know the height or any other graphical attribute of this
+ object, and whenever the font, GUI style, or colors of the list
+ view change.
+
+ The default calls widthChanged() and sets the item's height to the
+ height of a single line of text in the list view's font. (If you
+ use icons, multi-line text, etc., you will probably need to call
+ setHeight() yourself or reimplement it.)
+*/
+
+void Q3ListViewItem::setup()
+{
+ widthChanged();
+ Q3ListView *lv = listView();
+
+ int ph = 0;
+ int h = 0;
+ if (lv) {
+ for (int i = 0; i < lv->d->column.size(); ++i) {
+ if (pixmap(i))
+ ph = qMax(ph, pixmap(i)->height());
+ }
+
+ if (mlenabled) {
+ h = ph;
+ for (int c = 0; c < lv->columns(); ++c) {
+ int lines = text(c).count(QLatin1Char('\n')) + 1;
+ int tmph = lv->d->fontMetricsHeight
+ + lv->fontMetrics().lineSpacing() * (lines - 1);
+ h = qMax(h, tmph);
+ }
+ h += 2*lv->itemMargin();
+ } else {
+ h = qMax(lv->d->fontMetricsHeight, ph) + 2*lv->itemMargin();
+ }
+ }
+
+ h = qMax(h, QApplication::globalStrut().height());
+
+ if (h % 2 > 0)
+ h++;
+ setHeight(h);
+}
+
+
+
+
+/*!
+ This virtual function is called whenever the user presses the mouse
+ on this item or presses Space on it.
+
+ \sa activatedPos()
+*/
+
+void Q3ListViewItem::activate()
+{
+}
+
+
+/*!
+ When called from a reimplementation of activate(), this function
+ gives information on how the item was activated. Otherwise the
+ behavior is undefined.
+
+ If activate() was caused by a mouse press, the function sets \a
+ pos to where the user clicked and returns true; otherwise it
+ returns false and does not change \a pos.
+
+ \a pos is relative to the top-left corner of this item.
+
+ \sa activate()
+*/
+
+bool Q3ListViewItem::activatedPos(QPoint &pos)
+{
+ if (activatedByClick)
+ pos = activatedP;
+ return activatedByClick;
+}
+
+
+/*!
+ \fn bool Q3ListViewItem::isSelectable() const
+
+ Returns true if the item is selectable (as it is by default);
+ otherwise returns false
+
+ \sa setSelectable()
+*/
+
+
+/*!
+ Sets this items to be selectable if \a enable is true (the
+ default) or not to be selectable if \a enable is false.
+
+ The user is not able to select a non-selectable item using either
+ the keyboard or the mouse. The application programmer still can
+ though, e.g. using setSelected().
+
+ \sa isSelectable()
+*/
+
+void Q3ListViewItem::setSelectable(bool enable)
+{
+ selectable = enable;
+}
+
+
+/*!
+ \fn bool Q3ListViewItem::isExpandable() const
+
+ Returns true if this item is expandable even when it has no
+ children; otherwise returns false.
+*/
+
+/*!
+ Sets this item to be expandable even if it has no children if \a
+ enable is true, and to be expandable only if it has children if \a
+ enable is false (the default).
+
+ The dirview example uses this in the canonical fashion. It checks
+ whether the directory is empty in setup() and calls
+ setExpandable(true) if not; in setOpen() it reads the contents of
+ the directory and inserts items accordingly. This strategy means
+ that dirview can display the entire file system without reading
+ very much at startup.
+
+ Note that root items are not expandable by the user unless
+ Q3ListView::setRootIsDecorated() is set to true.
+
+ \sa setSelectable()
+*/
+
+void Q3ListViewItem::setExpandable(bool enable)
+{
+ expandable = enable;
+}
+
+
+/*!
+ Makes sure that this object's children are sorted appropriately.
+
+ This only works if every item from the root item down to this item
+ is already sorted.
+
+ \sa sortChildItems()
+*/
+
+void Q3ListViewItem::enforceSortOrder() const
+{
+ Q3ListView *lv = listView();
+ if (!lv || (lv && (lv->d->clearing || lv->d->sortcolumn == Unsorted)))
+ return;
+ if (parentItem &&
+ (parentItem->lsc != lsc || parentItem->lso != lso))
+ ((Q3ListViewItem *)this)->sortChildItems((int)parentItem->lsc,
+ (bool)parentItem->lso);
+ else if (!parentItem &&
+ ((int)lsc != lv->d->sortcolumn || (bool)lso != lv->d->ascending))
+ ((Q3ListViewItem *)this)->sortChildItems(lv->d->sortcolumn, lv->d->ascending);
+}
+
+
+/*!
+ \fn bool Q3ListViewItem::isSelected() const
+
+ Returns true if this item is selected; otherwise returns false.
+
+ \sa setSelected() Q3ListView::setSelected() Q3ListView::selectionChanged()
+*/
+
+
+/*!
+ If \a s is true this item is selected; otherwise it is deselected.
+
+ This function does not maintain any invariants or repaint anything
+ -- Q3ListView::setSelected() does that.
+
+ \sa height() totalHeight()
+*/
+
+void Q3ListViewItem::setSelected(bool s)
+{
+ bool old = selected;
+
+ Q3ListView *lv = listView();
+ if (lv && lv->selectionMode() != Q3ListView::NoSelection) {
+ if (s && isSelectable())
+ selected = true;
+ else
+ selected = false;
+
+#ifndef QT_NO_ACCESSIBILITY
+ if (old != (bool)selected) {
+ int ind = indexOfItem(this);
+ QAccessible::updateAccessibility(lv->viewport(), ind, QAccessible::StateChanged);
+ QAccessible::updateAccessibility(lv->viewport(), ind, selected ? QAccessible::SelectionAdd : QAccessible::SelectionRemove);
+ }
+#else
+ Q_UNUSED(old);
+#endif
+ }
+}
+
+/*!
+ Returns the total height of this object, including any visible
+ children. This height is recomputed lazily and cached for as long
+ as possible.
+
+ Functions which can affect the total height are, setHeight() which
+ is used to set an item's height, setOpen() to show or hide an
+ item's children, and invalidateHeight() to invalidate the cached
+ height.
+
+ \sa height()
+*/
+
+int Q3ListViewItem::totalHeight() const
+{
+ if (!visible)
+ return 0;
+ if (maybeTotalHeight >= 0)
+ return maybeTotalHeight;
+ Q3ListViewItem * that = (Q3ListViewItem *)this;
+ if (!that->configured) {
+ that->configured = true;
+ that->setup(); // ### virtual non-const function called in const
+ }
+ that->maybeTotalHeight = that->ownHeight;
+
+ if (!that->isOpen() || !that->childCount())
+ return that->ownHeight;
+
+ Q3ListViewItem * child = that->childItem;
+ while (child != 0) {
+ that->maybeTotalHeight += child->totalHeight();
+ child = child->siblingItem;
+ }
+ return that->maybeTotalHeight;
+}
+
+
+/*!
+ Returns the text in column \a column, or an empty string if there is
+ no text in that column.
+
+ \sa key() paintCell()
+*/
+
+QString Q3ListViewItem::text(int column) const
+{
+ Q3ListViewPrivate::ItemColumnInfo * l
+ = (Q3ListViewPrivate::ItemColumnInfo*) columns;
+
+ while(column && l) {
+ l = l->next;
+ column--;
+ }
+
+ return l ? l->text : QString();
+}
+
+
+/*!
+ Sets the text in column \a column to \a text, if \a column is a
+ valid column number and \a text is different from the existing
+ text.
+
+ If the text() function has been reimplemented, this function may
+ be a no-op.
+
+ \sa text() key()
+*/
+
+void Q3ListViewItem::setText(int column, const QString &text)
+{
+ if (column < 0)
+ return;
+
+ Q3ListViewPrivate::ItemColumnInfo * l
+ = (Q3ListViewPrivate::ItemColumnInfo*) columns;
+ if (!l) {
+ l = new Q3ListViewPrivate::ItemColumnInfo;
+ columns = (void*)l;
+ }
+ for(int c = 0; c < column; c++) {
+ if (!l->next)
+ l->next = new Q3ListViewPrivate::ItemColumnInfo;
+ l = l->next;
+ }
+ if (l->text == text)
+ return;
+
+ int oldLc = 0;
+ int newLc = 0;
+ if (mlenabled) {
+ if (!l->text.isEmpty())
+ oldLc = l->text.count(QLatin1Char('\n')) + 1;
+ if (!text.isEmpty())
+ newLc = text.count(QLatin1Char('\n')) + 1;
+ }
+
+ l->dirty = true;
+ l->text = text;
+ if (column == (int)lsc)
+ lsc = Unsorted;
+
+ if (mlenabled && oldLc != newLc)
+ setup();
+ else
+ widthChanged(column);
+
+ Q3ListView * lv = listView();
+ if (lv) {
+ lv->triggerUpdate();
+#ifndef QT_NO_ACCESSIBILITY
+ if (lv->isVisible())
+ QAccessible::updateAccessibility(lv->viewport(), indexOfItem(this), QAccessible::NameChanged);
+#endif
+ }
+}
+
+
+/*!
+ Sets the pixmap in column \a column to \a pm, if \a pm is non-null
+ and different from the current pixmap, and if \a column is
+ non-negative.
+
+ \sa pixmap() setText()
+*/
+
+void Q3ListViewItem::setPixmap(int column, const QPixmap & pm)
+{
+ if (column < 0)
+ return;
+
+ int oldW = 0;
+ int oldH = 0;
+ if (pixmap(column)) {
+ oldW = pixmap(column)->width();
+ oldH = pixmap(column)->height();
+ }
+
+ Q3ListViewPrivate::ItemColumnInfo * l
+ = (Q3ListViewPrivate::ItemColumnInfo*) columns;
+ if (!l) {
+ l = new Q3ListViewPrivate::ItemColumnInfo;
+ columns = (void*)l;
+ }
+
+ for(int c = 0; c < column; c++) {
+ if (!l->next)
+ l->next = new Q3ListViewPrivate::ItemColumnInfo;
+ l = l->next;
+ }
+
+ if ((pm.isNull() && (!l->pm || l->pm->isNull())) ||
+ (l->pm && pm.serialNumber() == l->pm->serialNumber()))
+ return;
+
+ if (pm.isNull()) {
+ delete l->pm;
+ l->pm = 0;
+ } else {
+ if (l->pm)
+ *(l->pm) = pm;
+ else
+ l->pm = new QPixmap(pm);
+ }
+
+ int newW = 0;
+ int newH = 0;
+ if (pixmap(column)) {
+ newW = pixmap(column)->width();
+ newH = pixmap(column)->height();
+ }
+
+ if (oldW != newW || oldH != newH) {
+ setup();
+ widthChanged(column);
+ invalidateHeight();
+ }
+ Q3ListView *lv = listView();
+ if (lv) {
+ lv->triggerUpdate();
+ }
+}
+
+
+/*!
+ Returns the pixmap for \a column, or 0 if there is no pixmap for
+ \a column.
+
+ \sa setText() setPixmap()
+*/
+
+const QPixmap * Q3ListViewItem::pixmap(int column) const
+{
+ Q3ListViewPrivate::ItemColumnInfo * l
+ = (Q3ListViewPrivate::ItemColumnInfo*) columns;
+
+ while(column && l) {
+ l = l->next;
+ column--;
+ }
+
+ return (l && l->pm) ? l->pm : 0;
+}
+
+
+/*
+ This function paints the contents of one column of an item
+ and aligns it as described by \a align.
+
+ \a p is a QPainter open on the relevant paint device. \a p is
+ translated so (0, 0) is the top-left pixel in the cell and \a
+ width-1, height()-1 is the bottom-right pixel \e in the cell. The
+ other properties of \a p (pen, brush, etc) are undefined. \a pal is
+ the color group to use. \a column is the logical column number
+ within the item that is to be painted; 0 is the column which may
+ contain a tree.
+
+ This function may use Q3ListView::itemMargin() for readability
+ spacing on the left and right sides of data such as text, and
+ should honor isSelected() and Q3ListView::allColumnsShowFocus().
+
+ If you reimplement this function, you should also reimplement
+ width().
+
+ The rectangle to be painted is in an undefined state when this
+ function is called, so you \e must draw on all the pixels. The
+ painter \a p has the right font on entry.
+
+ \sa paintBranches(), Q3ListView::drawContentsOffset()
+*/
+
+static QStyleOptionQ3ListView getStyleOption(const Q3ListView *lv, const Q3ListViewItem *item,
+ bool hierarchy = false)
+{
+ QStyleOptionQ3ListView opt;
+ opt.init(lv);
+ opt.subControls = QStyle::SC_None;
+ opt.activeSubControls = QStyle::SC_None;
+ QWidget *vp = lv->viewport();
+ opt.viewportPalette = vp->palette();
+ opt.viewportBGRole = vp->backgroundRole();
+ opt.itemMargin = lv->itemMargin();
+ opt.sortColumn = 0;
+ opt.treeStepSize = lv->treeStepSize();
+ opt.rootIsDecorated = lv->rootIsDecorated();
+ bool firstItem = true;
+ int y = item ? item->itemPos() : 0;
+ while (item) {
+ QStyleOptionQ3ListViewItem lvi;
+ lvi.height = item->height();
+ lvi.totalHeight = item->totalHeight();
+ lvi.itemY = y;
+ lvi.childCount = item->childCount();
+ lvi.features = QStyleOptionQ3ListViewItem::None;
+ lvi.state = QStyle::State_None;
+ if (item->isEnabled())
+ lvi.state |= QStyle::State_Enabled;
+ if (item->isOpen())
+ lvi.state |= QStyle::State_Open;
+ if (item->isExpandable())
+ lvi.features |= QStyleOptionQ3ListViewItem::Expandable;
+ if (item->multiLinesEnabled())
+ lvi.features |= QStyleOptionQ3ListViewItem::MultiLine;
+ if (item->isVisible())
+ lvi.features |= QStyleOptionQ3ListViewItem::Visible;
+ if (item->parent() && item->parent()->rtti() == 1
+ && static_cast<Q3CheckListItem *>(item->parent())->type() == Q3CheckListItem::Controller)
+ lvi.features |= QStyleOptionQ3ListViewItem::ParentControl;
+ opt.items.append(lvi);
+ // we only care about the children when we are painting the branches
+ // this is only enabled by Q3ListViewItem::paintBranches
+ if (hierarchy) {
+ if (!firstItem) {
+ item = item->nextSibling();
+ } else {
+ firstItem = false;
+ item = item->firstChild();
+ }
+ y += lvi.height;
+ } else {
+ break;
+ }
+ }
+ return opt;
+}
+
+/*!
+ \fn void Q3ListViewItem::paintCell(QPainter *painter, const QColorGroup & cg, int column, int width, int align)
+
+ This virtual function paints the contents of one column of an item
+ and aligns it as described by \a align.
+
+ The \a painter is a Q3Painter open on the relevant paint
+ device. It is translated so (0, 0) is the top-left pixel in the
+ cell and \a width - 1, height() - 1 is the bottom-right pixel \e
+ in the cell. The other properties of the \a painter (pen, brush, etc) are
+ undefined. \a cg is the color group to use. \a column is the
+ logical column number within the item that is to be painted; 0 is
+ the column which may contain a tree.
+
+ This function may use Q3ListView::itemMargin() for readability
+ spacing on the left and right sides of data such as text, and
+ should honor \l isSelected() and
+ Q3ListView::allColumnsShowFocus().
+
+ If you reimplement this function, you should also reimplement \l
+ width().
+
+ The rectangle to be painted is in an undefined state when this
+ function is called, so you \e must draw on all the pixels. The
+ \a painter has the right font on entry.
+
+ \sa paintBranches(), Q3ListView::drawContentsOffset()
+*/
+void Q3ListViewItem::paintCell(QPainter * p, const QColorGroup & cg,
+ int column, int width, int align)
+{
+ // Change width() if you change this.
+
+ QPalette pal = cg;
+ if (!p)
+ return;
+
+ Q3ListView *lv = listView();
+ if (!lv)
+ return;
+ QFontMetrics fm(p->fontMetrics());
+
+ // had, but we _need_ the column info for the ellipsis thingy!!!
+ if (!columns) {
+ for (int i = 0; i < lv->d->column.size(); ++i) {
+ setText(i, text(i));
+ }
+ }
+
+ QString t = text(column);
+
+ if (columns) {
+ Q3ListViewPrivate::ItemColumnInfo *ci = 0;
+ // try until we have a column info....
+ while (!ci) {
+ ci = (Q3ListViewPrivate::ItemColumnInfo*)columns;
+ for (int i = 0; ci && (i < column); ++i)
+ ci = ci->next;
+
+ if (!ci) {
+ setText(column, t);
+ ci = 0;
+ }
+ }
+
+ // if the column width changed and this item was not painted since this change
+ if (ci && (ci->width != width || ci->text != t || ci->dirty)) {
+ ci->text = t;
+ ci->dirty = false;
+ ci->width = width;
+ ci->truncated = false;
+ // if we have to do the ellipsis thingy calc the truncated text
+ int pw = lv->itemMargin()*2 - lv->d->minLeftBearing - lv->d->minRightBearing;
+ pw += pixmap(column) ? pixmap(column)->width() + lv->itemMargin() : 0;
+ if (!mlenabled && fm.width(t) + pw > width) {
+ // take care of arabic shaping in width calculation (lars)
+ ci->truncated = true;
+ ci->tmpText = qEllipsisText(t, fm, width - pw, align);
+ } else if (mlenabled && fm.width(t) + pw > width) {
+ QStringList list = t.split(QLatin1Char('\n'));
+ for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
+ QString z = *it;
+ if (fm.width(z) + pw > width) {
+ ci->truncated = true;
+ *it = qEllipsisText(z, fm, width - pw, align);
+ }
+ }
+
+ if (ci->truncated)
+ ci->tmpText = list.join(QString(QLatin1Char('\n')));
+ }
+ }
+
+ // if we have to draw the ellipsis thingy, use the truncated text
+ if (ci && ci->truncated)
+ t = ci->tmpText;
+ }
+
+ int marg = lv->itemMargin();
+ int r = marg;
+ const QPixmap * icon = pixmap(column);
+
+ const QPalette::ColorRole crole = lv->viewport()->backgroundRole();
+ if (pal.brush(crole) != lv->palette().brush(pal.currentColorGroup(), crole))
+ p->fillRect(0, 0, width, height(), pal.brush(crole));
+ else
+ lv->paintEmptyArea(p, QRect(0, 0, width, height()));
+
+ // (lars) what does this do???
+#if 0 // RS: ####
+ if (align != Qt::AlignLeft)
+ marg -= lv->d->minRightBearing;
+#endif
+ if (isSelected() &&
+ (column == 0 || lv->allColumnsShowFocus())) {
+ p->fillRect(r - marg, 0, qMax(0, width - r + marg), height(),
+ pal.brush(QPalette::Highlight));
+ if (enabled || !lv)
+ p->setPen(pal.highlightedText().color());
+ else if (!enabled && lv)
+ p->setPen(lv->palette().color(QPalette::Disabled, QPalette::HighlightedText));
+ } else {
+ if (enabled || !lv)
+ p->setPen(pal.text().color());
+ else if (!enabled && lv)
+ p->setPen(lv->palette().color(QPalette::Disabled, QPalette::Text));
+ }
+
+
+#if 0
+ bool reverse = QApplication::reverseLayout();
+#else
+ bool reverse = false;
+#endif
+ int iconWidth = 0;
+
+ if (icon) {
+ iconWidth = icon->width() + lv->itemMargin();
+ int xo = r;
+ // we default to Qt::AlignVCenter.
+ int yo = (height() - icon->height()) / 2;
+
+ // I guess we may as well always respect vertical alignment.
+ if (align & Qt::AlignBottom)
+ yo = height() - icon->height();
+ else if (align & Qt::AlignTop)
+ yo = 0;
+
+ // respect horizontal alignment when there is no text for an item.
+ if (text(column).isEmpty()) {
+ if (align & Qt::AlignRight)
+ xo = width - 2 * marg - iconWidth;
+ else if (align & Qt::AlignHCenter)
+ xo = (width - iconWidth) / 2;
+ }
+ if (reverse)
+ xo = width - 2 * marg - iconWidth;
+ p->drawPixmap(xo, yo, *icon);
+ }
+
+ if (!t.isEmpty()) {
+ if (!mlenabled) {
+ if (!(align & Qt::AlignTop || align & Qt::AlignBottom))
+ align |= Qt::AlignVCenter;
+ } else {
+ if (!(align & Qt::AlignVCenter || align & Qt::AlignBottom))
+ align |= Qt::AlignTop;
+ }
+ if (!reverse)
+ r += iconWidth;
+
+ if (!mlenabled) {
+ p->drawText(r, 0, width-marg-r, height(), align, t);
+ } else {
+ p->drawText(r, marg, width-marg-r, height(), align, t);
+ }
+ }
+
+ if (mlenabled && column == 0 && isOpen() && childCount()) {
+ int textheight = fm.size(align, t).height() + 2 * lv->itemMargin();
+ textheight = qMax(textheight, QApplication::globalStrut().height());
+ if (textheight % 2 > 0)
+ textheight++;
+ if (textheight < height()) {
+ int w = lv->treeStepSize() / 2;
+ QStyleOptionQ3ListView opt = getStyleOption(lv, this);
+ opt.rect.setRect(0, textheight, w + 1, height() - textheight + 1);
+ opt.palette = pal;
+ opt.subControls = QStyle::SC_Q3ListViewExpand;
+ opt.activeSubControls = QStyle::SC_All;
+ lv->style()->drawComplexControl(QStyle::CC_Q3ListView, &opt, p, lv);
+ }
+ }
+}
+
+/*!
+ Returns the number of pixels of width required to draw column \a c
+ of list view \a lv, using the metrics \a fm without cropping. The
+ list view containing this item may use this information depending
+ on the Q3ListView::WidthMode settings for the column.
+
+ The default implementation returns the width of the bounding
+ rectangle of the text of column \a c.
+
+ \sa listView() widthChanged() Q3ListView::setColumnWidthMode()
+ Q3ListView::itemMargin()
+*/
+int Q3ListViewItem::width(const QFontMetrics& fm,
+ const Q3ListView* lv, int c) const
+{
+ int w;
+ if (mlenabled)
+ w = fm.size(Qt::AlignVCenter, text(c)).width() + lv->itemMargin() * 2
+ - lv->d->minLeftBearing - lv->d->minRightBearing;
+ else
+ w = fm.width(text(c)) + lv->itemMargin() * 2
+ - lv->d->minLeftBearing - lv->d->minRightBearing;
+ const QPixmap * pm = pixmap(c);
+ if (pm)
+ w += pm->width() + lv->itemMargin(); // ### correct margin stuff?
+ return qMax(w, QApplication::globalStrut().width());
+}
+
+
+/*!
+ Paints a focus indicator on the rectangle \a r using painter \a p
+ and colors \a cg.
+
+ \a p is already clipped.
+
+ \sa paintCell() paintBranches() Q3ListView::setAllColumnsShowFocus()
+*/
+
+void Q3ListViewItem::paintFocus(QPainter *p, const QColorGroup &cg, const QRect &r)
+{
+ QPalette pal = cg;
+ Q3ListView *lv = listView();
+ if (lv) {
+ QStyleOptionFocusRect opt;
+ opt.init(lv);
+ opt.rect = r;
+ opt.palette = pal;
+ opt.state |= QStyle::State_KeyboardFocusChange;
+ if (isSelected()) {
+ opt.state |= QStyle::State_FocusAtBorder;
+ opt.backgroundColor = pal.highlight().color();
+ } else {
+ opt.state |= QStyle::State_None;
+ opt.backgroundColor = pal.base().color();
+ }
+ lv->style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p, lv);
+ }
+}
+
+
+/*!
+ Paints a set of branches from this item to (some of) its children.
+
+ Painter \a p is set up with clipping and translation so that you
+ can only draw in the rectangle that needs redrawing; \a cg is the
+ color group to use; the update rectangle is at (0, 0) and has size
+ width \a w by height \a h. The top of the rectangle you own is at
+ \a y (which is never greater than 0 but can be outside the window
+ system's allowed coordinate range).
+
+ The update rectangle is in an undefined state when this function
+ is called; this function must draw on \e all of the pixels.
+
+ \sa paintCell(), Q3ListView::drawContentsOffset()
+*/
+
+void Q3ListViewItem::paintBranches(QPainter * p, const QColorGroup & cg,
+ int w, int y, int h)
+{
+ Q3ListView *lv = listView();
+ if (lv)
+ lv->paintEmptyArea(p, QRect(0, 0, w, h));
+ if (!visible || !lv)
+ return;
+ QStyleOptionQ3ListView opt = getStyleOption(lv, this, true);
+ opt.rect.setRect(0, y, w, h);
+ opt.palette = cg;
+ opt.subControls = QStyle::SC_Q3ListViewBranch | QStyle::SC_Q3ListViewExpand;
+ opt.activeSubControls = QStyle::SC_None;
+ lv->style()->drawComplexControl(QStyle::CC_Q3ListView, &opt, p, lv);
+}
+
+
+Q3ListViewPrivate::Root::Root(Q3ListView * parent)
+ : Q3ListViewItem(parent)
+{
+ lv = parent;
+ setHeight(0);
+ setOpen(true);
+}
+
+
+void Q3ListViewPrivate::Root::setHeight(int)
+{
+ Q3ListViewItem::setHeight(0);
+}
+
+
+void Q3ListViewPrivate::Root::invalidateHeight()
+{
+ Q3ListViewItem::invalidateHeight();
+ lv->triggerUpdate();
+}
+
+
+Q3ListView * Q3ListViewPrivate::Root::theListView() const
+{
+ return lv;
+}
+
+
+void Q3ListViewPrivate::Root::setup()
+{
+ // explicitly nothing
+}
+
+
+
+/*!
+\internal
+If called after a mouse click, tells the list view to ignore a
+following double click. This state is reset after the next mouse click.
+*/
+
+void Q3ListViewItem::ignoreDoubleClick()
+{
+ Q3ListView *lv = listView();
+ if (lv)
+ lv->d->ignoreDoubleClick = true;
+}
+
+
+
+/*!
+ \fn void Q3ListView::onItem(Q3ListViewItem *i)
+
+ This signal is emitted when the user moves the mouse cursor onto
+ item \a i, similar to the QWidget::enterEvent() function.
+*/
+
+// ### bug here too? see qiconview.cppp onItem/onViewport
+
+/*!
+ \fn void Q3ListView::onViewport()
+
+ This signal is emitted when the user moves the mouse cursor from
+ an item to an empty part of the list view.
+*/
+
+/*!
+ \enum Q3ListView::SelectionMode
+
+ This enumerated type is used by Q3ListView to indicate how it
+ reacts to selection by the user.
+
+ \value Single When the user selects an item, any already-selected
+ item becomes unselected, and the user cannot unselect the selected
+ item.
+
+ \value Multi When the user selects an item in the usual way, the
+ selection status of that item is toggled and the other items are
+ left alone.
+
+ \value Extended When the user selects an item in the usual way,
+ 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.
+ And 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
+ over them.
+
+ \value NoSelection Items cannot be selected.
+
+ In other words, \c Single is a real single-selection list view, \c
+ Multi a real multi-selection list view, \c Extended is a list view
+ where users can select multiple items but usually want to select
+ either just one or a range of contiguous items, and \c NoSelection
+ is a list view where the user can look but not touch.
+*/
+
+/*!
+ \enum Q3ListView::ResizeMode
+
+ This enum describes how the list view's header adjusts to resize
+ events which affect the width of the list view.
+
+ \value NoColumn The columns do not get resized in resize events.
+
+ \value AllColumns All columns are resized equally to fit the width
+ of the list view.
+
+ \value LastColumn The last column is resized to fit the width of
+ the list view.
+*/
+
+/*!
+ \enum Q3ListView::RenameAction
+
+ This enum describes whether a rename operation is accepted if the
+ rename editor loses focus without the user pressing Enter.
+
+ \value Accept Rename if Enter is pressed or focus is lost.
+
+ \value Reject Discard the rename operation if focus is lost (and
+ Enter has not been pressed).
+*/
+
+/*!
+ \class Q3ListView
+ \brief The Q3ListView class implements a list/tree view.
+
+ \compat
+
+ It can display and control a hierarchy of multi-column items, and
+ provides the ability to add new items at any time. The user may
+ select one or many items (depending on the \c SelectionMode) and
+ sort the list in increasing or decreasing order by any column.
+
+ The simplest pattern of use is to create a Q3ListView, add some
+ column headers using addColumn() and create one or more
+ Q3ListViewItem or Q3CheckListItem objects with the Q3ListView as
+ parent.
+
+ Further nodes can be added to the list view object (the root of the
+ tree) or as child nodes to Q3ListViewItems.
+
+ The main setup functions are:
+ \table
+ \header \i Function \i Action
+ \row \i \l addColumn()
+ \i Adds a column with a text label and perhaps width. Columns
+ are counted from the left starting with column 0.
+ \row \i \l setColumnWidthMode()
+ \i Sets the column to be resized automatically or not.
+ \row \i \l setAllColumnsShowFocus()
+ \i Sets whether items should show keyboard focus using all
+ columns or just column 0. The default is to show focus
+ just using column 0.
+ \row \i \l setRootIsDecorated()
+ \i Sets whether root items can be opened and closed by the
+ user and have open/close decoration to their left. The
+ default is false.
+ \row \i \l setTreeStepSize()
+ \i Sets how many pixels an item's children are indented
+ relative to their parent. The default is 20. This is
+ mostly a matter of taste.
+ \row \i \l setSorting()
+ \i Sets whether the items should be sorted, whether it should
+ be in ascending or descending order, and by what column
+ they should be sorted. By default the list view is sorted
+ by the first column; to switch this off call setSorting(-1).
+ \endtable
+
+ There are several functions for mapping between items and
+ coordinates. itemAt() returns the item at a position on-screen,
+ itemRect() returns the rectangle an item occupies on the screen,
+ and itemPos() returns the position of any item (whether it is
+ on-screen or not). firstChild() returns the list view's first item
+ (not necessarily visible on-screen).
+
+ You can iterate over visible items using
+ Q3ListViewItem::itemBelow(); over a list view's top-level items
+ using Q3ListViewItem::firstChild() and
+ Q3ListViewItem::nextSibling(); or every item using a
+ Q3ListViewItemIterator. See
+ the Q3ListViewItem documentation for examples of traversal.
+
+ An item can be moved amongst its siblings using
+ Q3ListViewItem::moveItem(). To move an item in the hierarchy use
+ takeItem() and insertItem(). Item's (and all their child items)
+ are deleted with \c delete; to delete all the list view's items
+ use clear().
+
+ There are a variety of selection modes described in the
+ Q3ListView::SelectionMode documentation. The default is \c Single
+ selection, which you can change using setSelectionMode().
+
+ Because Q3ListView offers multiple selection it must display
+ keyboard focus and selection state separately. Therefore there are
+ functions both to set the selection state of an item
+ (setSelected()) and to set which item displays keyboard focus
+ (setCurrentItem()).
+
+ Q3ListView emits two groups of signals; one group signals changes
+ in selection/focus state and one indicates selection. The first
+ group consists of selectionChanged() (applicable to all list
+ views), selectionChanged(Q3ListViewItem*) (applicable only to a
+ \c Single selection list view), and currentChanged(Q3ListViewItem*).
+ The second group consists of doubleClicked(Q3ListViewItem*),
+ returnPressed(Q3ListViewItem*),
+ rightButtonClicked(Q3ListViewItem*, const QPoint&, int), etc.
+
+ Note that changing the state of the list view in a slot connected
+ to a list view signal may cause unexpected side effects. If you
+ need to change the list view's state in response to a signal, use
+ a \link QTimer::singleShot() single shot timer\endlink with a
+ time out of 0, and connect this timer to a slot that modifies the
+ list view's state.
+
+ In Motif style, Q3ListView deviates fairly strongly from the look
+ and feel of the Motif hierarchical tree view. This is done mostly
+ to provide a usable keyboard interface and to make the list view
+ look better with a white background.
+
+ If selectionMode() is \c Single (the default) the user can select
+ one item at a time, e.g. by clicking an item with the mouse, see
+ \l Q3ListView::SelectionMode for details.
+
+ The list view can be navigated either using the mouse or the
+ keyboard. Clicking a \bold{-} icon closes an item (hides its
+ children) and clicking a \bold{+} icon opens an item (shows its
+ children). The keyboard controls are these:
+ \table
+ \header \i Keypress \i Action
+ \row \i Home
+ \i Make the first item current and visible.
+ \row \i End
+ \i Make the last item current and visible.
+ \row \i Page Up
+ \i Make the item above the top visible item current and visible.
+ \row \i Page Down
+ \i Make the item below the bottom visible item current and visible.
+ \row \i Up Arrow
+ \i Make the item above the current item current and visible.
+ \row \i Down Arrow
+ \i Make the item below the current item current and visible.
+ \row \i Left Arrow
+ \i If the current item is closed (\bold{+} icon) or has no
+ children, make its parent item current and visible. If the
+ current item is open (\bold{-} icon) close it, i.e. hide its
+ children. Exception: if the current item is the first item
+ and is closed and the horizontal scroll bar is offset to
+ the right the list view will be scrolled left.
+ \row \i Right Arrow
+ \i If the current item is closed (\bold{+} icon) and has
+ children, the item is opened. If the current item is
+ opened (\bold{-} icon) and has children the item's first
+ child is made current and visible. If the current item has
+ no children the list view is scrolled right.
+ \endtable
+
+ If the user starts typing letters with the focus in the list view
+ an incremental search will occur. For example if the user types
+ 'd' the current item will change to the first item that begins
+ with the letter 'd'; if they then type 'a', the current item will
+ change to the first item that begins with 'da', and so on. If no
+ item begins with the letters they type the current item doesn't
+ change.
+
+ Note that the list view's size hint is calculated taking into
+ account the height \e and width to produce a nice aspect ratio.
+ This may mean that you need to reimplement sizeHint() in some
+ cases.
+
+ \warning The list view assumes ownership of all list view items
+ and will delete them when it does not need them any more.
+
+ \sa Q3ListViewItem Q3CheckListItem
+*/
+
+/*!
+ \fn void Q3ListView::itemRenamed(Q3ListViewItem * item, int col)
+
+ \overload
+
+ This signal is emitted when \a item has been renamed, e.g. by
+ in-place renaming, in column \a col.
+
+ \sa Q3ListViewItem::setRenameEnabled()
+*/
+
+/*!
+ \fn void Q3ListView::itemRenamed(Q3ListViewItem * item, int col, const QString &text)
+
+ This signal is emitted when \a item has been renamed to \a text,
+ e.g. by in in-place renaming, in column \a col.
+
+ \sa Q3ListViewItem::setRenameEnabled()
+*/
+
+/*!
+ Constructs a new empty list view called \a name with parent \a
+ parent and widget attributes \a f.
+
+ This constructor sets the \c WA_StaticContent and the \c
+ Qt::WA_NoBackground attributes to boost performance when drawing
+ Q3ListViewItems. This may be unsuitable for custom Q3ListViewItem
+ classes, in which case Qt::WA_StaticContents and Qt::WA_NoBackground
+ should be cleared on the viewport() after construction.
+
+ \sa QWidget::setAttribute()
+*/
+Q3ListView::Q3ListView(QWidget * parent, const char *name, Qt::WindowFlags f)
+ : Q3ScrollView(parent, name, f | Qt::WStaticContents | Qt::WNoAutoErase)
+{
+ init();
+}
+
+void Q3ListView::init()
+{
+ d = new Q3ListViewPrivate;
+ d->vci = 0;
+ d->timer = new QTimer(this);
+ d->levelWidth = 20;
+ d->r = 0;
+ d->rootIsExpandable = 0;
+ d->h = new Q3Header(this, "list view header");
+ d->h->installEventFilter(this);
+ d->focusItem = 0;
+ d->oldFocusItem = 0;
+ d->dirtyItemTimer = new QTimer(this);
+ d->visibleTimer = new QTimer(this);
+ d->renameTimer = new QTimer(this);
+ d->autoopenTimer = new QTimer(this);
+ d->margin = 1;
+ d->selectionMode = Q3ListView::Single;
+ d->sortcolumn = 0;
+ d->ascending = true;
+ d->allColumnsShowFocus = false;
+ d->fontMetricsHeight = fontMetrics().height();
+ d->h->setTracking(true);
+ d->buttonDown = false;
+ d->ignoreDoubleClick = false;
+ d->scrollTimer = 0;
+ d->sortIndicator = false;
+ d->clearing = false;
+ d->minLeftBearing = fontMetrics().minLeftBearing();
+ d->minRightBearing = fontMetrics().minRightBearing();
+ d->ellipsisWidth = fontMetrics().width(QLatin1String("...")) * 2;
+ d->highlighted = 0;
+ d->pressedItem = 0;
+ d->selectAnchor = 0;
+ d->select = true;
+ d->startDragItem = 0;
+ d->toolTips = true;
+ d->updateHeader = false;
+ d->fullRepaintOnComlumnChange = false;
+ d->resizeMode = NoColumn;
+ d->defRenameAction = Reject;
+ d->pressedEmptyArea = false;
+ d->startEdit = true;
+ d->ignoreEditAfterFocus = false;
+ d->inMenuMode = false;
+ d->pressedSelected = false;
+
+ setMouseTracking(true);
+ viewport()->setMouseTracking(true);
+
+ connect(d->timer, SIGNAL(timeout()),
+ this, SLOT(updateContents()));
+ connect(d->dirtyItemTimer, SIGNAL(timeout()),
+ this, SLOT(updateDirtyItems()));
+ connect(d->visibleTimer, SIGNAL(timeout()),
+ this, SLOT(makeVisible()));
+ connect(d->renameTimer, SIGNAL(timeout()),
+ this, SLOT(startRename()));
+ connect(d->autoopenTimer, SIGNAL(timeout()),
+ this, SLOT(openFocusItem()));
+
+ connect(d->h, SIGNAL(sizeChange(int,int,int)),
+ this, SLOT(handleSizeChange(int,int,int)));
+ connect(d->h, SIGNAL(indexChange(int,int,int)),
+ this, SLOT(handleIndexChange()));
+ connect(d->h, SIGNAL(sectionClicked(int)),
+ this, SLOT(changeSortColumn(int)));
+ connect(d->h, SIGNAL(sectionHandleDoubleClicked(int)),
+ this, SLOT(adjustColumn(int)));
+ connect(horizontalScrollBar(), SIGNAL(sliderMoved(int)),
+ d->h, SLOT(setOffset(int)));
+ connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
+ d->h, SLOT(setOffset(int)));
+
+ // will access d->r
+ Q3ListViewPrivate::Root * r = new Q3ListViewPrivate::Root(this);
+ r->is_root = true;
+ d->r = r;
+ d->r->setSelectable(false);
+
+ viewport()->setFocusProxy(this);
+ viewport()->setFocusPolicy(Qt::WheelFocus);
+ setFocusPolicy(Qt::WheelFocus);
+ viewport()->setBackgroundRole(QPalette::Base);
+ setAttribute(Qt::WA_MacShowFocusRect);
+}
+
+/*!
+ \property Q3ListView::showSortIndicator
+ \brief whether the list view header should display a sort indicator.
+
+ If this property is true, an arrow is drawn in the header of the
+ list view to indicate the sort order of the list view contents.
+ The arrow will be drawn in the correct column and will point up or
+ down, depending on the current sort direction. The default is
+ false (don't show an indicator).
+
+ \sa Q3Header::setSortIndicator()
+*/
+
+void Q3ListView::setShowSortIndicator(bool show)
+{
+ if (show == d->sortIndicator)
+ return;
+
+ d->sortIndicator = show;
+ if (d->sortcolumn != Unsorted && d->sortIndicator)
+ d->h->setSortIndicator(d->sortcolumn, d->ascending);
+ else
+ d->h->setSortIndicator(-1);
+}
+
+bool Q3ListView::showSortIndicator() const
+{
+ return d->sortIndicator;
+}
+
+/*!
+ \property Q3ListView::showToolTips
+ \brief whether this list view should show tooltips for truncated column texts
+
+ The default is true.
+*/
+
+void Q3ListView::setShowToolTips(bool b)
+{
+ d->toolTips = b;
+}
+
+bool Q3ListView::showToolTips() const
+{
+ return d->toolTips;
+}
+
+/*!
+ \property Q3ListView::resizeMode
+ \brief whether all, none or the only the last column should be resized
+
+ Specifies whether all, none or only the last column should be
+ resized to fit the full width of the list view. The values for this
+ property can be one of: \c NoColumn (the default), \c AllColumns
+ or \c LastColumn.
+
+ \warning Setting the resize mode should be done after all necessary
+ columns have been added to the list view, otherwise the behavior is
+ undefined.
+
+ \sa Q3Header, header()
+*/
+
+void Q3ListView::setResizeMode(ResizeMode m)
+{
+ d->resizeMode = m;
+ if (m == NoColumn)
+ header()->setStretchEnabled(false);
+ else if (m == AllColumns)
+ header()->setStretchEnabled(true);
+ else
+ header()->setStretchEnabled(true, header()->count() - 1);
+}
+
+Q3ListView::ResizeMode Q3ListView::resizeMode() const
+{
+ return d->resizeMode;
+}
+
+/*!
+ Destroys the list view, deleting all its items, and frees up all
+ allocated resources.
+*/
+
+Q3ListView::~Q3ListView()
+{
+ for (int j = 0; j < d->iterators.size(); ++j) {
+ Q3ListViewItemIterator *i = d->iterators.at(j);
+ i->listView = 0;
+ }
+
+ d->focusItem = 0;
+ delete d->r;
+ d->r = 0;
+ delete d->vci;
+ d->vci = 0;
+#if 0
+ delete d->toolTip;
+ d->toolTip = 0;
+#endif
+ delete d;
+ d = 0;
+}
+
+
+/*!
+ Calls Q3ListViewItem::paintCell() and
+ Q3ListViewItem::paintBranches() as necessary for all list view
+ items that require repainting in the \a cw pixels wide and \a ch
+ pixels high bounding rectangle starting at position \a cx, \a cy
+ with offset \a ox, \a oy. Uses the painter \a p.
+*/
+
+void Q3ListView::drawContentsOffset(QPainter * p, int ox, int oy,
+ int cx, int cy, int cw, int ch)
+{
+ if (columns() == 0) {
+ paintEmptyArea(p, QRect(cx, cy, cw, ch));
+ return;
+ }
+
+ if (d->drawables.isEmpty() ||
+ d->topPixel > cy ||
+ d->bottomPixel < cy + ch - 1 ||
+ d->r->maybeTotalHeight < 0)
+ buildDrawableList();
+
+ if (!d->dirtyItems.isEmpty()) {
+ QRect br(cx - ox, cy - oy, cw, ch);
+ for (int i = 0; i < d->dirtyItems.size(); ++i) {
+ const Q3ListViewItem * item = d->dirtyItems.at(i);
+ QRect ir = itemRect(item).intersected(viewport()->visibleRect());
+ if (ir.isEmpty() || br.contains(ir))
+ // we're painting this one, or it needs no painting: forget it
+ d->dirtyItems.removeAt(i);
+ }
+ if (d->dirtyItems.count()) {
+ // there are still items left that need repainting
+ d->dirtyItemTimer->start(0, true);
+ } else {
+ // we're painting all items that need to be painted
+ d->dirtyItems.clear();
+ d->dirtyItemTimer->stop();
+ }
+ }
+
+ p->setFont(font());
+
+ QRect r;
+ int fx = -1, x, fc = 0, lc = 0;
+ int tx = -1;
+
+ for (int i = 0; i < d->drawables.size(); ++i) {
+ Q3ListViewPrivate::DrawableItem current = d->drawables.at(i);
+ if (!current.i->isVisible())
+ continue;
+ int ih = current.i->height();
+ int ith = current.i->totalHeight();
+ int c;
+ int cs;
+
+ // need to paint current?
+ if (ih > 0 && current.y < cy+ch && current.y+ih > cy) {
+ if (fx < 0) {
+ // find first interesting column, once
+ x = 0;
+ c = 0;
+ cs = d->h->cellSize(0);
+ while (x + cs <= cx && c < d->h->count()) {
+ x += cs;
+ c++;
+ if (c < d->h->count())
+ cs = d->h->cellSize(c);
+ }
+ fx = x;
+ fc = c;
+ while(x < cx + cw && c < d->h->count()) {
+ x += cs;
+ c++;
+ if (c < d->h->count())
+ cs = d->h->cellSize(c);
+ }
+ lc = c;
+ }
+
+ x = fx;
+ c = fc;
+ // draw to last interesting column
+
+ bool drawActiveSelection = hasFocus() || d->inMenuMode ||
+ !style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this)
+ || (currentItem() && currentItem()->renameBox
+ && currentItem()->renameBox->hasFocus());
+ QPalette pal = palette();
+ if(!drawActiveSelection)
+ pal.setCurrentColorGroup(QPalette::Inactive);
+
+ while (c < lc) {
+ int i = d->h->mapToLogical(c);
+ cs = d->h->cellSize(c);
+ r.setRect(x - ox, current.y - oy, cs, ih);
+ if (i == 0 && current.i->parentItem)
+ r.setLeft(r.left() + current.l * treeStepSize());
+
+ p->save();
+ // No need to paint if the cell isn't technically visible
+ if (!(r.width() == 0 || r.height() == 0)) {
+ p->translate(r.left(), r.top());
+ int ac = d->h->mapToLogical(c);
+ // map to Left currently. This should change once we
+ // can really reverse the listview.
+ int align = columnAlignment(ac);
+ if (align == Qt::AlignAuto) align = Qt::AlignLeft;
+ current.i->paintCell(p, pal, ac, r.width(), align);
+ }
+ p->restore();
+ x += cs;
+ c++;
+ }
+
+ if (current.i == d->focusItem && hasFocus() &&
+ !d->allColumnsShowFocus) {
+ p->save();
+ int cell = d->h->mapToActual(0);
+ QRect r(d->h->cellPos(cell) - ox, current.y - oy, d->h->cellSize(cell), ih);
+ if (current.i->parentItem)
+ r.setLeft(r.left() + current.l * treeStepSize());
+ if (r.left() < r.right())
+ current.i->paintFocus(p, palette(), r);
+ p->restore();
+ }
+ }
+
+ const int cell = d->h->mapToActual(0);
+
+ // does current need focus indication?
+ if (current.i == d->focusItem && hasFocus() &&
+ d->allColumnsShowFocus) {
+ p->save();
+ int x = -contentsX();
+ int w = header()->cellPos(header()->count() - 1) +
+ header()->cellSize(header()->count() - 1);
+
+ r.setRect(x, current.y - oy, w, ih);
+ if (d->h->mapToActual(0) == 0 || (current.l == 0 && !rootIsDecorated())) {
+ int offsetx = qMin(current.l * treeStepSize(), d->h->cellSize(cell));
+ r.setLeft(r.left() + offsetx);
+ current.i->paintFocus(p, palette(), r);
+ } else {
+ int xdepth = qMin(treeStepSize() * (current.i->depth() + (rootIsDecorated() ? 1 : 0))
+ + itemMargin(), d->h->cellSize(cell));
+ xdepth += d->h->cellPos(cell);
+ QRect r1(r);
+ r1.setRight(d->h->cellPos(cell) - 1);
+ QRect r2(r);
+ r2.setLeft(xdepth - 1);
+ current.i->paintFocus(p, palette(), r1);
+ current.i->paintFocus(p, palette(), r2);
+ }
+ p->restore();
+ }
+
+ if (tx < 0)
+ tx = d->h->cellPos(cell);
+
+ // do any children of current need to be painted?
+ if (ih != ith &&
+ (current.i != d->r || d->rootIsExpandable) &&
+ current.y + ith > cy &&
+ current.y + ih < cy + ch &&
+ tx + current.l * treeStepSize() < cx + cw &&
+ tx + (current.l+1) * treeStepSize() > cx) {
+ // compute the clip rectangle the safe way
+
+ int rtop = current.y + ih;
+ int rbottom = current.y + ith;
+ int rleft = tx + current.l*treeStepSize();
+ int rright = rleft + treeStepSize();
+
+ int crtop = qMax(rtop, cy);
+ int crbottom = qMin(rbottom, cy+ch);
+ int crleft = qMax(rleft, cx);
+ int crright = qMin(rright, cx+cw);
+
+ r.setRect(crleft-ox, crtop-oy,
+ crright-crleft, crbottom-crtop);
+
+ if (r.isValid()) {
+ p->save();
+ p->setClipRect(QRect(d->h->cellPos(cell), 0, d->h->cellSize(cell), height()));
+ p->translate(rleft-ox, crtop-oy);
+
+ current.i->paintBranches(p, palette(), treeStepSize(),
+ rtop - crtop, r.height());
+ p->restore();
+ }
+ }
+ }
+
+ if (d->r->totalHeight() < cy + ch)
+ paintEmptyArea(p, QRect(cx - ox, d->r->totalHeight() - oy,
+ cw, cy + ch - d->r->totalHeight()));
+
+ int c = d->h->count()-1;
+ if (c >= 0 &&
+ d->h->cellPos(c) + d->h->cellSize(c) < cx + cw) {
+ c = d->h->cellPos(c) + d->h->cellSize(c);
+ paintEmptyArea(p, QRect(c - ox, cy - oy, cx + cw - c, ch));
+ }
+}
+
+
+
+/*!
+ Paints \a rect so that it looks like empty background using
+ painter \a p. \a rect is in widget coordinates, ready to be fed to
+ \a p.
+
+ The default function fills \a rect with the
+ viewport()->backgroundBrush().
+*/
+
+void Q3ListView::paintEmptyArea(QPainter * p, const QRect & rect)
+{
+ QStyleOptionQ3ListView opt = getStyleOption(this, 0);
+ opt.rect = rect;
+ opt.sortColumn = d->sortcolumn;
+ opt.subControls = QStyle::SC_Q3ListView;
+ style()->drawComplexControl(QStyle::CC_Q3ListView, &opt, p, this);
+}
+
+
+/*
+ Rebuilds the list of drawable Q3ListViewItems. This function is
+ const so that const functions can call it without requiring
+ d->drawables to be mutable.
+*/
+
+void Q3ListView::buildDrawableList() const
+{
+ d->r->enforceSortOrder();
+
+ QStack<Q3ListViewPrivate::DrawableItem> stack;
+ Q3ListViewPrivate::DrawableItem di(((int)d->rootIsExpandable)-1, 0, d->r);
+ stack.push(di);
+
+ Q3ListView *that = const_cast<Q3ListView *>(this);
+
+ // could mess with cy and ch in order to speed up vertical
+ // scrolling
+ int cy = contentsY();
+ int ch = that->visibleHeight();
+ d->topPixel = cy + ch; // one below bottom
+ d->bottomPixel = cy - 1; // one above top
+
+ that->d->drawables.clear();
+
+ while (!stack.isEmpty()) {
+ Q3ListViewPrivate::DrawableItem cur = stack.pop();
+
+ int ih = cur.i->height();
+ int ith = cur.i->totalHeight();
+
+ // is this item, or its branch symbol, inside the viewport?
+ if (cur.y + ith >= cy && cur.y < cy + ch) {
+ that->d->drawables.append(cur);
+ // perhaps adjust topPixel up to this item? may be adjusted
+ // down again if any children are not to be painted
+ if (cur.y < d->topPixel)
+ d->topPixel = cur.y;
+ // bottompixel is easy: the bottom item drawn contains it
+ d->bottomPixel = cur.y + ih - 1;
+ }
+
+ // push younger sibling of cur on the stack?
+ if (cur.y + ith < cy+ch && cur.i->siblingItem)
+ stack.push(Q3ListViewPrivate::DrawableItem(cur.l, cur.y + ith, cur.i->siblingItem));
+
+ // do any children of cur need to be painted?
+ if (cur.i->isOpen() && cur.i->childCount() &&
+ cur.y + ith > cy &&
+ cur.y + ih < cy + ch) {
+ cur.i->enforceSortOrder();
+
+ Q3ListViewItem * c = cur.i->childItem;
+ int y = cur.y + ih;
+
+ // if any of the children are not to be painted, skip them
+ // and invalidate topPixel
+ while (c && y + c->totalHeight() <= cy) {
+ y += c->totalHeight();
+ c = c->siblingItem;
+ d->topPixel = cy + ch;
+ }
+
+ // push one child on the stack, if there is at least one
+ // needing to be painted
+ if (c && y < cy+ch)
+ stack.push(Q3ListViewPrivate::DrawableItem(cur.l + 1, y, c));
+ }
+ }
+}
+
+/*!
+ \property Q3ListView::treeStepSize
+ \brief the number of pixels a child is offset from its parent
+
+ The default is 20 pixels.
+
+ Of course, this property is only meaningful for hierarchical list
+ views.
+*/
+
+int Q3ListView::treeStepSize() const
+{
+ return d->levelWidth;
+}
+
+void Q3ListView::setTreeStepSize(int size)
+{
+ if (size != d->levelWidth) {
+ d->levelWidth = size;
+ viewport()->repaint();
+ }
+}
+
+/*!
+ Inserts item \a i into the list view as a top-level item. You do
+ not need to call this unless you've called takeItem(\a i) or
+ Q3ListViewItem::takeItem(\a i) and need to reinsert \a i elsewhere.
+
+ \sa Q3ListViewItem::takeItem() takeItem()
+*/
+
+void Q3ListView::insertItem(Q3ListViewItem * i)
+{
+ if (d->r) // not for d->r itself
+ d->r->insertItem(i);
+}
+
+
+/*!
+ Removes and deletes all the items in this list view and triggers
+ an update.
+
+ \sa triggerUpdate()
+*/
+
+void Q3ListView::clear()
+{
+ bool wasUpdatesEnabled = viewport()->updatesEnabled();
+ if (wasUpdatesEnabled)
+ viewport()->setUpdatesEnabled(false);
+ setContentsPos(0, 0);
+ if (wasUpdatesEnabled)
+ viewport()->setUpdatesEnabled(true);
+
+ bool block = signalsBlocked();
+ blockSignals(true);
+ d->clearing = true;
+ clearSelection();
+ for (int j = 0; j < d->iterators.size(); ++j) {
+ Q3ListViewItemIterator *i = d->iterators.at(j);
+ i->curr = 0;
+ }
+
+ d->drawables.clear();
+ d->dirtyItems.clear();
+ d->dirtyItemTimer->stop();
+
+ d->highlighted = 0;
+ d->focusItem = 0;
+ d->selectAnchor = 0;
+ d->pressedItem = 0;
+ d->startDragItem = 0;
+
+ // if it's down its downness makes no sense, so undown it
+ d->buttonDown = false;
+
+ Q3ListViewItem *c = (Q3ListViewItem *)d->r->firstChild();
+ Q3ListViewItem *n;
+ while(c) {
+ n = (Q3ListViewItem *)c->nextSibling();
+ delete c;
+ c = n;
+ }
+ resizeContents(d->h->sizeHint().width(), contentsHeight());
+ delete d->r;
+ d->r = 0;
+ Q3ListViewPrivate::Root * r = new Q3ListViewPrivate::Root(this);
+ r->is_root = true;
+ d->r = r;
+ d->r->setSelectable(false);
+ blockSignals(block);
+ triggerUpdate();
+ d->clearing = false;
+}
+
+/*!
+ \reimp
+*/
+
+void Q3ListView::setContentsPos(int x, int y)
+{
+ updateGeometries();
+ Q3ScrollView::setContentsPos(x, y);
+}
+
+/*!
+ Adds a \a width pixels wide column with the column header \a label
+ to the list view, and returns the index of the new column.
+
+ All columns apart from the first one are inserted to the right of
+ the existing ones.
+
+ If \a width is negative, the new column's \l WidthMode is set to
+ \c Maximum instead of \c Manual.
+
+ \sa setColumnText() setColumnWidth() setColumnWidthMode()
+*/
+int Q3ListView::addColumn(const QString &label, int width)
+{
+ int c = d->h->addLabel(label, width);
+ d->column.resize(c+1);
+ d->column[c].wmode = (width >= 0 ? Manual : Maximum);
+ updateGeometries();
+ updateGeometry();
+ return c;
+}
+
+/*!
+ \overload
+
+ Adds a \a width pixels wide new column with the header \a label
+ and the \a icon to the list view, and returns the index of the
+ column.
+
+ If \a width is negative, the new column's \l WidthMode is set to
+ \c Maximum, and to \c Manual otherwise.
+
+ \sa setColumnText() setColumnWidth() setColumnWidthMode()
+*/
+int Q3ListView::addColumn(const QIcon& icon, const QString &label, int width)
+{
+ int c = d->h->addLabel(icon, label, width);
+ d->column.resize(c+1);
+ d->column[c].wmode = (width >= 0 ? Manual : Maximum);
+ updateGeometries();
+ updateGeometry();
+ return c;
+}
+
+/*!
+ \property Q3ListView::columns
+ \brief the number of columns in this list view
+
+ \sa addColumn(), removeColumn()
+*/
+
+int Q3ListView::columns() const
+{
+ return d->column.count();
+}
+
+/*!
+ Removes the column at position \a index.
+*/
+
+void Q3ListView::removeColumn(int index)
+{
+ if (index < 0 || index > (int)d->column.count() - 1)
+ return;
+
+ if (d->vci) {
+ Q3ListViewPrivate::ViewColumnInfo *vi = d->vci, *prev = 0, *next = 0;
+ for (int i = 0; i < index; ++i) {
+ if (vi) {
+ prev = vi;
+ vi = vi->next;
+ }
+ }
+ if (vi) {
+ next = vi->next;
+ if (prev)
+ prev->next = next;
+ vi->next = 0;
+ delete vi;
+ if (index == 0)
+ d->vci = next;
+ }
+ }
+
+ Q3ListViewItemIterator it(this);
+ for (; it.current(); ++it) {
+ Q3ListViewPrivate::ItemColumnInfo *ci = (Q3ListViewPrivate::ItemColumnInfo*)it.current()->columns;
+ if (ci) {
+ Q3ListViewPrivate::ItemColumnInfo *prev = 0, *next = 0;
+ for (int i = 0; i < index; ++i) {
+ if (ci) {
+ prev = ci;
+ ci = ci->next;
+ }
+ }
+ if (ci) {
+ next = ci->next;
+ if (prev)
+ prev->next = next;
+ ci->next = 0;
+ delete ci;
+ if (index == 0)
+ it.current()->columns = next;
+ }
+ }
+ }
+
+ for (int i = index; i < (int)d->column.size() - 1; ++i)
+ d->column[i] = d->column[i + 1];
+ d->column.resize(d->column.size() - 1);
+
+ d->h->removeLabel(index);
+ if (d->resizeMode == LastColumn)
+ d->h->setStretchEnabled(true, d->h->count() - 1);
+
+ updateGeometries();
+ if (d->column.count() == 0)
+ clear();
+ updateGeometry();
+ viewport()->update();
+}
+
+/*!
+ Sets the heading of column \a column to \a label.
+
+ \sa columnText()
+*/
+void Q3ListView::setColumnText(int column, const QString &label)
+{
+ if (column < d->h->count()) {
+ d->h->setLabel(column, label);
+ updateGeometries();
+ updateGeometry();
+ }
+}
+
+/*!
+ \overload
+
+ Sets the heading of column \a column to \a icon and \a label.
+
+ \sa columnText()
+*/
+void Q3ListView::setColumnText(int column, const QIcon& icon, const QString &label)
+{
+ if (column < d->h->count()) {
+ d->h->setLabel(column, icon, label);
+ updateGeometries();
+ }
+}
+
+/*!
+ Sets the width of column \a column to \a w pixels. Note that if
+ the column has a \c WidthMode other than \c Manual, this width
+ setting may be subsequently overridden.
+
+ \sa columnWidth()
+*/
+void Q3ListView::setColumnWidth(int column, int w)
+{
+ int oldw = d->h->sectionSize(column);
+ if (column < d->h->count() && oldw != w) {
+ d->h->resizeSection(column, w);
+ disconnect(d->h, SIGNAL(sizeChange(int,int,int)),
+ this, SLOT(handleSizeChange(int,int,int)));
+ emit d->h->sizeChange(column, oldw, w);
+ connect(d->h, SIGNAL(sizeChange(int,int,int)),
+ this, SLOT(handleSizeChange(int,int,int)));
+ viewport()->update();
+ }
+}
+
+
+/*!
+ Returns the text of column \a c.
+
+ \sa setColumnText()
+*/
+
+QString Q3ListView::columnText(int c) const
+{
+ return d->h->label(c);
+}
+
+/*!
+ Returns the width of column \a c.
+
+ \sa setColumnWidth()
+*/
+
+int Q3ListView::columnWidth(int c) const
+{
+ int actual = d->h->mapToActual(c);
+ return d->h->cellSize(actual);
+}
+
+
+/*!
+ \enum Q3ListView::WidthMode
+
+ This enum type describes how the width of a column in the view
+ changes.
+
+ \value Manual the column width does not change automatically.
+
+ \value Maximum the column is automatically sized according to the
+ widths of all items in the column. (Note: The column never shrinks
+ in this case.) This means that the column is always resized to the
+ width of the item with the largest width in the column.
+
+ \sa setColumnWidth() setColumnWidthMode() columnWidth()
+*/
+
+
+/*!
+ Sets column \a{c}'s width mode to \a mode. The default depends on
+ the original width argument to addColumn().
+
+ \sa Q3ListViewItem::width()
+*/
+
+void Q3ListView::setColumnWidthMode(int c, WidthMode mode)
+{
+ if (c >= 0 && c < d->h->count())
+ d->column[c].wmode = mode;
+}
+
+
+/*!
+ Returns the \c WidthMode for column \a c.
+
+ \sa setColumnWidthMode()
+*/
+
+Q3ListView::WidthMode Q3ListView::columnWidthMode(int c) const
+{
+ if (c >= 0 && c < d->h->count())
+ return d->column[c].wmode;
+ else
+ return Manual;
+}
+
+
+/*!
+ Sets column \a{column}'s alignment to \a align. The alignment is
+ ultimately passed to Q3ListViewItem::paintCell() for each item in
+ the list view. For horizontally aligned text with Qt::AlignLeft or
+ Qt::AlignHCenter the ellipsis (...) will be to the right, for
+ Qt::AlignRight the ellipsis will be to the left.
+
+ \sa Qt::Alignment
+*/
+
+void Q3ListView::setColumnAlignment(int column, int align)
+{
+ if (column < 0)
+ return;
+ if (!d->vci)
+ d->vci = new Q3ListViewPrivate::ViewColumnInfo;
+ Q3ListViewPrivate::ViewColumnInfo * l = d->vci;
+ while(column) {
+ if (!l->next)
+ l->next = new Q3ListViewPrivate::ViewColumnInfo;
+ l = l->next;
+ column--;
+ }
+ if (l->align == align)
+ return;
+ l->align = align;
+ triggerUpdate();
+}
+
+
+/*!
+ Returns the alignment of column \a column. The default is \c
+ Qt::AlignAuto.
+
+ \sa Qt::Alignment
+*/
+
+int Q3ListView::columnAlignment(int column) const
+{
+ if (column < 0 || !d->vci)
+ return Qt::AlignAuto;
+ Q3ListViewPrivate::ViewColumnInfo * l = d->vci;
+ while(column) {
+ if (!l->next)
+ l->next = new Q3ListViewPrivate::ViewColumnInfo;
+ l = l->next;
+ column--;
+ }
+ return l ? l->align : Qt::AlignAuto;
+}
+
+
+
+/*!
+ \internal
+*/
+void Q3ListView::show()
+{
+ // Reimplemented to setx the correct background mode and viewed
+ // area size.
+ if (!isVisible()) {
+ reconfigureItems();
+ updateGeometries();
+ }
+ Q3ScrollView::show();
+}
+
+
+/*!
+ Updates the sizes of the viewport, header, scroll bars and so on.
+
+ \warning Don't call this directly; call triggerUpdate() instead.
+*/
+
+void Q3ListView::updateContents()
+{
+ if (d->updateHeader)
+ header()->adjustHeaderSize();
+ d->updateHeader = false;
+ if (!isVisible()) {
+ // Not in response to a setText/setPixmap any more.
+ return;
+ }
+ d->drawables.clear();
+ viewport()->setUpdatesEnabled(false);
+ updateGeometries();
+ viewport()->setUpdatesEnabled(true);
+ viewport()->repaint();
+}
+
+
+void Q3ListView::updateGeometries()
+{
+ int th = d->r->totalHeight();
+ int tw = d->h->headerWidth();
+ if (d->h->offset() &&
+ tw < d->h->offset() + d->h->width())
+ horizontalScrollBar()->setValue(tw - Q3ListView::d->h->width());
+#if 0
+ if (QApplication::reverseLayout() && d->h->offset() != horizontalScrollBar()->value())
+ horizontalScrollBar()->setValue(d->h->offset());
+#endif
+ verticalScrollBar()->raise();
+ resizeContents(tw, th);
+ d->drawables.clear();
+ if (d->h->isHidden()) {
+ setMargins(0, 0, 0, 0);
+ } else {
+ QSize hs(d->h->sizeHint());
+ setMargins(0, hs.height(), 0, 0);
+ d->h->setGeometry(viewport()->x(), viewport()->y()-hs.height(),
+ visibleWidth(), hs.height());
+ }
+}
+
+
+/*!
+ Updates the display when the section \a section has changed size
+ from the old size, \a os, to the new size, \a ns.
+*/
+
+void Q3ListView::handleSizeChange(int section, int os, int ns)
+{
+ bool upe = viewport()->updatesEnabled();
+ if (upe)
+ viewport()->setUpdatesEnabled(false);
+ viewport()->setAttribute(Qt::WA_UpdatesDisabled, true);
+ int sx = horizontalScrollBar()->value();
+ bool sv = horizontalScrollBar()->isVisible();
+ updateGeometries();
+ bool fullRepaint = d->fullRepaintOnComlumnChange || sx != horizontalScrollBar()->value()
+ || sv != horizontalScrollBar()->isVisible();
+ d->fullRepaintOnComlumnChange = false;
+ if (upe)
+ viewport()->setUpdatesEnabled(true);
+
+ if (fullRepaint) {
+ viewport()->repaint();
+ return;
+ }
+
+ int actual = d->h->mapToActual(section);
+ int dx = ns - os;
+ int left = d->h->cellPos(actual) - contentsX() + d->h->cellSize(actual);
+ if (dx > 0)
+ left -= dx;
+ if (left < visibleWidth())
+ viewport()->scroll(dx, 0, QRect(left, 0, visibleWidth() - left, visibleHeight()));
+ viewport()->repaint(left - 4 - d->ellipsisWidth, 0, 4 + d->ellipsisWidth,
+ visibleHeight()); // border between the items and ellipses width
+
+ // map auto to left for now. Need to fix this once we support
+ // reverse layout on the listview.
+ int align = columnAlignment(section);
+ if (align == Qt::AlignAuto) align = Qt::AlignLeft;
+ if (align != Qt::AlignAuto && align != Qt::AlignLeft)
+ viewport()->repaint(d->h->cellPos(actual) - contentsX(), 0,
+ d->h->cellSize(actual), visibleHeight());
+
+ if (currentItem() && currentItem()->renameBox) {
+ QRect r = itemRect(currentItem());
+ r = QRect(viewportToContents(r.topLeft()), r.size());
+ r.setLeft(header()->sectionPos(currentItem()->renameCol));
+ r.setWidth(header()->sectionSize(currentItem()->renameCol) - 1);
+ if (currentItem()->renameCol == 0)
+ r.setLeft(r.left() + itemMargin() + (currentItem()->depth() +
+ (rootIsDecorated() ? 1 : 0)) * treeStepSize() - 1);
+ if (currentItem()->pixmap(currentItem()->renameCol))
+ r.setLeft(r.left() + currentItem()->pixmap(currentItem()->renameCol)->width());
+ if (r.x() - contentsX() < 0)
+ r.setX(contentsX());
+ if (r.width() > visibleWidth())
+ r.setWidth(visibleWidth());
+ addChild(currentItem()->renameBox, r.x(), r.y());
+ currentItem()->renameBox->resize(r.size());
+ }
+}
+
+
+/*
+ Very smart internal slot that repaints \e only the items that need
+ to be repainted. Don't use this directly; call repaintItem()
+ instead.
+*/
+
+void Q3ListView::updateDirtyItems()
+{
+ if (d->timer->isActive() || d->dirtyItems.isEmpty())
+ return;
+ QRect ir;
+ for (int i = 0; i < d->dirtyItems.size(); ++i) {
+ const Q3ListViewItem *item = d->dirtyItems.at(i);
+ ir = ir.united(itemRect(item));
+ }
+ d->dirtyItems.clear();
+ if (!ir.isEmpty()) { // rectangle to be repainted
+ if (ir.x() < 0)
+ ir.moveBy(-ir.x(), 0);
+ viewport()->repaint(ir);
+ }
+}
+
+
+void Q3ListView::makeVisible()
+{
+ if (d->focusItem)
+ ensureItemVisible(d->focusItem);
+}
+
+
+/*!
+ Ensures that the header is correctly sized and positioned when the
+ resize event \a e occurs.
+*/
+
+void Q3ListView::resizeEvent(QResizeEvent *e)
+{
+ Q3ScrollView::resizeEvent(e);
+ d->fullRepaintOnComlumnChange = true;
+ d->h->resize(visibleWidth(), d->h->height());
+ d->h->adjustHeaderSize();
+}
+
+/*! \reimp */
+
+void Q3ListView::viewportResizeEvent(QResizeEvent *e)
+{
+ Q3ScrollView::viewportResizeEvent(e);
+ d->h->resize(visibleWidth(), d->h->height());
+ if (resizeMode() != NoColumn && currentItem() && currentItem()->renameBox) {
+ QRect r = itemRect(currentItem());
+ r = QRect(viewportToContents(r.topLeft()), r.size());
+ r.setLeft(header()->sectionPos(currentItem()->renameCol));
+ r.setWidth(header()->sectionSize(currentItem()->renameCol) - 1);
+ if (currentItem()->renameCol == 0)
+ r.setLeft(r.left() + itemMargin() + (currentItem()->depth() +
+ (rootIsDecorated() ? 1 : 0)) * treeStepSize() - 1);
+ if (currentItem()->pixmap(currentItem()->renameCol))
+ r.setLeft(r.left() + currentItem()->pixmap(currentItem()->renameCol)->width());
+ if (r.x() - contentsX() < 0)
+ r.setX(contentsX());
+ if (r.width() > visibleWidth())
+ r.setWidth(visibleWidth());
+ addChild(currentItem()->renameBox, r.x(), r.y());
+ currentItem()->renameBox->resize(r.size());
+ }
+}
+
+/*!
+ Triggers a size, geometry and content update during the next
+ iteration of the event loop. Ensures that there'll be just one
+ update to avoid flicker.
+*/
+
+void Q3ListView::triggerUpdate()
+{
+ if (!isVisible() || !updatesEnabled()) {
+ // Not in response to a setText/setPixmap any more.
+ return; // it will update when shown, or something.
+ }
+
+ d->timer->start(0, true);
+}
+
+
+/*!
+ Redirects the event \a e relating to object \a o, for the viewport
+ to mousePressEvent(), keyPressEvent() and friends.
+*/
+
+bool Q3ListView::eventFilter(QObject * o, QEvent * e)
+{
+ if (o == d->h &&
+ e->type() >= QEvent::MouseButtonPress &&
+ e->type() <= QEvent::MouseMove) {
+ QMouseEvent * me = (QMouseEvent *)e;
+ QMouseEvent me2(me->type(),
+ QPoint(me->pos().x(),
+ me->pos().y() - d->h->height()),
+ me->button(), me->state());
+ switch(me2.type()) {
+ case QEvent::MouseButtonDblClick:
+ if (me2.button() == Qt::RightButton)
+ return true;
+ break;
+ case QEvent::MouseMove:
+ if (me2.state() & Qt::RightButton) {
+ viewportMouseMoveEvent(&me2);
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ } else if (o == viewport()) {
+ QFocusEvent * fe = (QFocusEvent *)e;
+
+ switch(e->type()) {
+ case QEvent::FocusIn:
+ focusInEvent(fe);
+ return true;
+ case QEvent::FocusOut:
+ focusOutEvent(fe);
+ return true;
+#ifndef QT_NO_TOOLTIP
+ case QEvent::ToolTip:
+ {
+ if (!showToolTips())
+ return false;
+
+ QHelpEvent *he = static_cast<QHelpEvent *>(e);
+ Q3ListViewItem *item = itemAt(he->pos());
+ QPoint contentsPos = viewportToContents(he->pos());
+ if (!item || !item->columns) {
+ QToolTip::showText(he->globalPos(), QString(), viewport());
+ return true;
+ }
+ int col = header()->sectionAt(contentsPos.x());
+ Q3ListViewPrivate::ItemColumnInfo *ci = (Q3ListViewPrivate::ItemColumnInfo*)item->columns;
+ for (int i = 0; ci && (i < col); ++i)
+ ci = ci->next;
+
+ if (!ci || !ci->truncated)
+ QToolTip::showText(he->globalPos(), QString(), viewport());
+ else
+ QToolTip::showText(he->globalPos(), item->text(col), viewport());
+ return true;
+ }
+#endif
+ default:
+ // nothing
+ break;
+ }
+ } else if (qobject_cast<QLineEdit*>(o)) {
+ if (currentItem() && currentItem()->renameBox) {
+ if (e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = (QKeyEvent*)e;
+ if (ke->key() == Qt::Key_Return ||
+ ke->key() == Qt::Key_Enter) {
+ currentItem()->okRename(currentItem()->renameCol);
+ return true;
+ } else if (ke->key() == Qt::Key_Escape) {
+ currentItem()->cancelRename(currentItem()->renameCol);
+ return true;
+ }
+ } else if (e->type() == QEvent::FocusOut) {
+ if (((QFocusEvent*)e)->reason() != Qt::PopupFocusReason) {
+ QCustomEvent *e = new QCustomEvent(9999);
+ QApplication::postEvent(o, e);
+ return true;
+ }
+ } else if (e->type() == 9999) {
+ if (d->defRenameAction == Reject)
+ currentItem()->cancelRename(currentItem()->renameCol);
+ else
+ currentItem()->okRename(currentItem()->renameCol);
+ return true;
+ }
+ }
+ }
+
+ return Q3ScrollView::eventFilter(o, e);
+}
+
+
+/*!
+ Returns a pointer to the list view containing this item.
+
+ Note that this function traverses the items to the root to find the
+ listview. This function will return 0 for taken items - see
+ Q3ListViewItem::takeItem()
+*/
+
+Q3ListView * Q3ListViewItem::listView() const
+{
+ const Q3ListViewItem* c = this;
+ while (c && !c->is_root)
+ c = c->parentItem;
+ if (!c)
+ return 0;
+ return ((Q3ListViewPrivate::Root*)c)->theListView();
+}
+
+
+/*!
+ Returns the depth of this item.
+*/
+int Q3ListViewItem::depth() const
+{
+ return parentItem ? parentItem->depth()+1 : -1; // -1 == the hidden root
+}
+
+
+/*!
+ Returns a pointer to the item immediately above this item on the
+ screen. This is usually the item's closest older sibling, but it
+ may also be its parent or its next older sibling's youngest child,
+ or something else if anyoftheabove->height() returns 0. Returns 0
+ if there is no item immediately above this item.
+
+ This function assumes that all parents of this item are open (i.e.
+ that this item is visible, or can be made visible by scrolling).
+
+ This function might be relatively slow because of the tree
+ traversions needed to find the correct item.
+
+ \sa itemBelow() Q3ListView::itemRect()
+*/
+
+Q3ListViewItem * Q3ListViewItem::itemAbove() const
+{
+ if (!parentItem)
+ return 0;
+
+ Q3ListViewItem * c = parentItem;
+ if (c->childItem != this) {
+ c = c->childItem;
+ while(c && c->siblingItem != this)
+ c = c->siblingItem;
+ if (!c)
+ return 0;
+ while(c->isOpen() && c->childItem) {
+ c = c->childItem;
+ while(c->siblingItem)
+ c = c->siblingItem; // assign c's sibling to c
+ }
+ }
+ if (c && (!c->height() || !c->isEnabled()))
+ return c->itemAbove();
+ return c;
+}
+
+
+/*!
+ Returns a pointer to the item immediately below this item on the
+ screen. This is usually the item's eldest child, but it may also
+ be its next younger sibling, its parent's next younger sibling,
+ grandparent's, etc., or something else if anyoftheabove->height()
+ returns 0. Returns 0 if there is no item immediately below this
+ item.
+
+ This function assumes that all parents of this item are open (i.e.
+ that this item is visible or can be made visible by scrolling).
+
+ \sa itemAbove() Q3ListView::itemRect()
+*/
+
+Q3ListViewItem * Q3ListViewItem::itemBelow() const
+{
+ Q3ListViewItem * c = 0;
+ if (isOpen() && childItem) {
+ c = childItem;
+ } else if (siblingItem) {
+ c = siblingItem;
+ } else if (parentItem) {
+ c = const_cast<Q3ListViewItem*>(this);
+ do {
+ c = c->parentItem;
+ } while(c->parentItem && !c->siblingItem);
+ if (c)
+ c = c->siblingItem;
+ }
+ if (c && (!c->height() || !c->isEnabled()))
+ return c->itemBelow();
+ return c;
+}
+
+
+/*!
+ \fn bool Q3ListViewItem::isOpen() const
+
+ Returns true if this list view item has children \e and they are
+ not explicitly hidden; otherwise returns false.
+
+ \sa setOpen()
+*/
+
+/*!
+ Returns the first (top) child of this item, or 0 if this item has
+ no children.
+
+ Note that the children are not guaranteed to be sorted properly.
+ Q3ListView and Q3ListViewItem try to postpone or avoid sorting to
+ the greatest degree possible, in order to keep the user interface
+ snappy.
+
+ \sa nextSibling() sortChildItems()
+*/
+
+Q3ListViewItem* Q3ListViewItem::firstChild() const
+{
+ enforceSortOrder();
+ return childItem;
+}
+
+
+/*!
+ Returns the parent of this item, or 0 if this item has no parent.
+
+ \sa firstChild(), nextSibling()
+*/
+
+Q3ListViewItem* Q3ListViewItem::parent() const
+{
+ if (!parentItem || parentItem->is_root) return 0;
+ return parentItem;
+}
+
+
+/*!
+ \fn Q3ListViewItem* Q3ListViewItem::nextSibling() const
+
+ Returns the sibling item below this item, or 0 if there is no
+ sibling item after this item.
+
+ Note that the siblings are not guaranteed to be sorted properly.
+ Q3ListView and Q3ListViewItem try to postpone or avoid sorting to
+ the greatest degree possible, in order to keep the user interface
+ snappy.
+
+ \sa firstChild() sortChildItems()
+*/
+
+/*!
+ \fn int Q3ListViewItem::childCount () const
+
+ Returns how many children this item has. The count only includes
+ the item's immediate children.
+*/
+
+
+/*!
+ Returns the height of this item in pixels. This does not include
+ the height of any children; totalHeight() returns that.
+*/
+int Q3ListViewItem::height() const
+{
+ Q3ListViewItem * that = (Q3ListViewItem *)this;
+ if (!that->configured) {
+ that->configured = true;
+ that->setup(); // ### virtual non-const function called in const
+ }
+
+ return visible ? ownHeight : 0;
+}
+
+/*!
+ Call this function when the value of width() may have changed for
+ column \a c. Normally, you should call this if text(c) changes.
+ Passing -1 for \a c indicates that all columns may have changed.
+ It is more efficient to pass -1 if two or more columns have
+ changed than to call widthChanged() separately for each one.
+
+ \sa width()
+*/
+void Q3ListViewItem::widthChanged(int c) const
+{
+ Q3ListView *lv = listView();
+ if (lv)
+ lv->widthChanged(this, c);
+}
+
+/*!
+ \fn void Q3ListView::dropped (QDropEvent * e)
+
+ This signal is emitted, when a drop event occurred on the
+ viewport (not onto an item).
+
+ \a e provides all the information about the drop.
+*/
+
+/*!
+ \fn void Q3ListView::selectionChanged()
+
+ This signal is emitted whenever the set of selected items has
+ changed (normally before the screen update). It is available both
+ in \c Single selection and \c Multi selection mode but is most
+ useful in \c Multi selection mode.
+
+ \warning Do not delete any Q3ListViewItem objects in slots
+ connected to this signal.
+
+ \sa setSelected() Q3ListViewItem::setSelected()
+*/
+
+
+/*!
+ \fn void Q3ListView::pressed(Q3ListViewItem *item)
+
+ This signal is emitted whenever the user presses the mouse button
+ in a list view. \a item is the list view item on which the user
+ pressed the mouse button, or 0 if the user didn't press the mouse
+ on an item.
+
+ \warning Do not delete any Q3ListViewItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void Q3ListView::pressed(Q3ListViewItem *item, const QPoint &pnt, int c)
+
+ \overload
+
+ This signal is emitted whenever the user presses the mouse button
+ in a list view. \a item is the list view item on which the user
+ pressed the mouse button, or 0 if the user didn't press the mouse
+ on an item. \a pnt is the position of the mouse cursor in global
+ coordinates, and \a c is the column where the mouse cursor was
+ when the user pressed the mouse button.
+
+ \warning Do not delete any Q3ListViewItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void Q3ListView::clicked(Q3ListViewItem *item)
+
+ This signal is emitted whenever the user clicks (mouse pressed \e
+ and mouse released) in the list view. \a item is the clicked list
+ view item, or 0 if the user didn't click on an item.
+
+ \warning Do not delete any Q3ListViewItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void Q3ListView::mouseButtonClicked(int button, Q3ListViewItem * item, const QPoint & pos, int c)
+
+ This signal is emitted whenever the user clicks (mouse pressed \e
+ and mouse released) in the list view at position \a pos. \a button
+ is the mouse button that the user pressed, \a item is the clicked
+ list view item or 0 if the user didn't click on an item. If \a
+ item is not 0, \a c is the list view column into which the user
+ pressed; if \a item is 0 \a{c}'s value is undefined.
+
+ \warning Do not delete any Q3ListViewItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void Q3ListView::mouseButtonPressed(int button, Q3ListViewItem * item, const QPoint & pos, int c)
+
+ This signal is emitted whenever the user pressed the mouse button
+ in the list view at position \a pos. \a button is the mouse button
+ which the user pressed, \a item is the pressed list view item or 0
+ if the user didn't press on an item. If \a item is not 0, \a c is
+ the list view column into which the user pressed; if \a item is 0
+ \a{c}'s value is undefined.
+
+ \warning Do not delete any Q3ListViewItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void Q3ListView::clicked(Q3ListViewItem *item, const QPoint &pnt, int c)
+
+ \overload
+
+ This signal is emitted whenever the user clicks (mouse pressed \e
+ and mouse released) in the list view. \a item is the clicked list
+ view item, or 0 if the user didn't click on an item. \a pnt is the
+ position where the user has clicked in global coordinates. If \a
+ item is not 0, \a c is the list view column into which the user
+ pressed; if \a item is 0 \a{c}'s value is undefined.
+
+ \warning Do not delete any Q3ListViewItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void Q3ListView::selectionChanged(Q3ListViewItem *item)
+
+ \overload
+
+ This signal is emitted whenever the selected item has changed in
+ \c Single selection mode (normally after the screen update). The
+ argument is the newly selected \a item.
+
+ In \c Multi selection mode, use the no argument overload of this
+ signal.
+
+ \warning Do not delete any Q3ListViewItem objects in slots
+ connected to this signal.
+
+ \sa setSelected() Q3ListViewItem::setSelected() currentChanged()
+*/
+
+
+/*!
+ \fn void Q3ListView::currentChanged(Q3ListViewItem *item)
+
+ This signal is emitted whenever the current item has changed
+ (normally after the screen update). The current item is the item
+ responsible for indicating keyboard focus.
+
+ The argument is the newly current \a item, or 0 if the change made
+ no item current. This can happen, for example, if all the items in
+ the list view are deleted.
+
+ \warning Do not delete any Q3ListViewItem objects in slots
+ connected to this signal.
+
+ \sa setCurrentItem() currentItem()
+*/
+
+
+/*!
+ \fn void Q3ListView::expanded(Q3ListViewItem *item)
+
+ This signal is emitted when \a item has been expanded, i.e. when
+ the children of \a item are shown.
+
+ \sa setOpen() collapsed()
+*/
+
+/*!
+ \fn void Q3ListView::collapsed(Q3ListViewItem *item)
+
+ This signal is emitted when the \a item has been collapsed, i.e.
+ when the children of \a item are hidden.
+
+ \sa setOpen() expanded()
+*/
+
+/*!
+ Processes the mouse press event \a e on behalf of the viewed widget.
+*/
+void Q3ListView::contentsMousePressEvent(QMouseEvent * e)
+{
+ contentsMousePressEventEx(e);
+}
+
+void Q3ListView::contentsMousePressEventEx(QMouseEvent * e)
+{
+ if (!e)
+ return;
+
+ if (!d->ignoreEditAfterFocus)
+ d->startEdit = true;
+ d->ignoreEditAfterFocus = false;
+
+ if (currentItem() && currentItem()->renameBox &&
+ !itemRect(currentItem()).contains(e->pos())) {
+ d->startEdit = false;
+ if (d->defRenameAction == Reject)
+ currentItem()->cancelRename(currentItem()->renameCol);
+ else
+ currentItem()->okRename(currentItem()->renameCol);
+ }
+
+ d->startDragItem = 0;
+ d->dragStartPos = e->pos();
+ QPoint vp = contentsToViewport(e->pos());
+
+ d->ignoreDoubleClick = false;
+ d->buttonDown = true;
+
+ Q3ListViewItem * i = itemAt(vp);
+ d->pressedEmptyArea = e->y() > contentsHeight();
+ if (i && !i->isEnabled())
+ return;
+ if (d->startEdit && (i != currentItem() || (i && !i->isSelected())))
+ d->startEdit = false;
+ Q3ListViewItem *oldCurrent = currentItem();
+
+ if (e->button() == Qt::RightButton && (e->state() & Qt::ControlButton))
+ goto emit_signals;
+
+ if (!i) {
+ if (!(e->state() & Qt::ControlButton))
+ clearSelection();
+ goto emit_signals;
+ } else {
+ // No new anchor when using shift
+ if (!(e->state() & Qt::ShiftButton))
+ d->selectAnchor = i;
+ }
+
+ if ((i->isExpandable() || i->childCount()) &&
+ d->h->mapToLogical(d->h->cellAt(vp.x())) == 0) {
+ int x1 = vp.x() +
+ d->h->offset() -
+ d->h->cellPos(d->h->mapToActual(0));
+ int draw = 0;
+ for (; draw < d->drawables.size(); ++draw)
+ if (d->drawables.at(draw).i == i)
+ break;
+
+ if (draw < d->drawables.size()) {
+ Q3ListViewPrivate::DrawableItem it = d->drawables.at(draw);
+ QStyleOptionQ3ListView opt = getStyleOption(this, i);
+ x1 -= treeStepSize() * (it.l - 1);
+ QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_Q3ListView, &opt,
+ QPoint(x1, e->pos().y()), this);
+ if (ctrl == QStyle::SC_Q3ListViewExpand &&
+ e->type() == style()->styleHint(QStyle::SH_Q3ListViewExpand_SelectMouseType, 0,
+ this)) {
+ d->buttonDown = false;
+ if (e->button() == Qt::LeftButton) {
+ bool close = i->isOpen();
+ setOpen(i, !close);
+ // ### Looks dangerous, removed because of reentrance problems
+ // qApp->processEvents();
+ if (!d->focusItem) {
+ d->focusItem = i;
+ repaintItem(d->focusItem);
+ emit currentChanged(d->focusItem);
+ }
+ if (close) {
+ bool newCurrent = false;
+ Q3ListViewItem *ci = d->focusItem;
+ while (ci) {
+ if (ci->parent() && ci->parent() == i) {
+ newCurrent = true;
+ break;
+ }
+ ci = ci->parent();
+ }
+ if (newCurrent) {
+ setCurrentItem(i);
+ }
+ }
+ }
+ d->ignoreDoubleClick = true;
+ d->buttonDown = false;
+ goto emit_signals;
+ }
+ }
+ }
+
+ d->select = d->selectionMode == Multi ? !i->isSelected() : true;
+
+ {// calculate activatedP
+ activatedByClick = true;
+ QPoint topLeft = itemRect(i).topLeft(); //### inefficient?
+ activatedP = vp - topLeft;
+ int xdepth = treeStepSize() * (i->depth() + (rootIsDecorated() ? 1 : 0))
+ + itemMargin();
+ xdepth += d->h->sectionPos(d->h->mapToSection(0));
+ activatedP.rx() -= xdepth;
+ }
+ i->activate();
+ activatedByClick = false;
+
+ if (i != d->focusItem)
+ setCurrentItem(i);
+ else
+ repaintItem(i);
+
+ d->pressedSelected = i && i->isSelected();
+
+ if (i->isSelectable() && selectionMode() != NoSelection) {
+ if (selectionMode() == Single)
+ setSelected(i, true);
+ else if (selectionMode() == Multi)
+ setSelected(i, d->select);
+ else if (selectionMode() == Extended) {
+ bool changed = false;
+ if (!(e->state() & (Qt::ControlButton | Qt::ShiftButton))) {
+ if (!i->isSelected()) {
+ bool blocked = signalsBlocked();
+ blockSignals(true);
+ clearSelection();
+ blockSignals(blocked);
+ i->setSelected(true);
+ changed = true;
+ }
+ } else {
+ if (e->state() & Qt::ShiftButton)
+ d->pressedSelected = false;
+ if ((e->state() & Qt::ControlButton) && !(e->state() & Qt::ShiftButton) && i) {
+ i->setSelected(!i->isSelected());
+ changed = true;
+ d->pressedSelected = false;
+ } else if (!oldCurrent || !i || oldCurrent == i) {
+ if ((bool)i->selected != d->select) {
+ changed = true;
+ i->setSelected(d->select);
+ }
+ // Shift pressed in Extended mode ---
+ } else {
+ changed = selectRange(i, oldCurrent, d->selectAnchor);
+ }
+ }
+ if (changed) {
+ triggerUpdate();
+ emit selectionChanged();
+
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
+#endif
+ }
+ }
+ }
+
+ emit_signals:
+
+ if (i && !d->buttonDown &&
+ vp.x() + contentsX() < itemMargin() + (i->depth() + (rootIsDecorated() ? 1 : 0)) * treeStepSize())
+ i = 0;
+ d->pressedItem = i;
+
+ int c = i ? d->h->mapToLogical(d->h->cellAt(vp.x())) : -1;
+ if (!i || (i && i->isEnabled())) {
+ emit pressed(i);
+ emit pressed(i, viewport()->mapToGlobal(vp), c);
+ }
+ emit mouseButtonPressed(e->button(), i, viewport()->mapToGlobal(vp), c);
+
+ if (e->button() == Qt::RightButton && i == d->pressedItem) {
+ if (!i && !(e->state() & Qt::ControlButton))
+ clearSelection();
+
+ emit rightButtonPressed(i, viewport()->mapToGlobal(vp), c);
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void Q3ListView::contentsContextMenuEvent(QContextMenuEvent *e)
+{
+ if (!receivers(SIGNAL(contextMenuRequested(Q3ListViewItem*,QPoint,int)))) {
+ e->ignore();
+ return;
+ }
+ if (e->reason() == QContextMenuEvent::Keyboard) {
+ Q3ListViewItem *item = currentItem();
+ if (item) {
+ QRect r = itemRect(item);
+ QPoint p = r.topLeft();
+ if (allColumnsShowFocus())
+ p += QPoint(width() / 2, (r.height() / 2));
+ else
+ p += QPoint(columnWidth(0) / 2, (r.height() / 2));
+ p.rx() = qMax(0, p.x());
+ p.rx() = qMin(visibleWidth(), p.x());
+ emit contextMenuRequested(item, viewport()->mapToGlobal(p), -1);
+ }
+ } else {
+ QPoint vp = contentsToViewport(e->pos());
+ Q3ListViewItem * i = itemAt(vp);
+ int c = i ? d->h->mapToLogical(d->h->cellAt(vp.x())) : -1;
+ emit contextMenuRequested(i, viewport()->mapToGlobal(vp), c);
+ }
+}
+
+/*!
+ Processes the mouse release event \a e on behalf of the viewed widget.
+*/
+void Q3ListView::contentsMouseReleaseEvent(QMouseEvent * e)
+{
+ contentsMouseReleaseEventEx(e);
+}
+
+void Q3ListView::contentsMouseReleaseEventEx(QMouseEvent * e)
+{
+ d->startDragItem = 0;
+ bool emitClicked = !d->pressedItem || d->buttonDown;
+ d->buttonDown = false;
+ // delete and disconnect autoscroll timer, if we have one
+ if (d->scrollTimer) {
+ disconnect(d->scrollTimer, SIGNAL(timeout()),
+ this, SLOT(doAutoScroll()));
+ d->scrollTimer->stop();
+ delete d->scrollTimer;
+ d->scrollTimer = 0;
+ }
+
+ if (!e)
+ return;
+
+ if (d->selectionMode == Extended &&
+ d->focusItem == d->pressedItem &&
+ d->pressedSelected && d->focusItem &&
+ e->button() == Qt::LeftButton) {
+ bool block = signalsBlocked();
+ blockSignals(true);
+ clearSelection();
+ blockSignals(block);
+ d->focusItem->setSelected(true);
+ emit selectionChanged();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
+#endif
+ }
+
+ QPoint vp = contentsToViewport(e->pos());
+ Q3ListViewItem *i = itemAt(vp);
+ if (i && !i->isEnabled())
+ return;
+
+ if (i && i == d->pressedItem && (i->isExpandable() || i->childCount()) &&
+ !d->h->mapToLogical(d->h->cellAt(vp.x())) && e->button() == Qt::LeftButton &&
+ e->type() == style()->styleHint(QStyle::SH_Q3ListViewExpand_SelectMouseType, 0, this)) {
+ int draw = 0;
+ for (; draw < d->drawables.size(); ++draw)
+ if (d->drawables.at(draw).i == i)
+ break;
+ if (draw < d->drawables.size()) {
+ int x1 = vp.x() + d->h->offset() - d->h->cellPos(d->h->mapToActual(0)) -
+ (treeStepSize() * (d->drawables.at(draw).l - 1));
+ QStyleOptionQ3ListView opt = getStyleOption(this, i);
+ QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_Q3ListView, &opt,
+ QPoint(x1, e->pos().y()), this);
+ if (ctrl == QStyle::SC_Q3ListViewExpand) {
+ bool close = i->isOpen();
+ setOpen(i, !close);
+ // ### Looks dangerous, removed because of reentrance problems
+ // qApp->processEvents();
+ if (!d->focusItem) {
+ d->focusItem = i;
+ repaintItem(d->focusItem);
+ emit currentChanged(d->focusItem);
+ }
+ if (close) {
+ bool newCurrent = false;
+ Q3ListViewItem *ci = d->focusItem;
+ while (ci) {
+ if (ci->parent() && ci->parent() == i) {
+ newCurrent = true;
+ break;
+ }
+ ci = ci->parent();
+ }
+ if (newCurrent)
+ setCurrentItem(i);
+ d->ignoreDoubleClick = true;
+ }
+ }
+ }
+ }
+
+ if (i == d->pressedItem && i && i->isSelected() && e->button() == Qt::LeftButton && d->startEdit) {
+ QRect r = itemRect(currentItem());
+ r = QRect(viewportToContents(r.topLeft()), r.size());
+ d->pressedColumn = header()->sectionAt( e->pos().x());
+ r.setLeft(header()->sectionPos(d->pressedColumn));
+ r.setWidth(header()->sectionSize(d->pressedColumn) - 1);
+ if (d->pressedColumn == 0)
+ r.setLeft(r.left() + itemMargin() + (currentItem()->depth() +
+ (rootIsDecorated() ? 1 : 0)) * treeStepSize() - 1);
+ if (r.contains(e->pos()) &&
+ !(e->state() & (Qt::ShiftButton | Qt::ControlButton)))
+ d->renameTimer->start(QApplication::doubleClickInterval(), true);
+ }
+ if (i && vp.x() + contentsX() < itemMargin() + (i->depth() + (rootIsDecorated() ? 1 : 0)) * treeStepSize())
+ i = 0;
+ emitClicked = emitClicked && d->pressedItem == i;
+ d->pressedItem = 0;
+
+ if (emitClicked) {
+ if (!i || (i && i->isEnabled())) {
+ emit clicked(i);
+ emit clicked(i, viewport()->mapToGlobal(vp), d->h->mapToLogical(d->h->cellAt(vp.x())));
+ }
+ emit mouseButtonClicked(e->button(), i, viewport()->mapToGlobal(vp),
+ i ? d->h->mapToLogical(d->h->cellAt(vp.x())) : -1);
+
+ if (e->button() == Qt::RightButton) {
+ if (!i) {
+ if (!(e->state() & Qt::ControlButton))
+ clearSelection();
+ emit rightButtonClicked(0, viewport()->mapToGlobal(vp), -1);
+ return;
+ }
+
+ int c = d->h->mapToLogical(d->h->cellAt(vp.x()));
+ emit rightButtonClicked(i, viewport()->mapToGlobal(vp), c);
+ }
+ }
+}
+
+
+/*!
+ Processes the mouse double-click event \a e on behalf of the viewed widget.
+*/
+void Q3ListView::contentsMouseDoubleClickEvent(QMouseEvent * e)
+{
+ d->renameTimer->stop();
+ d->startEdit = false;
+ if (!e || e->button() != Qt::LeftButton)
+ return;
+
+ // ensure that the following mouse moves and eventual release is
+ // ignored.
+ d->buttonDown = false;
+
+ if (d->ignoreDoubleClick) {
+ d->ignoreDoubleClick = false;
+ return;
+ }
+
+ QPoint vp = contentsToViewport(e->pos());
+
+ Q3ListViewItem * i = itemAt(vp);
+
+ // we emit doubleClicked when the item is null (or enabled) to be consistent with
+ // rightButtonClicked etc.
+ if (!i || i->isEnabled()) {
+ int c = d->h->mapToLogical(d->h->cellAt(vp.x()));
+ emit doubleClicked(i, viewport()->mapToGlobal(vp), c);
+ }
+
+ if (!i || !i->isEnabled())
+ return;
+
+ if (!i->isOpen()) {
+ if (i->isExpandable() || i->childCount())
+ setOpen(i, true);
+ } else {
+ setOpen(i, false);
+ }
+
+ // we emit the 'old' obsolete doubleClicked only if the item is not null and enabled
+ emit doubleClicked(i);
+}
+
+
+/*!
+ Processes the mouse move event \a e on behalf of the viewed widget.
+*/
+void Q3ListView::contentsMouseMoveEvent(QMouseEvent * e)
+{
+ if (!e)
+ return;
+
+ bool needAutoScroll = false;
+
+ QPoint vp = contentsToViewport(e->pos());
+
+ Q3ListViewItem * i = itemAt(vp);
+ if (i && !i->isEnabled())
+ return;
+ if (i != d->highlighted &&
+ !(d->pressedItem &&
+ (d->pressedItem->isSelected() || d->selectionMode == NoSelection) &&
+ d->pressedItem->dragEnabled())) {
+
+ if (i) {
+ emit onItem(i);
+ } else {
+ emit onViewport();
+ }
+ d->highlighted = i;
+ }
+
+ if (d->startDragItem)
+ i = d->startDragItem;
+
+ if (!d->buttonDown ||
+ ((e->state() & Qt::LeftButton) != Qt::LeftButton &&
+ (e->state() & Qt::MidButton) != Qt::MidButton &&
+ (e->state() & Qt::RightButton) != Qt::RightButton))
+ return;
+
+ if (d->pressedItem &&
+ (d->pressedItem->isSelected() || d->selectionMode == NoSelection) &&
+ d->pressedItem->dragEnabled()) {
+
+ if (!d->startDragItem) {
+ setSelected(d->pressedItem, true);
+ d->startDragItem = d->pressedItem;
+ }
+ if ((d->dragStartPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) {
+ d->buttonDown = false;
+#ifndef QT_NO_DRAGANDDROP
+ startDrag();
+#endif
+ }
+ return;
+ }
+
+ // check, if we need to scroll
+ if (vp.y() > visibleHeight() || vp.y() < 0)
+ needAutoScroll = true;
+
+ // if we need to scroll and no autoscroll timer is started,
+ // connect the timer
+ if (needAutoScroll && !d->scrollTimer) {
+ d->scrollTimer = new QTimer(this);
+ connect(d->scrollTimer, SIGNAL(timeout()),
+ this, SLOT(doAutoScroll()));
+ d->scrollTimer->start(100, false);
+ // call it once manually
+ doAutoScroll(vp);
+ }
+
+ // if we don't need to autoscroll
+ if (!needAutoScroll) {
+ // if there is a autoscroll timer, delete it
+ if (d->scrollTimer) {
+ disconnect(d->scrollTimer, SIGNAL(timeout()),
+ this, SLOT(doAutoScroll()));
+ d->scrollTimer->stop();
+ delete d->scrollTimer;
+ d->scrollTimer = 0;
+ }
+ // call this to select an item (using the pos from the event)
+ doAutoScroll(vp);
+ }
+}
+
+
+/*!
+ This slot handles auto-scrolling when the mouse button is pressed
+ and the mouse is outside the widget.
+*/
+void Q3ListView::doAutoScroll()
+{
+ doAutoScroll(QPoint());
+}
+
+/*
+ Handles auto-scrolling when the mouse button is pressed
+ and the mouse is outside the widget.
+
+ If cursorPos is (0,0) (isNull == true) it uses the current QCursor::pos, otherwise it uses cursorPos
+*/
+void Q3ListView::doAutoScroll(const QPoint &cursorPos)
+{
+ QPoint pos = cursorPos.isNull() ? viewport()->mapFromGlobal(QCursor::pos()) : cursorPos;
+ if (!d->focusItem || (d->pressedEmptyArea && pos.y() > contentsHeight()))
+ return;
+
+ bool down = pos.y() > itemRect(d->focusItem).y();
+
+ int g = pos.y() + contentsY();
+
+ if (down && pos.y() > height() )
+ g = height() + contentsY();
+ else if (pos.y() < 0)
+ g = contentsY();
+
+ Q3ListViewItem *c = d->focusItem, *old = 0;
+ Q3ListViewItem *oldCurrent = c;
+ if (down) {
+ int y = itemRect(d->focusItem).y() + contentsY();
+ while(c && y + c->height() <= g) {
+ y += c->height();
+ old = c;
+ c = c->itemBelow();
+ }
+ if (!c && old)
+ c = old;
+ } else {
+ int y = itemRect(d->focusItem).y() + contentsY();
+ while(c && y >= g) {
+ old = c;
+ c = c->itemAbove();
+ if (c)
+ y -= c->height();
+ }
+ if (!c && old)
+ c = old;
+ }
+
+ if (!c || c == d->focusItem)
+ return;
+
+ if (d->focusItem) {
+ if (d->selectionMode == Multi) {
+ // also (de)select the ones in between
+ Q3ListViewItem * b = d->focusItem;
+ bool down = (itemPos(c) > itemPos(b));
+ while(b && b != c) {
+ if (b->isSelectable())
+ setSelected(b, d->select);
+ b = down ? b->itemBelow() : b->itemAbove();
+ }
+ if (c->isSelectable())
+ setSelected(c, d->select);
+ } else if (d->selectionMode == Extended) {
+ if (selectRange(c, oldCurrent, d->selectAnchor)) {
+ triggerUpdate();
+ emit selectionChanged();
+ }
+ }
+ }
+
+ setCurrentItem(c);
+ d->visibleTimer->start(1, true);
+}
+
+/*!
+ \reimp
+*/
+
+void Q3ListView::focusInEvent(QFocusEvent *e)
+{
+ d->inMenuMode = false;
+ if (d->focusItem) {
+ repaintItem(d->focusItem);
+ } else if (firstChild() && e->reason() != Qt::MouseFocusReason) {
+ d->focusItem = firstChild();
+ emit currentChanged(d->focusItem);
+ repaintItem(d->focusItem);
+ }
+ if (e->reason() == Qt::MouseFocusReason) {
+ d->ignoreEditAfterFocus = true;
+ d->startEdit = false;
+ }
+ if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this)) {
+ viewport()->repaint();
+ }
+}
+
+/*!
+ \reimp
+*/
+QVariant Q3ListView::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ if (query == Qt::ImMicroFocus) {
+ QRect mfrect = itemRect(d->focusItem);
+ if (mfrect.isValid() && header() && header()->isVisible())
+ mfrect.moveBy(0, header()->height());
+ return mfrect;
+ }
+ return QWidget::inputMethodQuery(query);
+}
+
+/*!
+ \reimp
+*/
+
+void Q3ListView::focusOutEvent(QFocusEvent *e)
+{
+ if (e->reason() == Qt::PopupFocusReason && d->buttonDown)
+ d->buttonDown = false;
+ if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this)) {
+ d->inMenuMode =
+ e->reason() == Qt::PopupFocusReason
+ || (qApp->focusWidget() && qApp->focusWidget()->inherits("QMenuBar"));
+ if (!d->inMenuMode) {
+ viewport()->repaint();
+ }
+ }
+
+ if (d->focusItem)
+ repaintItem(d->focusItem);
+}
+
+
+/*!
+ \reimp
+*/
+
+void Q3ListView::keyPressEvent(QKeyEvent * e)
+{
+ if (currentItem() && currentItem()->renameBox)
+ return;
+ if (!firstChild()) {
+ e->ignore();
+ return; // subclass bug
+ }
+
+ Q3ListViewItem* oldCurrent = currentItem();
+ if (!oldCurrent) {
+ setCurrentItem(firstChild());
+ if (d->selectionMode == Single)
+ setSelected(firstChild(), true);
+ return;
+ }
+
+ Q3ListViewItem * i = currentItem();
+ Q3ListViewItem *old = i;
+
+ QRect r(itemRect(i));
+ Q3ListViewItem * i2;
+
+ bool singleStep = false;
+ bool selectCurrent = true;
+ bool wasNavigation = true;
+
+ switch(e->key()) {
+ case Qt::Key_Backspace:
+ case Qt::Key_Delete:
+ d->currentPrefix.truncate(0);
+ break;
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ d->currentPrefix.truncate(0);
+ if (i && !i->isSelectable() && i->isEnabled() &&
+ (i->childCount() || i->isExpandable() || i->isOpen())) {
+ i->setOpen(!i->isOpen());
+ return;
+ }
+ e->ignore();
+ if (currentItem() && !currentItem()->isEnabled())
+ break;
+ emit returnPressed(currentItem());
+ // do NOT accept. QDialog.
+ return;
+ case Qt::Key_Down:
+ selectCurrent = false;
+ i = i->itemBelow();
+ d->currentPrefix.truncate(0);
+ singleStep = true;
+ break;
+ case Qt::Key_Up:
+ selectCurrent = false;
+ i = i->itemAbove();
+ d->currentPrefix.truncate(0);
+ singleStep = true;
+ break;
+ case Qt::Key_Home:
+ selectCurrent = false;
+ i = firstChild();
+ if (!i->height() || !i->isEnabled())
+ i = i->itemBelow();
+ d->currentPrefix.truncate(0);
+ break;
+ case Qt::Key_End:
+ selectCurrent = false;
+ i = firstChild();
+ while (i->nextSibling() && i->nextSibling()->height() && i->nextSibling()->isEnabled())
+ i = i->nextSibling();
+ while (i->itemBelow())
+ i = i->itemBelow();
+ d->currentPrefix.truncate(0);
+ break;
+ case Qt::Key_Next:
+ selectCurrent = false;
+ i2 = itemAt(QPoint(0, visibleHeight()-1));
+ if (i2 == i || !r.isValid() ||
+ visibleHeight() <= itemRect(i).bottom()) {
+ if (i2)
+ i = i2;
+ int left = visibleHeight();
+ while((i2 = i->itemBelow()) != 0 && left > i2->height()) {
+ left -= i2->height();
+ i = i2;
+ }
+ } else {
+ if (!i2) {
+ // list is shorter than the view, goto last item
+ while((i2 = i->itemBelow()) != 0)
+ i = i2;
+ } else {
+ i = i2;
+ }
+ }
+ d->currentPrefix.truncate(0);
+ break;
+ case Qt::Key_Prior:
+ selectCurrent = false;
+ i2 = itemAt(QPoint(0, 0));
+ if (i == i2 || !r.isValid() || r.top() <= 0) {
+ if (i2)
+ i = i2;
+ int left = visibleHeight();
+ while((i2 = i->itemAbove()) != 0 && left > i2->height()) {
+ left -= i2->height();
+ i = i2;
+ }
+ } else {
+ i = i2;
+ }
+ d->currentPrefix.truncate(0);
+ break;
+ case Qt::Key_Plus:
+ d->currentPrefix.truncate(0);
+ if ( !i->isOpen() && (i->isExpandable() || i->childCount()))
+ setOpen(i, true);
+ else
+ return;
+ break;
+ case Qt::Key_Right:
+ d->currentPrefix.truncate(0);
+ if (i->isOpen() && i->childItem) {
+ i = i->childItem;
+ } else if (!i->isOpen() && (i->isExpandable() || i->childCount())) {
+ setOpen(i, true);
+ } else if (contentsX() + visibleWidth() < contentsWidth()) {
+ horizontalScrollBar()->triggerAction(QScrollBar::SliderSingleStepAdd);
+ return;
+ } else {
+ return;
+ }
+ break;
+ case Qt::Key_Minus:
+ d->currentPrefix.truncate(0);
+ if (i->isOpen())
+ setOpen(i, false);
+ else
+ return;
+ break;
+ case Qt::Key_Left:
+ d->currentPrefix.truncate(0);
+ if (i->isOpen()) {
+ setOpen(i, false);
+ } else if (i->parentItem && i->parentItem != d->r) {
+ i = i->parentItem;
+ } else if (contentsX()) {
+ horizontalScrollBar()->triggerAction(QScrollBar::SliderSingleStepSub);
+ return;
+ } else {
+ return;
+ }
+ break;
+ case Qt::Key_Space:
+ activatedByClick = false;
+ d->currentPrefix.truncate(0);
+ if (currentItem() && !currentItem()->isEnabled())
+ break;
+ i->activate();
+ if (i->isSelectable() && (d->selectionMode == Multi || d->selectionMode == Extended)) {
+ setSelected(i, !i->isSelected());
+ d->currentPrefix.truncate(0);
+ }
+ emit spacePressed(currentItem());
+ break;
+ case Qt::Key_Escape:
+ e->ignore(); // For QDialog
+ return;
+ case Qt::Key_F2:
+ if (currentItem() && currentItem()->renameEnabled(0))
+ currentItem()->startRename(0);
+ default:
+ if (e->text().length() > 0 && e->text()[0].isPrint()) {
+ selectCurrent = false;
+ wasNavigation = false;
+ QString input(d->currentPrefix);
+ Q3ListViewItem * keyItem = i;
+ QTime now(QTime::currentTime());
+ bool tryFirst = true;
+ while(keyItem) {
+ // try twice, first with the previous string and this char
+ if (d->currentPrefixTime.msecsTo(now) <= 400)
+ input = input + e->text().toLower();
+ else
+ input = e->text().toLower();
+ if (input.length() == e->text().length()) {
+ if (keyItem->itemBelow()) {
+ keyItem = keyItem->itemBelow();
+ tryFirst = true;
+ } else {
+ keyItem = firstChild();
+ tryFirst = false;
+ }
+ }
+ QString keyItemKey;
+ QString prefix;
+ while(keyItem) {
+ keyItemKey = QString::null;
+ // Look first in the sort column, then left to right
+ if (d->sortcolumn != Unsorted)
+ keyItemKey = keyItem->text(d->sortcolumn);
+ for (int col = 0; col < d->h->count() && keyItemKey.isNull(); ++col)
+ keyItemKey = keyItem->text(d->h->mapToSection(col));
+ if (!keyItemKey.isEmpty()) {
+ prefix = keyItemKey;
+ prefix.truncate(input.length());
+ prefix = prefix.toLower();
+ if (prefix == input) {
+ d->currentPrefix = input;
+ d->currentPrefixTime = now;
+ i = keyItem;
+ // nonoptimal double-break...
+ keyItem = 0;
+ input.truncate(0);
+ tryFirst = false;
+ }
+ }
+ if (keyItem)
+ keyItem = keyItem->itemBelow();
+ if (!keyItem && tryFirst) {
+ keyItem = firstChild();
+ tryFirst = false;
+ }
+ }
+ // then, if appropriate, with just this character
+ if (input.length() > e->text().length()) {
+ input.truncate(0);
+ keyItem = i;
+ }
+ }
+ } else {
+ d->currentPrefix.truncate(0);
+ if (e->state() & Qt::ControlButton) {
+ d->currentPrefix.clear();
+ switch (e->key()) {
+ case Qt::Key_A:
+ selectAll(true);
+ break;
+ }
+ }
+ e->ignore();
+ return;
+ }
+ }
+
+ if (!i)
+ return;
+
+ if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
+ d->selectAnchor = i;
+
+ setCurrentItem(i);
+ if (i->isSelectable())
+ handleItemChange(old, wasNavigation && (e->state() & Qt::ShiftButton),
+ wasNavigation && (e->state() & Qt::ControlButton));
+
+ if (d->focusItem && !d->focusItem->isSelected() && d->selectionMode == Single && selectCurrent)
+ setSelected(d->focusItem, true);
+
+ if (singleStep)
+ d->visibleTimer->start(1, true);
+ else
+ ensureItemVisible(i);
+}
+
+
+/*!
+ Returns the list view item at \a viewPos. Note that \a viewPos is
+ in the viewport()'s coordinate system, not in the list view's own,
+ much larger, coordinate system.
+
+ itemAt() returns 0 if there is no such item.
+
+ Note that you also get the pointer to the item if \a viewPos
+ points to the root decoration (see setRootIsDecorated()) of the
+ item. To check whether or not \a viewPos is on the root decoration
+ of the item, you can do something like this:
+
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 4
+
+ This might be interesting if you use this function to find out
+ where the user clicked and if you want to start a drag (which you
+ do not want to do if the user clicked onto the root decoration of
+ an item).
+
+ \sa itemPos() itemRect() viewportToContents()
+*/
+
+Q3ListViewItem * Q3ListView::itemAt(const QPoint & viewPos) const
+{
+ if (viewPos.x() > contentsWidth() - contentsX())
+ return 0;
+
+ if (d->drawables.isEmpty())
+ buildDrawableList();
+
+ int g = viewPos.y() + contentsY();
+
+ for (int i = 0; i < d->drawables.size(); ++i) {
+ Q3ListViewPrivate::DrawableItem c = d->drawables.at(i);
+ if (c.y + c.i->height() > g
+ && c.i->isVisible() && (!c.i->parent() || c.i->parent()->isVisible()))
+ return c.y <= g ? c.i : 0;
+ }
+ return 0;
+}
+
+
+/*!
+ Returns the y-coordinate of \a item in the list view's coordinate
+ system. This function is normally much slower than itemAt() but it
+ works for all items, whereas itemAt() normally works only for
+ items on the screen.
+
+ This is a thin wrapper around Q3ListViewItem::itemPos().
+
+ \sa itemAt() itemRect()
+*/
+
+int Q3ListView::itemPos(const Q3ListViewItem * item)
+{
+ return item ? item->itemPos() : 0;
+}
+
+
+/*!
+ \property Q3ListView::multiSelection
+ \brief whether the list view is in multi-selection or extended-selection mode
+
+ If you enable multi-selection, \c Multi, mode, it is possible to
+ specify whether or not this mode should be extended. \c Extended
+ means that the user can select multiple items only when pressing
+ the Shift or Ctrl key at the same time.
+
+ The default selection mode is \c Single.
+
+ \sa selectionMode()
+*/
+
+void Q3ListView::setMultiSelection(bool enable)
+{
+ if (!enable)
+ d->selectionMode = Q3ListView::Single;
+ else if ( d->selectionMode != Multi && d->selectionMode != Extended)
+ d->selectionMode = Q3ListView::Multi;
+}
+
+bool Q3ListView::isMultiSelection() const
+{
+ return d->selectionMode == Q3ListView::Extended || d->selectionMode == Q3ListView::Multi;
+}
+
+/*!
+ \property Q3ListView::selectionMode
+ \brief the list view's selection mode
+
+ The mode can be \c Single (the default), \c Extended, \c Multi or
+ \c NoSelection.
+
+ \sa multiSelection
+*/
+
+void Q3ListView::setSelectionMode(SelectionMode mode)
+{
+ if (d->selectionMode == mode)
+ return;
+
+ if ((d->selectionMode == Multi || d->selectionMode == Extended) &&
+ (mode == Q3ListView::Single || mode == Q3ListView::NoSelection)){
+ clearSelection();
+ if ((mode == Q3ListView::Single) && currentItem())
+ currentItem()->selected = true;
+ }
+
+ d->selectionMode = mode;
+}
+
+Q3ListView::SelectionMode Q3ListView::selectionMode() const
+{
+ return d->selectionMode;
+}
+
+
+/*!
+ If \a selected is true the \a item is selected; otherwise it is
+ unselected.
+
+ If the list view is in \c Single selection mode and \a selected is
+ true, the currently selected item is unselected and \a item is
+ made current. Unlike Q3ListViewItem::setSelected(), this function
+ updates the list view as necessary and emits the
+ selectionChanged() signals.
+
+ \sa isSelected() setMultiSelection() isMultiSelection()
+ setCurrentItem(), setSelectionAnchor()
+*/
+
+void Q3ListView::setSelected(Q3ListViewItem * item, bool selected)
+{
+ if (!item || item->isSelected() == selected ||
+ !item->isSelectable() || selectionMode() == NoSelection)
+ return;
+
+ bool emitHighlighted = false;
+ if (selectionMode() == Single && d->focusItem != item) {
+ Q3ListViewItem *o = d->focusItem;
+ if (d->focusItem && d->focusItem->selected)
+ d->focusItem->setSelected(false);
+ d->focusItem = item;
+ if (o)
+ repaintItem(o);
+ emitHighlighted = true;
+ }
+
+ item->setSelected(selected);
+
+ repaintItem(item);
+
+ if (d->selectionMode == Single && selected)
+ emit selectionChanged(item);
+ emit selectionChanged();
+
+ if (emitHighlighted)
+ emit currentChanged(d->focusItem);
+}
+
+/*!
+ Sets the selection anchor to \a item, if \a item is selectable.
+
+ The selection anchor is the item that remains selected when
+ Shift-selecting with either mouse or keyboard in \c Extended
+ selection mode.
+
+ \sa setSelected()
+*/
+
+void Q3ListView::setSelectionAnchor(Q3ListViewItem *item)
+{
+ if (item && item->isSelectable())
+ d->selectAnchor = item;
+}
+
+/*!
+ Sets all the items to be not selected, updates the list view as
+ necessary, and emits the selectionChanged() signals. Note that for
+ \c Multi selection list views this function needs to iterate over
+ \e all items.
+
+ \sa setSelected(), setMultiSelection()
+*/
+
+void Q3ListView::clearSelection()
+{
+ selectAll(false);
+}
+
+/*!
+ If \a select is true, all the items get selected; otherwise all
+ the items get unselected. This only works in the selection modes \c
+ Multi and \c Extended. In \c Single and \c NoSelection mode the
+ selection of the current item is just set to \a select.
+*/
+
+void Q3ListView::selectAll(bool select)
+{
+ if (d->selectionMode == Multi || d->selectionMode == Extended) {
+ bool b = signalsBlocked();
+ blockSignals(true);
+ bool anything = false;
+ Q3ListViewItemIterator it(this);
+ while (it.current()) {
+ Q3ListViewItem *i = it.current();
+ if ((bool)i->selected != select) {
+ i->setSelected(select);
+ anything = true;
+ }
+ ++it;
+ }
+ blockSignals(b);
+ if (anything) {
+ emit selectionChanged();
+ triggerUpdate();
+ }
+ } else if (d->focusItem) {
+ Q3ListViewItem * i = d->focusItem;
+ setSelected(i, select);
+ }
+}
+
+/*!
+ Inverts the selection. Only works in \c Multi and \c Extended
+ selection modes.
+*/
+
+void Q3ListView::invertSelection()
+{
+ if (d->selectionMode == Single ||
+ d->selectionMode == NoSelection)
+ return;
+
+ bool b = signalsBlocked();
+ blockSignals(true);
+ Q3ListViewItemIterator it(this);
+ for (; it.current(); ++it)
+ it.current()->setSelected(!it.current()->isSelected());
+ blockSignals(b);
+ emit selectionChanged();
+ triggerUpdate();
+}
+
+
+/*!
+ Returns true if the list view item \a i is selected; otherwise
+ returns false.
+
+ \sa Q3ListViewItem::isSelected()
+*/
+
+bool Q3ListView::isSelected(const Q3ListViewItem * i) const
+{
+ return i ? i->isSelected() : false;
+}
+
+
+/*!
+ Returns the selected item if the list view is in \c Single
+ selection mode and an item is selected.
+
+ If no items are selected or the list view is not in \c Single
+ selection mode this function returns 0.
+
+ \sa setSelected() setMultiSelection()
+*/
+
+Q3ListViewItem * Q3ListView::selectedItem() const
+{
+ if (d->selectionMode != Single)
+ return 0;
+ if (d->focusItem && d->focusItem->isSelected())
+ return d->focusItem;
+ return 0;
+}
+
+
+/*!
+ Sets item \a i to be the current item and repaints appropriately
+ (i.e. highlights the item). The current item is used for keyboard
+ navigation and focus indication; it is independent of any selected
+ items, although a selected item can also be the current item.
+
+ \sa currentItem() setSelected()
+*/
+
+void Q3ListView::setCurrentItem(Q3ListViewItem * i)
+{
+ if (!i || d->focusItem == i || !i->isEnabled())
+ return;
+
+ if (currentItem() && currentItem()->renameBox) {
+ if (d->defRenameAction == Reject)
+ currentItem()->cancelRename(currentItem()->renameCol);
+ else
+ currentItem()->okRename(currentItem()->renameCol);
+ }
+
+ Q3ListViewItem * prev = d->focusItem;
+ d->focusItem = i;
+
+ if (i != prev) {
+ if (i && d->selectionMode == Single) {
+ bool changed = false;
+ if (prev && prev->selected) {
+ changed = true;
+ prev->setSelected(false);
+ }
+ if (i && !i->selected && d->selectionMode != NoSelection && i->isSelectable()) {
+ i->setSelected(true);
+ changed = true;
+ emit selectionChanged(i);
+ }
+ if (changed)
+ emit selectionChanged();
+ }
+
+ if (i)
+ repaintItem(i);
+ if (prev)
+ repaintItem(prev);
+ emit currentChanged(i);
+
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), indexOfItem(i), QAccessible::Focus);
+#endif
+ }
+}
+
+
+/*!
+ Returns the current item, or 0 if there isn't one.
+
+ \sa setCurrentItem()
+*/
+
+Q3ListViewItem * Q3ListView::currentItem() const
+{
+ return d->focusItem;
+}
+
+
+/*!
+ Returns the rectangle on the screen that item \a item occupies in
+ viewport()'s coordinates, or an invalid rectangle if \a item is 0 or
+ is not currently visible.
+
+ The rectangle returned does not include any children of the
+ rectangle (i.e. it uses Q3ListViewItem::height(), rather than
+ Q3ListViewItem::totalHeight()). If you want the rectangle to
+ include children you can use something like this:
+
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 5
+
+ Note the way it avoids too-high rectangles. totalHeight() can be
+ much larger than the window system's coordinate system allows.
+
+ itemRect() is comparatively slow. It's best to call it only for
+ items that are probably on-screen.
+*/
+
+QRect Q3ListView::itemRect(const Q3ListViewItem * item) const
+{
+ if (d->drawables.isEmpty())
+ buildDrawableList();
+
+ for (int i = 0; i < d->drawables.size(); ++i) {
+ const Q3ListViewPrivate::DrawableItem &c = d->drawables.at(i);
+ if (c.i == item) {
+ int y = c.y - contentsY();
+ if (y + c.i->height() >= 0 && y < ((Q3ListView *)this)->visibleHeight()) {
+ return QRect(-contentsX(), y, d->h->width(), c.i->height());;
+ }
+ }
+ }
+
+ return QRect(0, 0, -1, -1);
+}
+
+
+/*!
+ \fn void Q3ListView::doubleClicked(Q3ListViewItem *item)
+
+ This signal is emitted whenever an item is double-clicked. It's
+ emitted on the second button press, not the second button release.
+ \a item is the list view item on which the user did the
+ double-click.
+*/
+
+/*!
+ \fn void Q3ListView::doubleClicked(Q3ListViewItem *item, const
+ QPoint& point, int column)
+
+ This signal is emitted when a double-click occurs. It's emitted on
+ the second button press, not the second button release. The \a
+ item is the Q3ListViewItem the button was double-clicked on (which
+ could be 0 if it wasn't double-clicked on an item). The \a point
+ where the double-click occurred is given in global coordinates. If
+ an item was double-clicked on, \a column is the column within the
+ item that was double-clicked; otherwise \a column is -1.
+
+ \warning Do not delete any Q3ListViewItem objects in slots
+ connected to this signal.
+*/
+
+
+/*!
+ \fn void Q3ListView::returnPressed(Q3ListViewItem *item)
+
+ This signal is emitted when Enter or Return is pressed. The
+ \a item parameter is the currentItem().
+*/
+
+/*!
+ \fn void Q3ListView::spacePressed(Q3ListViewItem *item)
+
+ This signal is emitted when Space is pressed. The \a item
+ parameter is the currentItem().
+*/
+
+
+/*!
+ Sets the list view to be sorted by column \a column in ascending
+ order if \a ascending is true or descending order if it is false.
+
+ If \a column is -1, sorting is disabled and the user cannot sort
+ columns by clicking on the column headers. If \a column is larger
+ than the number of columns the user must click on a column
+ header to sort the list view.
+*/
+
+void Q3ListView::setSorting(int column, bool ascending)
+{
+ if (column == -1)
+ column = Unsorted;
+
+ if (d->sortcolumn == column && d->ascending == ascending)
+ return;
+
+ d->ascending = ascending;
+ d->sortcolumn = column;
+ if (d->sortcolumn != Unsorted && d->sortIndicator)
+ d->h->setSortIndicator(d->sortcolumn, d->ascending);
+ else
+ d->h->setSortIndicator(-1);
+
+ triggerUpdate();
+
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), 0, QAccessible::ObjectReorder);
+#endif
+}
+
+/*!
+ Sets the \a column the list view is sorted by.
+
+ Sorting is triggered by choosing a header section.
+*/
+
+void Q3ListView::changeSortColumn(int column)
+{
+ if (isRenaming()) {
+ if (d->defRenameAction == Q3ListView::Reject) {
+ currentItem()->cancelRename(currentItem()->renameCol);
+ } else {
+ currentItem()->okRename(currentItem()->renameCol);
+ }
+ }
+ if (d->sortcolumn != Unsorted) {
+ int lcol = d->h->mapToLogical(column);
+ setSorting(lcol, d->sortcolumn == lcol ? !d->ascending : true);
+ }
+}
+
+/*!
+ \internal
+ Handles renaming when sections are being swapped by the user.
+*/
+
+void Q3ListView::handleIndexChange()
+{
+ if (isRenaming()) {
+ if (d->defRenameAction == Q3ListView::Reject) {
+ currentItem()->cancelRename(currentItem()->renameCol);
+ } else {
+ currentItem()->okRename(currentItem()->renameCol);
+ }
+ }
+ triggerUpdate();
+}
+
+/*!
+ Returns the column by which the list view is sorted, or -1 if
+ sorting is disabled.
+
+ \sa sortOrder()
+*/
+
+int Q3ListView::sortColumn() const
+{
+ return d->sortcolumn;
+}
+
+/*!
+ Sets the sorting column for the list view.
+
+ If \a column is -1, sorting is disabled and the user cannot sort
+ columns by clicking on the column headers. If \a column is larger
+ than the number of columns the user must click on a column header
+ to sort the list view.
+
+ \sa setSorting()
+*/
+void Q3ListView::setSortColumn(int column)
+{
+ setSorting(column, d->ascending);
+}
+
+/*!
+ Returns the sorting order of the list view items.
+
+ \sa sortColumn()
+*/
+Qt::SortOrder Q3ListView::sortOrder() const
+{
+ if (d->ascending)
+ return Qt::AscendingOrder;
+ return Qt::DescendingOrder;
+}
+
+/*!
+ Sets the sort order for the items in the list view to \a order.
+
+ \sa setSorting()
+*/
+void Q3ListView::setSortOrder(Qt::SortOrder order)
+{
+ setSorting(d->sortcolumn, order == Qt::AscendingOrder ? true : false);
+}
+
+/*!
+ Sorts the list view using the last sorting configuration (sort
+ column and ascending/descending).
+*/
+
+void Q3ListView::sort()
+{
+ if (d->r)
+ d->r->sort();
+}
+
+/*!
+ \property Q3ListView::itemMargin
+ \brief the advisory item margin that list items may use
+
+ The item margin defaults to one pixel and is the margin between
+ the item's edges and the area where it draws its contents.
+ Q3ListViewItem::paintFocus() draws in the margin.
+
+ \sa Q3ListViewItem::paintCell()
+*/
+
+void Q3ListView::setItemMargin(int m)
+{
+ if (d->margin == m)
+ return;
+ d->margin = m;
+ if (isVisible()) {
+ d->drawables.clear();
+ triggerUpdate();
+ }
+}
+
+int Q3ListView::itemMargin() const
+{
+ return d->margin;
+}
+
+
+/*!
+ \fn void Q3ListView::rightButtonClicked(Q3ListViewItem *item,
+ const QPoint& point, int column)
+
+ This signal is emitted when the right button is clicked. The \a
+ item is the Q3ListViewItem the button was clicked on (which could
+ be 0 if it wasn't clicked on an item). The \a point where the
+ click occurred is given in global coordinates. If an item was
+ clicked on, \a column is the column within the item that was
+ clicked; otherwise \a column is -1.
+*/
+
+
+/*!
+ \fn void Q3ListView::rightButtonPressed (Q3ListViewItem *item,
+ const QPoint &point, int column)
+
+ This signal is emitted when the right button is pressed. The \a
+ item is the Q3ListViewItem the button was pressed on (which could
+ be 0 if it wasn't pressed on an item). The \a point where the
+ press occurred is given in global coordinates. If an item was
+ pressed on, \a column is the column within the item that was
+ pressed; otherwise \a column is -1.
+*/
+
+/*!
+ \fn void Q3ListView::contextMenuRequested(Q3ListViewItem *item, const QPoint & pos, int col)
+
+ This signal is emitted when the user invokes a context menu with
+ the right mouse button or with special system keys. If the
+ keyboard was used \a item is the current item; if the mouse was
+ used, \a item is the item under the mouse pointer or 0 if there is
+ no item under the mouse pointer. If no item is clicked, the column
+ index emitted is -1.
+
+ \a pos is the position for the context menu in the global
+ coordinate system.
+
+ \a col is the column on which the user pressed, or -1 if the
+ signal was triggered by a key event.
+*/
+
+/*!
+ \reimp
+*/
+void Q3ListView::changeEvent(QEvent *ev)
+{
+ if(ev->type() == QEvent::StyleChange) {
+ reconfigureItems();
+ } else if(ev->type() == QEvent::ActivationChange) {
+ if (!isActiveWindow() && d->scrollTimer)
+ d->scrollTimer->stop();
+ if (!palette().isEqual(QPalette::Active, QPalette::Inactive))
+ viewport()->update();
+ }
+ Q3ScrollView::changeEvent(ev);
+
+ if (ev->type() == QEvent::ApplicationFontChange || ev->type() == QEvent::FontChange
+ || ev->type() == QEvent::ApplicationPaletteChange || ev->type() == QEvent::PaletteChange)
+ reconfigureItems();
+}
+
+/*!
+ Ensures that setup() is called for all currently visible items,
+ and that it will be called for currently invisible items as soon
+ as their parents are opened.
+
+ (A visible item, here, is an item whose parents are all open. The
+ item may happen to be off-screen.)
+
+ \sa Q3ListViewItem::setup()
+*/
+
+void Q3ListView::reconfigureItems()
+{
+ d->fontMetricsHeight = fontMetrics().height();
+ d->minLeftBearing = fontMetrics().minLeftBearing();
+ d->minRightBearing = fontMetrics().minRightBearing();
+ d->ellipsisWidth = fontMetrics().width(QLatin1String("...")) * 2;
+ d->r->setOpen(false);
+ d->r->configured = false;
+ d->r->setOpen(true);
+}
+
+/*!
+ Ensures that the width mode of column \a c is updated according to
+ the width of \a item.
+*/
+
+void Q3ListView::widthChanged(const Q3ListViewItem* item, int c)
+{
+ if (c >= d->h->count())
+ return;
+
+
+ QFontMetrics fm = fontMetrics();
+ int col = c < 0 ? 0 : c;
+ while (col == c || (c < 0 && col < d->h->count())) {
+ if (d->column[col].wmode == Maximum) {
+ int w = item->width(fm, this, col);
+ if (showSortIndicator()) {
+ int tw = d->h->sectionSizeHint( col, fm ).width();
+ tw += 40; //add space for the sort indicator
+ w = qMax(w, tw);
+ }
+ if (col == 0) {
+ int indent = treeStepSize() * item->depth();
+ if (rootIsDecorated())
+ indent += treeStepSize();
+ w += indent;
+ }
+ if (w > columnWidth(col) && !d->h->isStretchEnabled() && !d->h->isStretchEnabled(col)) {
+ d->updateHeader = true;
+ setColumnWidth(col, w);
+ }
+ }
+ col++;
+ }
+}
+
+/*!
+ \property Q3ListView::allColumnsShowFocus
+ \brief whether items should show keyboard focus using all columns
+
+ If this property is true all columns will show focus and selection
+ states, otherwise only column 0 will show focus.
+
+ The default is false.
+
+ Setting this to true if it's not necessary may cause noticeable
+ flicker.
+*/
+
+void Q3ListView::setAllColumnsShowFocus(bool enable)
+{
+ d->allColumnsShowFocus = enable;
+}
+
+bool Q3ListView::allColumnsShowFocus() const
+{
+ return d->allColumnsShowFocus;
+}
+
+
+/*!
+ Returns the first item in this Q3ListView. Returns 0 if there is no
+ first item.
+
+ A list view's items can be traversed using firstChild()
+ and nextSibling() or using a Q3ListViewItemIterator.
+
+ \sa itemAt() Q3ListViewItem::itemBelow() Q3ListViewItem::itemAbove()
+*/
+
+Q3ListViewItem * Q3ListView::firstChild() const
+{
+ if (!d->r)
+ return 0;
+
+ d->r->enforceSortOrder();
+ return d->r->childItem;
+}
+
+/*!
+ Returns the last item in the list view tree. Returns 0 if there
+ are no items in the Q3ListView.
+
+ This function is slow because it traverses the entire tree to find
+ the last item.
+*/
+
+Q3ListViewItem* Q3ListView::lastItem() const
+{
+ Q3ListViewItem* item = firstChild();
+ if (item) {
+ while (item->nextSibling() || item->firstChild()) {
+ if (item->nextSibling())
+ item = item->nextSibling();
+ else
+ item = item->firstChild();
+ }
+ }
+ return item;
+}
+
+/*!
+ Repaints this item on the screen if it is currently visible.
+*/
+
+void Q3ListViewItem::repaint() const
+{
+ Q3ListView *lv = listView();
+ if (lv)
+ lv->repaintItem(this);
+}
+
+
+/*!
+ Repaints \a item on the screen if \a item is currently visible.
+ Takes care to avoid multiple repaints.
+*/
+
+void Q3ListView::repaintItem(const Q3ListViewItem * item) const
+{
+ if (!item)
+ return;
+ d->dirtyItemTimer->start(0, true);
+ d->dirtyItems.append(item);
+}
+
+
+struct Q3CheckListItemPrivate
+{
+ Q3CheckListItemPrivate():
+ exclusive(0),
+ currentState(Q3CheckListItem::Off),
+ tristate(false) {}
+
+ Q3CheckListItem *exclusive;
+ Q3CheckListItem::ToggleState currentState;
+ QHash<Q3CheckListItem *, Q3CheckListItem::ToggleState> statesDict;
+ bool tristate;
+};
+
+
+/*!
+ \class Q3CheckListItem
+ \brief The Q3CheckListItem class provides checkable list view items.
+
+ \compat
+
+ Q3CheckListItems are used in \l{Q3ListView}s to provide
+ \l{Q3ListViewItem}s that are checkboxes, radio buttons or
+ controllers.
+
+ Checkbox and controller check list items may be inserted at any
+ level in a list view. Radio button check list items must be
+ children of a controller check list item.
+
+ The item can be checked or unchecked with setOn(). Its type can be
+ retrieved with type() and its text retrieved with text().
+
+ \img qlistviewitems.png List View Items
+
+ \sa Q3ListViewItem Q3ListView
+*/
+
+/*!
+ \enum Q3CheckListItem::Type
+
+ This enum type specifies a Q3CheckListItem's type:
+
+ \value RadioButton
+ \value CheckBox
+ \value RadioButtonController
+ \value CheckBoxController
+ \omitvalue Controller
+*/
+
+/*!
+ \enum Q3CheckListItem::ToggleState
+
+ This enum specifies a Q3CheckListItem's toggle state.
+
+ \value Off
+ \value NoChange
+ \value On
+*/
+
+
+/*!
+ Constructs a checkable item with parent \a parent, text \a text
+ and of type \a tt. Note that a \c RadioButton must be the child of a
+ \c RadioButtonController, otherwise it will not toggle.
+*/
+Q3CheckListItem::Q3CheckListItem(Q3CheckListItem *parent, const QString &text,
+ Type tt)
+ : Q3ListViewItem(parent, text, QString())
+{
+ myType = tt;
+ init();
+ if (myType == RadioButton) {
+ if (parent->type() != RadioButtonController)
+ qWarning("Q3CheckListItem::Q3CheckListItem(), radio button must be "
+ "child of a controller");
+ else
+ d->exclusive = parent;
+ }
+}
+
+/*!
+ Constructs a checkable item with parent \a parent, which is after
+ \a after in the parent's list of children, and with text \a text
+ and of type \a tt. Note that a \c RadioButton must be the child of
+ a \c RadioButtonController, otherwise it will not toggle.
+*/
+Q3CheckListItem::Q3CheckListItem(Q3CheckListItem *parent, Q3ListViewItem *after,
+ const QString &text, Type tt)
+ : Q3ListViewItem(parent, after, text)
+{
+ myType = tt;
+ init();
+ if (myType == RadioButton) {
+ if (parent->type() != RadioButtonController)
+ qWarning("Q3CheckListItem::Q3CheckListItem(), radio button must be "
+ "child of a controller");
+ else
+ d->exclusive = parent;
+ }
+}
+
+/*!
+ Constructs a checkable item with parent \a parent, text \a text
+ and of type \a tt. Note that this item must \e not be a \c
+ RadioButton. Radio buttons must be children of a \c
+ RadioButtonController.
+*/
+Q3CheckListItem::Q3CheckListItem(Q3ListViewItem *parent, const QString &text,
+ Type tt)
+ : Q3ListViewItem(parent, text, QString())
+{
+ myType = tt;
+ if (myType == RadioButton) {
+ qWarning("Q3CheckListItem::Q3CheckListItem(), radio button must be "
+ "child of a Q3CheckListItem");
+ }
+ init();
+}
+
+/*!
+ Constructs a checkable item with parent \a parent, which is after
+ \a after in the parent's list of children, with text \a text and
+ of type \a tt. Note that this item must \e not be a \c
+ RadioButton. Radio buttons must be children of a \c
+ RadioButtonController.
+*/
+Q3CheckListItem::Q3CheckListItem(Q3ListViewItem *parent, Q3ListViewItem *after,
+ const QString &text, Type tt)
+ : Q3ListViewItem(parent, after, text)
+{
+ myType = tt;
+ if (myType == RadioButton) {
+ qWarning("Q3CheckListItem::Q3CheckListItem(), radio button must be "
+ "child of a Q3CheckListItem");
+ }
+ init();
+}
+
+
+/*!
+ Constructs a checkable item with parent \a parent, text \a text
+ and of type \a tt. Note that \a tt must \e not be \c RadioButton.
+ Radio buttons must be children of a \c RadioButtonController.
+*/
+Q3CheckListItem::Q3CheckListItem(Q3ListView *parent, const QString &text,
+ Type tt)
+ : Q3ListViewItem(parent, text)
+{
+ myType = tt;
+ if (tt == RadioButton)
+ qWarning("Q3CheckListItem::Q3CheckListItem(), radio button must be "
+ "child of a Q3CheckListItem");
+ init();
+}
+
+/*!
+ Constructs a checkable item with parent \a parent, which is after
+ \a after in the parent's list of children, with text \a text and
+ of type \a tt. Note that \a tt must \e not be \c RadioButton.
+ Radio buttons must be children of a \c RadioButtonController.
+*/
+Q3CheckListItem::Q3CheckListItem(Q3ListView *parent, Q3ListViewItem *after,
+ const QString &text, Type tt)
+ : Q3ListViewItem(parent, after, text)
+{
+ myType = tt;
+ if (tt == RadioButton)
+ qWarning("Q3CheckListItem::Q3CheckListItem(), radio button must be "
+ "child of a Q3CheckListItem");
+ init();
+}
+
+
+/* \reimp */
+
+int Q3CheckListItem::rtti() const
+{
+ return RTTI;
+}
+
+/*!
+ Constructs a \c RadioButtonController item with parent \a parent,
+ text \a text and pixmap \a p.
+*/
+Q3CheckListItem::Q3CheckListItem(Q3ListView *parent, const QString &text,
+ const QPixmap & p)
+ : Q3ListViewItem(parent, text)
+{
+ myType = RadioButtonController;
+ setPixmap(0, p);
+ init();
+}
+
+/*!
+ Constructs a \c RadioButtonController item with parent \a parent,
+ text \a text and pixmap \a p.
+*/
+Q3CheckListItem::Q3CheckListItem(Q3ListViewItem *parent, const QString &text,
+ const QPixmap & p)
+ : Q3ListViewItem(parent, text)
+{
+ myType = RadioButtonController;
+ setPixmap(0, p);
+ init();
+}
+
+void Q3CheckListItem::init()
+{
+ d = new Q3CheckListItemPrivate();
+ on = false;
+ // CheckBoxControllers by default have tristate set to true
+ if (myType == CheckBoxController)
+ setTristate(true);
+}
+
+/*!
+ Destroys the item, and all its children to any depth, freeing up
+ all allocated resources.
+*/
+Q3CheckListItem::~Q3CheckListItem()
+{
+ if (myType == RadioButton
+ && d->exclusive && d->exclusive->d
+ && d->exclusive->d->exclusive == this)
+ d->exclusive->turnOffChild();
+ d->exclusive = 0; // so the children won't try to access us.
+ delete d;
+ d = 0;
+}
+
+/*!
+ \fn Q3CheckListItem::Type Q3CheckListItem::type() const
+
+ Returns the type of this item.
+*/
+
+/*!
+ \fn bool Q3CheckListItem::isOn() const
+
+ Returns true if the item is toggled on; otherwise returns false.
+*/
+
+/*!
+ Sets tristate to \a b if the \c Type is either a \c CheckBoxController or
+ a \c CheckBox.
+
+ \c CheckBoxControllers are tristate by default.
+
+ \sa state() isTristate()
+*/
+void Q3CheckListItem::setTristate(bool b)
+{
+ if ((myType != CheckBoxController) && (myType != CheckBox)) {
+ qWarning("Q3CheckListItem::setTristate(), has no effect on RadioButton "
+ "or RadioButtonController.");
+ return;
+ }
+ d->tristate = b;
+}
+
+/*!
+ Returns true if the item is tristate; otherwise returns false.
+
+ \sa setTristate()
+*/
+bool Q3CheckListItem::isTristate() const
+{
+ return d->tristate;
+}
+
+/*!
+ Returns the state of the item.
+
+ \sa Q3CheckListItem::ToggleState
+*/
+Q3CheckListItem::ToggleState Q3CheckListItem::state() const
+{
+ if (!isTristate() && internalState() == NoChange)
+ return Off;
+ else
+ return d->currentState;
+}
+
+/*
+ Same as the public state() except this one does not mask NoChange into Off
+ when tristate is disabled.
+*/
+Q3CheckListItem::ToggleState Q3CheckListItem::internalState() const
+{
+ return d->currentState;
+}
+
+
+
+
+/*!
+ Sets the toggle state of the checklistitem to \a s. \a s can be
+ \c Off, \c NoChange or \c On.
+
+ Tristate can only be enabled for \c CheckBox or \c CheckBoxController,
+ therefore the \c NoChange only applies to them.
+
+ Setting the state to \c On or \c Off on a \c CheckBoxController
+ will recursivly set the states of its children to the same state.
+
+ Setting the state to \c NoChange on a \c CheckBoxController will
+ make it recursivly recall the previous stored state of its
+ children. If there was no previous stored state the children are
+ all set to \c On.
+*/
+void Q3CheckListItem::setState(ToggleState s)
+{
+ if (myType == CheckBoxController && state() == NoChange)
+ updateStoredState(this);
+ setState(s, true, true);
+}
+
+/*
+ Sets the toggle state of the checklistitems. \a update tells if the
+ controller / parent controller should be aware of these changes, \a store
+ tells if the parent should store its children if certain conditions arise
+*/
+void Q3CheckListItem::setState(ToggleState s, bool update, bool store)
+{
+
+ if (s == internalState())
+ return;
+
+ if (myType == CheckBox) {
+ setCurrentState(s);
+ stateChange(state());
+ if (update && parent() && parent()->rtti() == 1
+ && ((Q3CheckListItem*)parent())->type() == CheckBoxController)
+ ((Q3CheckListItem*)parent())->updateController(update, store);
+ } else if (myType == CheckBoxController) {
+ if (s == NoChange && childCount()) {
+ restoreState(this);
+ } else {
+ Q3ListViewItem *item = firstChild();
+ int childCount = 0;
+ while(item) {
+ if (item->rtti() == 1 &&
+ (((Q3CheckListItem*)item)->type() == CheckBox ||
+ ((Q3CheckListItem*)item)->type() == CheckBoxController)) {
+ Q3CheckListItem *checkItem = (Q3CheckListItem*)item;
+ checkItem->setState(s, false, false);
+ childCount++;
+ }
+ item = item->nextSibling();
+ }
+ if (update) {
+ if (childCount > 0) {
+ ToggleState oldState = internalState();
+ updateController(false, false);
+ if (oldState != internalState() &&
+ parent() && parent()->rtti() == 1 &&
+ ((Q3CheckListItem*)parent())->type() == CheckBoxController)
+ ((Q3CheckListItem*)parent())->updateController(update, store);
+
+ updateController(update, store);
+ } else {
+ // if there are no children we simply set the CheckBoxController and update its parent
+ setCurrentState(s);
+ stateChange(state());
+ if (parent() && parent()->rtti() == 1
+ && ((Q3CheckListItem*)parent())->type() == CheckBoxController)
+ ((Q3CheckListItem*)parent())->updateController(update, store);
+ }
+ } else {
+ setCurrentState(s);
+ stateChange(state());
+ }
+
+ }
+ } else if (myType == RadioButton) {
+ if (s == On) {
+ if (d->exclusive && d->exclusive->d->exclusive != this)
+ d->exclusive->turnOffChild();
+ setCurrentState(s);
+ if (d->exclusive)
+ d->exclusive->d->exclusive = this;
+ } else {
+ if (d->exclusive && d->exclusive->d->exclusive == this)
+ d->exclusive->d->exclusive = 0;
+ setCurrentState(Off);
+ }
+ stateChange(state());
+ }
+ repaint();
+}
+
+/*
+ this function is needed because we need to update "on" every time we
+ update d->currentState. In order to retain binary compatibility the
+ inline function isOn() needs the "on" bool ### should be changed in
+ ver 4
+*/
+void Q3CheckListItem::setCurrentState(ToggleState s)
+{
+ ToggleState old = d->currentState;
+ d->currentState = s;
+ if (d->currentState == On)
+ on = true;
+ else
+ on = false;
+
+#ifndef QT_NO_ACCESSIBILITY
+ if (old != d->currentState && listView())
+ QAccessible::updateAccessibility(listView()->viewport(), indexOfItem(this), QAccessible::StateChanged);
+#else
+ Q_UNUSED(old);
+#endif
+}
+
+
+
+/*
+ updates the internally stored state of this item for the parent (key)
+*/
+void Q3CheckListItem::setStoredState(ToggleState newState, Q3CheckListItem *key)
+{
+ if (myType == CheckBox || myType == CheckBoxController)
+ d->statesDict[key] = newState;
+}
+
+/*
+ Returns the stored state for this item for the given key.
+ If the key is not found it returns Off.
+*/
+Q3CheckListItem::ToggleState Q3CheckListItem::storedState(Q3CheckListItem *key) const
+{
+ QHash<Q3CheckListItem *, Q3CheckListItem::ToggleState>::Iterator it = d->statesDict.find(key);
+ if (it != d->statesDict.end())
+ return it.value();
+ else
+ return Off;
+}
+
+
+/*!
+ \fn QString Q3CheckListItem::text() const
+
+ Returns the item's text.
+*/
+
+
+/*!
+ If this is a \c RadioButtonController that has \c RadioButton
+ children, turn off the child that is on.
+*/
+void Q3CheckListItem::turnOffChild()
+{
+ if (myType == RadioButtonController && d->exclusive)
+ d->exclusive->setOn(false);
+}
+
+/*!
+ Toggle check box or set radio button to on.
+*/
+void Q3CheckListItem::activate()
+{
+ Q3ListView * lv = listView();
+
+ if ((lv && !lv->isEnabled()) || !isEnabled())
+ return;
+
+ QPoint pos;
+ int boxsize = lv->style()->pixelMetric(QStyle::PM_CheckListButtonSize, 0, lv);
+ if (activatedPos(pos)) {
+ bool parentControl = false;
+ if (parent() && parent()->rtti() == 1 &&
+ ((Q3CheckListItem*) parent())->type() == RadioButtonController)
+ parentControl = true;
+
+ int x = parentControl ? 0 : 3;
+ int align = lv->columnAlignment(0);
+ int marg = lv->itemMargin();
+ int y = 0;
+
+ if (align & Qt::AlignVCenter)
+ y = ((height() - boxsize) / 2) + marg;
+ else
+ y = (lv->fontMetrics().height() + 2 + marg - boxsize) / 2;
+
+ QRect r(x, y, boxsize-3, boxsize-3);
+ // columns might have been swapped
+ r.moveBy(lv->header()->sectionPos(0), 0);
+ if (!r.contains(pos))
+ return;
+ }
+ if ((myType == CheckBox) || (myType == CheckBoxController)) {
+ lv->d->startEdit = FALSE;
+ switch (internalState()) {
+ case On:
+ setState(Off);
+ break;
+ case Off:
+ if ( (!isTristate() && myType == CheckBox) ||
+ (myType == CheckBoxController && !childCount()) ) {
+ setState(On);
+ } else {
+ setState(NoChange);
+ if (myType == CheckBoxController && internalState() != NoChange)
+ setState(On);
+ }
+ break;
+ case NoChange:
+ setState(On);
+ break;
+ }
+ ignoreDoubleClick();
+ } else if (myType == RadioButton) {
+ setOn(true);
+ ignoreDoubleClick();
+ }
+}
+
+/*!
+ Sets the button on if \a b is true, otherwise sets it off.
+ Maintains radio button exclusivity.
+*/
+void Q3CheckListItem::setOn(bool b )
+{
+ if (b)
+ setState(On , true, true);
+ else
+ setState(Off , true, true);
+}
+
+
+/*!
+ \fn void Q3CheckListItem::stateChange(bool b)
+
+ This virtual function is called when the item changes its state.
+ \a b is true if the state is \c On; otherwise the state is \c Off.
+ \c NoChange (if tristate is enabled and the type is either \c
+ CheckBox or \c CheckBoxController) reports the same as \c Off, so
+ use state() to determine if the state is actually \c Off or \c
+ NoChange.
+*/
+void Q3CheckListItem::stateChange(bool)
+{
+}
+
+/*
+ Calls the public virtual function if the state is changed to either On, NoChange or Off.
+ NoChange reports the same as Off - ### should be fixed in ver4
+*/
+void Q3CheckListItem::stateChange(ToggleState s)
+{
+ stateChange(s == On);
+}
+
+/*
+ sets the state of the CheckBox and CheckBoxController back to
+ previous stored state
+*/
+void Q3CheckListItem::restoreState(Q3CheckListItem *key, int depth)
+{
+ switch (type()) {
+ case CheckBox:
+ setCurrentState(storedState(key));
+ stateChange(state());
+ repaint();
+ break;
+ case CheckBoxController: {
+ Q3ListViewItem *item = firstChild();
+ int childCount = 0;
+ while (item) {
+ // recursively calling restoreState for children of type CheckBox and CheckBoxController
+ if (item->rtti() == 1 &&
+ (((Q3CheckListItem*)item)->type() == CheckBox ||
+ ((Q3CheckListItem*)item)->type() == CheckBoxController)) {
+ ((Q3CheckListItem*)item)->restoreState(key , depth+1);
+ childCount++;
+ }
+ item = item->nextSibling();
+ }
+ if (childCount > 0) {
+ if (depth == 0)
+ updateController(true);
+ else
+ updateController(false);
+ } else {
+ // if there are no children we retrieve the CheckBoxController state directly.
+ setState(storedState(key), true, false);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+/*
+ Checks the childrens state and updates the controllers state
+ if necessary. If the controllers state change, then his parent again is
+ called to update itself.
+*/
+void Q3CheckListItem::updateController(bool update , bool store)
+{
+ if (myType != CheckBoxController)
+ return;
+
+ Q3CheckListItem *controller = 0;
+ // checks if this CheckBoxController has another CheckBoxController as parent
+ if (parent() && parent()->rtti() == 1
+ && ((Q3CheckListItem*)parent())->type() == CheckBoxController)
+ controller = (Q3CheckListItem*)parent();
+
+ ToggleState theState = Off;
+ bool first = true;
+ Q3ListViewItem *item = firstChild();
+ while(item && theState != NoChange) {
+ if (item->rtti() == 1 &&
+ (((Q3CheckListItem*)item)->type() == CheckBox ||
+ ((Q3CheckListItem*)item)->type() == CheckBoxController)) {
+ Q3CheckListItem *checkItem = (Q3CheckListItem*)item;
+ if (first) {
+ theState = checkItem->internalState();
+ first = false;
+ } else {
+ if (checkItem->internalState() == NoChange ||
+ theState != checkItem->internalState())
+ theState = NoChange;
+ else
+ theState = checkItem->internalState();
+ }
+ }
+ item = item->nextSibling();
+ }
+ if (internalState() != theState) {
+ setCurrentState(theState);
+ if (store && (internalState() == On || internalState() == Off))
+ updateStoredState(this);
+ stateChange(state());
+ if (update && controller) {
+ controller->updateController(update, store);
+ }
+ repaint();
+ }
+}
+
+
+/*
+ Makes all the children CheckBoxes update their storedState
+*/
+void Q3CheckListItem::updateStoredState(Q3CheckListItem *key)
+{
+ if (myType != CheckBoxController)
+ return;
+
+ Q3ListViewItem *item = firstChild();
+ while(item) {
+ if (item->rtti() == 1) {
+ Q3CheckListItem *checkItem = (Q3CheckListItem*)item;
+ if (checkItem->type() == CheckBox)
+ checkItem->setStoredState(checkItem->internalState(), key);
+ else if (checkItem->type() == CheckBoxController)
+ checkItem->updateStoredState(key);
+ }
+ item = item->nextSibling();
+ }
+ // this state is only needed if the CheckBoxController has no CheckBox / CheckBoxController children.
+ setStoredState(internalState() , key);
+}
+
+
+/*!
+ \reimp
+*/
+void Q3CheckListItem::setup()
+{
+ Q3ListViewItem::setup();
+ int h = height();
+ Q3ListView *lv = listView();
+ if (lv)
+ h = qMax(lv->style()->pixelMetric(QStyle::PM_CheckListButtonSize, 0, lv),
+ h);
+ h = qMax(h, QApplication::globalStrut().height());
+ setHeight(h);
+}
+
+/*!
+ \reimp
+*/
+
+int Q3CheckListItem::width(const QFontMetrics& fm, const Q3ListView* lv, int column) const
+{
+ int r = Q3ListViewItem::width(fm, lv, column);
+ if (column == 0) {
+ r += lv->itemMargin();
+ if (myType == RadioButtonController && pixmap(0)) {
+ // r += 0;
+ } else {
+ r += lv->style()->pixelMetric(QStyle::PM_CheckListButtonSize, 0, lv) + 4;
+ }
+ }
+ return qMax(r, QApplication::globalStrut().width());
+}
+
+/*!
+ Paints the item using the painter \a p and the color group \a cg.
+ The item is in column \a column, has width \a width and has
+ alignment \a align. (See \l Qt::Alignment for valid alignments.)
+*/
+void Q3CheckListItem::paintCell(QPainter * p, const QColorGroup & cg,
+ int column, int width, int align)
+{
+ if (!p)
+ return;
+
+ Q3ListView *lv = listView();
+ if (!lv)
+ return;
+
+ const QPalette::ColorRole crole = lv->backgroundRole();
+ if (cg.brush(crole) != lv->palette().brush(cg.currentColorGroup(), crole))
+ p->fillRect(0, 0, width, height(), cg.brush(crole));
+ else
+ lv->paintEmptyArea(p, QRect(0, 0, width, height()));
+
+ if (column != 0) {
+ // The rest is text, or for subclasses to change.
+ Q3ListViewItem::paintCell(p, cg, column, width, align);
+ return;
+ }
+
+ bool parentControl = false;
+ if (parent() && parent()->rtti() == 1 &&
+ ((Q3CheckListItem*) parent())->type() == RadioButtonController)
+ parentControl = true;
+
+ QFontMetrics fm(lv->fontMetrics());
+ int boxsize = lv->style()->pixelMetric(myType == RadioButtonController ? QStyle::PM_CheckListControllerSize :
+ QStyle::PM_CheckListButtonSize, 0, lv);
+ int marg = lv->itemMargin();
+ int r = marg;
+
+ // Draw controller / check box / radio button ---------------------
+ QStyle::State styleflags = QStyle::State_None;
+ if (internalState() == On) {
+ styleflags |= QStyle::State_On;
+ } else if (internalState() == NoChange) {
+ if (myType == CheckBoxController && !isTristate())
+ styleflags |= QStyle::State_Off;
+ else
+ styleflags |= QStyle::State_NoChange;
+ } else {
+ styleflags |= QStyle::State_Off;
+ }
+ if (isSelected())
+ styleflags |= QStyle::State_Selected;
+ if (isEnabled() && lv->isEnabled())
+ styleflags |= QStyle::State_Enabled;
+ if (lv->window()->isActiveWindow())
+ styleflags |= QStyle::State_Active;
+
+ if (myType == RadioButtonController) {
+ int x = 0;
+ if(!parentControl)
+ x += 3;
+ if (!pixmap(0)) {
+ QStyleOptionQ3ListView opt = getStyleOption(lv, this);
+ opt.rect.setRect(x, 0, boxsize, fm.height() + 2 + marg);
+ opt.palette = cg;
+ opt.state = styleflags;
+ lv->style()->drawPrimitive(QStyle::PE_Q3CheckListController, &opt, p, lv);
+ r += boxsize + 4;
+ }
+ } else {
+ Q_ASSERT(lv); //###
+ int x = 0;
+ int y = 0;
+ if (!parentControl)
+ x += 3;
+ if (align & Qt::AlignVCenter)
+ y = ((height() - boxsize) / 2) + marg;
+ else
+ y = (fm.height() + 2 + marg - boxsize) / 2;
+
+ QStyleOptionQ3ListView opt = getStyleOption(lv, this);
+ opt.rect.setRect(x, y, boxsize, fm.height() + 2 + marg);
+ opt.palette = cg;
+ opt.state = styleflags;
+ lv->style()->drawPrimitive((myType == CheckBox || myType == CheckBoxController)
+ ? QStyle::PE_Q3CheckListIndicator
+ : QStyle::PE_Q3CheckListExclusiveIndicator, &opt, p, lv);
+ r += boxsize + 4;
+ }
+
+ // Draw text ----------------------------------------------------
+ p->translate(r, 0);
+ p->setPen(QPen(cg.text()));
+ Q3ListViewItem::paintCell(p, cg, column, width - r, align);
+}
+
+/*!
+ Draws the focus rectangle \a r using the color group \a cg on the
+ painter \a p.
+*/
+void Q3CheckListItem::paintFocus(QPainter *p, const QColorGroup & cg,
+ const QRect & r)
+{
+ bool intersect = true;
+ Q3ListView *lv = listView();
+ if (lv && lv->header()->mapToActual(0) != 0) {
+ int xdepth = lv->treeStepSize() * (depth() + (lv->rootIsDecorated() ? 1 : 0)) + lv->itemMargin();
+ int p = lv->header()->cellPos(lv->header()->mapToActual(0));
+ xdepth += p;
+ intersect = r.intersects(QRect(p, r.y(), xdepth - p + 1, r.height()));
+ }
+ bool parentControl = false;
+ if (parent() && parent()->rtti() == 1 &&
+ ((Q3CheckListItem*) parent())->type() == RadioButtonController)
+ parentControl = true;
+ if (myType != RadioButtonController && intersect &&
+ (lv->rootIsDecorated() || myType == RadioButton ||
+ (myType == CheckBox && parentControl))) {
+ QRect rect;
+ int boxsize = lv->style()->pixelMetric(QStyle::PM_CheckListButtonSize, 0, lv);
+ if (lv->columnAlignment(0) == Qt::AlignCenter) {
+ QFontMetrics fm(lv->font());
+ int bx = (lv->columnWidth(0) - (boxsize + fm.width(text())))/2 + boxsize;
+ if (bx < 0) bx = 0;
+ rect.setRect(r.x() + bx + 5, r.y(), r.width() - bx - 5,
+ r.height());
+ } else
+ rect.setRect(r.x() + boxsize + 5, r.y(), r.width() - boxsize - 5,
+ r.height());
+ Q3ListViewItem::paintFocus(p, cg, rect);
+ } else {
+ Q3ListViewItem::paintFocus(p, cg, r);
+ }
+}
+
+/*!
+ \reimp
+*/
+QSize Q3ListView::sizeHint() const
+{
+ if (cachedSizeHint().isValid())
+ return cachedSizeHint();
+
+ ensurePolished();
+
+ if (!isVisible() && d->drawables.isEmpty())
+ // force the column widths to sanity, if possible
+ buildDrawableList();
+
+ QSize s(d->h->sizeHint());
+ if (verticalScrollBar()->isVisible())
+ s.setWidth(s.width() + style()->pixelMetric(QStyle::PM_ScrollBarExtent));
+ s += QSize(frameWidth()*2,frameWidth()*2);
+ Q3ListViewItem * l = d->r;
+ while(l && !l->height())
+ l = l->childItem ? l->childItem : l->siblingItem;
+
+ if (l && l->height())
+ s.setHeight(s.height() + 10 * l->height());
+ else
+ s.setHeight(s.height() + 140);
+
+ if (s.width() > s.height() * 3)
+ s.setHeight(s.width() / 3);
+ else if (s.width() *3 < s.height())
+ s.setHeight(s.width() * 3);
+
+ setCachedSizeHint(s);
+
+ return s;
+}
+
+
+/*!
+ \reimp
+*/
+
+QSize Q3ListView::minimumSizeHint() const
+{
+ return Q3ScrollView::minimumSizeHint();
+}
+
+
+/*!
+ Sets \a item to be open if \a open is true and \a item is
+ expandable, and to be closed if \a open is false. Repaints
+ accordingly.
+
+ \sa Q3ListViewItem::setOpen() Q3ListViewItem::setExpandable()
+*/
+
+void Q3ListView::setOpen(Q3ListViewItem * item, bool open)
+{
+ if (!item ||
+ item->isOpen() == open ||
+ (open && !item->childCount() && !item->isExpandable()))
+ return;
+
+ Q3ListViewItem* nextParent = 0;
+ if (open)
+ nextParent = item->itemBelow();
+
+ item->setOpen(open);
+
+ if (open) {
+ Q3ListViewItem* lastChild = item;
+ Q3ListViewItem* tmp;
+ while (true) {
+ tmp = lastChild->itemBelow();
+ if (!tmp || tmp == nextParent)
+ break;
+ lastChild = tmp;
+ }
+ ensureItemVisible(lastChild);
+ ensureItemVisible(item);
+ }
+ buildDrawableList();
+
+ int i = 0;
+ for (; i < d->drawables.size(); ++i) {
+ const Q3ListViewPrivate::DrawableItem &c = d->drawables.at(i);
+ if(c.i == item)
+ break;
+ }
+
+ if (i < d->drawables.size()) {
+ d->dirtyItemTimer->start(0, true);
+ for (; i < d->drawables.size(); ++i) {
+ const Q3ListViewPrivate::DrawableItem &c = d->drawables.at(i);
+ d->dirtyItems.append(c.i);
+ }
+ }
+}
+
+
+/*!
+ Returns true if this list view item has children \e and they are
+ not explicitly hidden; otherwise returns false.
+
+ Identical to \a{item}->isOpen(). Provided for completeness.
+
+ \sa setOpen()
+*/
+
+bool Q3ListView::isOpen(const Q3ListViewItem * item) const
+{
+ return item->isOpen();
+}
+
+
+/*!
+ \property Q3ListView::rootIsDecorated
+ \brief whether the list view shows open/close signs on root items
+
+ Open/close signs are small \bold{+} or \bold{-} symbols in windows
+ style, or arrows in Motif style. The default is false.
+*/
+
+void Q3ListView::setRootIsDecorated(bool enable)
+{
+ if (enable != (bool)d->rootIsExpandable) {
+ d->rootIsExpandable = enable;
+ if (isVisible())
+ triggerUpdate();
+ }
+}
+
+bool Q3ListView::rootIsDecorated() const
+{
+ return d->rootIsExpandable;
+}
+
+
+/*!
+ Ensures that item \a i is visible, scrolling the list view
+ vertically if necessary and opening (expanding) any parent items
+ if this is required to show the item.
+
+ \sa itemRect() Q3ScrollView::ensureVisible()
+*/
+
+void Q3ListView::ensureItemVisible(const Q3ListViewItem * i)
+{
+ if (!i || !i->isVisible())
+ return;
+
+ Q3ListViewItem *parent = i->parent();
+ while (parent) {
+ if (!parent->isOpen())
+ parent->setOpen(true);
+ parent = parent->parent();
+ }
+
+ if (d->r->maybeTotalHeight < 0)
+ updateGeometries();
+ int y = itemPos(i);
+ int h = i->height();
+ if (isVisible() && y + h > contentsY() + visibleHeight())
+ setContentsPos(contentsX(), y - visibleHeight() + h);
+ else if (!isVisible() || y < contentsY())
+ setContentsPos(contentsX(), y);
+}
+
+
+/*!
+ \fn QString Q3CheckListItem::text(int n) const
+
+ \reimp
+*/
+
+/*!
+ Returns the Q3Header object that manages this list view's columns.
+ Please don't modify the header behind the list view's back.
+
+ You may safely call Q3Header::setClickEnabled(),
+ Q3Header::setResizeEnabled(), Q3Header::setMovingEnabled(),
+ Q3Header::hide() and all the const Q3Header functions.
+*/
+
+Q3Header * Q3ListView::header() const
+{
+ return d->h;
+}
+
+
+/*!
+ \property Q3ListView::childCount
+ \brief the number of parentless (top-level) Q3ListViewItem objects in this Q3ListView
+
+ Holds the current number of parentless (top-level) Q3ListViewItem
+ objects in this Q3ListView.
+
+ \sa Q3ListViewItem::childCount()
+*/
+
+int Q3ListView::childCount() const
+{
+ if (d->r)
+ return d->r->childCount();
+ return 0;
+}
+
+
+/*
+ Moves this item to just after \a olderSibling. \a olderSibling and
+ this object must have the same parent.
+
+ If you need to move an item in the hierarchy use takeItem() and
+ insertItem().
+*/
+
+void Q3ListViewItem::moveToJustAfter(Q3ListViewItem * olderSibling)
+{
+ if (parentItem && olderSibling &&
+ olderSibling->parentItem == parentItem && olderSibling != this) {
+ if (parentItem->childItem == this) {
+ parentItem->childItem = siblingItem;
+ } else {
+ Q3ListViewItem * i = parentItem->childItem;
+ while(i && i->siblingItem != this)
+ i = i->siblingItem;
+ if (i)
+ i->siblingItem = siblingItem;
+ }
+ siblingItem = olderSibling->siblingItem;
+ olderSibling->siblingItem = this;
+ parentItem->lsc = Unsorted;
+ }
+}
+
+/*!
+ Move the item to be after item \a after, which must be one of the
+ item's siblings. To move an item in the hierarchy, use takeItem()
+ and insertItem().
+
+ Note that this function will have no effect if sorting is enabled
+ in the list view.
+*/
+
+void Q3ListViewItem::moveItem(Q3ListViewItem *after)
+{
+ if (!after || after == this)
+ return;
+ if (parent() != after->parent()) {
+ if (parentItem)
+ parentItem->takeItem(this);
+ if (after->parentItem) {
+ int tmpLsc = after->parentItem->lsc;
+ after->parentItem->insertItem(this);
+ after->parentItem->lsc = tmpLsc;
+ }
+ }
+ moveToJustAfter(after);
+ Q3ListView *lv = listView();
+ if (lv)
+ lv->triggerUpdate();
+}
+
+/*
+ Recursively sorts items, from the root to this item.
+ (enforceSortOrder() won't work the other way around, as
+ documented.)
+*/
+void Q3ListViewItem::enforceSortOrderBackToRoot()
+{
+ if (parentItem) {
+ parentItem->enforceSortOrderBackToRoot();
+ parentItem->enforceSortOrder();
+ }
+}
+
+/*!
+ \reimp
+*/
+void Q3ListView::showEvent(QShowEvent *)
+{
+ d->drawables.clear();
+ d->dirtyItems.clear();
+ d->dirtyItemTimer->stop();
+ d->fullRepaintOnComlumnChange = true;
+
+ updateGeometries();
+}
+
+
+/*!
+ Returns the y coordinate of this item in the list view's
+ coordinate system. This function is normally much slower than
+ Q3ListView::itemAt(), but it works for all items whereas
+ Q3ListView::itemAt() normally only works for items on the screen.
+
+ \sa Q3ListView::itemAt() Q3ListView::itemRect() Q3ListView::itemPos()
+*/
+
+int Q3ListViewItem::itemPos() const
+{
+ QStack<Q3ListViewItem *> s;
+ Q3ListViewItem * i = (Q3ListViewItem *)this;
+ while(i) {
+ s.push(i);
+ i = i->parentItem;
+ }
+
+ int a = 0;
+ Q3ListViewItem * p = 0;
+ while(s.count()) {
+ i = s.pop();
+ if (p) {
+ if (!p->configured) {
+ p->configured = true;
+ p->setup(); // ### virtual non-const function called in const
+ }
+ a += p->height();
+ Q3ListViewItem * s = p->firstChild();
+ while(s && s != i) {
+ a += s->totalHeight();
+ s = s->nextSibling();
+ }
+ }
+ p = i;
+ }
+ return a;
+}
+
+
+/*!
+ \fn void Q3ListView::removeItem(Q3ListViewItem *item)
+
+ Removes the given \a item. Use takeItem() instead.
+*/
+
+/*!
+ Removes item \a i from the list view; \a i must be a top-level
+ item. The warnings regarding Q3ListViewItem::takeItem() apply to
+ this function, too.
+
+ \sa insertItem()
+*/
+void Q3ListView::takeItem(Q3ListViewItem * i)
+{
+ if (d->r)
+ d->r->takeItem(i);
+}
+
+
+void Q3ListView::openFocusItem()
+{
+ d->autoopenTimer->stop();
+ if (d->focusItem && !d->focusItem->isOpen()) {
+ d->focusItem->setOpen(true);
+ d->focusItem->repaint();
+ }
+}
+
+static const int autoopenTime = 750;
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*! \reimp */
+
+void Q3ListView::contentsDragEnterEvent(QDragEnterEvent *e)
+{
+ d->oldFocusItem = d->focusItem;
+ Q3ListViewItem *i = d->focusItem;
+ d->focusItem = itemAt(contentsToViewport(e->pos()));
+ if (i)
+ i->repaint();
+ if (d->focusItem) {
+ d->autoopenTimer->start(autoopenTime);
+ d->focusItem->dragEntered();
+ d->focusItem->repaint();
+ }
+ e->accept();
+}
+
+/*! \reimp */
+
+void Q3ListView::contentsDragMoveEvent(QDragMoveEvent *e)
+{
+ Q3ListViewItem *i = d->focusItem;
+ d->focusItem = itemAt(contentsToViewport(e->pos()));
+ if (i) {
+ if (i != d->focusItem)
+ i->dragLeft();
+ i->repaint();
+ }
+ if (d->focusItem) {
+ if (i != d->focusItem) {
+ d->focusItem->dragEntered();
+ d->autoopenTimer->stop();
+ d->autoopenTimer->start(autoopenTime);
+ }
+ d->focusItem->repaint();
+ } else {
+ d->autoopenTimer->stop();
+ }
+ if ((i && i->dropEnabled() && i->acceptDrop(e)) || acceptDrops())
+ e->accept();
+ else
+ e->ignore();
+}
+
+/*! \reimp */
+
+void Q3ListView::contentsDragLeaveEvent(QDragLeaveEvent *)
+{
+ d->autoopenTimer->stop();
+
+ if (d->focusItem)
+ d->focusItem->dragLeft();
+
+ setCurrentItem(d->oldFocusItem);
+ d->oldFocusItem = 0;
+}
+
+/*! \reimp */
+
+void Q3ListView::contentsDropEvent(QDropEvent *e)
+{
+ d->autoopenTimer->stop();
+
+ setCurrentItem(d->oldFocusItem);
+ Q3ListViewItem *i = itemAt(contentsToViewport(e->pos()));
+ if (i && i->dropEnabled() && i->acceptDrop(e)) {
+ i->dropped(e);
+ e->accept();
+ } else if (acceptDrops()) {
+ emit dropped(e);
+ e->accept();
+ }
+}
+
+/*!
+ If the user presses the mouse on an item and starts moving the
+ mouse, and the item allow dragging (see
+ Q3ListViewItem::setDragEnabled()), this function is called to get a
+ drag object and a drag is started unless dragObject() returns 0.
+
+ By default this function returns 0. You should reimplement it and
+ create a Q3DragObject depending on the selected items.
+*/
+
+Q3DragObject *Q3ListView::dragObject()
+{
+ return 0;
+}
+
+/*!
+ Starts a drag.
+*/
+
+void Q3ListView::startDrag()
+{
+ if (!d->startDragItem)
+ return;
+
+ d->startDragItem = 0;
+ d->buttonDown = false;
+
+ Q3DragObject *drag = dragObject();
+ if (!drag)
+ return;
+
+ drag->drag();
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*!
+ \property Q3ListView::defaultRenameAction
+ \brief What action to perform when the editor loses focus during renaming
+
+ If this property is \c Accept, and the user renames an item and
+ the editor loses focus (without the user pressing Enter), the
+ item will still be renamed. If the property's value is \c Reject,
+ the item will not be renamed unless the user presses Enter. The
+ default is \c Reject.
+*/
+
+void Q3ListView::setDefaultRenameAction(RenameAction a)
+{
+ d->defRenameAction = a;
+}
+
+Q3ListView::RenameAction Q3ListView::defaultRenameAction() const
+{
+ return d->defRenameAction;
+}
+
+/*!
+ Returns true if an item is being renamed; otherwise returns false.
+*/
+
+bool Q3ListView::isRenaming() const
+{
+ return currentItem() && currentItem()->renameBox;
+}
+
+/**********************************************************************
+ *
+ * Class Q3ListViewItemIterator
+ *
+ **********************************************************************/
+
+
+/*!
+ \class Q3ListViewItemIterator
+ \brief The Q3ListViewItemIterator class provides an iterator for collections of Q3ListViewItems.
+
+ \compat
+
+ Construct an instance of a Q3ListViewItemIterator, with either a
+ Q3ListView* or a Q3ListViewItem* as argument, to operate on the tree
+ of Q3ListViewItems, starting from the argument.
+
+ A Q3ListViewItemIterator iterates over all the items from its
+ starting point. This means that it always makes the first child of
+ the current item the new current item. If there is no child, the
+ next sibling becomes the new current item; and if there is no next
+ sibling, the next sibling of the parent becomes current.
+
+ The following example creates a list of all the items that have
+ been selected by the user, storing pointers to the items in a
+ QList:
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 6
+
+ An alternative approach is to use an \c IteratorFlag:
+ \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 7
+
+ A Q3ListViewItemIterator provides a convenient and easy way to
+ traverse a hierarchical Q3ListView.
+
+ Multiple Q3ListViewItemIterators can operate on the tree of
+ Q3ListViewItems. A Q3ListView knows about all iterators operating on
+ its Q3ListViewItems. So when a Q3ListViewItem gets removed all
+ iterators that point to this item are updated and point to the
+ following item if possible, otherwise to a valid item before the
+ current one or to 0. Note however that deleting the parent item of
+ an item that an iterator points to is not safe.
+
+ \sa Q3ListView, Q3ListViewItem
+*/
+
+/*!
+ \enum Q3ListViewItemIterator::IteratorFlag
+
+ These flags can be passed to a Q3ListViewItemIterator constructor
+ (OR-ed together if more than one is used), so that the iterator
+ will only iterate over items that match the given flags.
+
+ \value Visible
+ \value Invisible
+ \value Selected
+ \value Unselected
+ \value Selectable
+ \value NotSelectable
+ \value DragEnabled
+ \value DragDisabled
+ \value DropEnabled
+ \value DropDisabled
+ \value Expandable
+ \value NotExpandable
+ \value Checked
+ \value NotChecked
+*/
+
+/*!
+ Constructs an empty iterator.
+*/
+
+Q3ListViewItemIterator::Q3ListViewItemIterator()
+ : curr(0), listView(0), flags(0)
+{
+}
+
+/*!
+ Constructs an iterator for the Q3ListView that contains the \a
+ item. The current iterator item is set to point to the \a item.
+*/
+
+Q3ListViewItemIterator::Q3ListViewItemIterator(Q3ListViewItem *item)
+ : curr(item), listView(0), flags(0)
+{
+ if (item) {
+ item->enforceSortOrderBackToRoot();
+ listView = item->listView();
+ }
+ if (listView)
+ listView->d->iterators.append(this);
+}
+
+/*!
+ Constructs an iterator for the Q3ListView that contains the \a item
+ using the flags \a iteratorFlags. The current iterator item is set
+ to point to \a item or the next matching item if \a item doesn't
+ match the flags.
+
+ \sa Q3ListViewItemIterator::IteratorFlag
+*/
+
+Q3ListViewItemIterator::Q3ListViewItemIterator(Q3ListViewItem *item, int iteratorFlags)
+ : curr(item), listView(0), flags(iteratorFlags)
+{
+ // go to next matching item if the current don't match
+ if (curr && !matchesFlags(curr))
+ ++(*this);
+
+ if (curr) {
+ curr->enforceSortOrderBackToRoot();
+ listView = curr->listView();
+ }
+ if (listView)
+ listView->d->iterators.append(this);
+}
+
+
+/*!
+ Constructs an iterator for the same Q3ListView as \a it. The
+ current iterator item is set to point on the current item of \a
+ it.
+*/
+
+Q3ListViewItemIterator::Q3ListViewItemIterator(const Q3ListViewItemIterator& it)
+ : curr(it.curr), listView(it.listView), flags(it.flags)
+{
+ if (listView)
+ listView->d->iterators.append(this);
+}
+
+/*!
+ Constructs an iterator for the Q3ListView \a lv. The current
+ iterator item is set to point on the first child (Q3ListViewItem)
+ of \a lv.
+*/
+
+Q3ListViewItemIterator::Q3ListViewItemIterator(Q3ListView *lv)
+ : curr(lv->firstChild()), listView(lv), flags(0)
+{
+ if (listView)
+ listView->d->iterators.append(this);
+}
+
+/*!
+ Constructs an iterator for the Q3ListView \a lv with the flags \a
+ iteratorFlags. The current iterator item is set to point on the
+ first child (Q3ListViewItem) of \a lv that matches the flags.
+
+ \sa Q3ListViewItemIterator::IteratorFlag
+*/
+
+Q3ListViewItemIterator::Q3ListViewItemIterator(Q3ListView *lv, int iteratorFlags)
+ : curr (lv->firstChild()), listView(lv), flags(iteratorFlags)
+{
+ if (listView)
+ listView->d->iterators.append(this);
+ if (!matchesFlags(curr))
+ ++(*this);
+}
+
+
+
+/*!
+ Assignment. Makes a copy of \a it and returns a reference to its
+ iterator.
+*/
+
+Q3ListViewItemIterator &Q3ListViewItemIterator::operator=(const Q3ListViewItemIterator &it)
+{
+ if (listView)
+ listView->d->iterators.removeAll(this);
+
+ listView = it.listView;
+ curr = it.curr;
+ flags = it.flags;
+ if (listView)
+ listView->d->iterators.append(this);
+
+ // go to next matching item if the current don't match
+ if (curr && !matchesFlags(curr))
+ ++(*this);
+
+ return *this;
+}
+
+/*!
+ Destroys the iterator.
+*/
+
+Q3ListViewItemIterator::~Q3ListViewItemIterator()
+{
+ if (listView)
+ listView->d->iterators.removeAll(this);
+}
+
+/*!
+ Prefix ++. Makes the next item the new current item and returns
+ it. Returns 0 if the current item is the last item or the
+ Q3ListView is 0.
+*/
+
+Q3ListViewItemIterator &Q3ListViewItemIterator::operator++()
+{
+ if (!curr)
+ return *this;
+
+ Q3ListViewItem *item = curr->firstChild();
+ if (!item) {
+ while ((item = curr->nextSibling()) == 0 ) {
+ curr = curr->parent();
+ if (curr == 0)
+ break;
+ }
+ }
+ curr = item;
+ // if the next one doesn't match the flags we try one more ahead
+ if (curr && !matchesFlags(curr))
+ ++(*this);
+ return *this;
+}
+
+/*!
+ \overload
+
+ Postfix ++. Makes the next item the new current item and returns
+ the item that \e was the current item.
+*/
+
+const Q3ListViewItemIterator Q3ListViewItemIterator::operator++(int)
+{
+ Q3ListViewItemIterator oldValue = *this;
+ ++(*this);
+ return oldValue;
+}
+
+/*!
+ Sets the current item to the item \a j positions after the current
+ item. If that item is beyond the last item, the current item is
+ set to 0. Returns the current item.
+*/
+
+Q3ListViewItemIterator &Q3ListViewItemIterator::operator+=(int j)
+{
+ while (curr && j--)
+ ++(*this);
+
+ return *this;
+}
+
+/*!
+ Prefix --. Makes the previous item the new current item and
+ returns it. Returns 0 if the current item is the first item or the
+ Q3ListView is 0.
+*/
+
+Q3ListViewItemIterator &Q3ListViewItemIterator::operator--()
+{
+ if (!curr)
+ return *this;
+
+ if (!curr->parent()) {
+ // we are in the first depth
+ if (curr->listView()) {
+ if (curr->listView()->firstChild() != curr) {
+ // go the previous sibling
+ Q3ListViewItem *i = curr->listView()->firstChild();
+ while (i && i->siblingItem != curr)
+ i = i->siblingItem;
+
+ curr = i;
+
+ if (i && i->firstChild()) {
+ // go to the last child of this item
+ Q3ListViewItemIterator it(curr->firstChild());
+ for (; it.current() && it.current()->parent(); ++it)
+ curr = it.current();
+ }
+
+ if (curr && !matchesFlags(curr))
+ --(*this);
+
+ return *this;
+ } else {
+ //we are already the first child of the list view, so it's over
+ curr = 0;
+ return *this;
+ }
+ } else
+ return *this;
+ } else {
+ Q3ListViewItem *parent = curr->parent();
+
+ if (curr != parent->firstChild()) {
+ // go to the previous sibling
+ Q3ListViewItem *i = parent->firstChild();
+ while (i && i->siblingItem != curr)
+ i = i->siblingItem;
+
+ curr = i;
+
+ if (i && i->firstChild()) {
+ // go to the last child of this item
+ Q3ListViewItemIterator it(curr->firstChild());
+ for (; it.current() && it.current()->parent() != parent; ++it)
+ curr = it.current();
+ }
+
+ if (curr && !matchesFlags(curr))
+ --(*this);
+
+ return *this;
+ } else {
+ // make our parent the current item
+ curr = parent;
+
+ if (curr && !matchesFlags(curr))
+ --(*this);
+
+ return *this;
+ }
+ }
+}
+
+/*!
+ \overload
+
+ Postfix --. Makes the previous item the new current item and
+ returns the item that \e was the current item.
+*/
+
+const Q3ListViewItemIterator Q3ListViewItemIterator::operator--(int)
+{
+ Q3ListViewItemIterator oldValue = *this;
+ --(*this);
+ return oldValue;
+}
+
+/*!
+ Sets the current item to the item \a j positions before the
+ current item. If that item is before the first item, the current
+ item is set to 0. Returns the current item.
+*/
+
+Q3ListViewItemIterator &Q3ListViewItemIterator::operator-=(int j)
+{
+ while (curr && j--)
+ --(*this);
+
+ return *this;
+}
+
+/*!
+ Dereference operator. Returns a reference to the current item. The
+ same as current().
+*/
+
+Q3ListViewItem* Q3ListViewItemIterator::operator*()
+{
+ if (curr != 0 && !matchesFlags(curr))
+ qWarning("Q3ListViewItemIterator::operator*() curr out of sync");
+ return curr;
+}
+
+/*!
+ Returns iterator's current item.
+*/
+
+Q3ListViewItem *Q3ListViewItemIterator::current() const
+{
+ if (curr != 0 && !matchesFlags(curr))
+ qWarning("Q3ListViewItemIterator::current() curr out of sync");
+ return curr;
+}
+
+/*
+ This function is called to notify the iterator that the current
+ item has been deleted, and sets the current item point to another
+ (valid) item or 0.
+*/
+
+void Q3ListViewItemIterator::currentRemoved()
+{
+ if (!curr) return;
+
+ if (curr->parent())
+ curr = curr->parent();
+ else if (curr->nextSibling())
+ curr = curr->nextSibling();
+ else if (listView && listView->firstChild() &&
+ listView->firstChild() != curr)
+ curr = listView->firstChild();
+ else
+ curr = 0;
+}
+
+/*
+ returns true if the item \a item matches all of the flags set for the iterator
+*/
+bool Q3ListViewItemIterator::matchesFlags(const Q3ListViewItem *item) const
+{
+ if (!item)
+ return false;
+
+ if (flags == 0)
+ return true;
+
+ if (flags & Visible && !item->isVisible())
+ return false;
+ if (flags & Invisible && item->isVisible())
+ return false;
+ if (flags & Selected && !item->isSelected())
+ return false;
+ if (flags & Unselected && item->isSelected())
+ return false;
+ if (flags & Selectable && !item->isSelectable())
+ return false;
+ if (flags & NotSelectable && item->isSelectable())
+ return false;
+ if (flags & DragEnabled && !item->dragEnabled())
+ return false;
+ if (flags & DragDisabled && item->dragEnabled())
+ return false;
+ if (flags & DropEnabled && !item->dropEnabled())
+ return false;
+ if (flags & DropDisabled && item->dropEnabled())
+ return false;
+ if (flags & Expandable && !item->isExpandable())
+ return false;
+ if (flags & NotExpandable && item->isExpandable())
+ return false;
+ if (flags & Checked && !isChecked(item))
+ return false;
+ if (flags & NotChecked && isChecked(item))
+ return false;
+
+ return true;
+}
+
+/*
+ we want the iterator to check Q3CheckListItems as well, so we provide this convenience function
+ that checks if the rtti() is 1 which means Q3CheckListItem and if isOn is true, returns false otherwise.
+*/
+bool Q3ListViewItemIterator::isChecked(const Q3ListViewItem *item) const
+{
+ if (item->rtti() == 1)
+ return ((const Q3CheckListItem*)item)->isOn();
+ else return false;
+}
+
+void Q3ListView::handleItemChange(Q3ListViewItem *old, bool shift, bool control)
+{
+ if (d->selectionMode == Single) {
+ // nothing
+ } else if (d->selectionMode == Extended) {
+ if (shift) {
+ selectRange(d->selectAnchor ? d->selectAnchor : old,
+ d->focusItem, false, true, (d->selectAnchor && !control) ? true : false);
+ } else if (!control) {
+ bool block = signalsBlocked();
+ blockSignals(true);
+ selectAll(false);
+ blockSignals(block);
+ setSelected(d->focusItem, true);
+ }
+ } else if (d->selectionMode == Multi) {
+ if (shift)
+ selectRange(old, d->focusItem, true, false);
+ }
+}
+
+void Q3ListView::startRename()
+{
+ if (!currentItem())
+ return;
+ currentItem()->startRename(d->pressedColumn);
+ d->buttonDown = false;
+}
+
+/* unselects items from to, including children, returns true if any items were unselected */
+bool Q3ListView::clearRange(Q3ListViewItem *from, Q3ListViewItem *to, bool includeFirst)
+{
+ if (!from || !to)
+ return false;
+
+ // Swap
+ if (from->itemPos() > to->itemPos()) {
+ Q3ListViewItem *temp = from;
+ from = to;
+ to = temp;
+ }
+
+ // Start on second?
+ if (!includeFirst) {
+ Q3ListViewItem *below = (from == to) ? from : from->itemBelow();
+ if (below)
+ from = below;
+ }
+
+ // Clear items <from, to>
+ bool changed = false;
+
+ Q3ListViewItemIterator it(from);
+ while (it.current()) {
+ if (it.current()->isSelected()) {
+ it.current()->setSelected(false);
+ changed = true;
+ }
+ if (it.current() == to)
+ break;
+ ++it;
+ }
+
+ // NOTE! This function does _not_ emit
+ // any signals about selection changed
+ return changed;
+}
+
+void Q3ListView::selectRange(Q3ListViewItem *from, Q3ListViewItem *to, bool invert, bool includeFirst, bool clearSel)
+{
+ if (!from || !to)
+ return;
+ if (from == to && !includeFirst)
+ return;
+ bool swap = false;
+ if (to == from->itemAbove())
+ swap = true;
+ if (!swap && from != to && from != to->itemAbove()) {
+ Q3ListViewItemIterator it(from);
+ bool found = false;
+ for (; it.current(); ++it) {
+ if (it.current() == to) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ swap = true;
+ }
+ if (swap) {
+ Q3ListViewItem *i = from;
+ from = to;
+ to = i;
+ if (!includeFirst)
+ to = to->itemAbove();
+ } else {
+ if (!includeFirst)
+ from = from->itemBelow();
+ }
+
+ bool changed = false;
+ if (clearSel) {
+ Q3ListViewItemIterator it(firstChild());
+ for (; it.current(); ++it) {
+ if (it.current()->selected) {
+ it.current()->setSelected(false);
+ changed = true;
+ }
+ }
+ it = Q3ListViewItemIterator(to);
+ for (; it.current(); ++it) {
+ if (it.current()->selected) {
+ it.current()->setSelected(false);
+ changed = true;
+ }
+ }
+ }
+
+ for (Q3ListViewItem *i = from; i; i = i->itemBelow()) {
+ if (!invert) {
+ if (!i->selected && i->isSelectable()) {
+ i->setSelected(true);
+ changed = true;
+ }
+ } else {
+ bool sel = !i->selected;
+ if (((bool)i->selected != sel && sel && i->isSelectable()) || !sel) {
+ i->setSelected(sel);
+ changed = true;
+ }
+ }
+ if (i == to)
+ break;
+ }
+ if (changed) {
+ triggerUpdate();
+ emit selectionChanged();
+ }
+}
+
+/* clears selection from anchor to old, selects from anchor to new, does not emit selectionChanged on change */
+bool Q3ListView::selectRange(Q3ListViewItem *newItem, Q3ListViewItem *oldItem, Q3ListViewItem *anchorItem)
+{
+ if (!newItem || !oldItem || !anchorItem)
+ return false;
+
+ int anchorPos = anchorItem ? anchorItem->itemPos() : 0,
+ oldPos = oldItem ? oldItem->itemPos() : 0,
+ newPos = newItem->itemPos();
+ Q3ListViewItem *top=0, *bottom=0;
+ if (anchorPos > newPos) {
+ top = newItem;
+ bottom = anchorItem;
+ } else {
+ top = anchorItem;
+ bottom = newItem;
+ }
+
+ // removes the subControls of the old selection that will no longer be selected
+ bool changed = false;
+ int topPos = top ? top->itemPos() : 0,
+ bottomPos = bottom ? bottom->itemPos() : 0;
+ if (!(oldPos > topPos && oldPos < bottomPos)) {
+ if (oldPos < topPos)
+ changed = clearRange(oldItem, top);
+ else
+ changed = clearRange(bottom, oldItem);
+ }
+
+ // selects the new (not already selected) items
+ Q3ListViewItemIterator lit(top);
+ for (; lit.current(); ++lit) {
+ if ((bool)lit.current()->selected != d->select) {
+ lit.current()->setSelected(d->select);
+ changed = true;
+ }
+ // Include bottom, then break
+ if (lit.current() == bottom)
+ break;
+ }
+
+ return changed;
+}
+
+
+/*!
+ Finds the first list view item in column \a column, that matches
+ \a text and returns the item, or returns 0 of no such item could
+ be found. Pass OR-ed together \l ComparisonFlags values
+ in the \a compare flag, to control how the matching is performed.
+ The default comparison mode is case-sensitive, exact match.
+*/
+
+Q3ListViewItem *Q3ListView::findItem(const QString& text, int column,
+ ComparisonFlags compare) const
+{
+ if (text.isEmpty() && !(compare & ExactMatch))
+ return 0;
+
+ if (compare == Qt::CaseSensitive || compare == 0)
+ compare |= ExactMatch;
+
+ QString itmtxt;
+ QString comtxt = text;
+ if (!(compare & Qt::CaseSensitive))
+ comtxt = comtxt.toLower();
+
+ Q3ListViewItemIterator it(d->focusItem ? d->focusItem : firstChild());
+ Q3ListViewItem *sentinel = 0;
+ Q3ListViewItem *item;
+ Q3ListViewItem *beginsWithItem = 0;
+ Q3ListViewItem *endsWithItem = 0;
+ Q3ListViewItem *containsItem = 0;
+
+ for (int pass = 0; pass < 2; pass++) {
+ while ((item = it.current()) != sentinel) {
+ itmtxt = item->text(column);
+ if (!(compare & CaseSensitive))
+ itmtxt = itmtxt.toLower();
+
+ 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;
+ ++it;
+ }
+
+ it = Q3ListViewItemIterator(firstChild());
+ sentinel = d->focusItem ? d->focusItem : firstChild();
+ }
+
+ // Obey the priorities
+ if (beginsWithItem)
+ return beginsWithItem;
+ else if (endsWithItem)
+ return endsWithItem;
+ else if (containsItem)
+ return containsItem;
+ return 0;
+}
+
+/*!
+ Hides the column specified at \a column. This is a convenience
+ function that calls setColumnWidth(column, 0).
+
+ Note: The user may still be able to resize the hidden column using
+ the header handles. To prevent this, call setResizeEnabled(false,
+ \a column) on the list views header.
+
+ \sa setColumnWidth()
+*/
+
+void Q3ListView::hideColumn(int column)
+{
+ setColumnWidth(column, 0);
+}
+
+/*! Adjusts the column \a col to its preferred width */
+
+void Q3ListView::adjustColumn(int col)
+{
+ if (col < 0 || col > (int)d->column.count() - 1 || d->h->isStretchEnabled(col))
+ return;
+
+ int oldw = d->h->sectionSize(col);
+
+ int w = d->h->sectionSizeHint(col, fontMetrics()).width();
+ if (d->h->iconSet(col))
+ w += d->h->iconSet(col)->pixmap().width();
+ w = qMax(w, 20);
+ QFontMetrics fm(fontMetrics());
+ Q3ListViewItem* item = firstChild();
+ int rootDepth = rootIsDecorated() ? treeStepSize() : 0;
+ while (item) {
+ int iw = item->width(fm, this, col);
+ if (0 == col)
+ iw += itemMargin() + rootDepth + item->depth()*treeStepSize() - 1;
+ w = qMax(w, iw);
+ item = item->itemBelow();
+ }
+ w = qMax(w, QApplication::globalStrut().width());
+
+ d->h->adjustHeaderSize(oldw - w);
+ if (oldw != w) {
+ d->fullRepaintOnComlumnChange = true;
+ d->h->resizeSection(col, w);
+ emit d->h->sizeChange(col, oldw, w);
+ }
+}
+
+/*!
+ \enum Q3ListView::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 Q3ListView::ComparisonFlags
+
+ This typedef is used in Q3ListView's API for values that are OR'd
+ combinations of \l StringComparisonMode values.
+
+ \sa StringComparisonMode
+*/
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_LISTVIEW