/* This file is part of the KDE libraries Copyright (C) 2000 Reginald Stadlbauer Copyright (C) 2000,2003 Charles Samuels Copyright (C) 2000 Peter Putzer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "klistview.h" #include "klistviewlineedit.h" class KListView::Tooltip : public QToolTip { public: Tooltip (KListView* parent, TQToolTipGroup* group = 0L); virtual ~Tooltip () {} protected: /** * Reimplemented from TQToolTip for internal reasons. */ virtual void maybeTip (const TQPoint&); private: KListView* mParent; }; KListView::Tooltip::Tooltip (KListView* parent, TQToolTipGroup* group) : TQToolTip (parent, group), mParent (parent) { } void KListView::Tooltip::maybeTip (const TQPoint&) { // FIXME } class KListView::KListViewPrivate { public: KListViewPrivate (KListView* listview) : pCurrentItem (0), autoSelectDelay(0), dragOverItem(0), dragDelay (KGlobalSettings::dndEventDelay()), editor (new KListViewLineEdit (listview)), cursorInExecuteArea(false), itemsMovable (true), selectedBySimpleMove(false), selectedUsingMouse(false), itemsRenameable (false), validDrag (false), dragEnabled (false), autoOpen (true), disableAutoSelection (false), dropVisualizer (true), dropHighlighter (false), createChildren (true), pressedOnSelected (false), wasShiftEvent (false), fullWidth (false), sortAscending(true), tabRename(true), sortColumn(0), selectionDirection(0), tooltipColumn (0), selectionMode (Single), contextMenuKey (KGlobalSettings::contextMenuKey()), showContextMenusOnPress (KGlobalSettings::showContextMenusOnPress()), mDropVisualizerWidth (4), paintAbove (0), paintCurrent (0), paintBelow (0), painting (false), shadeSortColumn(KGlobalSettings::shadeSortColumn()) { renameable.append(0); connect(editor, TQT_SIGNAL(done(TQListViewItem*,int)), listview, TQT_SLOT(doneEditing(TQListViewItem*,int))); } ~KListViewPrivate () { delete editor; } TQListViewItem* pCurrentItem; TQTimer autoSelect; int autoSelectDelay; TQTimer dragExpand; TQListViewItem* dragOverItem; TQPoint dragOverPoint; TQPoint startDragPos; int dragDelay; KListViewLineEdit *editor; TQValueList renameable; bool cursorInExecuteArea:1; bool bUseSingle:1; bool bChangeCursorOverItem:1; bool itemsMovable:1; bool selectedBySimpleMove : 1; bool selectedUsingMouse:1; bool itemsRenameable:1; bool validDrag:1; bool dragEnabled:1; bool autoOpen:1; bool disableAutoSelection:1; bool dropVisualizer:1; bool dropHighlighter:1; bool createChildren:1; bool pressedOnSelected:1; bool wasShiftEvent:1; bool fullWidth:1; bool sortAscending:1; bool tabRename:1; int sortColumn; //+1 means downwards (y increases, -1 means upwards, 0 means not selected), aleXXX int selectionDirection; int tooltipColumn; SelectionModeExt selectionMode; int contextMenuKey; bool showContextMenusOnPress; TQRect mOldDropVisualizer; int mDropVisualizerWidth; TQRect mOldDropHighlighter; TQListViewItem *afterItemDrop; TQListViewItem *parentItemDrop; TQListViewItem *paintAbove; TQListViewItem *paintCurrent; TQListViewItem *paintBelow; bool painting:1; bool shadeSortColumn:1; TQColor alternateBackground; }; KListViewLineEdit::KListViewLineEdit(KListView *parent) : KLineEdit(parent->viewport()), item(0), col(0), p(parent) { setFrame( false ); hide(); connect( parent, TQT_SIGNAL( selectionChanged() ), TQT_SLOT( slotSelectionChanged() )); connect( parent, TQT_SIGNAL( itemRemoved( TQListViewItem * ) ), TQT_SLOT( slotItemRemoved( TQListViewItem * ) )); } KListViewLineEdit::~KListViewLineEdit() { } TQListViewItem *KListViewLineEdit::currentItem() const { return item; } void KListViewLineEdit::load(TQListViewItem *i, int c) { item=i; col=c; TQRect rect(p->itemRect(i)); setText(item->text(c)); home( true ); int fieldX = rect.x() - 1; int fieldW = p->columnWidth(col) + 2; TQHeader* const pHeader = p->header(); const int pos = pHeader->mapToIndex(col); for ( int index = 0; index < pos; ++index ) fieldX += p->columnWidth( pHeader->mapToSection( index )); if ( col == 0 ) { int d = i->depth() + (p->rootIsDecorated() ? 1 : 0); d *= p->treeStepSize(); fieldX += d; fieldW -= d; } if ( i->pixmap( col ) ) {// add width of pixmap int d = i->pixmap( col )->width(); fieldX += d; fieldW -= d; } setGeometry(fieldX, rect.y() - 1, fieldW, rect.height() + 2); show(); setFocus(); } /* Helper functions to for * tabOrderedRename functionality. */ static int nextCol (KListView *pl, TQListViewItem *pi, int start, int dir) { if (pi) { // Find the next renameable column in the current row for (; ((dir == +1) ? (start < pl->columns()) : (start >= 0)); start += dir) if (pl->isRenameable(start)) return start; } return -1; } static TQListViewItem *prevItem (TQListViewItem *pi) { TQListViewItem *pa = pi->itemAbove(); /* Does what the TQListViewItem::previousSibling() * of my dreams would do. */ if (pa && pa->parent() == pi->parent()) return pa; return 0; } static TQListViewItem *lastQChild (TQListViewItem *pi) { if (pi) { /* Since there's no TQListViewItem::lastChild(). * This finds the last sibling for the given * item. */ for (TQListViewItem *pt = pi->nextSibling(); pt; pt = pt->nextSibling()) pi = pt; } return pi; } void KListViewLineEdit::selectNextCell (TQListViewItem *pitem, int column, bool forward) { const int ncols = p->columns(); const int dir = forward ? +1 : -1; const int restart = forward ? 0 : (ncols - 1); TQListViewItem *top = (pitem && pitem->parent()) ? pitem->parent()->firstChild() : p->firstChild(); TQListViewItem *pi = pitem; terminate(); // Save current changes do { /* Check the rest of the current row for an editable column, * if that fails, check the entire next/previous row. The * last case goes back to the first item in the current branch * or the last item in the current branch depending on the * direction. */ if ((column = nextCol(p, pi, column + dir, dir)) != -1 || (column = nextCol(p, (pi = (forward ? pi->nextSibling() : prevItem(pi))), restart, dir)) != -1 || (column = nextCol(p, (pi = (forward ? top : lastQChild(pitem))), restart, dir)) != -1) { if (pi) { p->setCurrentItem(pi); // Calls terminate p->rename(pi, column); /* Some listviews may override rename() to * prevent certain items from being renamed, * if this is done, [m_]item will be NULL * after the rename() call... try again. */ if (!item) continue; break; } } } while (pi && !item); } #ifdef KeyPress #undef KeyPress #endif bool KListViewLineEdit::event (TQEvent *pe) { if (pe->type() == TQEvent::KeyPress) { TQKeyEvent *k = (TQKeyEvent *) pe; if ((k->key() == Qt::Key_Backtab || k->key() == Qt::Key_Tab) && p->tabOrderedRenaming() && p->itemsRenameable() && !(k->state() & ControlButton || k->state() & AltButton)) { selectNextCell(item, col, (k->key() == Key_Tab && !(k->state() & ShiftButton))); return true; } } return KLineEdit::event(pe); } void KListViewLineEdit::keyPressEvent(TQKeyEvent *e) { if(e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter ) terminate(true); else if(e->key() == Qt::Key_Escape) terminate(false); else if (e->key() == Qt::Key_Down || e->key() == Qt::Key_Up) { terminate(true); KLineEdit::keyPressEvent(e); } else KLineEdit::keyPressEvent(e); } void KListViewLineEdit::terminate() { terminate(true); } void KListViewLineEdit::terminate(bool commit) { if ( item ) { //kdDebug() << "KListViewLineEdit::terminate " << commit << endl; if (commit) item->setText(col, text()); int c=col; TQListViewItem *i=item; col=0; item=0; p->setFocus();// will call focusOutEvent, that's why we set item=0 before hide(); if (commit) emit done(i,c); } } void KListViewLineEdit::focusOutEvent(TQFocusEvent *ev) { TQFocusEvent * focusEv = static_cast(ev); // Don't let a RMB close the editor if (focusEv->reason() != TQFocusEvent::Popup && focusEv->reason() != TQFocusEvent::ActiveWindow) terminate(true); else KLineEdit::focusOutEvent(ev); } void KListViewLineEdit::paintEvent( TQPaintEvent *e ) { KLineEdit::paintEvent( e ); if ( !frame() ) { TQPainter p( this ); p.setClipRegion( e->region() ); p.drawRect( rect() ); } } // selection changed -> terminate. As our "item" can be already deleted, // we can't call terminate(false), because that would emit done() with // a dangling pointer to "item". void KListViewLineEdit::slotSelectionChanged() { item = 0; col = 0; hide(); } // if the current item was removed -> terminate. Can't call terminate(false) // due to same reason as slotSelectionChanged(). void KListViewLineEdit::slotItemRemoved(TQListViewItem *i) { if (currentItem() != i) return; item = 0; col = 0; hide(); } KListView::KListView( TQWidget *parent, const char *name ) : TQListView( parent, name ), d (new KListViewPrivate (this)) { setDragAutoScroll(true); connect( this, TQT_SIGNAL( onViewport() ), this, TQT_SLOT( slotOnViewport() ) ); connect( this, TQT_SIGNAL( onItem( TQListViewItem * ) ), this, TQT_SLOT( slotOnItem( TQListViewItem * ) ) ); connect (this, TQT_SIGNAL(contentsMoving(int,int)), this, TQT_SLOT(cleanDropVisualizer())); connect (this, TQT_SIGNAL(contentsMoving(int,int)), this, TQT_SLOT(cleanItemHighlighter())); slotSettingsChanged(KApplication::SETTINGS_MOUSE); if (kapp) { connect( kapp, TQT_SIGNAL( settingsChanged(int) ), TQT_SLOT( slotSettingsChanged(int) ) ); kapp->addKipcEventMask( KIPC::SettingsChanged ); } connect(&d->autoSelect, TQT_SIGNAL( timeout() ), this, TQT_SLOT( slotAutoSelect() ) ); connect(&d->dragExpand, TQT_SIGNAL( timeout() ), this, TQT_SLOT( slotDragExpand() ) ); // context menu handling if (d->showContextMenusOnPress) { connect (this, TQT_SIGNAL (rightButtonPressed (TQListViewItem*, const TQPoint&, int)), this, TQT_SLOT (emitContextMenu (TQListViewItem*, const TQPoint&, int))); } else { connect (this, TQT_SIGNAL (rightButtonClicked (TQListViewItem*, const TQPoint&, int)), this, TQT_SLOT (emitContextMenu (TQListViewItem*, const TQPoint&, int))); } connect (this, TQT_SIGNAL (menuShortCutPressed (KListView*, TQListViewItem*)), this, TQT_SLOT (emitContextMenu (KListView*, TQListViewItem*))); d->alternateBackground = KGlobalSettings::alternateBackgroundColor(); } KListView::~KListView() { delete d; } bool KListView::isExecuteArea( const TQPoint& point ) { TQListViewItem* item = itemAt( point ); if ( item ) { return isExecuteArea( point.x(), item ); } return false; } bool KListView::isExecuteArea( int x ) { return isExecuteArea( x, 0 ); } bool KListView::isExecuteArea( int x, TQListViewItem* item ) { if( allColumnsShowFocus() ) return true; else { int offset = 0; int width = columnWidth( 0 ); TQHeader* const thisHeader = header(); const int pos = thisHeader->mapToIndex( 0 ); for ( int index = 0; index < pos; ++index ) offset += columnWidth( thisHeader->mapToSection( index ) ); x += contentsX(); // in case of a horizontal scrollbar if ( item ) { width = treeStepSize()*( item->depth() + ( rootIsDecorated() ? 1 : 0 ) ); width += itemMargin(); int ca = AlignHorizontal_Mask & columnAlignment( 0 ); if ( ca == AlignLeft || ca == AlignAuto ) { width += item->width( fontMetrics(), this, 0 ); if ( width > columnWidth( 0 ) ) width = columnWidth( 0 ); } } return ( x > offset && x < ( offset + width ) ); } } void KListView::slotOnItem( TQListViewItem *item ) { TQPoint vp = viewport()->mapFromGlobal( TQCursor::pos() ); if ( item && isExecuteArea( vp.x() ) && (d->autoSelectDelay > -1) && d->bUseSingle ) { d->autoSelect.start( d->autoSelectDelay, true ); d->pCurrentItem = item; } } void KListView::slotOnViewport() { if ( d->bChangeCursorOverItem ) viewport()->unsetCursor(); d->autoSelect.stop(); d->pCurrentItem = 0L; } void KListView::slotSettingsChanged(int category) { switch (category) { case KApplication::SETTINGS_MOUSE: d->dragDelay = KGlobalSettings::dndEventDelay(); d->bUseSingle = KGlobalSettings::singleClick(); disconnect(this, TQT_SIGNAL (mouseButtonClicked (int, TQListViewItem*, const TQPoint &, int)), this, TQT_SLOT (slotMouseButtonClicked (int, TQListViewItem*, const TQPoint &, int))); if( d->bUseSingle ) connect (this, TQT_SIGNAL (mouseButtonClicked (int, TQListViewItem*, const TQPoint &, int)), this, TQT_SLOT (slotMouseButtonClicked( int, TQListViewItem*, const TQPoint &, int))); d->bChangeCursorOverItem = KGlobalSettings::changeCursorOverIcon(); if ( !d->disableAutoSelection ) d->autoSelectDelay = KGlobalSettings::autoSelectDelay(); if( !d->bUseSingle || !d->bChangeCursorOverItem ) viewport()->unsetCursor(); break; case KApplication::SETTINGS_POPUPMENU: d->contextMenuKey = KGlobalSettings::contextMenuKey (); d->showContextMenusOnPress = KGlobalSettings::showContextMenusOnPress (); if (d->showContextMenusOnPress) { disconnect (0L, 0L, this, TQT_SLOT (emitContextMenu (TQListViewItem*, const TQPoint&, int))); connect(this, TQT_SIGNAL (rightButtonPressed (TQListViewItem*, const TQPoint&, int)), this, TQT_SLOT (emitContextMenu (TQListViewItem*, const TQPoint&, int))); } else { disconnect (0L, 0L, this, TQT_SLOT (emitContextMenu (TQListViewItem*, const TQPoint&, int))); connect(this, TQT_SIGNAL (rightButtonClicked (TQListViewItem*, const TQPoint&, int)), this, TQT_SLOT (emitContextMenu (TQListViewItem*, const TQPoint&, int))); } break; default: break; } } void KListView::slotAutoSelect() { // check that the item still exists if( itemIndex( d->pCurrentItem ) == -1 ) return; if (!isActiveWindow()) { d->autoSelect.stop(); return; } //Give this widget the keyboard focus. if( !hasFocus() ) setFocus(); ButtonState keybstate = KApplication::keyboardMouseState(); TQListViewItem* previousItem = currentItem(); setCurrentItem( d->pCurrentItem ); if( d->pCurrentItem ) { //Shift pressed? if( (keybstate & Qt::ShiftButton) ) { bool block = signalsBlocked(); blockSignals( true ); //No Ctrl? Then clear before! if( !(keybstate & Qt::ControlButton) ) clearSelection(); bool select = !d->pCurrentItem->isSelected(); bool update = viewport()->isUpdatesEnabled(); viewport()->setUpdatesEnabled( false ); bool down = previousItem->itemPos() < d->pCurrentItem->itemPos(); TQListViewItemIterator lit( down ? previousItem : d->pCurrentItem ); for ( ; lit.current(); ++lit ) { if ( down && lit.current() == d->pCurrentItem ) { d->pCurrentItem->setSelected( select ); break; } if ( !down && lit.current() == previousItem ) { previousItem->setSelected( select ); break; } lit.current()->setSelected( select ); } blockSignals( block ); viewport()->setUpdatesEnabled( update ); triggerUpdate(); emit selectionChanged(); if( selectionMode() == TQListView::Single ) emit selectionChanged( d->pCurrentItem ); } else if( (keybstate & KApplication::ControlModifier) ) setSelected( d->pCurrentItem, !d->pCurrentItem->isSelected() ); else { bool block = signalsBlocked(); blockSignals( true ); if( !d->pCurrentItem->isSelected() ) clearSelection(); blockSignals( block ); setSelected( d->pCurrentItem, true ); } } else kdDebug() << "KListView::slotAutoSelect: Thatīs not supposed to happen!!!!" << endl; } void KListView::slotHeaderChanged() { const int colCount = columns(); if (d->fullWidth && colCount) { int w = 0; const int lastColumn = colCount - 1; for (int i = 0; i < lastColumn; ++i) w += columnWidth(i); setColumnWidth( lastColumn, viewport()->width() - w - 1 ); } } void KListView::emitExecute( TQListViewItem *item, const TQPoint &pos, int c ) { if( isExecuteArea( viewport()->mapFromGlobal(pos) ) ) { d->validDrag=false; // Double click mode ? if ( !d->bUseSingle ) { viewport()->unsetCursor(); emit executed( item ); emit executed( item, pos, c ); } else { ButtonState keybstate = KApplication::keyboardMouseState(); d->autoSelect.stop(); //Donīt emit executed if in SC mode and Shift or Ctrl are pressed if( !( ((keybstate & Qt::ShiftButton) || (keybstate & Qt::ControlButton)) ) ) { viewport()->unsetCursor(); emit executed( item ); emit executed( item, pos, c ); } } } } void KListView::focusInEvent( TQFocusEvent *fe ) { // kdDebug()<<"KListView::focusInEvent()"<selectedBySimpleMove) && (d->selectionMode == FileManager) && (fe->reason()!=TQFocusEvent::Popup) && (fe->reason()!=TQFocusEvent::ActiveWindow) && (currentItem())) { currentItem()->setSelected(true); currentItem()->repaint(); emit selectionChanged(); }; } void KListView::focusOutEvent( TQFocusEvent *fe ) { cleanDropVisualizer(); cleanItemHighlighter(); d->autoSelect.stop(); if ((d->selectedBySimpleMove) && (d->selectionMode == FileManager) && (fe->reason()!=TQFocusEvent::Popup) && (fe->reason()!=TQFocusEvent::ActiveWindow) && (currentItem()) && (!d->editor->isVisible())) { currentItem()->setSelected(false); currentItem()->repaint(); emit selectionChanged(); }; TQListView::focusOutEvent( fe ); } void KListView::leaveEvent( TQEvent *e ) { d->autoSelect.stop(); TQListView::leaveEvent( e ); } bool KListView::event( TQEvent *e ) { if (e->type() == TQEvent::ApplicationPaletteChange) d->alternateBackground=KGlobalSettings::alternateBackgroundColor(); return TQListView::event(e); } void KListView::contentsMousePressEvent( TQMouseEvent *e ) { if( (selectionModeExt() == Extended) && (e->state() & ShiftButton) && !(e->state() & ControlButton) ) { bool block = signalsBlocked(); blockSignals( true ); clearSelection(); blockSignals( block ); } else if ((selectionModeExt()==FileManager) && (d->selectedBySimpleMove)) { d->selectedBySimpleMove=false; d->selectedUsingMouse=true; if (currentItem()) { currentItem()->setSelected(false); currentItem()->repaint(); // emit selectionChanged(); } } TQPoint p( contentsToViewport( e->pos() ) ); TQListViewItem *at = itemAt (p); // true if the root decoration of the item "at" was clicked (i.e. the +/- sign) bool rootDecoClicked = at && ( p.x() <= header()->cellPos( header()->mapToActual( 0 ) ) + treeStepSize() * ( at->depth() + ( rootIsDecorated() ? 1 : 0) ) + itemMargin() ) && ( p.x() >= header()->cellPos( header()->mapToActual( 0 ) ) ); if (e->button() == LeftButton && !rootDecoClicked) { //Start a drag d->startDragPos = e->pos(); if (at) { d->validDrag = true; d->pressedOnSelected = at->isSelected(); } } TQListView::contentsMousePressEvent( e ); } void KListView::contentsMouseMoveEvent( TQMouseEvent *e ) { if (!dragEnabled() || d->startDragPos.isNull() || !d->validDrag) TQListView::contentsMouseMoveEvent (e); TQPoint vp = contentsToViewport(e->pos()); TQListViewItem *item = itemAt( vp ); //do we process cursor changes at all? if ( item && d->bChangeCursorOverItem && d->bUseSingle ) { //Cursor moved on a new item or in/out the execute area if( (item != d->pCurrentItem) || (isExecuteArea(vp) != d->cursorInExecuteArea) ) { d->cursorInExecuteArea = isExecuteArea(vp); if( d->cursorInExecuteArea ) //cursor moved in execute area viewport()->setCursor( KCursor::handCursor() ); else //cursor moved out of execute area viewport()->unsetCursor(); } } bool dragOn = dragEnabled(); TQPoint newPos = e->pos(); if (dragOn && d->validDrag && (newPos.x() > d->startDragPos.x()+d->dragDelay || newPos.x() < d->startDragPos.x()-d->dragDelay || newPos.y() > d->startDragPos.y()+d->dragDelay || newPos.y() < d->startDragPos.y()-d->dragDelay)) //(d->startDragPos - e->pos()).manhattanLength() > TQApplication::startDragDistance()) { TQListView::contentsMouseReleaseEvent( 0 ); startDrag(); d->startDragPos = TQPoint(); d->validDrag = false; } } void KListView::contentsMouseReleaseEvent( TQMouseEvent *e ) { if (e->button() == LeftButton) { // If the row was already selected, maybe we want to start an in-place editing if ( d->pressedOnSelected && itemsRenameable() ) { TQPoint p( contentsToViewport( e->pos() ) ); TQListViewItem *at = itemAt (p); if ( at ) { // true if the root decoration of the item "at" was clicked (i.e. the +/- sign) bool rootDecoClicked = ( p.x() <= header()->cellPos( header()->mapToActual( 0 ) ) + treeStepSize() * ( at->depth() + ( rootIsDecorated() ? 1 : 0) ) + itemMargin() ) && ( p.x() >= header()->cellPos( header()->mapToActual( 0 ) ) ); if (!rootDecoClicked) { int col = header()->mapToLogical( header()->cellAt( p.x() ) ); if ( d->renameable.contains(col) ) rename(at, col); } } } d->pressedOnSelected = false; d->validDrag = false; d->startDragPos = TQPoint(); } TQListView::contentsMouseReleaseEvent( e ); } void KListView::contentsMouseDoubleClickEvent ( TQMouseEvent *e ) { // We don't want to call the parent method because it does setOpen, // whereas we don't do it in single click mode... (David) //TQListView::contentsMouseDoubleClickEvent( e ); if ( !e || e->button() != LeftButton ) return; TQPoint vp = contentsToViewport(e->pos()); TQListViewItem *item = itemAt( vp ); emit TQListView::doubleClicked( item ); // we do it now int col = item ? header()->mapToLogical( header()->cellAt( vp.x() ) ) : -1; if( item ) { emit doubleClicked( item, e->globalPos(), col ); if( (e->button() == LeftButton) && !d->bUseSingle ) emitExecute( item, e->globalPos(), col ); } } void KListView::slotMouseButtonClicked( int btn, TQListViewItem *item, const TQPoint &pos, int c ) { if( (btn == LeftButton) && item ) emitExecute(item, pos, c); } void KListView::contentsDropEvent(TQDropEvent* e) { cleanDropVisualizer(); cleanItemHighlighter(); d->dragExpand.stop(); if (acceptDrag (e)) { e->acceptAction(); TQListViewItem *afterme; TQListViewItem *parent; findDrop(e->pos(), parent, afterme); if (e->source() == viewport() && itemsMovable()) movableDropEvent(parent, afterme); else { emit dropped(e, afterme); emit dropped(this, e, afterme); emit dropped(e, parent, afterme); emit dropped(this, e, parent, afterme); } } } void KListView::movableDropEvent (TQListViewItem* parent, TQListViewItem* afterme) { TQPtrList items, afterFirsts, afterNows; TQListViewItem *current=currentItem(); bool hasMoved=false; for (TQListViewItem *i = firstChild(), *iNext=0; i; i = iNext) { iNext=i->itemBelow(); if (!i->isSelected()) continue; // don't drop an item after itself, or else // it moves to the top of the list if (i==afterme) continue; i->setSelected(false); TQListViewItem *afterFirst = i->itemAbove(); if (!hasMoved) { emit aboutToMove(); hasMoved=true; } moveItem(i, parent, afterme); // ###### This should include the new parent !!! -> KDE 3.0 // If you need this right now, have a look at keditbookmarks. emit moved(i, afterFirst, afterme); items.append (i); afterFirsts.append (afterFirst); afterNows.append (afterme); afterme = i; } clearSelection(); for (TQListViewItem *i=items.first(); i; i=items.next() ) i->setSelected(true); if (current) setCurrentItem(current); emit moved(items,afterFirsts,afterNows); if (firstChild()) emit moved(); } void KListView::contentsDragMoveEvent(TQDragMoveEvent *event) { if (acceptDrag(event)) { event->acceptAction(); //Clean up the view findDrop(event->pos(), d->parentItemDrop, d->afterItemDrop); TQPoint vp = contentsToViewport( event->pos() ); TQListViewItem *item = isExecuteArea( vp ) ? itemAt( vp ) : 0L; if ( item != d->dragOverItem ) { d->dragExpand.stop(); d->dragOverItem = item; d->dragOverPoint = vp; if ( d->dragOverItem && d->dragOverItem->isExpandable() && !d->dragOverItem->isOpen() ) d->dragExpand.start( TQApplication::startDragTime(), true ); } if (dropVisualizer()) { TQRect tmpRect = drawDropVisualizer(0, d->parentItemDrop, d->afterItemDrop); if (tmpRect != d->mOldDropVisualizer) { cleanDropVisualizer(); d->mOldDropVisualizer=tmpRect; viewport()->repaint(tmpRect); } } if (dropHighlighter()) { TQRect tmpRect = drawItemHighlighter(0, itemAt( vp )); if (tmpRect != d->mOldDropHighlighter) { cleanItemHighlighter(); d->mOldDropHighlighter=tmpRect; viewport()->repaint(tmpRect); } } } else event->ignore(); } void KListView::slotDragExpand() { if ( itemAt( d->dragOverPoint ) == d->dragOverItem ) d->dragOverItem->setOpen( true ); } void KListView::contentsDragLeaveEvent (TQDragLeaveEvent*) { d->dragExpand.stop(); cleanDropVisualizer(); cleanItemHighlighter(); } void KListView::cleanDropVisualizer() { if (d->mOldDropVisualizer.isValid()) { TQRect rect=d->mOldDropVisualizer; d->mOldDropVisualizer = TQRect(); viewport()->repaint(rect, true); } } int KListView::depthToPixels( int depth ) { return treeStepSize() * ( depth + (rootIsDecorated() ? 1 : 0) ) + itemMargin(); } void KListView::findDrop(const TQPoint &pos, TQListViewItem *&parent, TQListViewItem *&after) { TQPoint p (contentsToViewport(pos)); // Get the position to put it in TQListViewItem *atpos = itemAt(p); TQListViewItem *above; if (!atpos) // put it at the end above = lastItem(); else { // Get the closest item before us ('atpos' or the one above, if any) if (p.y() - itemRect(atpos).topLeft().y() < (atpos->height()/2)) above = atpos->itemAbove(); else above = atpos; } if (above) { // if above has children, I might need to drop it as the first item there if (above->firstChild() && above->isOpen()) { parent = above; after = 0; return; } // Now, we know we want to go after "above". But as a child or as a sibling ? // We have to ask the "above" item if it accepts children. if (above->isExpandable()) { // The mouse is sufficiently on the right ? - doesn't matter if 'above' has visible children if (p.x() >= depthToPixels( above->depth() + 1 ) || (above->isOpen() && above->childCount() > 0) ) { parent = above; after = 0L; return; } } // Ok, there's one more level of complexity. We may want to become a new // sibling, but of an upper-level group, rather than the "above" item TQListViewItem * betterAbove = above->parent(); TQListViewItem * last = above; while ( betterAbove ) { // We are allowed to become a sibling of "betterAbove" only if we are // after its last child if ( !last->nextSibling() ) { if (p.x() < depthToPixels ( betterAbove->depth() + 1 )) above = betterAbove; // store this one, but don't stop yet, there may be a better one else break; // not enough on the left, so stop last = betterAbove; betterAbove = betterAbove->parent(); // up one level } else break; // we're among the child of betterAbove, not after the last one } } // set as sibling after = above; parent = after ? after->parent() : 0L ; } TQListViewItem* KListView::lastChild () const { TQListViewItem* lastchild = firstChild(); if (lastchild) for (; lastchild->nextSibling(); lastchild = lastchild->nextSibling()); return lastchild; } TQListViewItem *KListView::lastItem() const { TQListViewItem* last = lastChild(); for (TQListViewItemIterator it (last); it.current(); ++it) last = it.current(); return last; } KLineEdit *KListView::renameLineEdit() const { return d->editor; } void KListView::startDrag() { TQDragObject *drag = dragObject(); if (!drag) return; if (drag->drag() && drag->target() != viewport()) emit moved(); } TQDragObject *KListView::dragObject() { if (!currentItem()) return 0; return new TQStoredDrag("application/x-qlistviewitem", viewport()); } void KListView::setItemsMovable(bool b) { d->itemsMovable=b; } bool KListView::itemsMovable() const { return d->itemsMovable; } void KListView::setItemsRenameable(bool b) { d->itemsRenameable=b; } bool KListView::itemsRenameable() const { return d->itemsRenameable; } void KListView::setDragEnabled(bool b) { d->dragEnabled=b; } bool KListView::dragEnabled() const { return d->dragEnabled; } void KListView::setAutoOpen(bool b) { d->autoOpen=b; } bool KListView::autoOpen() const { return d->autoOpen; } bool KListView::dropVisualizer() const { return d->dropVisualizer; } void KListView::setDropVisualizer(bool b) { d->dropVisualizer=b; } TQPtrList KListView::selectedItems() const { return selectedItems(true); } TQPtrList KListView::selectedItems(bool includeHiddenItems) const { TQPtrList list; // Using selectionMode() instead of selectionModeExt() since for the cases that // we're interested in selectionMode() should work for either variety of the // setSelectionMode(). switch(selectionMode()) { case NoSelection: break; case Single: if(selectedItem() && (includeHiddenItems || selectedItem()->isVisible())) list.append(selectedItem()); break; default: { int flags = TQListViewItemIterator::Selected; if (!includeHiddenItems) { flags |= TQListViewItemIterator::Visible; } TQListViewItemIterator it(const_cast(this), flags); for(; it.current(); ++it) list.append(it.current()); break; } } return list; } void KListView::moveItem(TQListViewItem *item, TQListViewItem *parent, TQListViewItem *after) { // sanity check - don't move a item into its own child structure TQListViewItem *i = parent; while(i) { if(i == item) return; i = i->parent(); } if (after) { item->moveItem(after); return; } // Basically reimplementing the TQListViewItem(TQListViewItem*, TQListViewItem*) constructor // in here, without ever deleting the item. if (item->parent()) item->parent()->takeItem(item); else takeItem(item); if (parent) parent->insertItem(item); else insertItem(item); } void KListView::contentsDragEnterEvent(TQDragEnterEvent *event) { if (acceptDrag (event)) event->accept(); } void KListView::setDropVisualizerWidth (int w) { d->mDropVisualizerWidth = w > 0 ? w : 1; } TQRect KListView::drawDropVisualizer(TQPainter *p, TQListViewItem *parent, TQListViewItem *after) { TQRect insertmarker; if (!after && !parent) insertmarker = TQRect (0, 0, viewport()->width(), d->mDropVisualizerWidth/2); else { int level = 0; if (after) { TQListViewItem* it = 0L; if (after->isOpen()) { // Look for the last child (recursively) it = after->firstChild(); if (it) while (it->nextSibling() || it->firstChild()) if ( it->nextSibling() ) it = it->nextSibling(); else it = it->firstChild(); } insertmarker = itemRect (it ? it : after); level = after->depth(); } else if (parent) { insertmarker = itemRect (parent); level = parent->depth() + 1; } insertmarker.setLeft( treeStepSize() * ( level + (rootIsDecorated() ? 1 : 0) ) + itemMargin() ); insertmarker.setRight (viewport()->width()); insertmarker.setTop (insertmarker.bottom() - d->mDropVisualizerWidth/2 + 1); insertmarker.setBottom (insertmarker.bottom() + d->mDropVisualizerWidth/2); } // This is not used anymore, at least by KListView itself (see viewportPaintEvent) // Remove for KDE 4.0. if (p) p->fillRect(insertmarker, Dense4Pattern); return insertmarker; } TQRect KListView::drawItemHighlighter(TQPainter *painter, TQListViewItem *item) { TQRect r; if (item) { r = itemRect(item); r.setLeft(r.left()+(item->depth()+(rootIsDecorated() ? 1 : 0))*treeStepSize()); if (painter) style().drawPrimitive(TQStyle::PE_FocusRect, painter, r, colorGroup(), TQStyle::Style_FocusAtBorder, colorGroup().highlight()); } return r; } void KListView::cleanItemHighlighter () { if (d->mOldDropHighlighter.isValid()) { TQRect rect=d->mOldDropHighlighter; d->mOldDropHighlighter = TQRect(); viewport()->repaint(rect, true); } } void KListView::rename(TQListViewItem *item, int c) { if (d->renameable.contains(c)) { ensureItemVisible(item); d->editor->load(item,c); } } bool KListView::isRenameable (int col) const { return d->renameable.contains(col); } void KListView::setRenameable (int col, bool renameable) { if (col>=header()->count()) return; d->renameable.remove(col); if (renameable) d->renameable+=col; } void KListView::doneEditing(TQListViewItem *item, int row) { emit itemRenamed(item, item->text(row), row); emit itemRenamed(item); } bool KListView::acceptDrag(TQDropEvent* e) const { return acceptDrops() && itemsMovable() && (e->source()==viewport()); } void KListView::setCreateChildren(bool b) { d->createChildren=b; } bool KListView::createChildren() const { return d->createChildren; } int KListView::tooltipColumn() const { return d->tooltipColumn; } void KListView::setTooltipColumn(int column) { d->tooltipColumn=column; } void KListView::setDropHighlighter(bool b) { d->dropHighlighter=b; } bool KListView::dropHighlighter() const { return d->dropHighlighter; } bool KListView::showTooltip(TQListViewItem *item, const TQPoint &, int column) const { return ((column==tooltipColumn()) && !tooltip(item, column).isEmpty()); } TQString KListView::tooltip(TQListViewItem *item, int column) const { return item->text(column); } void KListView::setTabOrderedRenaming(bool b) { d->tabRename = b; } bool KListView::tabOrderedRenaming() const { return d->tabRename; } void KListView::keyPressEvent (TQKeyEvent* e) { //don't we need a contextMenuModifier too ? (aleXXX) if (e->key() == d->contextMenuKey) { emit menuShortCutPressed (this, currentItem()); return; } if (d->selectionMode != FileManager) TQListView::keyPressEvent (e); else fileManagerKeyPressEvent (e); } void KListView::activateAutomaticSelection() { d->selectedBySimpleMove=true; d->selectedUsingMouse=false; if (currentItem()) { currentItem()->setSelected(true); currentItem()->repaint(); emit selectionChanged(); }; } void KListView::deactivateAutomaticSelection() { d->selectedBySimpleMove=false; } bool KListView::automaticSelection() const { return d->selectedBySimpleMove; } void KListView::fileManagerKeyPressEvent (TQKeyEvent* e) { //don't care whether it's on the keypad or not int e_state=(e->state() & ~Keypad); int oldSelectionDirection(d->selectionDirection); if ((e->key()!=Key_Shift) && (e->key()!=Key_Control) && (e->key()!=Key_Meta) && (e->key()!=Key_Alt)) { if ((e_state==ShiftButton) && (!d->wasShiftEvent) && (!d->selectedBySimpleMove)) selectAll(false); d->selectionDirection=0; d->wasShiftEvent = (e_state == ShiftButton); }; //d->wasShiftEvent = (e_state == ShiftButton); TQListViewItem* item = currentItem(); if (!item) return; TQListViewItem* repaintItem1 = item; TQListViewItem* repaintItem2 = 0L; TQListViewItem* visItem = 0L; TQListViewItem* nextItem = 0L; int items = 0; bool shiftOrCtrl((e_state==ControlButton) || (e_state==ShiftButton)); int selectedItems(0); for (TQListViewItem *tmpItem=firstChild(); tmpItem; tmpItem=tmpItem->nextSibling()) if (tmpItem->isSelected()) selectedItems++; if (((!selectedItems) || ((selectedItems==1) && (d->selectedUsingMouse))) && (e_state==NoButton) && ((e->key()==Key_Down) || (e->key()==Key_Up) || (e->key()==Key_Next) || (e->key()==Key_Prior) || (e->key()==Key_Home) || (e->key()==Key_End))) { d->selectedBySimpleMove=true; d->selectedUsingMouse=false; } else if (selectedItems>1) d->selectedBySimpleMove=false; bool emitSelectionChanged(false); switch (e->key()) { case Key_Escape: selectAll(false); emitSelectionChanged=true; break; case Key_Space: //toggle selection of current item if (d->selectedBySimpleMove) d->selectedBySimpleMove=false; item->setSelected(!item->isSelected()); emitSelectionChanged=true; break; case Key_Insert: //toggle selection of current item and move to the next item if (d->selectedBySimpleMove) { d->selectedBySimpleMove=false; if (!item->isSelected()) item->setSelected(true); } else { item->setSelected(!item->isSelected()); }; nextItem=item->itemBelow(); if (nextItem) { repaintItem2=nextItem; visItem=nextItem; setCurrentItem(nextItem); }; d->selectionDirection=1; emitSelectionChanged=true; break; case Key_Down: nextItem=item->itemBelow(); //toggle selection of current item and move to the next item if (shiftOrCtrl) { d->selectionDirection=1; if (d->selectedBySimpleMove) d->selectedBySimpleMove=false; else { if (oldSelectionDirection!=-1) { item->setSelected(!item->isSelected()); emitSelectionChanged=true; }; }; } else if ((d->selectedBySimpleMove) && (nextItem)) { item->setSelected(false); emitSelectionChanged=true; }; if (nextItem) { if (d->selectedBySimpleMove) nextItem->setSelected(true); repaintItem2=nextItem; visItem=nextItem; setCurrentItem(nextItem); }; break; case Key_Up: nextItem=item->itemAbove(); d->selectionDirection=-1; //move to the prev. item and toggle selection of this one // => No, can't select the last item, with this. For symmetry, let's // toggle selection and THEN move up, just like we do in down (David) if (shiftOrCtrl) { if (d->selectedBySimpleMove) d->selectedBySimpleMove=false; else { if (oldSelectionDirection!=1) { item->setSelected(!item->isSelected()); emitSelectionChanged=true; }; } } else if ((d->selectedBySimpleMove) && (nextItem)) { item->setSelected(false); emitSelectionChanged=true; }; if (nextItem) { if (d->selectedBySimpleMove) nextItem->setSelected(true); repaintItem2=nextItem; visItem=nextItem; setCurrentItem(nextItem); }; break; case Key_End: //move to the last item and toggle selection of all items inbetween nextItem=item; if (d->selectedBySimpleMove) item->setSelected(false); if (shiftOrCtrl) d->selectedBySimpleMove=false; while(nextItem) { if (shiftOrCtrl) nextItem->setSelected(!nextItem->isSelected()); if (!nextItem->itemBelow()) { if (d->selectedBySimpleMove) nextItem->setSelected(true); repaintItem2=nextItem; visItem=nextItem; setCurrentItem(nextItem); } nextItem=nextItem->itemBelow(); } emitSelectionChanged=true; break; case Key_Home: // move to the first item and toggle selection of all items inbetween nextItem = firstChild(); visItem = nextItem; repaintItem2 = visItem; if (d->selectedBySimpleMove) item->setSelected(false); if (shiftOrCtrl) { d->selectedBySimpleMove=false; while ( nextItem != item ) { nextItem->setSelected( !nextItem->isSelected() ); nextItem = nextItem->itemBelow(); } item->setSelected( !item->isSelected() ); } setCurrentItem( firstChild() ); emitSelectionChanged=true; break; case Key_Next: items=visibleHeight()/item->height(); nextItem=item; if (d->selectedBySimpleMove) item->setSelected(false); if (shiftOrCtrl) { d->selectedBySimpleMove=false; d->selectionDirection=1; }; for (int i=0; isetSelected(!nextItem->isSelected()); //the end if ((i==items-1) || (!nextItem->itemBelow())) { if (shiftOrCtrl) nextItem->setSelected(!nextItem->isSelected()); if (d->selectedBySimpleMove) nextItem->setSelected(true); ensureItemVisible(nextItem); setCurrentItem(nextItem); update(); if ((shiftOrCtrl) || (d->selectedBySimpleMove)) { emit selectionChanged(); } return; } nextItem=nextItem->itemBelow(); } break; case Key_Prior: items=visibleHeight()/item->height(); nextItem=item; if (d->selectedBySimpleMove) item->setSelected(false); if (shiftOrCtrl) { d->selectionDirection=-1; d->selectedBySimpleMove=false; }; for (int i=0; isetSelected(!nextItem->isSelected()); //the end if ((i==items-1) || (!nextItem->itemAbove())) { if (d->selectedBySimpleMove) nextItem->setSelected(true); ensureItemVisible(nextItem); setCurrentItem(nextItem); update(); if ((shiftOrCtrl) || (d->selectedBySimpleMove)) { emit selectionChanged(); } return; } nextItem=nextItem->itemAbove(); } break; case Key_Minus: if ( item->isOpen() ) setOpen( item, false ); break; case Key_Plus: if ( !item->isOpen() && (item->isExpandable() || item->childCount()) ) setOpen( item, true ); break; default: bool realKey = ((e->key()!=Key_Shift) && (e->key()!=Key_Control) && (e->key()!=Key_Meta) && (e->key()!=Key_Alt)); bool selectCurrentItem = (d->selectedBySimpleMove) && (item->isSelected()); if (realKey && selectCurrentItem) item->setSelected(false); //this is mainly for the "goto filename beginning with pressed char" feature (aleXXX) TQListView::SelectionMode oldSelectionMode = selectionMode(); setSelectionMode (TQListView::Multi); TQListView::keyPressEvent (e); setSelectionMode (oldSelectionMode); if (realKey && selectCurrentItem) { currentItem()->setSelected(true); emitSelectionChanged=true; } repaintItem2=currentItem(); if (realKey) visItem=currentItem(); break; } if (visItem) ensureItemVisible(visItem); TQRect ir; if (repaintItem1) ir = ir.unite( itemRect(repaintItem1) ); if (repaintItem2) ir = ir.unite( itemRect(repaintItem2) ); if ( !ir.isEmpty() ) { // rectangle to be repainted if ( ir.x() < 0 ) ir.moveBy( -ir.x(), 0 ); viewport()->repaint( ir, false ); } /*if (repaintItem1) repaintItem1->repaint(); if (repaintItem2) repaintItem2->repaint();*/ update(); if (emitSelectionChanged) emit selectionChanged(); } void KListView::setSelectionModeExt (SelectionModeExt mode) { d->selectionMode = mode; switch (mode) { case Single: case Multi: case Extended: case NoSelection: setSelectionMode (static_cast(static_cast(mode))); break; case FileManager: setSelectionMode (TQListView::Extended); break; default: kdWarning () << "Warning: illegal selection mode " << int(mode) << " set!" << endl; break; } } KListView::SelectionModeExt KListView::selectionModeExt () const { return d->selectionMode; } int KListView::itemIndex( const TQListViewItem *item ) const { if ( !item ) return -1; if ( item == firstChild() ) return 0; else { TQListViewItemIterator it(firstChild()); uint j = 0; for (; it.current() && it.current() != item; ++it, ++j ); if( !it.current() ) return -1; return j; } } TQListViewItem* KListView::itemAtIndex(int index) { if (index<0) return 0; int j(0); for (TQListViewItemIterator it=firstChild(); it.current(); ++it) { if (j==index) return it.current(); ++j; }; return 0; } void KListView::emitContextMenu (KListView*, TQListViewItem* i) { TQPoint p; if (i) p = viewport()->mapToGlobal(itemRect(i).center()); else p = mapToGlobal(rect().center()); emit contextMenu (this, i, p); } void KListView::emitContextMenu (TQListViewItem* i, const TQPoint& p, int) { emit contextMenu (this, i, p); } void KListView::setAcceptDrops (bool val) { TQListView::setAcceptDrops (val); viewport()->setAcceptDrops (val); } int KListView::dropVisualizerWidth () const { return d->mDropVisualizerWidth; } void KListView::viewportPaintEvent(TQPaintEvent *e) { d->paintAbove = 0; d->paintCurrent = 0; d->paintBelow = 0; d->painting = true; TQListView::viewportPaintEvent(e); if (d->mOldDropVisualizer.isValid() && e->rect().intersects(d->mOldDropVisualizer)) { TQPainter painter(viewport()); // This is where we actually draw the drop-visualizer painter.fillRect(d->mOldDropVisualizer, Dense4Pattern); } if (d->mOldDropHighlighter.isValid() && e->rect().intersects(d->mOldDropHighlighter)) { TQPainter painter(viewport()); // This is where we actually draw the drop-highlighter style().drawPrimitive(TQStyle::PE_FocusRect, &painter, d->mOldDropHighlighter, colorGroup(), TQStyle::Style_FocusAtBorder); } d->painting = false; } void KListView::setFullWidth() { setFullWidth(true); } void KListView::setFullWidth(bool fullWidth) { d->fullWidth = fullWidth; header()->setStretchEnabled(fullWidth, columns()-1); } bool KListView::fullWidth() const { return d->fullWidth; } int KListView::addColumn(const TQString& label, int width) { int result = TQListView::addColumn(label, width); if (d->fullWidth) { header()->setStretchEnabled(false, columns()-2); header()->setStretchEnabled(true, columns()-1); } return result; } int KListView::addColumn(const TQIconSet& iconset, const TQString& label, int width) { int result = TQListView::addColumn(iconset, label, width); if (d->fullWidth) { header()->setStretchEnabled(false, columns()-2); header()->setStretchEnabled(true, columns()-1); } return result; } void KListView::removeColumn(int index) { TQListView::removeColumn(index); if (d->fullWidth && index == columns()) header()->setStretchEnabled(true, columns()-1); } void KListView::viewportResizeEvent(TQResizeEvent* e) { TQListView::viewportResizeEvent(e); } const TQColor &KListView::alternateBackground() const { return d->alternateBackground; } void KListView::setAlternateBackground(const TQColor &c) { d->alternateBackground = c; repaint(); } void KListView::setShadeSortColumn(bool shadeSortColumn) { d->shadeSortColumn = shadeSortColumn; repaint(); } bool KListView::shadeSortColumn() const { return d->shadeSortColumn; } void KListView::saveLayout(KConfig *config, const TQString &group) const { KConfigGroupSaver saver(config, group); TQStringList widths, order; const int colCount = columns(); TQHeader* const thisHeader = header(); for (int i = 0; i < colCount; ++i) { widths << TQString::number(columnWidth(i)); order << TQString::number(thisHeader->mapToIndex(i)); } config->writeEntry("ColumnWidths", widths); config->writeEntry("ColumnOrder", order); config->writeEntry("SortColumn", d->sortColumn); config->writeEntry("SortAscending", d->sortAscending); } void KListView::restoreLayout(KConfig *config, const TQString &group) { KConfigGroupSaver saver(config, group); TQStringList cols = config->readListEntry("ColumnWidths"); int i = 0; { // scope the iterators TQStringList::ConstIterator it = cols.constBegin(); const TQStringList::ConstIterator itEnd = cols.constEnd(); for (; it != itEnd; ++it) setColumnWidth(i++, (*it).toInt()); } // move sections in the correct sequence: from lowest to highest index position // otherwise we move a section from an index, which modifies // all index numbers to the right of the moved one cols = config->readListEntry("ColumnOrder"); const int colCount = columns(); for (i = 0; i < colCount; ++i) // final index positions from lowest to highest { TQStringList::ConstIterator it = cols.constBegin(); const TQStringList::ConstIterator itEnd = cols.constEnd(); int section = 0; for (; (it != itEnd) && ((*it).toInt() != i); ++it, ++section) ; if ( it != itEnd ) { // found the section to move to position i header()->moveSection(section, i); } } if (config->hasKey("SortColumn")) setSorting(config->readNumEntry("SortColumn"), config->readBoolEntry("SortAscending", true)); } void KListView::setSorting(int column, bool ascending) { TQListViewItem *selected = 0; if (selectionMode() == TQListView::Single) { selected = selectedItem(); if (selected && !selected->isVisible()) selected = 0; } else if (selectionMode() != TQListView::NoSelection) { TQListViewItem *item = firstChild(); while (item && !selected) { if (item->isSelected() && item->isVisible()) selected = item; item = item->itemBelow(); } } d->sortColumn = column; d->sortAscending = ascending; TQListView::setSorting(column, ascending); if (selected) ensureItemVisible(selected); TQListViewItem* item = firstChild(); while ( item ) { KListViewItem *kItem = dynamic_cast(item); if (kItem) kItem->m_known = false; item = item->itemBelow(); } } int KListView::columnSorted(void) const { return d->sortColumn; } bool KListView::ascendingSort(void) const { return d->sortAscending; } void KListView::takeItem(TQListViewItem *item) { if(item && item == d->editor->currentItem()) d->editor->terminate(); TQListView::takeItem(item); } void KListView::disableAutoSelection() { if ( d->disableAutoSelection ) return; d->disableAutoSelection = true; d->autoSelect.stop(); d->autoSelectDelay = -1; } void KListView::resetAutoSelection() { if ( !d->disableAutoSelection ) return; d->disableAutoSelection = false; d->autoSelectDelay = KGlobalSettings::autoSelectDelay(); } void KListView::doubleClicked( TQListViewItem *item, const TQPoint &pos, int c ) { emit TQListView::doubleClicked( item, pos, c ); } KListViewItem::KListViewItem(TQListView *parent) : TQListViewItem(parent) { init(); } KListViewItem::KListViewItem(TQListViewItem *parent) : TQListViewItem(parent) { init(); } KListViewItem::KListViewItem(TQListView *parent, TQListViewItem *after) : TQListViewItem(parent, after) { init(); } KListViewItem::KListViewItem(TQListViewItem *parent, TQListViewItem *after) : TQListViewItem(parent, after) { init(); } KListViewItem::KListViewItem(TQListView *parent, TQString label1, TQString label2, TQString label3, TQString label4, TQString label5, TQString label6, TQString label7, TQString label8) : TQListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8) { init(); } KListViewItem::KListViewItem(TQListViewItem *parent, TQString label1, TQString label2, TQString label3, TQString label4, TQString label5, TQString label6, TQString label7, TQString label8) : TQListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8) { init(); } KListViewItem::KListViewItem(TQListView *parent, TQListViewItem *after, TQString label1, TQString label2, TQString label3, TQString label4, TQString label5, TQString label6, TQString label7, TQString label8) : TQListViewItem(parent, after, label1, label2, label3, label4, label5, label6, label7, label8) { init(); } KListViewItem::KListViewItem(TQListViewItem *parent, TQListViewItem *after, TQString label1, TQString label2, TQString label3, TQString label4, TQString label5, TQString label6, TQString label7, TQString label8) : TQListViewItem(parent, after, label1, label2, label3, label4, label5, label6, label7, label8) { init(); } KListViewItem::~KListViewItem() { if(listView()) emit static_cast(listView())->itemRemoved(this); } void KListViewItem::init() { m_odd = m_known = false; KListView *lv = static_cast(listView()); setDragEnabled( dragEnabled() || lv->dragEnabled() ); emit lv->itemAdded(this); } void KListViewItem::insertItem(TQListViewItem *item) { TQListViewItem::insertItem(item); if(listView()) emit static_cast(listView())->itemAdded(item); } void KListViewItem::takeItem(TQListViewItem *item) { TQListViewItem::takeItem(item); if(listView()) emit static_cast(listView())->itemRemoved(item); } const TQColor &KListViewItem::backgroundColor() { if (isAlternate()) return static_cast< KListView* >(listView())->alternateBackground(); return listView()->viewport()->colorGroup().base(); } TQColor KListViewItem::backgroundColor(int column) { KListView* view = static_cast< KListView* >(listView()); TQColor color = isAlternate() ? view->alternateBackground() : view->viewport()->colorGroup().base(); // calculate a different color if the current column is sorted (only if more than 1 column) if ( (view->columns() > 1) && view->shadeSortColumn() && (column == view->columnSorted()) ) { if ( color == Qt::black ) color = TQColor(55, 55, 55); // dark gray else { int h,s,v; color.hsv(&h, &s, &v); if ( v > 175 ) color = color.dark(104); else color = color.light(120); } } return color; } bool KListViewItem::isAlternate() { KListView* const lv = static_cast(listView()); if (lv && lv->alternateBackground().isValid()) { KListViewItem *above; KListView::KListViewPrivate* const lvD = lv->d; // Ok, there's some weirdness here that requires explanation as this is a // speed hack. itemAbove() is a O(n) operation (though this isn't // immediately clear) so we want to call it as infrequently as possible -- // especially in the case of painting a cell. // // So, in the case that we *are* painting a cell: (1) we're assuming that // said painting is happening top to bottem -- this assumption is present // elsewhere in the implementation of this class, (2) itemBelow() is fast -- // roughly constant time. // // Given these assumptions we can do a mixture of caching and telling the // next item that the when that item is the current item that the now // current item will be the item above it. // // Ideally this will make checking to see if the item above the current item // is the alternate color a constant time operation rather than 0(n). if (lvD->painting) { if (lvD->paintCurrent != this) { lvD->paintAbove = lvD->paintBelow == this ? lvD->paintCurrent : itemAbove(); lvD->paintCurrent = this; lvD->paintBelow = itemBelow(); } above = dynamic_cast(lvD->paintAbove); } else { above = dynamic_cast(itemAbove()); } m_known = above ? above->m_known : true; if (m_known) { m_odd = above ? !above->m_odd : false; } else { KListViewItem *item; bool previous = true; if (parent()) { item = dynamic_cast(parent()); if (item) previous = item->m_odd; item = dynamic_cast(parent()->firstChild()); } else { item = dynamic_cast(lv->firstChild()); } while(item) { previous = !previous; item->m_odd = previous; item->m_known = true; item = dynamic_cast(item->nextSibling()); } } return m_odd; } return false; } void KListViewItem::paintCell(TQPainter *p, const TQColorGroup &cg, int column, int width, int alignment) { TQColorGroup _cg = cg; TQListView* lv = listView(); const TQPixmap *pm = lv->viewport()->backgroundPixmap(); if (pm && !pm->isNull()) { _cg.setBrush(TQColorGroup::Base, TQBrush(backgroundColor(column), *pm)); TQPoint o = p->brushOrigin(); p->setBrushOrigin( o.x()-lv->contentsX(), o.y()-lv->contentsY() ); } else { _cg.setColor((lv->viewport()->backgroundMode() == Qt::FixedColor) ? TQColorGroup::Background : TQColorGroup::Base, backgroundColor(column)); } TQListViewItem::paintCell(p, _cg, column, width, alignment); } void KListView::virtual_hook( int, void* ) { /*BASE::virtual_hook( id, data );*/ } #include "klistview.moc" #include "klistviewlineedit.moc" // vim: noet