diff options
Diffstat (limited to 'src/widgets/tqlistview.cpp')
-rw-r--r-- | src/widgets/tqlistview.cpp | 8206 |
1 files changed, 8206 insertions, 0 deletions
diff --git a/src/widgets/tqlistview.cpp b/src/widgets/tqlistview.cpp new file mode 100644 index 000000000..d5b083520 --- /dev/null +++ b/src/widgets/tqlistview.cpp @@ -0,0 +1,8206 @@ +/**************************************************************************** +** +** Implementation of TQListView widget class +** +** Created : 970809 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the widgets module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at [email protected]. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "tqlistview.h" +#ifndef TQT_NO_LISTVIEW +#include "tqtimer.h" +#include "tqheader.h" +#include "tqpainter.h" +#include "ntqcursor.h" +#include "tqptrstack.h" +#include "tqptrlist.h" +#include "tqstrlist.h" +#include "ntqapplication.h" +#include "tqbitmap.h" +#include "tqdatetime.h" +#include "tqptrdict.h" +#include "tqptrvector.h" +#include "tqiconset.h" +#include "ntqcleanuphandler.h" +#include "tqpixmapcache.h" +#include "tqpopupmenu.h" +#include "ntqtl.h" +#include "tqdragobject.h" +#include "tqlineedit.h" +#include "ntqvbox.h" +#include "tqtooltip.h" +#include "tqstyle.h" +#include "tqstylesheet.h" +#include "../kernel/qinternal_p.h" +#if defined(QT_ACCESSIBILITY_SUPPORT) +#include "ntqaccessible.h" +#endif + +const int Unsorted = 16383; + +static TQCleanupHandler<TQBitmap> qlv_cleanup_bitmap; + +struct TQListViewItemIteratorPrivate +{ + TQListViewItemIteratorPrivate( uint f ) : flags( f ) + { + // nothing yet + } + + uint flags; +}; + +static TQPtrDict<TQListViewItemIteratorPrivate> *qt_iteratorprivate_dict = 0; + +struct TQListViewPrivate +{ + // classes that are here to avoid polluting the global name space + + // the magical hidden mother of all items + class Root: public TQListViewItem { + public: + Root( TQListView * parent ); + + void setHeight( int ); + void invalidateHeight(); + void setup(); + TQListView * theListView() const; + + TQListView * lv; + }; + + // for the stack used in drawContentsOffset() + class Pending { + public: + Pending( int level, int ypos, TQListViewItem * item) + : l(level), y(ypos), i(item) {}; + + int l; // level of this item; root is -1 or 0 + int y; // level of this item in the tree + TQListViewItem * i; // the item itself + }; + + // to remember what's on screen + class DrawableItem { + public: + DrawableItem( Pending * pi ) { y = pi->y; l = pi->l; i = pi->i; }; + int y; + int l; + TQListViewItem * i; + }; + + // for sorting + class SortableItem { + public: + /* + We could be smarter and keep a pointer to the TQListView + 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 + chosing the secondary key. + */ + TQListViewItem * 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; } + TQString text, tmpText; + TQPixmap * pm; + ItemColumnInfo * next; + uint truncated : 1; + uint dirty : 1; + uint allow_rename : 1; + int width; + }; + + class ViewColumnInfo { + public: + ViewColumnInfo(): align(TQt::AlignAuto), sortable(TRUE), next( 0 ) {} + ~ViewColumnInfo() { delete next; } + int align; + bool sortable; + ViewColumnInfo * next; + }; + + // private variables used in TQListView + ViewColumnInfo * vci; + TQHeader * h; + Root * r; + uint rootIsExpandable : 1; + int margin; + + TQListViewItem * focusItem, *highlighted, *oldFocusItem; + + TQTimer * timer; + TQTimer * dirtyItemTimer; + TQTimer * visibleTimer; + int levelWidth; + + // the list of drawables, and the range drawables covers entirely + // (it may also include a few items above topPixel) + TQPtrList<DrawableItem> * drawables; + int topPixel; + int bottomPixel; + + TQPtrDict<void> * dirtyItems; + + TQListView::SelectionMode selectionMode; + + // Per-column structure for information not in the TQHeader + struct Column { + TQListView::WidthMode wmode; + }; + TQPtrVector<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 + TQString currentPrefix; + TQTime currentPrefixTime; + + // holds a list of iterators + TQPtrList<TQListViewItemIterator> *iterators; + TQListViewItem *pressedItem, *selectAnchor; + + TQTimer *scrollTimer; + TQTimer *renameTimer; + TQTimer *autoopenTimer; + + // sort column and order #### may need to move to TQHeader [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 useDoubleBuffer :1; + bool toolTips :1; + bool fullRepaintOnComlumnChange:1; + bool updateHeader :1; + + bool startEdit : 1; + bool ignoreEditAfterFocus : 1; + bool inMenuMode :1; + + TQListView::RenameAction defRenameAction; + + TQListViewItem *startDragItem; + TQPoint dragStartPos; + TQListViewToolTip *toolTip; + int pressedColumn; + TQListView::ResizeMode resizeMode; +}; + +#ifndef TQT_NO_TOOLTIP +class TQListViewToolTip : public TQToolTip +{ +public: + TQListViewToolTip( TQWidget *parent, TQListView *lv ); + virtual ~TQListViewToolTip(); + + void maybeTip( const TQPoint &pos ); + +private: + TQListView *view; + +}; + +TQListViewToolTip::TQListViewToolTip( TQWidget *parent, TQListView *lv ) + : TQToolTip( parent ), view( lv ) +{ +} + +TQListViewToolTip::~TQListViewToolTip() +{ +} + +void TQListViewToolTip::maybeTip( const TQPoint &pos ) +{ + if ( !parentWidget() || !view || !view->showToolTips() ) + return; + + TQListViewItem *item = view->itemAt( pos ); + TQPoint contentsPos = view->viewportToContents( pos ); + if ( !item || !item->columns ) + return; + int col = view->header()->sectionAt( contentsPos.x() ); + TQListViewPrivate::ItemColumnInfo *ci = (TQListViewPrivate::ItemColumnInfo*)item->columns; + for ( int i = 0; ci && ( i < col ); ++i ) + ci = ci->next; + + if ( !ci || !ci->truncated ) + return; + + TQRect r = view->itemRect( item ); + int headerPos = view->header()->sectionPos( col ); + r.setLeft( headerPos ); + r.setRight( headerPos + view->header()->sectionSize( col ) ); + tip( r, TQStyleSheet::escape(item->text( col ) ) ); +} +#endif + +// these should probably be in TQListViewPrivate, for future thread safety +static bool activatedByClick; + +// Holds the position of activation. The position is relative to the top left corner in the row minus the root decoration and its branches/depth. +// Used to track the point clicked for CheckBoxes and RadioButtons. +static TQPoint activatedP; + +#if defined(QT_ACCESSIBILITY_SUPPORT) +static int indexOfItem( TQListViewItem *item ) +{ + if ( !TQAccessible::isActive() ) + return 0; + + static TQListViewItem *lastItem = 0; + static int lastIndex = 0; + + if ( !item || !item->listView() ) + return 0; + + if ( item == lastItem ) + return lastIndex; + + lastItem = item; + int index = 1; + + TQListViewItemIterator it( item->listView() ); + while ( it.current() ) { + if ( it.current() == item ) { + lastIndex = index; + return index; + } + ++it; + ++index; + } + lastIndex = 0; + return 0; +} +#endif + +/*! + \internal + Creates a string with ... like "Trollte..." or "...olltech" depending on the alignment +*/ + +static TQString qEllipsisText( const TQString &org, const TQFontMetrics &fm, int width, int align ) +{ + int ellWidth = fm.width( "..." ); + TQString text = TQString::fromLatin1(""); + int i = 0; + int len = org.length(); + int offset = (align & TQt::AlignRight) ? (len-1) - i : i; + while ( i < len && fm.width( text + org[ offset ] ) + ellWidth < width ) { + if ( align & TQt::AlignRight ) + text.prepend( org[ offset ] ); + else + text += org[ offset ]; + offset = (align & TQt::AlignRight) ? (len-1) - ++i : ++i; + } + if ( text.isEmpty() ) + text = ( align & TQt::AlignRight ) ? org.right( 1 ) : text = org.left( 1 ); + if ( align & TQt::AlignRight ) + text.prepend( "..." ); + else + text += "..."; + return text; +} + +/*! + \class TQListViewItem + \brief The TQListViewItem class implements a list view item. + + \ingroup advanced + + A list view item is a multi-column object capable of displaying + itself in a TQListView. + + The easiest way to use TQListViewItem is to construct one with a + few constant strings, and either a TQListView or another + TQListViewItem as parent. + \code + (void) new TQListViewItem( listView, "Column 1", "Column 2" ); + (void) new TQListViewItem( listView->firstChild(), "A", "B", "C" ); + \endcode + We've discarded the pointers to the items since we can still access + them via their parent \e listView. By default, TQListView sorts its + items; this can be switched off with TQListView::setSorting(-1). + + The parent must be another TQListViewItem or a TQListView. If the + parent is a TQListView, the item becomes a top-level item within + that TQListView. If the parent is another TQListViewItem, 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 TQListViewItem in a TQListView using + TQListView::selectedItem(), TQListView::currentItem(), + TQListView::firstChild(), TQListView::lastItem() and + TQListView::findItem(). + + If you call \c delete on a list view item, it will be deleted as + expected, and as usual for \l{TQObject}s, if it has any child items + (to any depth), all these will be deleted too. + + \l{TQCheckListItem}s are list view items that have a checkbox or + radio button and can be used in place of plain TQListViewItems. + + 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: + \code + TQListViewItem * myChild = myItem->firstChild(); + while( myChild ) { + doSomething( myChild ); + myChild = myChild->nextSibling(); + } + \endcode + + 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 starting from a + particular item, initialize the iterator with the item: + + \code + TQListViewItemIterator it( listview ); + while ( it.current() ) { + TQListViewItem *item = it.current(); + doSomething( item ); + ++it; + } + \endcode + + 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; TQListView will + always call it before it needs to show an item. + + Many programs will need to reimplement TQListViewItem. 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, TQFileDialog + 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 tqlistviewitems.png List View Items + + \sa TQCheckListItem TQListView +*/ + +/*! + \fn int TQCheckListItem::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 with no parent +*/ + +TQListViewItem::TQListViewItem( ) +{ + init(); +} + +/*! + Constructs a new top-level list view item in the TQListView \a + parent. +*/ + +TQListViewItem::TQListViewItem( TQListView * 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. +*/ + +TQListViewItem::TQListViewItem( TQListViewItem * 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 TQListView the item will be a top-level item. +*/ + +TQListViewItem::TQListViewItem( TQListView * parent, TQListViewItem * 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. +*/ + +TQListViewItem::TQListViewItem( TQListViewItem * parent, TQListViewItem * after ) +{ + init(); + parent->insertItem( this ); + moveToJustAfter( after ); +} + + + +/*! + Constructs a new top-level list view item in the TQListView \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() +*/ + +TQListViewItem::TQListViewItem( TQListView * parent, + TQString label1, + TQString label2, + TQString label3, + TQString label4, + TQString label5, + TQString label6, + TQString label7, + TQString 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 TQListViewItem \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() +*/ + +TQListViewItem::TQListViewItem( TQListViewItem * parent, + TQString label1, + TQString label2, + TQString label3, + TQString label4, + TQString label5, + TQString label6, + TQString label7, + TQString 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 TQListView \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 TQListViewItem::key() + unless the list view's sorting is disabled using + TQListView::setSorting(-1). + + \sa setText() +*/ + +TQListViewItem::TQListViewItem( TQListView * parent, TQListViewItem * after, + TQString label1, + TQString label2, + TQString label3, + TQString label4, + TQString label5, + TQString label6, + TQString label7, + TQString 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 TQListViewItem \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 TQListViewItem::key() + unless the list view's sorting is disabled using + TQListView::setSorting(-1). + + \sa setText() +*/ + +TQListViewItem::TQListViewItem( TQListViewItem * parent, TQListViewItem * after, + TQString label1, + TQString label2, + TQString label3, + TQString label4, + TQString label5, + TQString label6, + TQString label7, + TQString 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 TQListViewItem::sort() +{ + if ( !listView() ) + return; + lsc = Unsorted; + enforceSortOrder(); + listView()->triggerUpdate(); +} + +int TQListViewItem::RTTI = 0; + +/*! + 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 TQListViewItem::rtti() const +{ + return RTTI; +} + +/* + Performs the initializations that's common to the constructors. +*/ + +void TQListViewItem::init() +{ + ownHeight = 0; + maybeTotalHeight = -1; + open = FALSE; + + nChildren = 0; + parentItem = 0; + siblingItem = childItem = 0; + + columns = 0; + + selected = 0; + + 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. + TQListViewItemIterator. +*/ + +void TQListViewItem::setVisible( bool b ) +{ + if ( b == (bool)visible ) + return; + TQListView *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 ( TQListViewItem *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 TQListViewItem::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 TQListViewItem::setRenameEnabled( int col, bool b ) +{ + TQListViewPrivate::ItemColumnInfo * l = (TQListViewPrivate::ItemColumnInfo*)columns; + if ( !l ) { + l = new TQListViewPrivate::ItemColumnInfo; + columns = (void*)l; + } + for( int c = 0; c < col; c++ ) { + if ( !l->next ) + l->next = new TQListViewPrivate::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 TQListViewItem::renameEnabled( int col ) const +{ + TQListViewPrivate::ItemColumnInfo * l = (TQListViewPrivate::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 TQListViewItem::setEnabled( bool b ) +{ + if ( (bool)enabled == b ) + return; + enabled = b; + if ( !enabled ) + selected = FALSE; + TQListView *lv = listView(); + if ( lv ) { + lv->triggerUpdate(); +#if defined(QT_ACCESSIBILITY_SUPPORT) + TQAccessible::updateAccessibility( lv->viewport(), indexOfItem( this ), TQAccessible::StateChanged ); +#endif + } +} + +/*! + Returns TRUE if this item is enabled; otherwise returns FALSE. + + \sa setEnabled() +*/ + +bool TQListViewItem::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 TQListViewItem::startRename( int col ) +{ + if ( !renameEnabled( col ) ) + return; + if ( renameBox ) + cancelRename( col ); + TQListView *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 == TQListView::Reject ) + lv->currentItem()->cancelRename( lv->currentItem()->renameCol ); + else + lv->currentItem()->okRename( lv->currentItem()->renameCol ); + } + + if ( this != lv->currentItem() ) + lv->setCurrentItem( this ); + + TQRect r = lv->itemRect( this ); + r = TQRect( lv->viewportToContents( r.topLeft() ), r.size() ); + r.setLeft( lv->header()->sectionPos( col ) ); + r.setWidth(TQMIN(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 TQLineEdit( lv->viewport(), "qt_renamebox" ); + renameBox->setFrameStyle( TQFrame::Box | TQFrame::Plain ); + renameBox->setLineWidth( 1 ); + 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 TQListViewItem::removeRenameBox() +{ + // Sanity, it should be checked by the functions calling this first anyway + TQListView *lv = listView(); + if ( !lv || !renameBox ) + return; + const bool resetFocus = lv->viewport()->focusProxy() == renameBox; + const bool renameBoxHadFocus = renameBox->hasFocus(); + delete renameBox; + renameBox = 0; + if ( resetFocus ) + lv->viewport()->setFocusProxy( lv ); + if (renameBoxHadFocus) + 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 TQListViewItem::okRename( int col ) +{ + TQListView *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 TQListViewItem::cancelRename( int ) +{ + TQListView *lv = listView(); + if ( !lv || !renameBox ) + return; + removeRenameBox(); +} + +/*! + Destroys the item, deleting all its children and freeing up all + allocated resources. +*/ + +TQListViewItem::~TQListViewItem() +{ + if ( renameBox ) { + delete renameBox; + renameBox = 0; + } + + TQListView *lv = listView(); + + if ( lv ) { + if ( lv->d->oldFocusItem == this ) + lv->d->oldFocusItem = 0; + if ( lv->d->iterators ) { + TQListViewItemIterator *i = lv->d->iterators->first(); + while ( i ) { + if ( i->current() == this ) + i->currentRemoved(); + i = lv->d->iterators->next(); + } + } + } + + if ( parentItem ) + parentItem->takeItem( this ); + TQListViewItem * i = childItem; + childItem = 0; + while ( i ) { + i->parentItem = 0; + TQListViewItem * n = i->siblingItem; + delete i; + i = n; + } + delete (TQListViewPrivate::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 TQListViewItem::setMultiLinesEnabled( bool b ) +{ + mlenabled = b; +} + +/*! + Returns TRUE if the item can display multiple lines of text in its + columns; otherwise returns FALSE. +*/ + +bool TQListViewItem::multiLinesEnabled() const +{ + return mlenabled; +} + +/*! + If \a allow is TRUE, the list view starts a drag (see + TQListView::dragObject()) when the user presses and moves the mouse + on this item. +*/ + + +void TQListViewItem::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 TQListViewItem::setDropEnabled( bool allow ) +{ + allow_drop = (uint)allow; +} + +/*! + Returns TRUE if this item can be dragged; otherwise returns FALSE. + + \sa setDragEnabled() +*/ + +bool TQListViewItem::dragEnabled() const +{ + return (bool)allow_drag; +} + +/*! + Returns TRUE if this item accepts drops; otherwise returns FALSE. + + \sa setDropEnabled(), acceptDrop() +*/ + +bool TQListViewItem::dropEnabled() const +{ + return (bool)allow_drop; +} + +/*! + Returns TRUE if the item can accept drops of type TQMimeSource \a + mime; otherwise returns FALSE. + + The default implementation does nothing and returns FALSE. A + subclass must reimplement this to accept drops. +*/ + +bool TQListViewItem::acceptDrop( const TQMimeSource * ) const +{ + return FALSE; +} + +#ifndef TQT_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 TQListViewItem::dropped( TQDropEvent *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 TQListViewItem::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 TQListViewItem::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 TQListViewItem::insertItem( TQListViewItem * newChild ) +{ + TQListView *lv = listView(); + if ( lv && lv->currentItem() && lv->currentItem()->renameBox ) { + if ( lv->d->defRenameAction == TQListView::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 TQListViewItem::removeItem( TQListViewItem * ) + \obsolete + + This function has been renamed takeItem(). +*/ + + +/*! + 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 + TQListViewItem::~TQListViewItem() 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 TQListViewItem::insertItem() +*/ + +void TQListViewItem::takeItem( TQListViewItem * item ) +{ + if ( !item ) + return; + + TQListView *lv = listView(); + if ( lv && lv->currentItem() && lv->currentItem()->renameBox ) { + if ( lv->d->defRenameAction == TQListView::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; + + if ( lv->d->iterators ) { + TQListViewItemIterator *i = lv->d->iterators->first(); + while ( i ) { + if ( i->current() == item ) + i->currentRemoved(); + i = lv->d->iterators->next(); + } + } + + invalidateHeight(); + + if ( lv->d && lv->d->drawables ) { + delete lv->d->drawables; + lv->d->drawables = 0; + } + + if ( lv->d->dirtyItems ) { + if ( item->childItem ) { + delete lv->d->dirtyItems; + lv->d->dirtyItems = 0; + lv->d->dirtyItemTimer->stop(); + lv->triggerUpdate(); + } else { + lv->d->dirtyItems->take( (void *)item ); + } + } + + if ( lv->d->focusItem ) { + const TQListViewItem * 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 TQListViewItem *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--; + + TQListViewItem ** 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 ); +#if defined(QT_ACCESSIBILITY_SUPPORT) + TQAccessible::updateAccessibility( lv->viewport(), 0, TQAccessible::Focus ); +#endif + } +} + + +/*! + \fn TQString TQListViewItem::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() +*/ + +TQString TQListViewItem::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 + TQString::localeAwareCompare(). A reimplementation can use + different values and a different comparison function. Here is a + reimplementation that uses plain Unicode comparison: + + \code + int MyListViewItem::compare( TQListViewItem *i, int col, + bool ascending ) const + { + return key( col, ascending ).compare( i->key( col, ascending) ); + } + \endcode + We don't recommend using \a ascending so your code can safely + ignore it. + + \sa key() TQString::localeAwareCompare() TQString::compare() +*/ + +int TQListViewItem::compare( TQListViewItem *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. (TQListView and + TQListViewItem 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 TQListViewItem::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 ); + + // only sort if the item have more than one child. + if ( column > nColumns || childItem == 0 || (childItem->siblingItem == 0 && childItem->childItem == 0)) + return; + + // make an array for qHeapSort() + TQListViewPrivate::SortableItem * siblings + = new TQListViewPrivate::SortableItem[nChildren]; + TQListViewItem * 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 TQListViewItem::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 TQListViewItem::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 <b>-</b> 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 <b>+</b> icon to the left + of the item. + + \sa height() totalHeight() isOpen() +*/ + +void TQListViewItem::setOpen( bool o ) +{ + if ( o == (bool)open || !enabled ) + return; + open = o; + + // If no children to show simply emit signals and return + if ( !nChildren ) { + TQListView *lv = listView(); + if ( lv && this != lv->d->r ) { + if ( o ) + emit lv->expanded( this ); + else + emit lv->collapsed( this ); +#if defined(QT_ACCESSIBILITY_SUPPORT) + TQAccessible::updateAccessibility( lv->viewport(), indexOfItem( this ), TQAccessible::StateChanged ); +#endif + } + return; + } + invalidateHeight(); + + if ( !configured ) { + TQListViewItem * l = this; + TQPtrStack<TQListViewItem> s; + while( l ) { + if ( l->open && l->childItem ) { + s.push( l->childItem ); + } else if ( l->childItem ) { + // first invisible child is unconfigured + TQListViewItem * 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(); + } + } + + TQListView *lv = listView(); + + if ( open && lv) + enforceSortOrder(); + + if ( isVisible() && lv && lv->d && lv->d->drawables ) { + lv->d->drawables->clear(); + lv->buildDrawableList(); + } + + if ( lv && this != lv->d->r ) { + if ( o ) + emit lv->expanded( this ); + else + emit lv->collapsed( this ); +#if defined(QT_ACCESSIBILITY_SUPPORT) + TQAccessible::updateAccessibility( lv->viewport(), indexOfItem( this ), TQAccessible::StateChanged ); +#endif + } +} + + +/*! + This virtual function is called before the first time TQListView + 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 TQListViewItem::setup() +{ + widthChanged(); + TQListView *lv = listView(); + + int ph = 0; + int h = 0; + if ( lv ) { + for ( uint i = 0; i < lv->d->column.size(); ++i ) { + if ( pixmap( i ) ) + ph = TQMAX( ph, pixmap( i )->height() ); + } + + if ( mlenabled ) { + h = ph; + for ( int c = 0; c < lv->columns(); ++c ) { + int lines = text( c ).contains( TQChar('\n') ) + 1; + int tmph = lv->d->fontMetricsHeight + + lv->fontMetrics().lineSpacing() * ( lines - 1 ); + h = TQMAX( h, tmph ); + } + h += 2*lv->itemMargin(); + } else { + h = TQMAX( lv->d->fontMetricsHeight, ph ) + 2*lv->itemMargin(); + } + } + + h = TQMAX( h, TQApplication::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 TQListViewItem::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. + + \warning We recommend that you ignore this function; it is + scheduled to become obsolete. + + \sa activate() +*/ + +bool TQListViewItem::activatedPos( TQPoint &pos ) +{ + if ( activatedByClick ) + pos = activatedP; + return activatedByClick; +} + + +/*! + \fn bool TQListViewItem::isSelectable() const + + Returns TRUE if the item is selectable (as it is by default); + otherwise returns FALSE + + \sa setSelectable() +*/ + + +/*! + Sets this item 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. This also applies for the application + programmer (e.g. setSelected() respects this value). + + \sa isSelectable() +*/ + +void TQListViewItem::setSelectable( bool enable ) +{ + selectable = enable; +} + + +/*! + \fn bool TQListViewItem::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 + TQListView::setRootIsDecorated() is set to TRUE. + + \sa setSelectable() +*/ + +void TQListViewItem::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 TQListViewItem::enforceSortOrder() const +{ + TQListView *lv = listView(); + if ( !lv || (lv && (lv->d->clearing || lv->d->sortcolumn == Unsorted)) ) + return; + if ( parentItem && + (parentItem->lsc != lsc || parentItem->lso != lso) ) + ((TQListViewItem *)this)->sortChildItems( (int)parentItem->lsc, + (bool)parentItem->lso ); + else if ( !parentItem && + ( (int)lsc != lv->d->sortcolumn || (bool)lso != lv->d->ascending ) ) + ((TQListViewItem *)this)->sortChildItems( lv->d->sortcolumn, lv->d->ascending ); +} + + +/*! + \fn bool TQListViewItem::isSelected() const + + Returns TRUE if this item is selected; otherwise returns FALSE. + + \sa setSelected() TQListView::setSelected() TQListView::selectionChanged() +*/ + + +/*! + If \a s is TRUE this item is selected; otherwise it is deselected. + + This function does not maintain any invariants or repaint anything + -- TQListView::setSelected() does that. + + \sa height() totalHeight() +*/ + +void TQListViewItem::setSelected( bool s ) +{ + bool old = selected; + + TQListView *lv = listView(); + if ( lv && lv->selectionMode() != TQListView::NoSelection) { + if ( s && isSelectable() ) + selected = TRUE; + else + selected = FALSE; + +#if defined(QT_ACCESSIBILITY_SUPPORT) + if ( old != (bool)selected ) { + int ind = indexOfItem( this ); + TQAccessible::updateAccessibility( lv->viewport(), ind, TQAccessible::StateChanged ); + TQAccessible::updateAccessibility( lv->viewport(), ind, selected ? TQAccessible::SelectionAdd : TQAccessible::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 TQListViewItem::totalHeight() const +{ + if ( !visible ) + return 0; + if ( maybeTotalHeight >= 0 ) + return maybeTotalHeight; + TQListViewItem * that = (TQListViewItem *)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; + + TQListViewItem * child = that->childItem; + while ( child != 0 ) { + that->maybeTotalHeight += child->totalHeight(); + child = child->siblingItem; + } + return that->maybeTotalHeight; +} + + +/*! + Returns the text in column \a column, or TQString::null if there is + no text in that column. + + \sa key() paintCell() +*/ + +TQString TQListViewItem::text( int column ) const +{ + TQListViewPrivate::ItemColumnInfo * l + = (TQListViewPrivate::ItemColumnInfo*) columns; + + while( column && l ) { + l = l->next; + column--; + } + + return l ? l->text : TQString::null; +} + + +/*! + 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 \a text() has been reimplemented, this function may be a no-op. + + \sa text() key() +*/ + +void TQListViewItem::setText( int column, const TQString &text ) +{ + if ( column < 0 ) + return; + + TQListViewPrivate::ItemColumnInfo * l + = (TQListViewPrivate::ItemColumnInfo*) columns; + if ( !l ) { + l = new TQListViewPrivate::ItemColumnInfo; + columns = (void*)l; + } + for( int c = 0; c < column; c++ ) { + if ( !l->next ) + l->next = new TQListViewPrivate::ItemColumnInfo; + l = l->next; + } + if ( l->text == text ) + return; + + int oldLc = 0; + int newLc = 0; + if ( mlenabled ) { + if ( !l->text.isEmpty() ) + oldLc = l->text.contains( TQChar( '\n' ) ) + 1; + if ( !text.isEmpty() ) + newLc = text.contains( TQChar( '\n' ) ) + 1; + } + + l->dirty = TRUE; + l->text = text; + if ( column == (int)lsc ) + lsc = Unsorted; + + if ( mlenabled && oldLc != newLc ) + setup(); + else + widthChanged( column ); + + TQListView * lv = listView(); + if ( lv ) { + lv->d->useDoubleBuffer = TRUE; + lv->triggerUpdate(); +#if defined(QT_ACCESSIBILITY_SUPPORT) + if ( lv->isVisible() ) + TQAccessible::updateAccessibility( lv->viewport(), indexOfItem(this), TQAccessible::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 TQListViewItem::setPixmap( int column, const TQPixmap & pm ) +{ + if ( column < 0 ) + return; + + int oldW = 0; + int oldH = 0; + if ( pixmap( column ) ) { + oldW = pixmap( column )->width(); + oldH = pixmap( column )->height(); + } + + TQListViewPrivate::ItemColumnInfo * l + = (TQListViewPrivate::ItemColumnInfo*) columns; + if ( !l ) { + l = new TQListViewPrivate::ItemColumnInfo; + columns = (void*)l; + } + + for( int c = 0; c < column; c++ ) { + if ( !l->next ) + l->next = new TQListViewPrivate::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 TQPixmap( 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(); + } + TQListView *lv = listView(); + if ( lv ) { + lv->d->useDoubleBuffer = TRUE; + lv->triggerUpdate(); + } +} + + +/*! + Returns the pixmap for \a column, or 0 if there is no pixmap for + \a column. + + \sa setText() setPixmap() +*/ + +const TQPixmap * TQListViewItem::pixmap( int column ) const +{ + TQListViewPrivate::ItemColumnInfo * l + = (TQListViewPrivate::ItemColumnInfo*) columns; + + while( column && l ) { + l = l->next; + column--; + } + + return (l && l->pm) ? l->pm : 0; +} + + +/*! + This virtual function paints the contents of one column of an item + and aligns it as described by \a align. + + \a p is a TQPainter 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 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 TQListView::itemMargin() for readability + spacing on the left and right sides of data such as text, and + should honor isSelected() and TQListView::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(), TQListView::drawContentsOffset() +*/ + +void TQListViewItem::paintCell( TQPainter * p, const TQColorGroup & cg, + int column, int width, int align ) +{ + // Change width() if you change this. + + if ( !p ) + return; + + TQListView *lv = listView(); + if ( !lv ) + return; + TQFontMetrics fm( p->fontMetrics() ); + + // had, but we _need_ the column info for the ellipsis thingy!!! + if ( !columns ) { + for ( uint i = 0; i < lv->d->column.size(); ++i ) { + setText( i, text( i ) ); + } + } + + TQString t = text( column ); + + if ( columns ) { + TQListViewPrivate::ItemColumnInfo *ci = 0; + // try until we have a column info.... + while ( !ci ) { + ci = (TQListViewPrivate::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 ) { +#ifndef TQT_NO_STRINGLIST + TQStringList list = TQStringList::split( TQChar('\n'), t, TRUE ); + for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + TQString 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( TQString("\n") ); +#endif + } + } + + // 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 TQPixmap * icon = pixmap( column ); + + const BackgroundMode bgmode = lv->viewport()->backgroundMode(); + const TQColorGroup::ColorRole crole = TQPalette::backgroundRoleFromMode( bgmode ); + if ( cg.brush( crole ) != lv->colorGroup().brush( crole ) ) + p->fillRect( 0, 0, width, height(), cg.brush( crole ) ); + else + lv->paintEmptyArea( p, TQRect( 0, 0, width, height() ) ); + + + // (lars) what does this do??? +#if 0 // RS: #### + if ( align != AlignLeft ) + marg -= lv->d->minRightBearing; +#endif + if ( isSelected() && + (column == 0 || lv->allColumnsShowFocus()) ) { + p->fillRect( r - marg, 0, width - r + marg, height(), + cg.brush( TQColorGroup::Highlight ) ); + if ( enabled || !lv ) + p->setPen( cg.highlightedText() ); + else if ( !enabled && lv) + p->setPen( lv->palette().disabled().highlightedText() ); + } else { + if ( enabled || !lv ) + p->setPen( cg.text() ); + else if ( !enabled && lv) + p->setPen( lv->palette().disabled().text() ); + } + + +#if 0 + bool reverse = TQApplication::reverseLayout(); +#else + bool reverse = FALSE; +#endif + int iconWidth = 0; + + if ( icon ) { + iconWidth = icon->width() + lv->itemMargin(); + int xo = r; + // we default to AlignVCenter. + int yo = ( height() - icon->height() ) / 2; + + // I guess we may as well always respect vertical alignment. + if ( align & AlignBottom ) + yo = height() - icon->height(); + else if ( align & AlignTop ) + yo = 0; + + // respect horizontal alignment when there is no text for an item. + if ( text(column).isEmpty() ) { + if ( align & AlignRight ) + xo = width - 2 * marg - iconWidth; + else if ( align & AlignHCenter ) + xo = ( width - iconWidth ) / 2; + } + if ( reverse ) + xo = width - 2 * marg - iconWidth; + p->drawPixmap( xo, yo, *icon ); + } + + if ( !t.isEmpty() ) { + if ( !mlenabled ) { + if ( !(align & AlignTop || align & AlignBottom) ) + align |= AlignVCenter; + } else { + if ( !(align & AlignVCenter || align & AlignBottom) ) + align |= 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 = TQMAX( textheight, TQApplication::globalStrut().height() ); + if ( textheight % 2 > 0 ) + textheight++; + if ( textheight < height() ) { + int w = lv->treeStepSize() / 2; + lv->style().drawComplexControl( TQStyle::CC_ListView, p, lv, + TQRect( 0, textheight, w + 1, height() - textheight + 1 ), cg, + lv->isEnabled() ? TQStyle::Style_Enabled : TQStyle::Style_Default, + TQStyle::SC_ListViewExpand, + (uint)TQStyle::SC_All, TQStyleOption( this ) ); + } + } +} + +/*! + 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 TQListView::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() TQListView::setColumnWidthMode() + TQListView::itemMargin() +*/ +int TQListViewItem::width( const TQFontMetrics& fm, + const TQListView* lv, int c ) const +{ + int w; + if ( mlenabled ) + w = fm.size( 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 TQPixmap * pm = pixmap( c ); + if ( pm ) + w += pm->width() + lv->itemMargin(); // ### correct margin stuff? + return TQMAX( w, TQApplication::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() TQListView::setAllColumnsShowFocus() +*/ + +void TQListViewItem::paintFocus( TQPainter *p, const TQColorGroup &cg, + const TQRect & r ) +{ + TQListView *lv = listView(); + if ( lv ) + lv->style().drawPrimitive( TQStyle::PE_FocusRect, p, r, cg, + (isSelected() ? + TQStyle::Style_FocusAtBorder : + TQStyle::Style_Default), + TQStyleOption(isSelected() ? cg.highlight() : cg.base() )); +} + + +/*! + 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(), TQListView::drawContentsOffset() +*/ + +void TQListViewItem::paintBranches( TQPainter * p, const TQColorGroup & cg, + int w, int y, int h ) +{ + TQListView *lv = listView(); + if ( lv ) + lv->paintEmptyArea( p, TQRect( 0, 0, w, h ) ); + if ( !visible || !lv ) + return; + lv->style().drawComplexControl( TQStyle::CC_ListView, p, lv, + TQRect( 0, y, w, h ), + cg, + lv->isEnabled() ? TQStyle::Style_Enabled : + TQStyle::Style_Default, + (TQStyle::SC_ListViewBranch | + TQStyle::SC_ListViewExpand), + TQStyle::SC_None, TQStyleOption(this) ); +} + + +TQListViewPrivate::Root::Root( TQListView * parent ) + : TQListViewItem( parent ) +{ + lv = parent; + setHeight( 0 ); + setOpen( TRUE ); +} + + +void TQListViewPrivate::Root::setHeight( int ) +{ + TQListViewItem::setHeight( 0 ); +} + + +void TQListViewPrivate::Root::invalidateHeight() +{ + TQListViewItem::invalidateHeight(); + lv->triggerUpdate(); +} + + +TQListView * TQListViewPrivate::Root::theListView() const +{ + return lv; +} + + +void TQListViewPrivate::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 TQListViewItem::ignoreDoubleClick() +{ + TQListView *lv = listView(); + if ( lv ) + lv->d->ignoreDoubleClick = TRUE; +} + + + +/*! + \fn void TQListView::onItem( TQListViewItem *i ) + + This signal is emitted when the user moves the mouse cursor onto + item \a i, similar to the TQWidget::enterEvent() function. +*/ + +// ### bug here too? see tqiconview.cpp onItem/onViewport + +/*! + \fn void TQListView::onViewport() + + This signal is emitted when the user moves the mouse cursor from + an item to an empty part of the list view. +*/ + +/*! + \enum TQListView::SelectionMode + + This enumerated type is used by TQListView to indicate how it + reacts to selection by the user. + + \value Single When the user selects an item, any already-selected + item becomes unselected. The user can unselect the selected + item by clicking on some empty space within the view. + + \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. Also, multiple items can be selected by dragging the + mouse while the left mouse button stays pressed. + + \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 TQListView::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 TQListView::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 TQListView + \brief The TQListView class implements a list/tree view. + + \ingroup advanced + \mainclass + + 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 TQListView, add some + column headers using addColumn() and create one or more + TQListViewItem or TQCheckListItem objects with the TQListView as + parent: + + \quotefile xml/tagreader-with-features/structureparser.h + \skipto TQListView * table + \printline + \quotefile xml/tagreader-with-features/structureparser.cpp + \skipto addColumn + \printline addColumn + \printline + \skipto new TQListViewItem( table + \printline + + Further nodes can be added to the list view object (the root of the + tree) or as child nodes to TQListViewItems: + + \skipto for ( int i = 0 ; i < attributes.length(); + \printuntil } + + (From \link xml/tagreader-with-features/structureparser.cpp + xml/tagreader-with-features/structureparser.cpp\endlink) + + 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 should show 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 + + To handle events such as mouse presses on the list view, derived + classes can reimplement the TQScrollView functions: + \link TQScrollView::contentsMousePressEvent() contentsMousePressEvent\endlink, + \link TQScrollView::contentsMouseReleaseEvent() contentsMouseReleaseEvent\endlink, + \link TQScrollView::contentsMouseDoubleClickEvent() contentsMouseDoubleClickEvent\endlink, + \link TQScrollView::contentsMouseMoveEvent() contentsMouseMoveEvent\endlink, + \link TQScrollView::contentsDragEnterEvent() contentsDragEnterEvent\endlink, + \link TQScrollView::contentsDragMoveEvent() contentsDragMoveEvent\endlink, + \link TQScrollView::contentsDragLeaveEvent() contentsDragLeaveEvent\endlink, + \link TQScrollView::contentsDropEvent() contentsDropEvent\endlink, and + \link TQScrollView::contentsWheelEvent() contentsWheelEvent\endlink. + + There are also 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 + TQListViewItem::itemBelow(); over a list view's top-level items + using TQListViewItem::firstChild() and + TQListViewItem::nextSibling(); or every item using a + TQListViewItemIterator. See + the TQListViewItem documentation for examples of traversal. + + An item can be moved amongst its siblings using + TQListViewItem::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 + TQListView::SelectionMode documentation. The default is \c Single + selection, which you can change using setSelectionMode(). + + Because TQListView 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()). + + TQListView 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(TQListViewItem*) (applicable only to a + \c Single selection list view), and currentChanged(TQListViewItem*). + The second group consists of doubleClicked(TQListViewItem*), + returnPressed(TQListViewItem*), + rightButtonClicked(TQListViewItem*, const TQPoint&, 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 TQTimer::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, TQListView 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 TQListView::SelectionMode for details. + + The list view can be navigated either using the mouse or the + keyboard. Clicking a <b>-</b> icon closes an item (hides its + children) and clicking a <b>+</b> 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 (<b>+</b> icon) or has no + children, make its parent item current and visible. If the + current item is open (<b>-</b> icon) close it, i.e. hide its + children. Exception: if the current item is the first item + and is closed and the horizontal scrollbar is offset to + the right the list view will be scrolled left. + \row \i Right Arrow + \i If the current item is closed (<b>+</b> icon) and has + children, the item is opened. If the current item is + opened (<b>-</b> 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. + + \warning The list view assumes ownership of all list view items + and will delete them when it does not need them any more. + + <img src=tqlistview-m.png> <img src=tqlistview-w.png> + + \sa TQListViewItem TQCheckListItem +*/ + +/*! + \fn void TQListView::itemRenamed( TQListViewItem * 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 TQListViewItem::setRenameEnabled() +*/ + +/*! + \fn void TQListView::itemRenamed( TQListViewItem * item, int col, const TQString &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 TQListViewItem::setRenameEnabled() +*/ + +/*! + Constructs a new empty list view called \a name with parent \a + parent. + + Performance is boosted by modifying the widget flags \a f so that + only part of the TQListViewItem children is redrawn. This may be + unsuitable for custom TQListViewItem classes, in which case \c + WStaticContents and \c WNoAutoErase should be cleared. + + \sa TQWidget::clearWFlags() TQt::WidgetFlags +*/ +TQListView::TQListView( TQWidget * parent, const char *name, WFlags f ) + : TQScrollView( parent, name, f | WStaticContents | WNoAutoErase ) +{ + init(); +} + +void TQListView::init() +{ + d = new TQListViewPrivate; + d->vci = 0; + d->timer = new TQTimer( this ); + d->levelWidth = 20; + d->r = 0; + d->rootIsExpandable = 0; + d->h = new TQHeader( this, "list view header" ); + d->h->installEventFilter( this ); + d->focusItem = 0; + d->oldFocusItem = 0; + d->drawables = 0; + d->dirtyItems = 0; + d->dirtyItemTimer = new TQTimer( this ); + d->visibleTimer = new TQTimer( this ); + d->renameTimer = new TQTimer( this ); + d->autoopenTimer = new TQTimer( this ); + d->margin = 1; + d->selectionMode = TQListView::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->column.setAutoDelete( TRUE ); + d->iterators = 0; + d->scrollTimer = 0; + d->sortIndicator = FALSE; + d->clearing = FALSE; + d->minLeftBearing = fontMetrics().minLeftBearing(); + d->minRightBearing = fontMetrics().minRightBearing(); + d->ellipsisWidth = fontMetrics().width( "..." ) * 2; + d->highlighted = 0; + d->pressedItem = 0; + d->selectAnchor = 0; + d->select = TRUE; + d->useDoubleBuffer = FALSE; + d->startDragItem = 0; + d->toolTips = TRUE; +#ifndef TQT_NO_TOOLTIP + d->toolTip = new TQListViewToolTip( viewport(), this ); +#endif + 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, TQ_SIGNAL(timeout()), + this, TQ_SLOT(updateContents()) ); + connect( d->dirtyItemTimer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(updateDirtyItems()) ); + connect( d->visibleTimer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(makeVisible()) ); + connect( d->renameTimer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(startRename()) ); + connect( d->autoopenTimer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(openFocusItem()) ); + + connect( d->h, TQ_SIGNAL(sizeChange(int,int,int)), + this, TQ_SLOT(handleSizeChange(int,int,int)) ); + connect( d->h, TQ_SIGNAL(indexChange(int,int,int)), + this, TQ_SLOT(handleIndexChange()) ); + connect( d->h, TQ_SIGNAL(sectionClicked(int)), + this, TQ_SLOT(changeSortColumn(int)) ); + connect( d->h, TQ_SIGNAL(sectionHandleDoubleClicked(int)), + this, TQ_SLOT(adjustColumn(int)) ); + connect( horizontalScrollBar(), TQ_SIGNAL(sliderMoved(int)), + d->h, TQ_SLOT(setOffset(int)) ); + connect( horizontalScrollBar(), TQ_SIGNAL(valueChanged(int)), + d->h, TQ_SLOT(setOffset(int)) ); + + // will access d->r + TQListViewPrivate::Root * r = new TQListViewPrivate::Root( this ); + r->is_root = TRUE; + d->r = r; + d->r->setSelectable( FALSE ); + + viewport()->setFocusProxy( this ); + viewport()->setFocusPolicy( WheelFocus ); + viewport()->setBackgroundMode( PaletteBase ); + setBackgroundMode( PaletteBackground, PaletteBase ); +} + +/*! + \property TQListView::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 TQHeader::setSortIndicator() +*/ + +void TQListView::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 TQListView::showSortIndicator() const +{ + return d->sortIndicator; +} + +/*! + \property TQListView::showToolTips + \brief whether this list view should show tooltips for truncated column texts + + The default is TRUE. +*/ + +void TQListView::setShowToolTips( bool b ) +{ + d->toolTips = b; +} + +bool TQListView::showToolTips() const +{ + return d->toolTips; +} + +/*! + \property TQListView::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 TQHeader, header() +*/ + +void TQListView::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 ); +} + +TQListView::ResizeMode TQListView::resizeMode() const +{ + return d->resizeMode; +} + +/*! + Destroys the list view, deleting all its items, and frees up all + allocated resources. +*/ + +TQListView::~TQListView() +{ + if ( d->iterators ) { + TQListViewItemIterator *i = d->iterators->first(); + while ( i ) { + i->listView = 0; + i = d->iterators->next(); + } + delete d->iterators; + d->iterators = 0; + } + + d->focusItem = 0; + delete d->r; + d->r = 0; + delete d->dirtyItems; + d->dirtyItems = 0; + delete d->drawables; + d->drawables = 0; + delete d->vci; + d->vci = 0; +#ifndef TQT_NO_TOOLTIP + delete d->toolTip; + d->toolTip = 0; +#endif + delete d; + d = 0; +} + + +/*! + Calls TQListViewItem::paintCell() and + TQListViewItem::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 TQListView::drawContentsOffset( TQPainter * p, int ox, int oy, + int cx, int cy, int cw, int ch ) +{ + if ( columns() == 0 ) { + paintEmptyArea( p, TQRect( cx, cy, cw, ch ) ); + return; + } + + if ( !d->drawables || + d->drawables->isEmpty() || + d->topPixel > cy || + d->bottomPixel < cy + ch - 1 || + d->r->maybeTotalHeight < 0 ) + buildDrawableList(); + + if ( d->dirtyItems ) { + TQRect br( cx - ox, cy - oy, cw, ch ); + TQPtrDictIterator<void> it( *(d->dirtyItems) ); + TQListViewItem * i; + while( (i = (TQListViewItem *)(it.currentKey())) != 0 ) { + ++it; + TQRect ir = itemRect( i ).intersect( viewport()->rect() ); + if ( ir.isEmpty() || br.contains( ir ) ) + // we're painting this one, or it needs no painting: forget it + d->dirtyItems->remove( (void *)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 + delete d->dirtyItems; + d->dirtyItems = 0; + d->dirtyItemTimer->stop(); + } + } + + p->setFont( font() ); + + TQPtrListIterator<TQListViewPrivate::DrawableItem> it( *(d->drawables) ); + + TQRect r; + int fx = -1, x, fc = 0, lc = 0; + int tx = -1; + TQListViewPrivate::DrawableItem * current; + + while ( (current = it.current()) != 0 ) { + ++it; + 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( TQStyle::SH_ItemView_ChangeHighlightOnFocus, this ) || + ( currentItem() && currentItem()->renameBox && currentItem()->renameBox->hasFocus() ); + const TQColorGroup &cg = ( drawActiveSelection ? colorGroup() : palette().inactive() ); + + while ( c < lc && d->drawables ) { + 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 == AlignAuto ) align = AlignLeft; + if ( d->useDoubleBuffer ) { + TQRect a( 0, 0, r.width(), current->i->height() ); + TQSharedDoubleBuffer buffer( p, a, TQSharedDoubleBuffer::Force ); + if ( buffer.isBuffered() ) + paintEmptyArea( buffer.painter(), a ); + buffer.painter()->setFont( p->font() ); + buffer.painter()->setPen( p->pen() ); + buffer.painter()->setBrush( p->brush() ); + buffer.painter()->setBrushOrigin( -r.left(), -r.top() ); + current->i->paintCell( buffer.painter(), cg, ac, r.width(), + align ); + } else { + current->i->paintCell( p, cg, 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 ); + TQRect 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, colorGroup(), 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 = TQMIN( current->l * treeStepSize(), d->h->cellSize( cell ) ); + r.setLeft( r.left() + offsetx ); + current->i->paintFocus( p, colorGroup(), r ); + } else { + int xdepth = TQMIN( treeStepSize() * ( current->i->depth() + ( rootIsDecorated() ? 1 : 0) ) + + itemMargin(), d->h->cellSize( cell ) ); + xdepth += d->h->cellPos( cell ); + TQRect r1( r ); + r1.setRight( d->h->cellPos( cell ) - 1 ); + TQRect r2( r ); + r2.setLeft( xdepth - 1 ); + current->i->paintFocus( p, colorGroup(), r1 ); + current->i->paintFocus( p, colorGroup(), 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 = TQMAX( rtop, cy ); + int crbottom = TQMIN( rbottom, cy+ch ); + int crleft = TQMAX( rleft, cx ); + int crright = TQMIN( rright, cx+cw ); + + r.setRect( crleft-ox, crtop-oy, + crright-crleft, crbottom-crtop ); + + if ( r.isValid() ) { + p->save(); + p->translate( rleft-ox, crtop-oy ); + current->i->paintBranches( p, colorGroup(), treeStepSize(), + rtop - crtop, r.height() ); + p->restore(); + } + } + } + + if ( d->r->totalHeight() < cy + ch ) + paintEmptyArea( p, TQRect( 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, TQRect( 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 TQListView::paintEmptyArea( TQPainter * p, const TQRect & rect ) +{ + TQStyleOption opt( d->sortcolumn, 0 ); // ### hack; in 3.1, add a property in TQListView and TQHeader + TQStyle::SFlags how = TQStyle::Style_Default; + if ( isEnabled() ) + how |= TQStyle::Style_Enabled; + + style().drawComplexControl( TQStyle::CC_ListView, + p, this, rect, colorGroup(), + how, TQStyle::SC_ListView, TQStyle::SC_None, + opt ); +} + + +/* + Rebuilds the list of drawable TQListViewItems. This function is + const so that const functions can call it without requiring + d->drawables to be mutable. +*/ + +void TQListView::buildDrawableList() const +{ + d->r->enforceSortOrder(); + + TQPtrStack<TQListViewPrivate::Pending> stack; + stack.push( new TQListViewPrivate::Pending( ((int)d->rootIsExpandable)-1, + 0, d->r ) ); + + // could mess with cy and ch in order to speed up vertical + // scrolling + int cy = contentsY(); + int ch = ((TQListView *)this)->visibleHeight(); + d->topPixel = cy + ch; // one below bottom + d->bottomPixel = cy - 1; // one above top + + TQListViewPrivate::Pending * cur; + + // used to work around lack of support for mutable + TQPtrList<TQListViewPrivate::DrawableItem> * dl; + + dl = new TQPtrList<TQListViewPrivate::DrawableItem>; + dl->setAutoDelete( TRUE ); + if ( d->drawables ) + delete ((TQListView *)this)->d->drawables; + ((TQListView *)this)->d->drawables = dl; + + while ( !stack.isEmpty() ) { + cur = stack.pop(); + + int ih = cur->i->height(); + int ith = cur->i->totalHeight(); + + // if this is not true, buildDrawableList has been called recursivly + Q_ASSERT( dl == d->drawables ); + + // is this item, or its branch symbol, inside the viewport? + if ( cur->y + ith >= cy && cur->y < cy + ch ) { + dl->append( new TQListViewPrivate::DrawableItem(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( new TQListViewPrivate::Pending(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(); + + TQListViewItem * 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( new TQListViewPrivate::Pending( cur->l + 1, + y, c ) ); + } + + delete cur; + } +} + +/*! + \property TQListView::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 TQListView::treeStepSize() const +{ + return d->levelWidth; +} + +void TQListView::setTreeStepSize( int size ) +{ + if ( size != d->levelWidth ) { + d->levelWidth = size; + viewport()->repaint( FALSE ); + } +} + +/*! + 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 + TQListViewItem::takeItem(\a i) and need to reinsert \a i elsewhere. + + \sa TQListViewItem::takeItem() takeItem() +*/ + +void TQListView::insertItem( TQListViewItem * 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. + + Note that the currentChanged() signal is not emitted when this slot is invoked. + \sa triggerUpdate() +*/ + +void TQListView::clear() +{ + bool wasUpdatesEnabled = viewport()->isUpdatesEnabled(); + viewport()->setUpdatesEnabled( FALSE ); + setContentsPos( 0, 0 ); + viewport()->setUpdatesEnabled( wasUpdatesEnabled ); + bool block = signalsBlocked(); + blockSignals( TRUE ); + d->clearing = TRUE; + clearSelection(); + if ( d->iterators ) { + TQListViewItemIterator *i = d->iterators->first(); + while ( i ) { + i->curr = 0; + i = d->iterators->next(); + } + } + + if ( d->drawables ) + d->drawables->clear(); + delete d->dirtyItems; + d->dirtyItems = 0; + d->dirtyItemTimer->stop(); + + d->focusItem = 0; + d->selectAnchor = 0; + d->pressedItem = 0; + d->highlighted = 0; + d->startDragItem = 0; + + // if it's down its downness makes no sense, so undown it + d->buttonDown = FALSE; + + TQListViewItem *c = (TQListViewItem *)d->r->firstChild(); + TQListViewItem *n; + while( c ) { + n = (TQListViewItem *)c->nextSibling(); + delete c; + c = n; + } + resizeContents( d->h->sizeHint().width(), contentsHeight() ); + delete d->r; + d->r = 0; + TQListViewPrivate::Root * r = new TQListViewPrivate::Root( this ); + r->is_root = TRUE; + d->r = r; + d->r->setSelectable( FALSE ); + blockSignals( block ); + triggerUpdate(); + d->clearing = FALSE; +} + +/*! + \reimp +*/ + +void TQListView::setContentsPos( int x, int y ) +{ + updateGeometries(); + TQScrollView::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 TQListView::addColumn( const TQString &label, int width ) +{ + int c = d->h->addLabel( label, width ); + d->column.resize( c+1 ); + d->column.insert( c, new TQListViewPrivate::Column ); + 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 iconset 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 TQListView::addColumn( const TQIconSet& iconset, const TQString &label, int width ) +{ + int c = d->h->addLabel( iconset, label, width ); + d->column.resize( c+1 ); + d->column.insert( c, new TQListViewPrivate::Column ); + d->column[c]->wmode = width >=0 ? Manual : Maximum; + updateGeometries(); + updateGeometry(); + return c; +} + +/*! + \property TQListView::columns + \brief the number of columns in this list view + + \sa addColumn(), removeColumn() +*/ + +int TQListView::columns() const +{ + return d->column.count(); +} + +/*! + Removes the column at position \a index. + + If no columns remain after the column is removed, the + list view will be cleared. + + \sa clear() +*/ + +void TQListView::removeColumn( int index ) +{ + if ( index < 0 || index > (int)d->column.count() - 1 ) + return; + + if ( d->vci ) { + TQListViewPrivate::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; + } + } + + TQListViewItemIterator it( this ); + for ( ; it.current(); ++it ) { + TQListViewPrivate::ItemColumnInfo *ci = (TQListViewPrivate::ItemColumnInfo*)it.current()->columns; + if ( ci ) { + TQListViewPrivate::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(); ++i ) { + TQListViewPrivate::Column *c = d->column.take( i ); + if ( i == index ) + delete c; + if ( i < (int)d->column.size()-1 ) + d->column.insert( 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 TQListView::setColumnText( int column, const TQString &label ) +{ + if ( column < d->h->count() ) { + d->h->setLabel( column, label ); + updateGeometries(); + updateGeometry(); + } +} + +/*! + \overload + + Sets the heading of column \a column to \a iconset and \a label. + + \sa columnText() +*/ +void TQListView::setColumnText( int column, const TQIconSet& iconset, const TQString &label ) +{ + if ( column < d->h->count() ) { + d->h->setLabel( column, iconset, 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 TQListView::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, TQ_SIGNAL(sizeChange(int,int,int)), + this, TQ_SLOT(handleSizeChange(int,int,int)) ); + emit d->h->sizeChange( column, oldw, w); + connect( d->h, TQ_SIGNAL(sizeChange(int,int,int)), + this, TQ_SLOT(handleSizeChange(int,int,int)) ); + updateGeometries(); + viewport()->update(); + } +} + + +/*! + Returns the text of column \a c. + + \sa setColumnText() +*/ + +TQString TQListView::columnText( int c ) const +{ + return d->h->label(c); +} + +/*! + Returns the width of column \a c. + + \sa setColumnWidth() +*/ + +int TQListView::columnWidth( int c ) const +{ + int actual = d->h->mapToActual( c ); + return d->h->cellSize( actual ); +} + + +/*! + \enum TQListView::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 TQListViewItem::width() +*/ + +void TQListView::setColumnWidthMode( int c, WidthMode mode ) +{ + if ( c < d->h->count() ) + d->column[c]->wmode = mode; +} + + +/*! + Returns the \c WidthMode for column \a c. + + \sa setColumnWidthMode() +*/ + +TQListView::WidthMode TQListView::columnWidthMode( int c ) const +{ + if ( 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 TQListViewItem::paintCell() for each item in + the list view. For horizontally aligned text with TQt::AlignLeft or + TQt::AlignHCenter the ellipsis (...) will be to the right, for + TQt::AlignRight the ellipsis will be to the left. + + \sa TQt::AlignmentFlags +*/ + +void TQListView::setColumnAlignment( int column, int align ) +{ + if ( column < 0 ) + return; + if ( !d->vci ) + d->vci = new TQListViewPrivate::ViewColumnInfo; + TQListViewPrivate::ViewColumnInfo * l = d->vci; + while( column ) { + if ( !l->next ) + l->next = new TQListViewPrivate::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 + AlignAuto. + + \sa TQt::AlignmentFlags +*/ + +int TQListView::columnAlignment( int column ) const +{ + if ( column < 0 || !d->vci ) + return AlignAuto; + TQListViewPrivate::ViewColumnInfo * l = d->vci; + while( column ) { + if ( !l->next ) + l->next = new TQListViewPrivate::ViewColumnInfo; + l = l->next; + column--; + } + return l ? l->align : AlignAuto; +} + + + +/*! + \reimp + */ +void TQListView::show() +{ + // Reimplemented to setx the correct background mode and viewed + // area size. + if ( !isVisible() ) { + reconfigureItems(); + updateGeometries(); + } + TQScrollView::show(); +} + + +/*! + Updates the sizes of the viewport, header, scroll bars and so on. + + \warning Don't call this directly; call triggerUpdate() instead. +*/ + +void TQListView::updateContents() +{ + if ( d->updateHeader ) + header()->adjustHeaderSize(); + d->updateHeader = FALSE; + if ( !isVisible() ) { + // Not in response to a setText/setPixmap any more. + d->useDoubleBuffer = FALSE; + + return; + } + if ( d->drawables ) { + delete d->drawables; + d->drawables = 0; + } + viewport()->setUpdatesEnabled( FALSE ); + updateGeometries(); + viewport()->setUpdatesEnabled( TRUE ); + viewport()->repaint( FALSE ); + d->useDoubleBuffer = FALSE; +} + + +void TQListView::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 - TQListView::d->h->width() ); +#if 0 + if ( TQApplication::reverseLayout() && d->h->offset() != horizontalScrollBar()->value() ) + horizontalScrollBar()->setValue( d->h->offset() ); +#endif + verticalScrollBar()->raise(); + resizeContents( tw, th ); + if ( d->h->isHidden() ) { + setMargins( 0, 0, 0, 0 ); + } else { + TQSize 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 TQListView::handleSizeChange( int section, int os, int ns ) +{ + bool upe = viewport()->isUpdatesEnabled(); + viewport()->setUpdatesEnabled( FALSE ); + int sx = horizontalScrollBar()->value(); + bool sv = horizontalScrollBar()->isVisible(); + updateGeometries(); + bool fullRepaint = d->fullRepaintOnComlumnChange || sx != horizontalScrollBar()->value() + || sv != horizontalScrollBar()->isVisible(); + d->fullRepaintOnComlumnChange = FALSE; + viewport()->setUpdatesEnabled( upe ); + + if ( fullRepaint ) { + viewport()->repaint( FALSE ); + 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, TQRect( left, 0, visibleWidth() - left, visibleHeight() ) ); + viewport()->repaint( left - 4 - d->ellipsisWidth, 0, 4 + d->ellipsisWidth, + visibleHeight(), FALSE ); // 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 == AlignAuto ) align = AlignLeft; + if ( align != AlignAuto && align != AlignLeft ) + viewport()->repaint( d->h->cellPos( actual ) - contentsX(), 0, + d->h->cellSize( actual ), visibleHeight() ); + + if ( currentItem() && currentItem()->renameBox ) { + TQRect r = itemRect( currentItem() ); + r = TQRect( 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 TQListView::updateDirtyItems() +{ + if ( d->timer->isActive() || !d->dirtyItems ) + return; + TQRect ir; + TQPtrDictIterator<void> it( *(d->dirtyItems) ); + TQListViewItem * i; + while( (i = (TQListViewItem *)(it.currentKey())) != 0 ) { + ++it; + ir = ir.unite( itemRect(i) ); + } + if ( !ir.isEmpty() ) { // rectangle to be repainted + if ( ir.x() < 0 ) + ir.moveBy( -ir.x(), 0 ); + viewport()->repaint( ir, FALSE ); + } +} + + +void TQListView::makeVisible() +{ + if ( d->focusItem ) + ensureItemVisible( d->focusItem ); +} + + +/*! + Ensures that the header is correctly sized and positioned when the + resize event \a e occurs. +*/ + +void TQListView::resizeEvent( TQResizeEvent *e ) +{ + TQScrollView::resizeEvent( e ); + d->fullRepaintOnComlumnChange = TRUE; + d->h->resize( visibleWidth(), d->h->height() ); +} + +/*! \reimp */ + +void TQListView::viewportResizeEvent( TQResizeEvent *e ) +{ + TQScrollView::viewportResizeEvent( e ); + d->h->resize( visibleWidth(), d->h->height() ); + if ( resizeMode() != NoColumn && currentItem() && currentItem()->renameBox ) { + TQRect r = itemRect( currentItem() ); + r = TQRect( 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 TQListView::triggerUpdate() +{ + if ( !isVisible() || !isUpdatesEnabled() ) { + // Not in response to a setText/setPixmap any more. + d->useDoubleBuffer = FALSE; + + 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 TQListView::eventFilter( TQObject * o, TQEvent * e ) +{ + if ( o == d->h && + e->type() >= TQEvent::MouseButtonPress && + e->type() <= TQEvent::MouseMove ) { + TQMouseEvent * me = (TQMouseEvent *)e; + TQMouseEvent me2( me->type(), + TQPoint( me->pos().x(), + me->pos().y() - d->h->height() ), + me->button(), me->state() ); + switch( me2.type() ) { + case TQEvent::MouseButtonDblClick: + if ( me2.button() == RightButton ) + return TRUE; + break; + case TQEvent::MouseMove: + if ( me2.state() & RightButton ) { + viewportMouseMoveEvent( &me2 ); + return TRUE; + } + break; + default: + break; + } + } else if ( o == viewport() ) { + TQFocusEvent * fe = (TQFocusEvent *)e; + + switch( e->type() ) { + case TQEvent::FocusIn: + focusInEvent( fe ); + return TRUE; + case TQEvent::FocusOut: + focusOutEvent( fe ); + return TRUE; + default: + // nothing + break; + } + } else if ( ::tqt_cast<TQLineEdit*>(o) ) { + if ( currentItem() && currentItem()->renameBox ) { + if ( e->type() == TQEvent::KeyPress ) { + TQKeyEvent *ke = (TQKeyEvent*)e; + if ( ke->key() == Key_Return || + ke->key() == Key_Enter ) { + currentItem()->okRename( currentItem()->renameCol ); + return TRUE; + } else if ( ke->key() == Key_Escape ) { + currentItem()->cancelRename( currentItem()->renameCol ); + return TRUE; + } + } else if ( e->type() == TQEvent::FocusOut ) { + if ( ( (TQFocusEvent*)e )->reason() != TQFocusEvent::Popup ) { + TQCustomEvent *e = new TQCustomEvent( 9999 ); + TQApplication::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 TQScrollView::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 + TQListViewItem::takeItem() +*/ + +TQListView * TQListViewItem::listView() const +{ + const TQListViewItem* c = this; + while ( c && !c->is_root ) + c = c->parentItem; + if ( !c ) + return 0; + return ((TQListViewPrivate::Root*)c)->theListView(); +} + + +/*! + Returns the depth of this item. +*/ +int TQListViewItem::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() TQListView::itemRect() +*/ + +TQListViewItem * TQListViewItem::itemAbove() +{ + if ( !parentItem ) + return 0; + + TQListViewItem * 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() TQListView::itemRect() +*/ + +TQListViewItem * TQListViewItem::itemBelow() +{ + TQListViewItem * c = 0; + if ( isOpen() && childItem ) { + c = childItem; + } else if ( siblingItem ) { + c = siblingItem; + } else if ( parentItem ) { + c = 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 TQListViewItem::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. + TQListView and TQListViewItem try to postpone or avoid sorting to + the greatest degree possible, in order to keep the user interface + snappy. + + \sa nextSibling() sortChildItems() +*/ + +TQListViewItem* TQListViewItem::firstChild() const +{ + enforceSortOrder(); + return childItem; +} + + +/*! + Returns the parent of this item, or 0 if this item has no parent. + + \sa firstChild(), nextSibling() +*/ + +TQListViewItem* TQListViewItem::parent() const +{ + if ( !parentItem || parentItem->is_root ) return 0; + return parentItem; +} + + +/*! + \fn TQListViewItem* TQListViewItem::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. + TQListView and TQListViewItem try to postpone or avoid sorting to + the greatest degree possible, in order to keep the user interface + snappy. + + \sa firstChild() sortChildItems() +*/ + +/*! + \fn int TQListViewItem::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 TQListViewItem::height() const +{ + TQListViewItem * that = (TQListViewItem *)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 TQListViewItem::widthChanged( int c ) const +{ + TQListView *lv = listView(); + if ( lv ) + lv->widthChanged( this, c ); +} + +/*! + \fn void TQListView::dropped ( TQDropEvent * 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 TQListView::selectionChanged() + + This signal is emitted whenever the set of selected items has + changed (normally before the screen update). It is available in + \c Single, \c Multi, and \c Extended selection modes, but is most + useful in \c Multi selection mode. + + \warning Do not delete any TQListViewItem objects in slots + connected to this signal. + + \sa setSelected() TQListViewItem::setSelected() +*/ + + +/*! + \fn void TQListView::pressed( TQListViewItem *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 TQListViewItem objects in slots + connected to this signal. +*/ + +/*! + \fn void TQListView::pressed( TQListViewItem *item, const TQPoint &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 TQListViewItem objects in slots + connected to this signal. +*/ + +/*! + \fn void TQListView::clicked( TQListViewItem *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 TQListViewItem objects in slots + connected to this signal. +*/ + +/*! + \fn void TQListView::mouseButtonClicked(int button, TQListViewItem * item, const TQPoint & 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 TQListViewItem objects in slots + connected to this signal. +*/ + +/*! + \fn void TQListView::mouseButtonPressed(int button, TQListViewItem * item, const TQPoint & 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 TQListViewItem objects in slots + connected to this signal. +*/ + +/*! + \fn void TQListView::clicked( TQListViewItem *item, const TQPoint &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 TQListViewItem objects in slots + connected to this signal. +*/ + +/*! + \fn void TQListView::selectionChanged( TQListViewItem * ) + + \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 item. If the selection is cleared + (when, for example, the user clicks in the unused area of the list + view) then this signal will not be emitted. + + In \c Multi selection mode, use the no argument overload of this + signal. + + \warning Do not delete any TQListViewItem objects in slots + connected to this signal. + + \sa setSelected() TQListViewItem::setSelected() currentChanged() +*/ + + +/*! + \fn void TQListView::currentChanged( TQListViewItem * ) + + 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 item, or 0 if the change made no + item current. This can happen, for example, if all items in the + list view are deleted. + + \warning Do not delete any TQListViewItem objects in slots + connected to this signal. + + \sa setCurrentItem() currentItem() +*/ + + +/*! + \fn void TQListView::expanded( TQListViewItem *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 TQListView::collapsed( TQListViewItem *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 TQListView::contentsMousePressEvent( TQMouseEvent * e ) +{ + contentsMousePressEventEx( e ); +} + +void TQListView::contentsMousePressEventEx( TQMouseEvent * 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(); + TQPoint vp = contentsToViewport( e->pos() ); + + d->ignoreDoubleClick = FALSE; + d->buttonDown = TRUE; + + TQListViewItem * i = itemAt( vp ); + d->pressedEmptyArea = e->y() > contentsHeight(); + if ( i && !i->isEnabled() ) + return; + if ( d->startEdit && ( i != currentItem() || (i && !i->isSelected()) ) ) + d->startEdit = FALSE; + TQListViewItem *oldCurrent = currentItem(); + + if ( e->button() == RightButton && (e->state() & ControlButton ) ) + goto emit_signals; + + if ( !i ) { + if ( !( e->state() & ControlButton ) ) + clearSelection(); + goto emit_signals; + } else { + // No new anchor when using shift + if ( !(e->state() & 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 ) ); + TQPtrListIterator<TQListViewPrivate::DrawableItem> it( *(d->drawables) ); + while( it.current() && it.current()->i != i ) + ++it; + + if ( it.current() ) { + x1 -= treeStepSize() * (it.current()->l - 1); + TQStyle::SubControl ctrl = + style().querySubControl( TQStyle::CC_ListView, + this, TQPoint(x1, e->pos().y()), + TQStyleOption(i) ); + if( ctrl == TQStyle::SC_ListViewExpand && + e->type() == style().styleHint(TQStyle::SH_ListViewExpand_SelectMouseType, this)) { + d->buttonDown = FALSE; + if ( e->button() == LeftButton ) { + bool close = i->isOpen(); + setOpen( i, !close ); + // ### Looks dangerous, removed because of reentrance problems + // tqApp->processEvents(); + if ( !d->focusItem ) { + d->focusItem = i; + repaintItem( d->focusItem ); + emit currentChanged( d->focusItem ); + } + if ( close ) { + bool newCurrent = FALSE; + TQListViewItem *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; + TQPoint topLeft = itemRect( i ).topLeft(); //### inefficient? + activatedP = vp - topLeft; + int xdepth = treeStepSize() * (i->depth() + (rootIsDecorated() ? 1 : 0)) + + itemMargin(); + + // This returns the position of the first visual section?!? Shouldn't that always be 0? Keep it just in case we have missed something. + 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() & (ControlButton | ShiftButton)) ) { + if ( !i->isSelected() ) { + bool blocked = signalsBlocked(); + blockSignals( TRUE ); + clearSelection(); + blockSignals( blocked ); + i->setSelected( TRUE ); + changed = TRUE; + } + } else { + if ( e->state() & ShiftButton ) + d->pressedSelected = FALSE; + if ( (e->state() & ControlButton) && !(e->state() & 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 ) { + d->useDoubleBuffer = TRUE; + triggerUpdate(); + emit selectionChanged(); + +#if defined(QT_ACCESSIBILITY_SUPPORT) + TQAccessible::updateAccessibility( viewport(), 0, TQAccessible::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() == RightButton && i == d->pressedItem ) { + if ( !i && !(e->state() & ControlButton) ) + clearSelection(); + + emit rightButtonPressed( i, viewport()->mapToGlobal( vp ), c ); + } +} + +/*! + \reimp +*/ + +void TQListView::contentsContextMenuEvent( TQContextMenuEvent *e ) +{ + if ( !receivers( TQ_SIGNAL(contextMenuRequested(TQListViewItem*,const TQPoint&,int)) ) ) { + e->ignore(); + return; + } + if ( e->reason() == TQContextMenuEvent::Keyboard ) { + TQListViewItem *item = currentItem(); + if ( item ) { + TQRect r = itemRect( item ); + TQPoint p = r.topLeft(); + if ( allColumnsShowFocus() ) + p += TQPoint( width() / 2, ( r.height() / 2 ) ); + else + p += TQPoint( columnWidth( 0 ) / 2, ( r.height() / 2 ) ); + p.rx() = TQMAX( 0, p.x() ); + p.rx() = TQMIN( visibleWidth(), p.x() ); + emit contextMenuRequested( item, viewport()->mapToGlobal( p ), -1 ); + } + } else { + TQPoint vp = contentsToViewport( e->pos() ); + TQListViewItem * 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 TQListView::contentsMouseReleaseEvent( TQMouseEvent * e ) +{ + contentsMouseReleaseEventEx( e ); +} + +void TQListView::contentsMouseReleaseEventEx( TQMouseEvent * 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, TQ_SIGNAL(timeout()), + this, TQ_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() == LeftButton) { + bool block = signalsBlocked(); + blockSignals( TRUE ); + clearSelection(); + blockSignals( block ); + d->focusItem->setSelected( TRUE ); + emit selectionChanged(); +#if defined(QT_ACCESSIBILITY_SUPPORT) + TQAccessible::updateAccessibility( viewport(), 0, TQAccessible::Selection ); +#endif + } + + TQPoint vp = contentsToViewport(e->pos()); + TQListViewItem *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() == LeftButton && + e->type() == style().styleHint(TQStyle::SH_ListViewExpand_SelectMouseType, this)) { + TQPtrListIterator<TQListViewPrivate::DrawableItem> it( *(d->drawables) ); + while( it.current() && it.current()->i != i ) + ++it; + if ( it.current() ) { + int x1 = vp.x() + d->h->offset() - d->h->cellPos( d->h->mapToActual( 0 ) ) - + (treeStepSize() * (it.current()->l - 1)); + TQStyle::SubControl ctrl = style().querySubControl( TQStyle::CC_ListView, + this, TQPoint(x1, e->pos().y()), + TQStyleOption(i) ); + if( ctrl == TQStyle::SC_ListViewExpand ) { + bool close = i->isOpen(); + setOpen( i, !close ); + // ### Looks dangerous, removed because of reentrance problems + // tqApp->processEvents(); + if ( !d->focusItem ) { + d->focusItem = i; + repaintItem( d->focusItem ); + emit currentChanged( d->focusItem ); + } + if ( close ) { + bool newCurrent = FALSE; + TQListViewItem *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() == LeftButton && d->startEdit ) { + TQRect r = itemRect( currentItem() ); + r = TQRect( 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() & ( ShiftButton | ControlButton ) ) ) + d->renameTimer->start( TQApplication::doubleClickInterval(), TRUE ); + } + // Check if we are clicking at the root decoration. + int rootColumnPos = d->h->sectionPos( 0 ); + if ( i && vp.x() + contentsX() < rootColumnPos + itemMargin() + ( i->depth() + ( rootIsDecorated() ? 1 : 0 ) ) * treeStepSize() + && vp.x() + contentsX() > rootColumnPos ) { + i = 0; + } + emitClicked = emitClicked && d->pressedItem == i; + d->pressedItem = 0; + d->highlighted = 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() == RightButton ) { + if ( !i ) { + if ( !(e->state() & 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 TQListView::contentsMouseDoubleClickEvent( TQMouseEvent * e ) +{ + d->renameTimer->stop(); + d->startEdit = FALSE; + if ( !e || e->button() != LeftButton ) + return; + + // ensure that the following mouse moves and eventual release is + // ignored. + d->buttonDown = FALSE; + + if ( d->ignoreDoubleClick ) { + d->ignoreDoubleClick = FALSE; + return; + } + + TQPoint vp = contentsToViewport(e->pos()); + + TQListViewItem * 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 TQListView::contentsMouseMoveEvent( TQMouseEvent * e ) +{ + if ( !e ) + return; + + bool needAutoScroll = FALSE; + + TQPoint vp = contentsToViewport(e->pos()); + + TQListViewItem * 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() & LeftButton ) != LeftButton && + ( e->state() & MidButton ) != MidButton && + ( e->state() & RightButton ) != 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() > TQApplication::startDragDistance() ) { + d->buttonDown = FALSE; +#ifndef TQT_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 TQTimer( this ); + connect( d->scrollTimer, TQ_SIGNAL(timeout()), + this, TQ_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, TQ_SIGNAL(timeout()), + this, TQ_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 TQListView::doAutoScroll() +{ + doAutoScroll( TQPoint() ); +} + +/* + 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 TQCursor::pos, otherwise it uses cursorPos +*/ +void TQListView::doAutoScroll( const TQPoint &cursorPos ) +{ + TQPoint pos = cursorPos.isNull() ? viewport()->mapFromGlobal( TQCursor::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(); + + TQListViewItem *c = d->focusItem, *old = 0; + TQListViewItem *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 + TQListViewItem * 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 ) ) { + d->useDoubleBuffer = TRUE; + triggerUpdate(); + emit selectionChanged(); + } + } + } + + setCurrentItem( c ); + d->visibleTimer->start( 1, TRUE ); +} + +/*! + \reimp +*/ + +void TQListView::focusInEvent( TQFocusEvent* ) +{ + d->inMenuMode = FALSE; + if ( d->focusItem ) { + repaintItem( d->focusItem ); + } else if ( firstChild() && TQFocusEvent::reason() != TQFocusEvent::Mouse ) { + d->focusItem = firstChild(); + emit currentChanged( d->focusItem ); + repaintItem( d->focusItem ); + } + if ( TQFocusEvent::reason() == TQFocusEvent::Mouse ) { + d->ignoreEditAfterFocus = TRUE; + d->startEdit = FALSE; + } + if ( style().styleHint( TQStyle::SH_ItemView_ChangeHighlightOnFocus, this ) ) { + bool db = d->useDoubleBuffer; + d->useDoubleBuffer = TRUE; + viewport()->repaint( FALSE ); + d->useDoubleBuffer = db; + } + + TQRect mfrect = itemRect( d->focusItem ); + if ( mfrect.isValid() ) { + if ( header() && header()->isVisible() ) + setMicroFocusHint( mfrect.x(), mfrect.y()+header()->height(), mfrect.width(), mfrect.height(), FALSE ); + else + setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE ); + } +} + + +/*! + \reimp +*/ + +void TQListView::focusOutEvent( TQFocusEvent* ) +{ + if ( TQFocusEvent::reason() == TQFocusEvent::Popup && d->buttonDown ) + d->buttonDown = FALSE; + if ( style().styleHint( TQStyle::SH_ItemView_ChangeHighlightOnFocus, this ) ) { + d->inMenuMode = + TQFocusEvent::reason() == TQFocusEvent::Popup + || (tqApp->focusWidget() && tqApp->focusWidget()->inherits("TQMenuBar")); + if ( !d->inMenuMode ) { + bool db = d->useDoubleBuffer; + d->useDoubleBuffer = TRUE; + viewport()->repaint( FALSE ); + d->useDoubleBuffer = db; + } + } + + if ( d->focusItem ) + repaintItem( d->focusItem ); +} + + +/*! + \reimp +*/ + +void TQListView::keyPressEvent( TQKeyEvent * e ) +{ + if (currentItem() && currentItem()->renameBox) + return; + if (!firstChild()) { + e->ignore(); + return; // subclass bug + } + + TQListViewItem* oldCurrent = currentItem(); + if ( !oldCurrent ) { + setCurrentItem( firstChild() ); + if ( d->selectionMode == Single ) + setSelected( firstChild(), TRUE ); + return; + } + + TQListViewItem * i = currentItem(); + TQListViewItem *old = i; + + TQRect r( itemRect( i ) ); + TQListViewItem * i2; + + bool singleStep = FALSE; + bool selectCurrent = TRUE; + bool wasNavigation = TRUE; + + switch( e->key() ) { + case Key_Backspace: + case Key_Delete: + d->currentPrefix.truncate( 0 ); + break; + case Key_Enter: + case 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. TQDialog. + return; + case Key_Down: + selectCurrent = FALSE; + i = i->itemBelow(); + d->currentPrefix.truncate( 0 ); + singleStep = TRUE; + break; + case Key_Up: + selectCurrent = FALSE; + i = i->itemAbove(); + d->currentPrefix.truncate( 0 ); + singleStep = TRUE; + break; + case Key_Home: + selectCurrent = FALSE; + i = firstChild(); + if (!i->height() || !i->isEnabled()) + i = i->itemBelow(); + d->currentPrefix.truncate( 0 ); + break; + case 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 Key_Next: + selectCurrent = FALSE; + i2 = itemAt( TQPoint( 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 Key_Prior: + selectCurrent = FALSE; + i2 = itemAt( TQPoint( 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 Key_Plus: + d->currentPrefix.truncate( 0 ); + if ( !i->isOpen() && (i->isExpandable() || i->childCount()) ) + setOpen( i, TRUE ); + else + return; + break; + case Key_Right: + d->currentPrefix.truncate( 0 ); + if ( i->isOpen() && i->childItem) { + TQListViewItem *childItem = i->childItem; + while (childItem && !childItem->isVisible()) + childItem = childItem->nextSibling(); + if (childItem) + i = childItem; + } else if ( !i->isOpen() && (i->isExpandable() || i->childCount()) ) { + setOpen( i, TRUE ); + } else if ( contentsX() + visibleWidth() < contentsWidth() ) { + horizontalScrollBar()->addLine(); + return; + } else { + return; + } + break; + case Key_Minus: + d->currentPrefix.truncate( 0 ); + if ( i->isOpen() ) + setOpen( i, FALSE ); + else + return; + break; + case 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()->subtractLine(); + return; + } else { + return; + } + break; + case 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 Key_Escape: + e->ignore(); // For TQDialog + return; + case Key_F2: + if ( currentItem() && currentItem()->renameEnabled( 0 ) ) + currentItem()->startRename( 0 ); + default: + if ( e->text().length() > 0 && e->text()[ 0 ].isPrint() ) { + selectCurrent = FALSE; + wasNavigation = FALSE; + TQString input( d->currentPrefix ); + TQListViewItem * keyItem = i; + TQTime now( TQTime::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().lower(); + else + input = e->text().lower(); + if ( input.length() == e->text().length() ) { + if ( keyItem->itemBelow() ) { + keyItem = keyItem->itemBelow(); + tryFirst = TRUE; + } else { + keyItem = firstChild(); + tryFirst = FALSE; + } + } + TQString keyItemKey; + TQString prefix; + while( keyItem ) { + keyItemKey = TQString::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.lower(); + 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() & ControlButton ) { + d->currentPrefix = TQString::null; + switch ( e->key() ) { + case Key_A: + selectAll( TRUE ); + break; + } + } + e->ignore(); + return; + } + } + + if ( !i ) + return; + + if ( !( e->state() & ShiftButton ) || !d->selectAnchor ) + d->selectAnchor = i; + + setCurrentItem( i ); + if ( i->isSelectable() ) + handleItemChange( old, wasNavigation && (e->state() & ShiftButton), + wasNavigation && (e->state() & 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: + + \code + TQListViewItem *i = itemAt( p ); + if ( i ) { + if ( p.x() > header()->sectionPos( header()->mapToIndex( 0 ) ) + + treeStepSize() * ( i->depth() + ( rootIsDecorated() ? 1 : 0) ) + itemMargin() || + p.x() < header()->sectionPos( header()->mapToIndex( 0 ) ) ) { + ; // p is not on root decoration + else + ; // p is on the root decoration + } + \endcode + + 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() +*/ + +TQListViewItem * TQListView::itemAt( const TQPoint & viewPos ) const +{ + if ( viewPos.x() > contentsWidth() - contentsX() ) { + return 0; + } + + if ( !d->drawables || d->drawables->isEmpty() ) { + buildDrawableList(); + } + + TQListViewPrivate::DrawableItem * c = d->drawables->first(); + int g = viewPos.y() + contentsY(); + + while( c && c->i && ( c->y + c->i->height() <= g || + !c->i->isVisible() || + ( c->i->parent() && !c->i->parent()->isVisible() ) ) ) + c = d->drawables->next(); + + TQListViewItem *i = (c && c->y <= g) ? c->i : 0; + return i; +} + + +/*! + 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 TQListViewItem::itemPos(). + + \sa itemAt() itemRect() +*/ + +int TQListView::itemPos( const TQListViewItem * item ) +{ + return item ? item->itemPos() : 0; +} + + +/*! \obsolete + \property TQListView::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 TQListView::setMultiSelection( bool enable ) +{ + if ( !enable ) + d->selectionMode = TQListView::Single; + else if ( d->selectionMode != Multi && d->selectionMode != Extended ) + d->selectionMode = TQListView::Multi; +} + +bool TQListView::isMultiSelection() const +{ + return d->selectionMode == TQListView::Extended || d->selectionMode == TQListView::Multi; +} + +/*! + \property TQListView::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 TQListView::setSelectionMode( SelectionMode mode ) +{ + if ( d->selectionMode == mode ) + return; + + if ( ( d->selectionMode == Multi || d->selectionMode == Extended ) && + ( mode == TQListView::Single || mode == TQListView::NoSelection ) ){ + clearSelection(); + if ( ( mode == TQListView::Single ) && currentItem() ) + currentItem()->selected = TRUE; + } + + d->selectionMode = mode; +} + +TQListView::SelectionMode TQListView::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 TQListViewItem::setSelected(), this function + updates the list view as necessary and emits the + selectionChanged() signals. + + \sa isSelected() setMultiSelection() isMultiSelection() + setCurrentItem(), setSelectionAnchor() +*/ + +void TQListView::setSelected( TQListViewItem * item, bool selected ) +{ + if ( !item || item->isSelected() == selected || + !item->isSelectable() || selectionMode() == NoSelection ) + return; + + bool emitHighlighted = FALSE; + if ( selectionMode() == Single && d->focusItem != item ) { + TQListViewItem *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 TQListView::setSelectionAnchor( TQListViewItem *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 TQListView::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 TQListView::selectAll( bool select ) +{ + if ( d->selectionMode == Multi || d->selectionMode == Extended ) { + bool b = signalsBlocked(); + blockSignals( TRUE ); + bool anything = FALSE; + TQListViewItemIterator it( this ); + while ( it.current() ) { + TQListViewItem *i = it.current(); + if ( i->isVisible()) { + if ( (bool)i->selected != select ) { + i->setSelected( select ); + anything = TRUE; + } + } + else { + if ( (bool)i->selected != FALSE ) { + i->setSelected( FALSE ); + anything = TRUE; + } + } + ++it; + } + blockSignals( b ); + if ( anything ) { + emit selectionChanged(); + d->useDoubleBuffer = TRUE; + triggerUpdate(); + } + } else if ( d->focusItem ) { + TQListViewItem * i = d->focusItem; + setSelected( i, select ); + } +} + +/*! + Inverts the selection. Only works in \c Multi and \c Extended + selection modes. +*/ + +void TQListView::invertSelection() +{ + if ( d->selectionMode == Single || + d->selectionMode == NoSelection ) + return; + + bool b = signalsBlocked(); + blockSignals( TRUE ); + TQListViewItemIterator it( this ); + for ( ; it.current(); ++it ) { + if (it.current()->isVisible()) { + it.current()->setSelected( !it.current()->isSelected() ); + } + else { + if ( FALSE != it.current()->isSelected() ) { + it.current()->setSelected( FALSE ); + } + } + } + blockSignals( b ); + emit selectionChanged(); + triggerUpdate(); +} + + +/*! + Returns TRUE if the list view item \a i is selected; otherwise + returns FALSE. + + \sa TQListViewItem::isSelected() +*/ + +bool TQListView::isSelected( const TQListViewItem * 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() +*/ + +TQListViewItem * TQListView::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. + + This function does not set the selection anchor. Use + setSelectionAnchor() instead. + + \sa currentItem() setSelected() +*/ + +void TQListView::setCurrentItem( TQListViewItem * 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 ); + } + + TQListViewItem * prev = d->focusItem; + d->focusItem = i; + + TQRect mfrect = itemRect( i ); + if ( mfrect.isValid() ) { + if ( header() && header()->isVisible() ) + setMicroFocusHint( mfrect.x(), mfrect.y()+header()->height(), mfrect.width(), mfrect.height(), FALSE ); + else + setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE ); + } + + 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 ); + +#if defined(QT_ACCESSIBILITY_SUPPORT) + TQAccessible::updateAccessibility( viewport(), indexOfItem( i ), TQAccessible::Focus ); +#endif + } +} + + +/*! + Returns the current item, or 0 if there isn't one. + + \sa setCurrentItem() +*/ + +TQListViewItem * TQListView::currentItem() const +{ + return d->focusItem; +} + + +/*! + Returns the rectangle on the screen that item \a i occupies in + viewport()'s coordinates, or an invalid rectangle if \a i is 0 or + is not currently visible. + + The rectangle returned does not include any children of the + rectangle (i.e. it uses TQListViewItem::height(), rather than + TQListViewItem::totalHeight()). If you want the rectangle to + include children you can use something like this: + + \code + TQRect r( listView->itemRect( item ) ); + r.setHeight( (TQCOORD)(TQMIN( item->totalHeight(), + listView->viewport->height() - r.y() ) ) ) + \endcode + + 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. +*/ + +TQRect TQListView::itemRect( const TQListViewItem * i ) const +{ + if ( !d->drawables || d->drawables->isEmpty() ) + buildDrawableList(); + + TQListViewPrivate::DrawableItem * c = d->drawables->first(); + + while( c && c->i && c->i != i ) + c = d->drawables->next(); + + if ( c && c->i == i ) { + int y = c->y - contentsY(); + if ( y + c->i->height() >= 0 && + y < ((TQListView *)this)->visibleHeight() ) { + TQRect r( -contentsX(), y, d->h->width(), i->height() ); + return r; + } + } + + return TQRect( 0, 0, -1, -1 ); +} + + +/*! + \fn void TQListView::doubleClicked( TQListViewItem *item ) + + \obsolete (use doubleClicked( TQListViewItem *, const TQPoint&, int )) + + 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 TQListView::doubleClicked( TQListViewItem *, const TQPoint&, int ) + + This signal is emitted whenever an item is double-clicked. It's + emitted on the second button press, not the second button release. + The arguments are the relevant TQListViewItem (may be 0), the point + in global coordinates and the relevant column (or -1 if the click + was outside the list). + + \warning Do not delete any TQListViewItem objects in slots + connected to this signal. +*/ + + +/*! + \fn void TQListView::returnPressed( TQListViewItem * ) + + This signal is emitted when Enter or Return is pressed. The + argument is the currentItem(). +*/ + +/*! + \fn void TQListView::spacePressed( TQListViewItem * ) + + This signal is emitted when Space is pressed. The argument 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 TQListView::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(); + +#if defined(QT_ACCESSIBILITY_SUPPORT) + TQAccessible::updateAccessibility( viewport(), 0, TQAccessible::ObjectReorder ); +#endif +} + +/*! + \enum TQt::SortOrder + + This enum describes how the items in a widget are sorted. + + \value Ascending The items are sorted ascending e.g. starts with + 'AAA' ends with 'ZZZ' in Latin-1 locales + + \value Descending The items are sorted descending e.g. starts with + 'ZZZ' ends with 'AAA' in Latin-1 locales +*/ + +/*! + Sets the \a column the list view is sorted by. + + Sorting is triggered by choosing a header section. +*/ + +void TQListView::changeSortColumn( int column ) +{ + if ( isRenaming() ) { + if ( d->defRenameAction == TQListView::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 TQListView::handleIndexChange() +{ + if ( isRenaming() ) { + if ( d->defRenameAction == TQListView::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 TQListView::sortColumn() const +{ + return d->sortcolumn == Unsorted ? -1 : 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 TQListView::setSortColumn( int column ) +{ + setSorting( column, d->ascending ); +} + +/*! + Returns the sorting order of the list view items. + + \sa sortColumn() +*/ +TQt::SortOrder TQListView::sortOrder() const +{ + if ( d->ascending ) + return Ascending; + return Descending; +} + +/*! + Sets the sort order for the items in the list view to \a order. + + \sa setSorting() +*/ +void TQListView::setSortOrder( SortOrder order ) +{ + setSorting( d->sortcolumn, order == Ascending ? TRUE : FALSE ); +} + +/*! + Sorts the list view using the last sorting configuration (sort + column and ascending/descending). +*/ + +void TQListView::sort() +{ + if ( d->r ) + d->r->sort(); +} + +/*! + \property TQListView::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. + TQListViewItem::paintFocus() draws in the margin. + + \sa TQListViewItem::paintCell() +*/ + +void TQListView::setItemMargin( int m ) +{ + if ( d->margin == m ) + return; + d->margin = m; + if ( isVisible() ) { + if ( d->drawables ) + d->drawables->clear(); + triggerUpdate(); + } +} + +int TQListView::itemMargin() const +{ + return d->margin; +} + + +/*! + \fn void TQListView::rightButtonClicked( TQListViewItem *, const TQPoint&, int ) + + This signal is emitted when the right button is clicked (i.e. when + it's released). The arguments are the relevant TQListViewItem (may + be 0), the point in global coordinates and the relevant column (or + -1 if the click was outside the list). +*/ + + +/*! + \fn void TQListView::rightButtonPressed (TQListViewItem *, const TQPoint &, int) + + This signal is emitted when the right button is pressed. The + arguments are the relevant TQListViewItem (may be 0), the point in + global coordinates and the relevant column (or -1 if the click was + outside the list). +*/ + +/*! + \fn void TQListView::contextMenuRequested( TQListViewItem *item, const TQPoint & 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 TQListView::styleChange( TQStyle& old ) +{ + TQScrollView::styleChange( old ); + reconfigureItems(); +} + + +/*! + \reimp +*/ +void TQListView::setFont( const TQFont & f ) +{ + TQScrollView::setFont( f ); + reconfigureItems(); +} + + +/*! + \reimp +*/ +void TQListView::setPalette( const TQPalette & p ) +{ + TQScrollView::setPalette( p ); + 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 TQListViewItem::setup() +*/ + +void TQListView::reconfigureItems() +{ + d->fontMetricsHeight = fontMetrics().height(); + d->minLeftBearing = fontMetrics().minLeftBearing(); + d->minRightBearing = fontMetrics().minRightBearing(); + d->ellipsisWidth = fontMetrics().width( "..." ) * 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 TQListView::widthChanged( const TQListViewItem* item, int c ) +{ + if ( c >= d->h->count() ) + return; + + + TQFontMetrics 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 = TQMAX( 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 TQListView::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 TQListView::setAllColumnsShowFocus( bool enable ) +{ + d->allColumnsShowFocus = enable; +} + +bool TQListView::allColumnsShowFocus() const +{ + return d->allColumnsShowFocus; +} + + +/*! + Returns the first item in this TQListView. Returns 0 if there is no + first item. + + A list view's items can be traversed using firstChild() + and nextSibling() or using a TQListViewItemIterator. + + \sa itemAt() TQListViewItem::itemBelow() TQListViewItem::itemAbove() +*/ + +TQListViewItem * TQListView::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 TQListView. + + This function is slow because it traverses the entire tree to find + the last item. +*/ + +TQListViewItem* TQListView::lastItem() const +{ + TQListViewItem* 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 TQListViewItem::repaint() const +{ + TQListView *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 TQListView::repaintItem( const TQListViewItem * item ) const +{ + if ( !item ) + return; + d->dirtyItemTimer->start( 0, TRUE ); + if ( !d->dirtyItems ) + d->dirtyItems = new TQPtrDict<void>(); + d->dirtyItems->replace( (void *)item, (void *)item ); +} + + +struct TQCheckListItemPrivate +{ + TQCheckListItemPrivate(): + exclusive( 0 ), + currentState( TQCheckListItem::Off ), + statesDict( 0 ), + tristate( FALSE ) {} + + TQCheckListItem *exclusive; + TQCheckListItem::ToggleState currentState; + TQPtrDict<TQCheckListItem::ToggleState> *statesDict; + bool tristate; +}; + + +/*! + \class TQCheckListItem + \brief The TQCheckListItem class provides checkable list view items. + + \ingroup advanced + + TQCheckListItems are used in \l{TQListView}s to provide + \l{TQListViewItem}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 tqlistviewitems.png List View Items + + \sa TQListViewItem TQListView +*/ + +// ### obscenity is warranted. + +/*! + \enum TQCheckListItem::Type + + This enum type specifies a TQCheckListItem's type: + + \value RadioButton + \value CheckBox + \value Controller \e obsolete (use \c RadioButtonController instead) + \value RadioButtonController + \value CheckBoxController +*/ + +/*! + \enum TQCheckListItem::ToggleState + + This enum specifies a TQCheckListItem'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. +*/ +TQCheckListItem::TQCheckListItem( TQCheckListItem *parent, const TQString &text, + Type tt ) + : TQListViewItem( parent, text, TQString::null ) +{ + myType = tt; + init(); + if ( myType == RadioButton ) { + if ( parent->type() != RadioButtonController ) + tqWarning( "TQCheckListItem::TQCheckListItem(), 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. +*/ +TQCheckListItem::TQCheckListItem( TQCheckListItem *parent, TQListViewItem *after, + const TQString &text, Type tt ) + : TQListViewItem( parent, after, text ) +{ + myType = tt; + init(); + if ( myType == RadioButton ) { + if ( parent->type() != RadioButtonController ) + tqWarning( "TQCheckListItem::TQCheckListItem(), 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. +*/ +TQCheckListItem::TQCheckListItem( TQListViewItem *parent, const TQString &text, + Type tt ) + : TQListViewItem( parent, text, TQString::null ) +{ + myType = tt; + if ( myType == RadioButton ) { + tqWarning( "TQCheckListItem::TQCheckListItem(), radio button must be " + "child of a TQCheckListItem" ); + } + 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. +*/ +TQCheckListItem::TQCheckListItem( TQListViewItem *parent, TQListViewItem *after, + const TQString &text, Type tt ) + : TQListViewItem( parent, after, text ) +{ + myType = tt; + if ( myType == RadioButton ) { + tqWarning( "TQCheckListItem::TQCheckListItem(), radio button must be " + "child of a TQCheckListItem" ); + } + 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. +*/ +TQCheckListItem::TQCheckListItem( TQListView *parent, const TQString &text, + Type tt ) + : TQListViewItem( parent, text ) +{ + myType = tt; + if ( tt == RadioButton ) + tqWarning( "TQCheckListItem::TQCheckListItem(), radio button must be " + "child of a TQCheckListItem" ); + 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. +*/ +TQCheckListItem::TQCheckListItem( TQListView *parent, TQListViewItem *after, + const TQString &text, Type tt ) + : TQListViewItem( parent, after, text ) +{ + myType = tt; + if ( tt == RadioButton ) + tqWarning( "TQCheckListItem::TQCheckListItem(), radio button must be " + "child of a TQCheckListItem" ); + init(); +} + + +int TQCheckListItem::RTTI = 1; + +/* \reimp */ + +int TQCheckListItem::rtti() const +{ + return RTTI; +} + +/*! + Constructs a \c RadioButtonController item with parent \a parent, + text \a text and pixmap \a p. +*/ +TQCheckListItem::TQCheckListItem( TQListView *parent, const TQString &text, + const TQPixmap & p ) + : TQListViewItem( parent, text ) +{ + myType = RadioButtonController; + setPixmap( 0, p ); + init(); +} + +/*! + Constructs a \c RadioButtonController item with parent \a parent, + text \a text and pixmap \a p. +*/ +TQCheckListItem::TQCheckListItem( TQListViewItem *parent, const TQString &text, + const TQPixmap & p ) + : TQListViewItem( parent, text ) +{ + myType = RadioButtonController; + setPixmap( 0, p ); + init(); +} + +void TQCheckListItem::init() +{ + d = new TQCheckListItemPrivate(); + on = FALSE; // ### remove on ver 4 + if ( myType == CheckBoxController || myType == CheckBox ) { + d->statesDict = new TQPtrDict<ToggleState>(101); + d->statesDict->setAutoDelete( TRUE ); + } + // 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. +*/ +TQCheckListItem::~TQCheckListItem() +{ + 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. + if ( d->statesDict ) + delete d->statesDict; + delete d; + d = 0; +} + +/*! + \fn TQCheckListItem::Type TQCheckListItem::type() const + + Returns the type of this item. +*/ + +/*! + \fn bool TQCheckListItem::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 TQCheckListItem::setTristate( bool b ) +{ + if ( ( myType != CheckBoxController ) && ( myType != CheckBox ) ) { + tqWarning( "TQCheckListItem::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 TQCheckListItem::isTristate() const +{ + return d->tristate; +} + +/*! + Returns the state of the item. + + \sa TQCheckListItem::ToggleState +*/ +TQCheckListItem::ToggleState TQCheckListItem::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. +*/ +TQCheckListItem::ToggleState TQCheckListItem::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 TQCheckListItem::setState( ToggleState s ) +{ + if ( myType == CheckBoxController && state() == NoChange ) + updateStoredState( (void*) 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 TQCheckListItem::setState( ToggleState s, bool update, bool store) +{ + + if ( s == internalState() ) + return; + + if ( myType == CheckBox ) { + setCurrentState( s ); + stateChange( state() ); + if ( update && parent() && parent()->rtti() == 1 + && ((TQCheckListItem*)parent())->type() == CheckBoxController ) + ((TQCheckListItem*)parent())->updateController( update, store ); + } else if ( myType == CheckBoxController ) { + if ( s == NoChange && childCount()) { + restoreState( (void*) this ); + } else { + TQListViewItem *item = firstChild(); + int childCount = 0; + while( item ) { + if ( item->rtti() == 1 && + ( ((TQCheckListItem*)item)->type() == CheckBox || + ((TQCheckListItem*)item)->type() == CheckBoxController ) ) { + TQCheckListItem *checkItem = (TQCheckListItem*)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 && + ((TQCheckListItem*)parent())->type() == CheckBoxController ) + ((TQCheckListItem*)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 + && ((TQCheckListItem*)parent())->type() == CheckBoxController ) + ((TQCheckListItem*)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 becase we need to update "on" everytime + 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 TQCheckListItem::setCurrentState( ToggleState s ) +{ + ToggleState old = d->currentState; + d->currentState = s; + if (d->currentState == On) + on = TRUE; + else + on = FALSE; + +#if defined(QT_ACCESSIBILITY_SUPPORT) + if ( old != d->currentState && listView() ) + TQAccessible::updateAccessibility( listView()->viewport(), indexOfItem( this ), TQAccessible::StateChanged ); +#else + Q_UNUSED( old ); +#endif +} + + + +/* + updates the internally stored state of this item for the parent (key) +*/ +void TQCheckListItem::setStoredState( ToggleState newState, void *key ) +{ + if ( myType == CheckBox || myType == CheckBoxController ) + d->statesDict->replace( key, new ToggleState(newState) ); +} + +/* + Returns the stored state for this item for the given key. + If the key is not found it returns Off. +*/ +TQCheckListItem::ToggleState TQCheckListItem::storedState( void *key ) const +{ + if ( !d->statesDict ) + return Off; + + ToggleState *foundState = d->statesDict->find( key ); + if ( foundState ) + return ToggleState( *foundState ); + else + return Off; +} + + +/*! + \fn TQString TQCheckListItem::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 TQCheckListItem::turnOffChild() +{ + if ( myType == RadioButtonController && d->exclusive ) + d->exclusive->setOn( FALSE ); +} + +/*! + Toggle check box or set radio button to on. +*/ +void TQCheckListItem::activate() +{ + TQListView * lv = listView(); + + if ( ( lv && !lv->isEnabled() ) || !isEnabled() ) + return; + + TQPoint pos; + int boxsize = lv->style().pixelMetric(TQStyle::PM_CheckListButtonSize, lv); + if ( activatedPos( pos ) ) { + bool parentControl = FALSE; + if ( parent() && parent()->rtti() == 1 && + ((TQCheckListItem*) parent())->type() == RadioButtonController ) + parentControl = TRUE; + + int x = parentControl ? 0 : 3; + int align = lv->columnAlignment( 0 ); + int marg = lv->itemMargin(); + int y = 0; + + if ( align & AlignVCenter ) + y = ( ( height() - boxsize ) / 2 ) + marg; + else + y = (lv->fontMetrics().height() + 2 + marg - boxsize) / 2; + + TQRect 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) ) { + 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 TQCheckListItem::setOn( bool b ) +{ + if ( b ) + setState( On , TRUE, TRUE ); + else + setState( Off , TRUE, TRUE ); +} + + +/*! + This virtual function is called when the item changes its state. + \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 TQCheckListItem::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 TQCheckListItem::stateChange( ToggleState s ) +{ + stateChange( s == On ); +} + +/* + sets the state of the CheckBox and CheckBoxController back to + previous stored state +*/ +void TQCheckListItem::restoreState( void *key, int depth ) +{ + switch ( type() ) { + case CheckBox: + setCurrentState( storedState( key ) ); + stateChange( state() ); + repaint(); + break; + case CheckBoxController: { + TQListViewItem *item = firstChild(); + int childCount = 0; + while ( item ) { + // recursively calling restoreState for children of type CheckBox and CheckBoxController + if ( item->rtti() == 1 && + ( ((TQCheckListItem*)item)->type() == CheckBox || + ((TQCheckListItem*)item)->type() == CheckBoxController ) ) { + ((TQCheckListItem*)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 TQCheckListItem::updateController( bool update , bool store ) +{ + if ( myType != CheckBoxController ) + return; + + TQCheckListItem *controller = 0; + // checks if this CheckBoxController has another CheckBoxController as parent + if ( parent() && parent()->rtti() == 1 + && ((TQCheckListItem*)parent())->type() == CheckBoxController ) + controller = (TQCheckListItem*)parent(); + + ToggleState theState = Off; + bool first = TRUE; + TQListViewItem *item = firstChild(); + while( item && theState != NoChange ) { + if ( item->rtti() == 1 && + ( ((TQCheckListItem*)item)->type() == CheckBox || + ((TQCheckListItem*)item)->type() == CheckBoxController ) ) { + TQCheckListItem *checkItem = (TQCheckListItem*)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( (void*) this ); + stateChange( state() ); + if ( update && controller ) { + controller->updateController( update, store ); + } + repaint(); + } +} + + +/* + Makes all the children CheckBoxes update their storedState +*/ +void TQCheckListItem::updateStoredState( void *key ) +{ + if ( myType != CheckBoxController ) + return; + + TQListViewItem *item = firstChild(); + while( item ) { + if ( item->rtti() == 1 ) { + TQCheckListItem *checkItem = (TQCheckListItem*)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 TQCheckListItem::setup() +{ + TQListViewItem::setup(); + int h = height(); + TQListView *lv = listView(); + if ( lv ) + h = TQMAX( lv->style().pixelMetric(TQStyle::PM_CheckListButtonSize, lv), + h ); + h = TQMAX( h, TQApplication::globalStrut().height() ); + setHeight( h ); +} + +/*! + \reimp +*/ + +int TQCheckListItem::width( const TQFontMetrics& fm, const TQListView* lv, int column) const +{ + int r = TQListViewItem::width( fm, lv, column ); + if ( column == 0 ) { + r += lv->itemMargin(); + if ( myType == RadioButtonController && pixmap( 0 ) ) { + // r += 0; + } else { + r += lv->style().pixelMetric(TQStyle::PM_CheckListButtonSize, lv) + 4; + } + } + return TQMAX( r, TQApplication::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 TQt::AlignmentFlags for valid alignments.) +*/ +void TQCheckListItem::paintCell( TQPainter * p, const TQColorGroup & cg, + int column, int width, int align ) +{ + if ( !p ) + return; + + TQListView *lv = listView(); + if ( !lv ) + return; + + const BackgroundMode bgmode = lv->viewport()->backgroundMode(); + const TQColorGroup::ColorRole crole = TQPalette::backgroundRoleFromMode( bgmode ); + if ( cg.brush( crole ) != lv->colorGroup().brush( crole ) ) + p->fillRect( 0, 0, width, height(), cg.brush( crole ) ); + else + lv->paintEmptyArea( p, TQRect( 0, 0, width, height() ) ); + + if ( column != 0 ) { + // The rest is text, or for subclasses to change. + TQListViewItem::paintCell( p, cg, column, width, align ); + return; + } + + bool parentControl = FALSE; + if ( parent() && parent()->rtti() == 1 && + ((TQCheckListItem*) parent())->type() == RadioButtonController ) + parentControl = TRUE; + + TQFontMetrics fm( lv->fontMetrics() ); + int boxsize = lv->style().pixelMetric( myType == RadioButtonController ? TQStyle::PM_CheckListControllerSize : + TQStyle::PM_CheckListButtonSize, lv); + int marg = lv->itemMargin(); + int r = marg; + + // Draw controller / checkbox / radiobutton --------------------- + int styleflags = TQStyle::Style_Default; + if ( internalState() == On ) { + styleflags |= TQStyle::Style_On; + } else if ( internalState() == NoChange ) { + if ( myType == CheckBoxController && !isTristate() ) + styleflags |= TQStyle::Style_Off; + else + styleflags |= TQStyle::Style_NoChange; + } else { + styleflags |= TQStyle::Style_Off; + } + if ( isSelected() ) + styleflags |= TQStyle::Style_Selected; + if ( isEnabled() && lv->isEnabled() ) + styleflags |= TQStyle::Style_Enabled; + + if ( myType == RadioButtonController ) { + int x = 0; + if(!parentControl) + x += 3; + if ( !pixmap( 0 ) ) { + lv->style().drawPrimitive(TQStyle::PE_CheckListController, p, + TQRect(x, 0, boxsize, + fm.height() + 2 + marg), + cg, styleflags, TQStyleOption(this)); + r += boxsize + 4; + } + } else { + Q_ASSERT( lv ); //### + int x = 0; + int y = 0; + if ( !parentControl ) + x += 3; + if ( align & AlignVCenter ) + y = ( ( height() - boxsize ) / 2 ) + marg; + else + y = (fm.height() + 2 + marg - boxsize) / 2; + + if ( ( myType == CheckBox ) || ( myType == CheckBoxController ) ) { + lv->style().drawPrimitive(TQStyle::PE_CheckListIndicator, p, + TQRect(x, y, boxsize, + fm.height() + 2 + marg), + cg, styleflags, TQStyleOption(this)); + } else { //radio button look + lv->style().drawPrimitive(TQStyle::PE_CheckListExclusiveIndicator, + p, TQRect(x, y, boxsize, + fm.height() + 2 + marg), + cg, styleflags, TQStyleOption(this)); + } + r += boxsize + 4; + } + + // Draw text ---------------------------------------------------- + p->translate( r, 0 ); + p->setPen( TQPen( cg.text() ) ); + TQListViewItem::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 TQCheckListItem::paintFocus( TQPainter *p, const TQColorGroup & cg, + const TQRect & r ) +{ + bool intersect = TRUE; + TQListView *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( TQRect( p, r.y(), xdepth - p + 1, r.height() ) ); + } + bool parentControl = FALSE; + if ( parent() && parent()->rtti() == 1 && + ((TQCheckListItem*) parent())->type() == RadioButtonController ) + parentControl = TRUE; + if ( myType != RadioButtonController && intersect && + (lv->rootIsDecorated() || myType == RadioButton || + (myType == CheckBox && parentControl) ) ) { + TQRect rect; + int boxsize = lv->style().pixelMetric(TQStyle::PM_CheckListButtonSize, lv); + if ( lv->columnAlignment(0) == AlignCenter ) { + TQFontMetrics 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() ); + TQListViewItem::paintFocus(p, cg, rect); + } else { + TQListViewItem::paintFocus(p, cg, r); + } +} + +/*! + \reimp +*/ +TQSize TQListView::sizeHint() const +{ + if ( cachedSizeHint().isValid() ) + return cachedSizeHint(); + + constPolish(); + + if ( !isVisible() && (!d->drawables || d->drawables->isEmpty()) ) + // force the column widths to sanity, if possible + buildDrawableList(); + + TQSize s( d->h->sizeHint() ); + if ( verticalScrollBar()->isVisible() ) + s.setWidth( s.width() + style().pixelMetric(TQStyle::PM_ScrollBarExtent) ); + s += TQSize(frameWidth()*2,frameWidth()*2); + TQListViewItem * 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 +*/ + +TQSize TQListView::minimumSizeHint() const +{ + return TQScrollView::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 TQListViewItem::setOpen() TQListViewItem::setExpandable() +*/ + +void TQListView::setOpen( TQListViewItem * item, bool open ) +{ + if ( !item || + item->isOpen() == open || + (open && !item->childCount() && !item->isExpandable()) ) + return; + + TQListViewItem* nextParent = 0; + if ( open ) + nextParent = item->itemBelow(); + + item->setOpen( open ); + + if ( open ) { + TQListViewItem* lastChild = item; + TQListViewItem* tmp; + while ( TRUE ) { + tmp = lastChild->itemBelow(); + if ( !tmp || tmp == nextParent ) + break; + lastChild = tmp; + } + ensureItemVisible( lastChild ); + ensureItemVisible( item ); + } + if ( d->drawables ) + d->drawables->clear(); + buildDrawableList(); + + TQListViewPrivate::DrawableItem * c = d->drawables->first(); + + while( c && c->i && c->i != item ) + c = d->drawables->next(); + + if ( c && c->i == item ) { + d->dirtyItemTimer->start( 0, TRUE ); + if ( !d->dirtyItems ) + d->dirtyItems = new TQPtrDict<void>(); + while( c && c->i ) { + d->dirtyItems->insert( (void *)(c->i), (void *)(c->i) ); + c = d->drawables->next(); + } + } +} + + +/*! + Identical to \a{item}->isOpen(). Provided for completeness. + + \sa setOpen() +*/ + +bool TQListView::isOpen( const TQListViewItem * item ) const +{ + return item->isOpen(); +} + + +/*! + \property TQListView::rootIsDecorated + \brief whether the list view shows open/close signs on root items + + Open/close signs are small <b>+</b> or <b>-</b> symbols in windows + style, or arrows in Motif style. The default is FALSE. +*/ + +void TQListView::setRootIsDecorated( bool enable ) +{ + if ( enable != (bool)d->rootIsExpandable ) { + d->rootIsExpandable = enable; + if ( isVisible() ) + triggerUpdate(); + } +} + +bool TQListView::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() TQScrollView::ensureVisible() +*/ + +void TQListView::ensureItemVisible( const TQListViewItem * i ) +{ + if ( !i || !i->isVisible() ) + return; + + TQListViewItem *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 TQString TQCheckListItem::text( int n ) const + + \reimp +*/ + +/*! + Returns the TQHeader object that manages this list view's columns. + Please don't modify the header behind the list view's back. + + You may safely call TQHeader::setClickEnabled(), + TQHeader::setResizeEnabled(), TQHeader::setMovingEnabled(), + TQHeader::hide() and all the const TQHeader functions. +*/ + +TQHeader * TQListView::header() const +{ + return d->h; +} + + +/*! + \property TQListView::childCount + \brief the number of parentless (top-level) TQListViewItem objects in this TQListView + + Holds the current number of parentless (top-level) TQListViewItem + objects in this TQListView. + + \sa TQListViewItem::childCount() +*/ + +int TQListView::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 TQListViewItem::moveToJustAfter( TQListViewItem * olderSibling ) +{ + if ( parentItem && olderSibling && + olderSibling->parentItem == parentItem && olderSibling != this ) { + if ( parentItem->childItem == this ) { + parentItem->childItem = siblingItem; + } else { + TQListViewItem * 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 TQListViewItem::moveItem( TQListViewItem *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 ); + TQListView *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 TQListViewItem::enforceSortOrderBackToRoot() +{ + if ( parentItem ) { + parentItem->enforceSortOrderBackToRoot(); + parentItem->enforceSortOrder(); + } +} + +/*! + \reimp +*/ +void TQListView::showEvent( TQShowEvent * ) +{ + if ( d->drawables ) + d->drawables->clear(); + delete d->dirtyItems; + d->dirtyItems = 0; + 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 + TQListView::itemAt(), but it works for all items whereas + TQListView::itemAt() normally only works for items on the screen. + + \sa TQListView::itemAt() TQListView::itemRect() TQListView::itemPos() +*/ + +int TQListViewItem::itemPos() const +{ + TQPtrStack<TQListViewItem> s; + TQListViewItem * i = (TQListViewItem *)this; + while( i ) { + s.push( i ); + i = i->parentItem; + } + + int a = 0; + TQListViewItem * 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(); + TQListViewItem * s = p->firstChild(); + while( s && s != i ) { + a += s->totalHeight(); + s = s->nextSibling(); + } + } + p = i; + } + return a; +} + + +/*! + \fn void TQListView::removeItem( TQListViewItem * ) + \obsolete + + This function has been renamed takeItem(). +*/ + +/*! + Removes item \a i from the list view; \a i must be a top-level + item. The warnings regarding TQListViewItem::takeItem() apply to + this function, too. + + \sa insertItem() +*/ +void TQListView::takeItem( TQListViewItem * i ) +{ + if ( d->r ) + d->r->takeItem( i ); +} + + +void TQListView::openFocusItem() +{ + d->autoopenTimer->stop(); + if ( d->focusItem && !d->focusItem->isOpen() ) { + d->focusItem->setOpen( TRUE ); + d->focusItem->repaint(); + } +} + +static const int autoopenTime = 750; + +#ifndef TQT_NO_DRAGANDDROP + +/*! \reimp */ + +void TQListView::contentsDragEnterEvent( TQDragEnterEvent *e ) +{ + d->oldFocusItem = d->focusItem; + TQListViewItem *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(); + } + if ( ( i && i->dropEnabled() && i->acceptDrop( e ) ) || acceptDrops() ) + e->accept(); + else + e->ignore(); +} + +/*! \reimp */ + +void TQListView::contentsDragMoveEvent( TQDragMoveEvent *e ) +{ + TQListViewItem *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 TQListView::contentsDragLeaveEvent( TQDragLeaveEvent * ) +{ + d->autoopenTimer->stop(); + + if ( d->focusItem ) + d->focusItem->dragLeft(); + + setCurrentItem( d->oldFocusItem ); + d->oldFocusItem = 0; +} + +/*! \reimp */ + +void TQListView::contentsDropEvent( TQDropEvent *e ) +{ + d->autoopenTimer->stop(); + + setCurrentItem( d->oldFocusItem ); + TQListViewItem *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 + TQListViewItem::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 TQDragObject depending on the selected items. +*/ + +TQDragObject *TQListView::dragObject() +{ + return 0; +} + +/*! + Starts a drag. +*/ + +void TQListView::startDrag() +{ + if ( !d->startDragItem ) + return; + + d->startDragItem = 0; + d->buttonDown = FALSE; + + TQDragObject *drag = dragObject(); + if ( !drag ) + return; + + drag->drag(); +} + +#endif // TQT_NO_DRAGANDDROP + +/*! + \property TQListView::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 TQListView::setDefaultRenameAction( RenameAction a ) +{ + d->defRenameAction = a; +} + +TQListView::RenameAction TQListView::defaultRenameAction() const +{ + return d->defRenameAction; +} + +/*! + Returns TRUE if an item is being renamed; otherwise returns FALSE. +*/ + +bool TQListView::isRenaming() const +{ + return currentItem() && currentItem()->renameBox; +} + +/********************************************************************** + * + * Class TQListViewItemIterator + * + **********************************************************************/ + + +/*! + \class TQListViewItemIterator + \brief The TQListViewItemIterator class provides an iterator for collections of TQListViewItems. + + \ingroup advanced + + Construct an instance of a TQListViewItemIterator, with either a + TQListView* or a TQListViewItem* as argument, to operate on the tree + of TQListViewItems, starting from the argument. + + A TQListViewItemIterator 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 + TQPtrList: + \code + TQPtrList<TQListViewItem> lst; + TQListViewItemIterator it( myListView ); + while ( it.current() ) { + if ( it.current()->isSelected() ) + lst.append( it.current() ); + ++it; + } + \endcode + + An alternative approach is to use an \c IteratorFlag: + \code + TQPtrList<TQListViewItem> lst; + TQListViewItemIterator it( myListView, TQListViewItemIterator::Selected ); + while ( it.current() ) { + lst.append( it.current() ); + ++it; + } + \endcode + + A TQListViewItemIterator provides a convenient and easy way to + traverse a hierarchical TQListView. + + Multiple TQListViewItemIterators can operate on the tree of + TQListViewItems. A TQListView knows about all iterators operating on + its TQListViewItems. So when a TQListViewItem 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 TQListView, TQListViewItem +*/ + +/*! + \enum TQListViewItemIterator::IteratorFlag + + These flags can be passed to a TQListViewItemIterator 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. +*/ + +TQListViewItemIterator::TQListViewItemIterator() + : curr( 0 ), listView( 0 ) +{ + init( 0 ); +} + +/*! + Constructs an iterator for the TQListView that contains the \a + item. The current iterator item is set to point to the \a item. +*/ + +TQListViewItemIterator::TQListViewItemIterator( TQListViewItem *item ) + : curr( item ), listView( 0 ) +{ + init( 0 ); + + if ( item ) { + item->enforceSortOrderBackToRoot(); + listView = item->listView(); + } + addToListView(); +} + +/*! + Constructs an iterator for the TQListView 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 TQListViewItemIterator::IteratorFlag +*/ + +TQListViewItemIterator::TQListViewItemIterator( TQListViewItem *item, int iteratorFlags ) + : curr( item ), listView( 0 ) +{ + init( iteratorFlags ); + + // go to next matching item if the current don't match + if ( curr && !matchesFlags( curr ) ) + ++( *this ); + + if ( curr ) { + curr->enforceSortOrderBackToRoot(); + listView = curr->listView(); + } + addToListView(); +} + + +/*! + Constructs an iterator for the same TQListView as \a it. The + current iterator item is set to point on the current item of \a + it. +*/ + +TQListViewItemIterator::TQListViewItemIterator( const TQListViewItemIterator& it ) + : curr( it.curr ), listView( it.listView ) +{ + init(it.d() ? it.d()->flags : 0); + + addToListView(); +} + +/*! + Constructs an iterator for the TQListView \a lv. The current + iterator item is set to point on the first child (TQListViewItem) + of \a lv. +*/ + +TQListViewItemIterator::TQListViewItemIterator( TQListView *lv ) + : curr( lv->firstChild() ), listView( lv ) +{ + init( 0 ); + + addToListView(); +} + +/*! + Constructs an iterator for the TQListView \a lv with the flags \a + iteratorFlags. The current iterator item is set to point on the + first child (TQListViewItem) of \a lv that matches the flags. + + \sa TQListViewItemIterator::IteratorFlag +*/ + +TQListViewItemIterator::TQListViewItemIterator( TQListView *lv, int iteratorFlags ) + : curr ( lv->firstChild() ), listView( lv ) +{ + init( iteratorFlags ); + + addToListView(); + if ( !matchesFlags( curr ) ) + ++( *this ); +} + + + +/*! + Assignment. Makes a copy of \a it and returns a reference to its + iterator. +*/ + +TQListViewItemIterator &TQListViewItemIterator::operator=( const TQListViewItemIterator &it ) +{ + if ( listView ) { + if ( listView->d->iterators->removeRef( this ) ) { + if ( listView->d->iterators->count() == 0 ) { + delete listView->d->iterators; + listView->d->iterators = 0; + } + } + } + + listView = it.listView; + addToListView(); + curr = it.curr; + + // sets flags to be the same as the input iterators flags + if ( d() && it.d() ) + d()->flags = it.d()->flags; + + // go to next matching item if the current don't match + if ( curr && !matchesFlags( curr ) ) + ++( *this ); + + return *this; +} + +/*! + Destroys the iterator. +*/ + +TQListViewItemIterator::~TQListViewItemIterator() +{ + if ( listView ) { + if ( listView->d->iterators->removeRef( this ) ) { + if ( listView->d->iterators->count() == 0 ) { + delete listView->d->iterators; + listView->d->iterators = 0; + } + } + } + // removs the d-ptr from the dict ( autodelete on), and deletes the + // ptrdict if it becomes empty + if ( qt_iteratorprivate_dict ) { + qt_iteratorprivate_dict->remove( this ); + if ( qt_iteratorprivate_dict->isEmpty() ) { + delete qt_iteratorprivate_dict; + qt_iteratorprivate_dict = 0; + } + } +} + +/*! + Prefix ++. Makes the next item the new current item and returns + it. Returns 0 if the current item is the last item or the + TQListView is 0. +*/ + +TQListViewItemIterator &TQListViewItemIterator::operator++() +{ + do { + if ( !curr ) + return *this; + + TQListViewItem *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 + } while ( curr && !matchesFlags( curr ) ); + return *this; +} + +/*! + \overload + + Postfix ++. Makes the next item the new current item and returns + the item that \e was the current item. +*/ + +const TQListViewItemIterator TQListViewItemIterator::operator++( int ) +{ + TQListViewItemIterator 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. +*/ + +TQListViewItemIterator &TQListViewItemIterator::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 + TQListView is 0. +*/ + +TQListViewItemIterator &TQListViewItemIterator::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 + TQListViewItem *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 + TQListViewItemIterator 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 { + TQListViewItem *parent = curr->parent(); + + if ( curr != parent->firstChild() ) { + // go to the previous sibling + TQListViewItem *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 + TQListViewItemIterator 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 TQListViewItemIterator TQListViewItemIterator::operator--( int ) +{ + TQListViewItemIterator 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. +*/ + +TQListViewItemIterator &TQListViewItemIterator::operator-=( int j ) +{ + while ( curr && j-- ) + --( *this ); + + return *this; +} + +/*! + Dereference operator. Returns a reference to the current item. The + same as current(). +*/ + +TQListViewItem* TQListViewItemIterator::operator*() +{ + if ( curr != 0 && !matchesFlags( curr ) ) + tqWarning( "TQListViewItemIterator::operator*() curr out of sync" ); + return curr; +} + +/*! + Returns iterator's current item. +*/ + +TQListViewItem *TQListViewItemIterator::current() const +{ + if ( curr != 0 && !matchesFlags( curr ) ) + tqWarning( "TQListViewItemIterator::current() curr out of sync" ); + return curr; +} + +TQListViewItemIteratorPrivate* TQListViewItemIterator::d() const +{ + return qt_iteratorprivate_dict ? + qt_iteratorprivate_dict->find( (void *)this ) : 0; +} + +void TQListViewItemIterator::init( int iteratorFlags ) +{ + // makes new global ptrdict if it doesn't exist + if ( !qt_iteratorprivate_dict ) { + qt_iteratorprivate_dict = new TQPtrDict<TQListViewItemIteratorPrivate>; + qt_iteratorprivate_dict->setAutoDelete( TRUE ); + } + + // sets flag, or inserts new TQListViewItemIteratorPrivate with flag + if ( d() ) + d()->flags = iteratorFlags; + else + qt_iteratorprivate_dict->insert( this, new TQListViewItemIteratorPrivate( iteratorFlags ) ); +} + + +/* + Adds this iterator to its TQListView's list of iterators. +*/ + +void TQListViewItemIterator::addToListView() +{ + if ( listView ) { + if ( !listView->d->iterators ) { + listView->d->iterators = new TQPtrList<TQListViewItemIterator>; + TQ_CHECK_PTR( listView->d->iterators ); + } + listView->d->iterators->append( this ); + } +} + +/* + 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 TQListViewItemIterator::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 TQListViewItemIterator::matchesFlags( const TQListViewItem *item ) const +{ + if ( !item ) + return FALSE; + + int flags = d() ? d()->flags : 0; + + 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 TQCheckListItems as well, so we provide this convenience function + that checks if the rtti() is 1 which means TQCheckListItem and if isOn is TRUE, returns FALSE otherwise. +*/ +bool TQListViewItemIterator::isChecked( const TQListViewItem *item ) const +{ + if ( item->rtti() == 1 ) + return ((const TQCheckListItem*)item)->isOn(); + else return FALSE; +} + +void TQListView::handleItemChange( TQListViewItem *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 TQListView::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 TQListView::clearRange( TQListViewItem *from, TQListViewItem *to, bool includeFirst ) +{ + if ( !from || !to ) + return FALSE; + + // Swap + if ( from->itemPos() > to->itemPos() ) { + TQListViewItem *temp = from; + from = to; + to = temp; + } + + // Start on second? + if ( !includeFirst ) { + TQListViewItem *below = (from == to) ? from : from->itemBelow(); + if ( below ) + from = below; + } + + // Clear items <from, to> + bool changed = FALSE; + + TQListViewItemIterator 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 TQListView::selectRange( TQListViewItem *from, TQListViewItem *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() ) { + TQListViewItemIterator it( from ); + bool found = FALSE; + for ( ; it.current(); ++it ) { + if ( it.current() == to ) { + found = TRUE; + break; + } + } + if ( !found ) + swap = TRUE; + } + if ( swap ) { + TQListViewItem *i = from; + from = to; + to = i; + if ( !includeFirst ) + to = to->itemAbove(); + } else { + if ( !includeFirst ) + from = from->itemBelow(); + } + + bool changed = FALSE; + if ( clearSel ) { + TQListViewItemIterator it( firstChild() ); + for ( ; it.current(); ++it ) { + if ( it.current()->selected ) { + it.current()->setSelected( FALSE ); + changed = TRUE; + } + } + it = TQListViewItemIterator( to ); + for ( ; it.current(); ++it ) { + if ( it.current()->selected ) { + it.current()->setSelected( FALSE ); + changed = TRUE; + } + } + } + + for ( TQListViewItem *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 ) { + d->useDoubleBuffer = TRUE; + triggerUpdate(); + emit selectionChanged(); + } +} + +/* clears selection from anchor to old, selects from anchor to new, does not emit selectionChanged on change */ +bool TQListView::selectRange( TQListViewItem *newItem, TQListViewItem *oldItem, TQListViewItem *anchorItem ) +{ + if ( !newItem || !oldItem || !anchorItem ) + return FALSE; + + int anchorPos = anchorItem ? anchorItem->itemPos() : 0, + oldPos = oldItem ? oldItem->itemPos() : 0, + newPos = newItem->itemPos(); + TQListViewItem *top=0, *bottom=0; + if ( anchorPos > newPos ) { + top = newItem; + bottom = anchorItem; + } else { + top = anchorItem; + bottom = newItem; + } + + // removes the parts 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 + TQListViewItemIterator 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. + The search starts from the current item if the current item exists, + otherwise it starts from the first list view item. After reaching + the last item the search continues from the first item. + Pass OR-ed together \l TQt::StringComparisonMode values + in the \a compare flag, to control how the matching is performed. + The default comparison mode is case-sensitive, exact match. +*/ + +TQListViewItem *TQListView::findItem( const TQString& text, int column, + ComparisonFlags compare ) const +{ + if (text.isEmpty() && !(compare & ExactMatch)) + return 0; + + if ( compare == CaseSensitive || compare == 0 ) + compare |= ExactMatch; + + TQString itmtxt; + TQString comtxt = text; + if ( !(compare & CaseSensitive) ) + comtxt = comtxt.lower(); + + TQListViewItemIterator it( d->focusItem ? d->focusItem : firstChild() ); + TQListViewItem *sentinel = 0; + TQListViewItem *item; + TQListViewItem *beginsWithItem = 0; + TQListViewItem *endsWithItem = 0; + TQListViewItem *containsItem = 0; + + for ( int pass = 0; pass < 2; pass++ ) { + while ( (item = it.current()) != sentinel ) { + itmtxt = item->text( column ); + if ( !(compare & CaseSensitive) ) + itmtxt = itmtxt.lower(); + + if ( compare & 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 & Contains && !containsItem && itmtxt.contains( comtxt ) ) + containsItem = item; + ++it; + } + + it = TQListViewItemIterator( 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; +} + +/*! \reimp */ +void TQListView::windowActivationChange( bool oldActive ) +{ + if ( oldActive && d->scrollTimer ) + d->scrollTimer->stop(); + if ( palette().active() != palette().inactive() ) + viewport()->update(); + TQScrollView::windowActivationChange( oldActive ); +} + +/*! + Hides the column specified at \a column. This is a convenience + function that calls setColumnWidth( \a 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 TQListView::hideColumn( int column ) +{ + setColumnWidth( column, 0 ); +} + +/*! Adjusts the column \a col to its preferred width */ + +void TQListView::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 = TQMAX( w, 20 ); + TQFontMetrics fm( fontMetrics() ); + TQListViewItem* 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 = TQMAX( w, iw ); + item = item->itemBelow(); + } + w = TQMAX( w, TQApplication::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); + } +} + +#endif // TQT_NO_LISTVIEW |