kdeui Library API Documentation

klistview.cpp

00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2000 Reginald Stadlbauer <reggie@kde.org>
00003    Copyright (C) 2000,2003 Charles Samuels <charles@kde.org>
00004    Copyright (C) 2000 Peter Putzer
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License version 2 as published by the Free Software Foundation.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.
00019 */
00020 #include "config.h"
00021 
00022 #include <qdragobject.h>
00023 #include <qtimer.h>
00024 #include <qheader.h>
00025 #include <qcursor.h>
00026 #include <qtooltip.h>
00027 #include <qstyle.h>
00028 #include <qpainter.h>
00029 
00030 #include <kglobalsettings.h>
00031 #include <kconfig.h>
00032 #include <kcursor.h>
00033 #include <kapplication.h>
00034 #include <kipc.h>
00035 #include <kdebug.h>
00036 
00037 #include "klistview.h"
00038 #include "klistviewlineedit.h"
00039 
00040 class KListView::Tooltip : public QToolTip
00041 {
00042 public:
00043   Tooltip (KListView* parent, QToolTipGroup* group = 0L);
00044   virtual ~Tooltip () {}
00045 
00046 protected:
00050   virtual void maybeTip (const QPoint&);
00051 
00052 private:
00053   KListView* mParent;
00054 };
00055 
00056 KListView::Tooltip::Tooltip (KListView* parent, QToolTipGroup* group)
00057   : QToolTip (parent, group),
00058         mParent (parent)
00059 {
00060 }
00061 
00062 void KListView::Tooltip::maybeTip (const QPoint&)
00063 {
00064   // FIXME
00065 }
00066 
00067 class KListView::KListViewPrivate
00068 {
00069 public:
00070   KListViewPrivate (KListView* listview)
00071     : pCurrentItem (0),
00072       autoSelectDelay(0),
00073       dragOverItem(0),
00074       dragDelay (KGlobalSettings::dndEventDelay()),
00075       editor (new KListViewLineEdit (listview)),
00076       cursorInExecuteArea(false),
00077       itemsMovable (true),
00078       selectedBySimpleMove(false),
00079       selectedUsingMouse(false),
00080       itemsRenameable (false),
00081       validDrag (false),
00082       dragEnabled (false),
00083       autoOpen (true),
00084       disableAutoSelection (false),
00085       dropVisualizer (true),
00086       dropHighlighter (false),
00087       createChildren (true),
00088       pressedOnSelected (false),
00089       wasShiftEvent (false),
00090       fullWidth (false),
00091       sortAscending(true),
00092       tabRename(true),
00093       sortColumn(0),
00094       selectionDirection(0),
00095       tooltipColumn (0),
00096       selectionMode (Single),
00097       contextMenuKey (KGlobalSettings::contextMenuKey()),
00098       showContextMenusOnPress (KGlobalSettings::showContextMenusOnPress()),
00099       mDropVisualizerWidth (4),
00100       paintAbove (0),
00101       paintCurrent (0),
00102       paintBelow (0),
00103       painting (false),
00104       shadeSortColumn(KGlobalSettings::shadeSortColumn())
00105   {
00106       renameable.append(0);
00107       connect(editor, SIGNAL(done(QListViewItem*,int)), listview, SLOT(doneEditing(QListViewItem*,int)));
00108   }
00109 
00110   ~KListViewPrivate ()
00111   {
00112     delete editor;
00113   }
00114 
00115   QListViewItem* pCurrentItem;
00116 
00117   QTimer autoSelect;
00118   int autoSelectDelay;
00119 
00120   QTimer dragExpand;
00121   QListViewItem* dragOverItem;
00122   QPoint dragOverPoint;
00123 
00124   QPoint startDragPos;
00125   int dragDelay;
00126 
00127   KListViewLineEdit *editor;
00128   QValueList<int> renameable;
00129 
00130   bool cursorInExecuteArea:1;
00131   bool bUseSingle:1;
00132   bool bChangeCursorOverItem:1;
00133   bool itemsMovable:1;
00134   bool selectedBySimpleMove : 1;
00135   bool selectedUsingMouse:1;
00136   bool itemsRenameable:1;
00137   bool validDrag:1;
00138   bool dragEnabled:1;
00139   bool autoOpen:1;
00140   bool disableAutoSelection:1;
00141   bool dropVisualizer:1;
00142   bool dropHighlighter:1;
00143   bool createChildren:1;
00144   bool pressedOnSelected:1;
00145   bool wasShiftEvent:1;
00146   bool fullWidth:1;
00147   bool sortAscending:1;
00148   bool tabRename:1;
00149 
00150   int sortColumn;
00151 
00152   //+1 means downwards (y increases, -1 means upwards, 0 means not selected), aleXXX
00153   int selectionDirection;
00154   int tooltipColumn;
00155 
00156   SelectionModeExt selectionMode;
00157   int contextMenuKey;
00158   bool showContextMenusOnPress;
00159 
00160   QRect mOldDropVisualizer;
00161   int mDropVisualizerWidth;
00162   QRect mOldDropHighlighter;
00163   QListViewItem *afterItemDrop;
00164   QListViewItem *parentItemDrop;
00165 
00166   QListViewItem *paintAbove;
00167   QListViewItem *paintCurrent;
00168   QListViewItem *paintBelow;
00169   bool painting:1;
00170   bool shadeSortColumn:1;
00171 
00172   QColor alternateBackground;
00173 };
00174 
00175 
00176 KListViewLineEdit::KListViewLineEdit(KListView *parent)
00177         : KLineEdit(parent->viewport()), item(0), col(0), p(parent)
00178 {
00179         setFrame( false );
00180         hide();
00181         connect( parent, SIGNAL( selectionChanged() ), SLOT( slotSelectionChanged() ));
00182 }
00183 
00184 KListViewLineEdit::~KListViewLineEdit()
00185 {
00186 }
00187 
00188 QListViewItem *KListViewLineEdit::currentItem() const
00189 {
00190     return item;
00191 }
00192 
00193 void KListViewLineEdit::load(QListViewItem *i, int c)
00194 {
00195         item=i;
00196         col=c;
00197 
00198         QRect rect(p->itemRect(i));
00199         setText(item->text(c));
00200         home( true );
00201 
00202         int fieldX = rect.x() - 1;
00203         int fieldW = p->columnWidth(col) + 2;
00204 
00205         QHeader* const pHeader = p->header();
00206 
00207         const int pos = pHeader->mapToIndex(col);
00208         for ( int index = 0; index < pos; ++index )
00209             fieldX += p->columnWidth( pHeader->mapToSection( index ));
00210 
00211         if ( col == 0 ) {
00212             int d = i->depth() + (p->rootIsDecorated() ? 1 : 0);
00213             d *= p->treeStepSize();
00214             fieldX += d;
00215             fieldW -= d;
00216         }
00217 
00218         if ( i->pixmap( col ) ) {// add width of pixmap
00219             int d = i->pixmap( col )->width();
00220             fieldX += d;
00221             fieldW -= d;
00222         }
00223 
00224         setGeometry(fieldX, rect.y() - 1, fieldW, rect.height() + 2);
00225         show();
00226         setFocus();
00227 }
00228 
00229 /*  Helper functions to for
00230  *  tabOrderedRename functionality.
00231  */
00232 
00233 static int nextCol (KListView *pl, QListViewItem *pi, int start, int dir)
00234 {
00235     if (pi)
00236     {
00237         //  Find the next renameable column in the current row
00238         for (; ((dir == +1) ? (start < pl->columns()) : (start >= 0)); start += dir)
00239             if (pl->isRenameable(start))
00240                 return start;
00241     }
00242 
00243     return -1;
00244 }
00245 
00246 static QListViewItem *prevItem (QListViewItem *pi)
00247 {
00248     QListViewItem *pa = pi->itemAbove();
00249 
00250     /*  Does what the QListViewItem::previousSibling()
00251      *  of my dreams would do.
00252      */
00253     if (pa && pa->parent() == pi->parent())
00254         return pa;
00255 
00256     return 0;
00257 }
00258 
00259 static QListViewItem *lastQChild (QListViewItem *pi)
00260 {
00261     if (pi)
00262     {
00263         /*  Since there's no QListViewItem::lastChild().
00264          *  This finds the last sibling for the given
00265          *  item.
00266          */
00267         for (QListViewItem *pt = pi->nextSibling(); pt; pt = pt->nextSibling())
00268             pi = pt;
00269     }
00270 
00271     return pi;
00272 }
00273 
00274 void KListViewLineEdit::selectNextCell (QListViewItem *pitem, int column, bool forward)
00275 {
00276     const int ncols = p->columns();
00277     const int dir = forward ? +1 : -1;
00278     const int restart = forward ? 0 : (ncols - 1);
00279     QListViewItem *top = (pitem && pitem->parent())
00280         ? pitem->parent()->firstChild()
00281         : p->firstChild();
00282     QListViewItem *pi = pitem;
00283 
00284     terminate();        //  Save current changes
00285 
00286     do
00287     {
00288         /*  Check the rest of the current row for an editable column,
00289          *  if that fails, check the entire next/previous row. The
00290          *  last case goes back to the first item in the current branch
00291          *  or the last item in the current branch depending on the
00292          *  direction.
00293          */
00294         if ((column = nextCol(p, pi, column + dir, dir)) != -1 ||
00295             (column = nextCol(p, (pi = (forward ? pi->nextSibling() : prevItem(pi))), restart, dir)) != -1 ||
00296             (column = nextCol(p, (pi = (forward ? top : lastQChild(pitem))), restart, dir)) != -1)
00297         {
00298             if (pi)
00299             {
00300                 p->setCurrentItem(pi);      //  Calls terminate
00301                 p->rename(pi, column);
00302 
00303                 /*  Some listviews may override rename() to
00304                  *  prevent certain items from being renamed,
00305                  *  if this is done, [m_]item will be NULL
00306                  *  after the rename() call... try again.
00307                  */
00308                 if (!item)
00309                     continue;
00310 
00311                 break;
00312             }
00313         }
00314     }
00315     while (pi && !item);
00316 }
00317 
00318 #ifdef KeyPress
00319 #undef KeyPress
00320 #endif
00321 
00322 bool KListViewLineEdit::event (QEvent *pe)
00323 {
00324     if (pe->type() == QEvent::KeyPress)
00325     {
00326         QKeyEvent *k = (QKeyEvent *) pe;
00327 
00328         if ((k->key() == Qt::Key_Backtab || k->key() == Qt::Key_Tab) &&
00329             p->tabOrderedRenaming() && p->itemsRenameable() &&
00330             !(k->state() & ControlButton || k->state() & AltButton))
00331         {
00332             selectNextCell(item, col,
00333                 (k->key() == Key_Tab && !(k->state() & ShiftButton)));
00334             return true;
00335         }
00336     }
00337 
00338     return KLineEdit::event(pe);
00339 }
00340 
00341 void KListViewLineEdit::keyPressEvent(QKeyEvent *e)
00342 {
00343     if(e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter )
00344         terminate(true);
00345     else if(e->key() == Qt::Key_Escape)
00346         terminate(false);
00347         else if (e->key() == Qt::Key_Down || e->key() == Qt::Key_Up)
00348         {
00349         terminate(true);
00350                 KLineEdit::keyPressEvent(e);
00351         }
00352     else
00353         KLineEdit::keyPressEvent(e);
00354 }
00355 
00356 void KListViewLineEdit::terminate()
00357 {
00358     terminate(true);
00359 }
00360 
00361 void KListViewLineEdit::terminate(bool commit)
00362 {
00363     if ( item )
00364     {
00365         //kdDebug() << "KListViewLineEdit::terminate " << commit << endl;
00366         if (commit)
00367             item->setText(col, text());
00368         int c=col;
00369         QListViewItem *i=item;
00370         col=0;
00371         item=0;
00372         p->setFocus();// will call focusOutEvent, that's why we set item=0 before
00373         hide();
00374         if (commit)
00375             emit done(i,c);
00376     }
00377 }
00378 
00379 void KListViewLineEdit::focusOutEvent(QFocusEvent *ev)
00380 {
00381     QFocusEvent * focusEv = static_cast<QFocusEvent*>(ev);
00382     // Don't let a RMB close the editor
00383     if (focusEv->reason() != QFocusEvent::Popup && focusEv->reason() != QFocusEvent::ActiveWindow)
00384         terminate(true);
00385     else
00386         KLineEdit::focusOutEvent(ev);
00387 }
00388 
00389 void KListViewLineEdit::paintEvent( QPaintEvent *e )
00390 {
00391     KLineEdit::paintEvent( e );
00392 
00393     if ( !frame() ) {
00394         QPainter p( this );
00395         p.setClipRegion( e->region() );
00396         p.drawRect( rect() );
00397     }
00398 }
00399 
00400 // selection changed -> terminate. As our "item" can be already deleted,
00401 // we can't call terminate(false), because that would emit done() with
00402 // a dangling pointer to "item".
00403 void KListViewLineEdit::slotSelectionChanged()
00404 {
00405     item = 0;
00406     col = 0;
00407     hide();
00408 }
00409 
00410 
00411 KListView::KListView( QWidget *parent, const char *name )
00412   : QListView( parent, name ),
00413         d (new KListViewPrivate (this))
00414 {
00415   setDragAutoScroll(true);
00416 
00417   connect( this, SIGNAL( onViewport() ),
00418                    this, SLOT( slotOnViewport() ) );
00419   connect( this, SIGNAL( onItem( QListViewItem * ) ),
00420                    this, SLOT( slotOnItem( QListViewItem * ) ) );
00421 
00422   connect (this, SIGNAL(contentsMoving(int,int)),
00423                    this, SLOT(cleanDropVisualizer()));
00424   connect (this, SIGNAL(contentsMoving(int,int)),
00425                    this, SLOT(cleanItemHighlighter()));
00426 
00427   slotSettingsChanged(KApplication::SETTINGS_MOUSE);
00428   if (kapp)
00429   {
00430     connect( kapp, SIGNAL( settingsChanged(int) ), SLOT( slotSettingsChanged(int) ) );
00431     kapp->addKipcEventMask( KIPC::SettingsChanged );
00432   }
00433 
00434   connect(&d->autoSelect, SIGNAL( timeout() ),
00435                   this, SLOT( slotAutoSelect() ) );
00436   connect(&d->dragExpand, SIGNAL( timeout() ),
00437                   this, SLOT( slotDragExpand() ) );
00438 
00439   // context menu handling
00440   if (d->showContextMenusOnPress)
00441         {
00442           connect (this, SIGNAL (rightButtonPressed (QListViewItem*, const QPoint&, int)),
00443                            this, SLOT (emitContextMenu (QListViewItem*, const QPoint&, int)));
00444         }
00445   else
00446         {
00447           connect (this, SIGNAL (rightButtonClicked (QListViewItem*, const QPoint&, int)),
00448                            this, SLOT (emitContextMenu (QListViewItem*, const QPoint&, int)));
00449         }
00450 
00451   connect (this, SIGNAL (menuShortCutPressed (KListView*, QListViewItem*)),
00452                    this, SLOT (emitContextMenu (KListView*, QListViewItem*)));
00453   d->alternateBackground = KGlobalSettings::alternateBackgroundColor();
00454 }
00455 
00456 KListView::~KListView()
00457 {
00458   delete d;
00459 }
00460 
00461 bool KListView::isExecuteArea( const QPoint& point )
00462 {
00463   QListViewItem* item = itemAt( point );
00464   if ( item ) {
00465     return isExecuteArea( point.x(), item );
00466   }
00467 
00468   return false;
00469 }
00470 
00471 bool KListView::isExecuteArea( int x )
00472 {
00473   return isExecuteArea( x, 0 );
00474 }
00475 
00476 bool KListView::isExecuteArea( int x, QListViewItem* item )
00477 {
00478   if( allColumnsShowFocus() )
00479     return true;
00480   else {
00481     int offset = 0;
00482 
00483 
00484     int width = columnWidth( 0 );
00485 
00486     QHeader* const thisHeader = header();
00487     const int pos = thisHeader->mapToIndex( 0 );
00488 
00489     for ( int index = 0; index < pos; ++index )
00490       offset += columnWidth( thisHeader->mapToSection( index ) );
00491 
00492     x += contentsX(); // in case of a horizontal scrollbar
00493 
00494     if ( item )
00495     {
00496     width = treeStepSize()*( item->depth() + ( rootIsDecorated() ? 1 : 0 ) );
00497     width += itemMargin();
00498     int ca = AlignHorizontal_Mask & columnAlignment( 0 );
00499     if ( ca == AlignLeft || ca == AlignAuto ) {
00500         width += item->width( fontMetrics(), this, 0 );
00501         if ( width > columnWidth( 0 ) )
00502         width = columnWidth( 0 );
00503     }
00504     }
00505 
00506     return ( x > offset && x < ( offset + width ) );
00507   }
00508 }
00509 
00510 void KListView::slotOnItem( QListViewItem *item )
00511 {
00512   QPoint vp = viewport()->mapFromGlobal( QCursor::pos() );
00513   if ( item && isExecuteArea( vp.x() ) && (d->autoSelectDelay > -1) && d->bUseSingle ) {
00514     d->autoSelect.start( d->autoSelectDelay, true );
00515     d->pCurrentItem = item;
00516   }
00517 }
00518 
00519 void KListView::slotOnViewport()
00520 {
00521   if ( d->bChangeCursorOverItem )
00522     viewport()->unsetCursor();
00523 
00524   d->autoSelect.stop();
00525   d->pCurrentItem = 0L;
00526 }
00527 
00528 void KListView::slotSettingsChanged(int category)
00529 {
00530   switch (category)
00531   {
00532   case KApplication::SETTINGS_MOUSE:
00533     d->dragDelay =  KGlobalSettings::dndEventDelay();
00534     d->bUseSingle = KGlobalSettings::singleClick();
00535 
00536     disconnect(this, SIGNAL (mouseButtonClicked (int, QListViewItem*, const QPoint &, int)),
00537                this, SLOT (slotMouseButtonClicked (int, QListViewItem*, const QPoint &, int)));
00538 
00539     if( d->bUseSingle )
00540       connect (this, SIGNAL (mouseButtonClicked (int, QListViewItem*, const QPoint &, int)),
00541                this, SLOT (slotMouseButtonClicked( int, QListViewItem*, const QPoint &, int)));
00542 
00543     d->bChangeCursorOverItem = KGlobalSettings::changeCursorOverIcon();
00544     if ( !d->disableAutoSelection )
00545       d->autoSelectDelay = KGlobalSettings::autoSelectDelay();
00546 
00547     if( !d->bUseSingle || !d->bChangeCursorOverItem )
00548        viewport()->unsetCursor();
00549 
00550     break;
00551 
00552   case KApplication::SETTINGS_POPUPMENU:
00553     d->contextMenuKey = KGlobalSettings::contextMenuKey ();
00554     d->showContextMenusOnPress = KGlobalSettings::showContextMenusOnPress ();
00555 
00556     if (d->showContextMenusOnPress)
00557     {
00558       disconnect (0L, 0L, this, SLOT (emitContextMenu (QListViewItem*, const QPoint&, int)));
00559 
00560       connect(this, SIGNAL (rightButtonPressed (QListViewItem*, const QPoint&, int)),
00561               this, SLOT (emitContextMenu (QListViewItem*, const QPoint&, int)));
00562     }
00563     else
00564     {
00565       disconnect (0L, 0L, this, SLOT (emitContextMenu (QListViewItem*, const QPoint&, int)));
00566 
00567       connect(this, SIGNAL (rightButtonClicked (QListViewItem*, const QPoint&, int)),
00568               this, SLOT (emitContextMenu (QListViewItem*, const QPoint&, int)));
00569     }
00570     break;
00571 
00572   default:
00573     break;
00574   }
00575 }
00576 
00577 void KListView::slotAutoSelect()
00578 {
00579   // check that the item still exists
00580   if( itemIndex( d->pCurrentItem ) == -1 )
00581     return;
00582 
00583   if (!isActiveWindow())
00584         {
00585           d->autoSelect.stop();
00586           return;
00587         }
00588 
00589   //Give this widget the keyboard focus.
00590   if( !hasFocus() )
00591     setFocus();
00592 
00593   ButtonState keybstate = KApplication::keyboardMouseState();
00594 
00595   QListViewItem* previousItem = currentItem();
00596   setCurrentItem( d->pCurrentItem );
00597 
00598   if( d->pCurrentItem ) {
00599     //Shift pressed?
00600     if( (keybstate & Qt::ShiftButton) ) {
00601       bool block = signalsBlocked();
00602       blockSignals( true );
00603 
00604       //No Ctrl? Then clear before!
00605       if( !(keybstate & Qt::ControlButton) )
00606                 clearSelection();
00607 
00608       bool select = !d->pCurrentItem->isSelected();
00609       bool update = viewport()->isUpdatesEnabled();
00610       viewport()->setUpdatesEnabled( false );
00611 
00612       bool down = previousItem->itemPos() < d->pCurrentItem->itemPos();
00613       QListViewItemIterator lit( down ? previousItem : d->pCurrentItem );
00614       for ( ; lit.current(); ++lit ) {
00615                 if ( down && lit.current() == d->pCurrentItem ) {
00616                   d->pCurrentItem->setSelected( select );
00617                   break;
00618                 }
00619                 if ( !down && lit.current() == previousItem ) {
00620                   previousItem->setSelected( select );
00621                   break;
00622                 }
00623                 lit.current()->setSelected( select );
00624       }
00625 
00626       blockSignals( block );
00627       viewport()->setUpdatesEnabled( update );
00628       triggerUpdate();
00629 
00630       emit selectionChanged();
00631 
00632       if( selectionMode() == QListView::Single )
00633                 emit selectionChanged( d->pCurrentItem );
00634     }
00635     else if( (keybstate & KApplication::ControlModifier) )
00636       setSelected( d->pCurrentItem, !d->pCurrentItem->isSelected() );
00637     else {
00638       bool block = signalsBlocked();
00639       blockSignals( true );
00640 
00641       if( !d->pCurrentItem->isSelected() )
00642                 clearSelection();
00643 
00644       blockSignals( block );
00645 
00646       setSelected( d->pCurrentItem, true );
00647     }
00648   }
00649   else
00650     kdDebug() << "KListView::slotAutoSelect: That´s not supposed to happen!!!!" << endl;
00651 }
00652 
00653 void KListView::slotHeaderChanged()
00654 {
00655 
00656   const int colCount = columns();
00657   if (d->fullWidth && colCount)
00658   {
00659     int w = 0;
00660     const int lastColumn = colCount - 1;
00661     for (int i = 0; i < lastColumn; ++i) w += columnWidth(i);
00662     setColumnWidth( lastColumn, viewport()->width() - w - 1 );
00663   }
00664 }
00665 
00666 void KListView::emitExecute( QListViewItem *item, const QPoint &pos, int c )
00667 {
00668     if( isExecuteArea( viewport()->mapFromGlobal(pos) ) ) {
00669     d->validDrag=false;
00670 
00671         // Double click mode ?
00672         if ( !d->bUseSingle )
00673         {
00674             viewport()->unsetCursor();
00675             emit executed( item );
00676             emit executed( item, pos, c );
00677         }
00678         else
00679         {
00680             ButtonState keybstate = KApplication::keyboardMouseState();
00681 
00682             d->autoSelect.stop();
00683 
00684             //Don´t emit executed if in SC mode and Shift or Ctrl are pressed
00685             if( !( ((keybstate & Qt::ShiftButton) || (keybstate & Qt::ControlButton)) ) ) {
00686                 viewport()->unsetCursor();
00687                 emit executed( item );
00688                 emit executed( item, pos, c );
00689             }
00690         }
00691     }
00692 }
00693 
00694 void KListView::focusInEvent( QFocusEvent *fe )
00695 {
00696  //   kdDebug()<<"KListView::focusInEvent()"<<endl;
00697   QListView::focusInEvent( fe );
00698   if ((d->selectedBySimpleMove)
00699       && (d->selectionMode == FileManager)
00700       && (fe->reason()!=QFocusEvent::Popup)
00701       && (fe->reason()!=QFocusEvent::ActiveWindow)
00702       && (currentItem()))
00703   {
00704       currentItem()->setSelected(true);
00705       currentItem()->repaint();
00706       emit selectionChanged();
00707   };
00708 }
00709 
00710 void KListView::focusOutEvent( QFocusEvent *fe )
00711 {
00712   cleanDropVisualizer();
00713   cleanItemHighlighter();
00714 
00715   d->autoSelect.stop();
00716 
00717   if ((d->selectedBySimpleMove)
00718       && (d->selectionMode == FileManager)
00719       && (fe->reason()!=QFocusEvent::Popup)
00720       && (fe->reason()!=QFocusEvent::ActiveWindow)
00721       && (currentItem())
00722       && (!d->editor->isVisible()))
00723   {
00724       currentItem()->setSelected(false);
00725       currentItem()->repaint();
00726       emit selectionChanged();
00727   };
00728 
00729   QListView::focusOutEvent( fe );
00730 }
00731 
00732 void KListView::leaveEvent( QEvent *e )
00733 {
00734   d->autoSelect.stop();
00735 
00736   QListView::leaveEvent( e );
00737 }
00738 
00739 bool KListView::event( QEvent *e )
00740 {
00741   if (e->type() == QEvent::ApplicationPaletteChange)
00742     d->alternateBackground=KGlobalSettings::alternateBackgroundColor();
00743 
00744   return QListView::event(e);
00745 }
00746 
00747 void KListView::contentsMousePressEvent( QMouseEvent *e )
00748 {
00749   if( (selectionModeExt() == Extended) && (e->state() & ShiftButton) && !(e->state() & ControlButton) )
00750   {
00751     bool block = signalsBlocked();
00752     blockSignals( true );
00753 
00754     clearSelection();
00755 
00756     blockSignals( block );
00757   }
00758   else if ((selectionModeExt()==FileManager) && (d->selectedBySimpleMove))
00759   {
00760      d->selectedBySimpleMove=false;
00761      d->selectedUsingMouse=true;
00762      if (currentItem())
00763      {
00764         currentItem()->setSelected(false);
00765         currentItem()->repaint();
00766 //        emit selectionChanged();
00767      }
00768   }
00769 
00770   QPoint p( contentsToViewport( e->pos() ) );
00771   QListViewItem *at = itemAt (p);
00772 
00773   // true if the root decoration of the item "at" was clicked (i.e. the +/- sign)
00774   bool rootDecoClicked = at
00775            && ( p.x() <= header()->cellPos( header()->mapToActual( 0 ) ) +
00776                 treeStepSize() * ( at->depth() + ( rootIsDecorated() ? 1 : 0) ) + itemMargin() )
00777            && ( p.x() >= header()->cellPos( header()->mapToActual( 0 ) ) );
00778 
00779   if (e->button() == LeftButton && !rootDecoClicked)
00780   {
00781     //Start a drag
00782     d->startDragPos = e->pos();
00783 
00784     if (at)
00785     {
00786       d->validDrag = true;
00787       d->pressedOnSelected = at->isSelected();
00788     }
00789   }
00790 
00791   QListView::contentsMousePressEvent( e );
00792 }
00793 
00794 void KListView::contentsMouseMoveEvent( QMouseEvent *e )
00795 {
00796   if (!dragEnabled() || d->startDragPos.isNull() || !d->validDrag)
00797       QListView::contentsMouseMoveEvent (e);
00798 
00799   QPoint vp = contentsToViewport(e->pos());
00800   QListViewItem *item = itemAt( vp );
00801 
00802   //do we process cursor changes at all?
00803   if ( item && d->bChangeCursorOverItem && d->bUseSingle )
00804     {
00805       //Cursor moved on a new item or in/out the execute area
00806       if( (item != d->pCurrentItem) ||
00807           (isExecuteArea(vp) != d->cursorInExecuteArea) )
00808         {
00809           d->cursorInExecuteArea = isExecuteArea(vp);
00810 
00811           if( d->cursorInExecuteArea ) //cursor moved in execute area
00812             viewport()->setCursor( KCursor::handCursor() );
00813           else //cursor moved out of execute area
00814             viewport()->unsetCursor();
00815         }
00816     }
00817 
00818   bool dragOn = dragEnabled();
00819   QPoint newPos = e->pos();
00820   if (dragOn && d->validDrag &&
00821       (newPos.x() > d->startDragPos.x()+d->dragDelay ||
00822        newPos.x() < d->startDragPos.x()-d->dragDelay ||
00823        newPos.y() > d->startDragPos.y()+d->dragDelay ||
00824        newPos.y() < d->startDragPos.y()-d->dragDelay))
00825     //(d->startDragPos - e->pos()).manhattanLength() > QApplication::startDragDistance())
00826     {
00827       QListView::contentsMouseReleaseEvent( 0 );
00828       startDrag();
00829       d->startDragPos = QPoint();
00830       d->validDrag = false;
00831     }
00832 }
00833 
00834 void KListView::contentsMouseReleaseEvent( QMouseEvent *e )
00835 {
00836   if (e->button() == LeftButton)
00837   {
00838     // If the row was already selected, maybe we want to start an in-place editing
00839     if ( d->pressedOnSelected && itemsRenameable() )
00840     {
00841       QPoint p( contentsToViewport( e->pos() ) );
00842       QListViewItem *at = itemAt (p);
00843       if ( at )
00844       {
00845         // true if the root decoration of the item "at" was clicked (i.e. the +/- sign)
00846         bool rootDecoClicked =
00847                   ( p.x() <= header()->cellPos( header()->mapToActual( 0 ) ) +
00848                     treeStepSize() * ( at->depth() + ( rootIsDecorated() ? 1 : 0) ) + itemMargin() )
00849                && ( p.x() >= header()->cellPos( header()->mapToActual( 0 ) ) );
00850 
00851         if (!rootDecoClicked)
00852         {
00853           int col = header()->mapToLogical( header()->cellAt( p.x() ) );
00854           if ( d->renameable.contains(col) )
00855             rename(at, col);
00856         }
00857       }
00858     }
00859 
00860     d->pressedOnSelected = false;
00861     d->validDrag = false;
00862     d->startDragPos = QPoint();
00863   }
00864   QListView::contentsMouseReleaseEvent( e );
00865 }
00866 
00867 void KListView::contentsMouseDoubleClickEvent ( QMouseEvent *e )
00868 {
00869   // We don't want to call the parent method because it does setOpen,
00870   // whereas we don't do it in single click mode... (David)
00871   //QListView::contentsMouseDoubleClickEvent( e );
00872   if ( !e || e->button() != LeftButton )
00873     return;
00874 
00875   QPoint vp = contentsToViewport(e->pos());
00876   QListViewItem *item = itemAt( vp );
00877   emit QListView::doubleClicked( item ); // we do it now
00878 
00879   int col = item ? header()->mapToLogical( header()->cellAt( vp.x() ) ) : -1;
00880 
00881   if( item ) {
00882     emit doubleClicked( item, e->globalPos(), col );
00883 
00884     if( (e->button() == LeftButton) && !d->bUseSingle )
00885       emitExecute( item, e->globalPos(), col );
00886   }
00887 }
00888 
00889 void KListView::slotMouseButtonClicked( int btn, QListViewItem *item, const QPoint &pos, int c )
00890 {
00891   if( (btn == LeftButton) && item )
00892     emitExecute(item, pos, c);
00893 }
00894 
00895 void KListView::contentsDropEvent(QDropEvent* e)
00896 {
00897   cleanDropVisualizer();
00898   cleanItemHighlighter();
00899   d->dragExpand.stop();
00900 
00901   if (acceptDrag (e))
00902   {
00903     e->acceptAction();
00904     QListViewItem *afterme;
00905     QListViewItem *parent;
00906 
00907     findDrop(e->pos(), parent, afterme);
00908 
00909     if (e->source() == viewport() && itemsMovable())
00910         movableDropEvent(parent, afterme);
00911     else
00912     {
00913         emit dropped(e, afterme);
00914         emit dropped(this, e, afterme);
00915         emit dropped(e, parent, afterme);
00916         emit dropped(this, e, parent, afterme);
00917     }
00918   }
00919 }
00920 
00921 void KListView::movableDropEvent (QListViewItem* parent, QListViewItem* afterme)
00922 {
00923   QPtrList<QListViewItem> items, afterFirsts, afterNows;
00924   QListViewItem *current=currentItem();
00925   bool hasMoved=false;
00926   for (QListViewItem *i = firstChild(), *iNext=0; i; i = iNext)
00927   {
00928     iNext=i->itemBelow();
00929     if (!i->isSelected())
00930       continue;
00931 
00932     // don't drop an item after itself, or else
00933     // it moves to the top of the list
00934     if (i==afterme)
00935       continue;
00936 
00937     i->setSelected(false);
00938 
00939     QListViewItem *afterFirst = i->itemAbove();
00940 
00941         if (!hasMoved)
00942         {
00943                 emit aboutToMove();
00944                 hasMoved=true;
00945         }
00946 
00947     moveItem(i, parent, afterme);
00948 
00949     // ###### This should include the new parent !!! -> KDE 3.0
00950     // If you need this right now, have a look at keditbookmarks.
00951     emit moved(i, afterFirst, afterme);
00952 
00953     items.append (i);
00954     afterFirsts.append (afterFirst);
00955     afterNows.append (afterme);
00956 
00957     afterme = i;
00958   }
00959   clearSelection();
00960   for (QListViewItem *i=items.first(); i; i=items.next() )
00961     i->setSelected(true);
00962   if (current)
00963     setCurrentItem(current);
00964 
00965   emit moved(items,afterFirsts,afterNows);
00966 
00967   if (firstChild())
00968     emit moved();
00969 }
00970 
00971 void KListView::contentsDragMoveEvent(QDragMoveEvent *event)
00972 {
00973   if (acceptDrag(event))
00974   {
00975     event->acceptAction();
00976     //Clean up the view
00977 
00978     findDrop(event->pos(), d->parentItemDrop, d->afterItemDrop);
00979     QPoint vp = contentsToViewport( event->pos() );
00980     QListViewItem *item = isExecuteArea( vp ) ? itemAt( vp ) : 0L;
00981 
00982     if ( item != d->dragOverItem )
00983     {
00984       d->dragExpand.stop();
00985       d->dragOverItem = item;
00986       d->dragOverPoint = vp;
00987       if ( d->dragOverItem && d->dragOverItem->isExpandable() && !d->dragOverItem->isOpen() )
00988         d->dragExpand.start( QApplication::startDragTime(), true );
00989     }
00990     if (dropVisualizer())
00991     {
00992       QRect tmpRect = drawDropVisualizer(0, d->parentItemDrop, d->afterItemDrop);
00993       if (tmpRect != d->mOldDropVisualizer)
00994       {
00995         cleanDropVisualizer();
00996         d->mOldDropVisualizer=tmpRect;
00997         viewport()->repaint(tmpRect);
00998       }
00999     }
01000     if (dropHighlighter())
01001     {
01002       QRect tmpRect = drawItemHighlighter(0, itemAt( vp ));
01003       if (tmpRect != d->mOldDropHighlighter)
01004       {
01005         cleanItemHighlighter();
01006         d->mOldDropHighlighter=tmpRect;
01007         viewport()->repaint(tmpRect);
01008       }
01009     }
01010   }
01011   else
01012       event->ignore();
01013 }
01014 
01015 void KListView::slotDragExpand()
01016 {
01017   if ( itemAt( d->dragOverPoint ) == d->dragOverItem )
01018     d->dragOverItem->setOpen( true );
01019 }
01020 
01021 void KListView::contentsDragLeaveEvent (QDragLeaveEvent*)
01022 {
01023   d->dragExpand.stop();
01024   cleanDropVisualizer();
01025   cleanItemHighlighter();
01026 }
01027 
01028 void KListView::cleanDropVisualizer()
01029 {
01030   if (d->mOldDropVisualizer.isValid())
01031   {
01032     QRect rect=d->mOldDropVisualizer;
01033     d->mOldDropVisualizer = QRect();
01034     viewport()->repaint(rect, true);
01035   }
01036 }
01037 
01038 int KListView::depthToPixels( int depth )
01039 {
01040     return treeStepSize() * ( depth + (rootIsDecorated() ? 1 : 0) ) + itemMargin();
01041 }
01042 
01043 void KListView::findDrop(const QPoint &pos, QListViewItem *&parent, QListViewItem *&after)
01044 {
01045     QPoint p (contentsToViewport(pos));
01046 
01047     // Get the position to put it in
01048     QListViewItem *atpos = itemAt(p);
01049 
01050     QListViewItem *above;
01051     if (!atpos) // put it at the end
01052         above = lastItem();
01053     else
01054     {
01055         // Get the closest item before us ('atpos' or the one above, if any)
01056         if (p.y() - itemRect(atpos).topLeft().y() < (atpos->height()/2))
01057             above = atpos->itemAbove();
01058         else
01059             above = atpos;
01060     }
01061 
01062     if (above)
01063     {
01064         // if above has children, I might need to drop it as the first item there
01065 
01066         if (above->firstChild() && above->isOpen())
01067         {
01068             parent = above;
01069             after = 0;
01070             return;
01071         }
01072 
01073       // Now, we know we want to go after "above". But as a child or as a sibling ?
01074       // We have to ask the "above" item if it accepts children.
01075       if (above->isExpandable())
01076       {
01077           // The mouse is sufficiently on the right ? - doesn't matter if 'above' has visible children
01078           if (p.x() >= depthToPixels( above->depth() + 1 ) ||
01079               (above->isOpen() && above->childCount() > 0) )
01080           {
01081               parent = above;
01082               after = 0L;
01083               return;
01084           }
01085       }
01086 
01087       // Ok, there's one more level of complexity. We may want to become a new
01088       // sibling, but of an upper-level group, rather than the "above" item
01089       QListViewItem * betterAbove = above->parent();
01090       QListViewItem * last = above;
01091       while ( betterAbove )
01092       {
01093           // We are allowed to become a sibling of "betterAbove" only if we are
01094           // after its last child
01095           if ( !last->nextSibling() )
01096           {
01097               if (p.x() < depthToPixels ( betterAbove->depth() + 1 ))
01098                   above = betterAbove; // store this one, but don't stop yet, there may be a better one
01099               else
01100                   break; // not enough on the left, so stop
01101               last = betterAbove;
01102               betterAbove = betterAbove->parent(); // up one level
01103           } else
01104               break; // we're among the child of betterAbove, not after the last one
01105       }
01106   }
01107   // set as sibling
01108   after = above;
01109   parent = after ? after->parent() : 0L ;
01110 }
01111 
01112 QListViewItem* KListView::lastChild () const
01113 {
01114   QListViewItem* lastchild = firstChild();
01115 
01116   if (lastchild)
01117         for (; lastchild->nextSibling(); lastchild = lastchild->nextSibling());
01118 
01119   return lastchild;
01120 }
01121 
01122 QListViewItem *KListView::lastItem() const
01123 {
01124   QListViewItem* last = lastChild();
01125 
01126   for (QListViewItemIterator it (last); it.current(); ++it)
01127     last = it.current();
01128 
01129   return last;
01130 }
01131 
01132 KLineEdit *KListView::renameLineEdit() const
01133 {
01134   return d->editor;
01135 }
01136 
01137 void KListView::startDrag()
01138 {
01139   QDragObject *drag = dragObject();
01140 
01141   if (!drag)
01142         return;
01143 
01144   if (drag->drag() && drag->target() != viewport())
01145     emit moved();
01146 }
01147 
01148 QDragObject *KListView::dragObject()
01149 {
01150   if (!currentItem())
01151         return 0;
01152 
01153 
01154   return new QStoredDrag("application/x-qlistviewitem", viewport());
01155 }
01156 
01157 void KListView::setItemsMovable(bool b)
01158 {
01159   d->itemsMovable=b;
01160 }
01161 
01162 bool KListView::itemsMovable() const
01163 {
01164   return d->itemsMovable;
01165 }
01166 
01167 void KListView::setItemsRenameable(bool b)
01168 {
01169   d->itemsRenameable=b;
01170 }
01171 
01172 bool KListView::itemsRenameable() const
01173 {
01174   return d->itemsRenameable;
01175 }
01176 
01177 
01178 void KListView::setDragEnabled(bool b)
01179 {
01180   d->dragEnabled=b;
01181 }
01182 
01183 bool KListView::dragEnabled() const
01184 {
01185   return d->dragEnabled;
01186 }
01187 
01188 void KListView::setAutoOpen(bool b)
01189 {
01190   d->autoOpen=b;
01191 }
01192 
01193 bool KListView::autoOpen() const
01194 {
01195   return d->autoOpen;
01196 }
01197 
01198 bool KListView::dropVisualizer() const
01199 {
01200   return d->dropVisualizer;
01201 }
01202 
01203 void KListView::setDropVisualizer(bool b)
01204 {
01205   d->dropVisualizer=b;
01206 }
01207 
01208 QPtrList<QListViewItem> KListView::selectedItems() const
01209 {
01210   return selectedItems(true);
01211 }
01212 
01213 QPtrList<QListViewItem> KListView::selectedItems(bool includeHiddenItems) const
01214 {
01215   QPtrList<QListViewItem> list;
01216 
01217   // Using selectionMode() instead of selectionModeExt() since for the cases that
01218   // we're interested in selectionMode() should work for either variety of the
01219   // setSelectionMode().
01220 
01221   switch(selectionMode())
01222   {
01223   case NoSelection:
01224       break;
01225   case Single:
01226       if(selectedItem() && (includeHiddenItems || selectedItem()->isVisible()))
01227           list.append(selectedItem());
01228       break;
01229   default:
01230   {
01231       int flags = QListViewItemIterator::Selected;
01232       if (!includeHiddenItems)
01233       {
01234         flags |= QListViewItemIterator::Visible;
01235       }
01236 
01237       QListViewItemIterator it(const_cast<KListView *>(this), flags);
01238 
01239       for(; it.current(); ++it)
01240           list.append(it.current());
01241 
01242       break;
01243   }
01244   }
01245 
01246   return list;
01247 }
01248 
01249 
01250 void KListView::moveItem(QListViewItem *item, QListViewItem *parent, QListViewItem *after)
01251 {
01252   // sanity check - don't move a item into its own child structure
01253   QListViewItem *i = parent;
01254   while(i)
01255     {
01256       if(i == item)
01257         return;
01258       i = i->parent();
01259     }
01260 
01261   if (after)
01262   {
01263       item->moveItem(after);
01264       return;
01265   }
01266 
01267   // Basically reimplementing the QListViewItem(QListViewItem*, QListViewItem*) constructor
01268   // in here, without ever deleting the item.
01269   if (item->parent())
01270         item->parent()->takeItem(item);
01271   else
01272         takeItem(item);
01273 
01274   if (parent)
01275         parent->insertItem(item);
01276   else
01277         insertItem(item);
01278 }
01279 
01280 void KListView::contentsDragEnterEvent(QDragEnterEvent *event)
01281 {
01282   if (acceptDrag (event))
01283     event->accept();
01284 }
01285 
01286 void KListView::setDropVisualizerWidth (int w)
01287 {
01288   d->mDropVisualizerWidth = w > 0 ? w : 1;
01289 }
01290 
01291 QRect KListView::drawDropVisualizer(QPainter *p, QListViewItem *parent,
01292                                     QListViewItem *after)
01293 {
01294     QRect insertmarker;
01295 
01296     if (!after && !parent)
01297         insertmarker = QRect (0, 0, viewport()->width(), d->mDropVisualizerWidth/2);
01298     else
01299     {
01300         int level = 0;
01301         if (after)
01302         {
01303             QListViewItem* it = 0L;
01304             if (after->isOpen())
01305             {
01306                 // Look for the last child (recursively)
01307                 it = after->firstChild();
01308                 if (it)
01309                     while (it->nextSibling() || it->firstChild())
01310                         if ( it->nextSibling() )
01311                             it = it->nextSibling();
01312                         else
01313                             it = it->firstChild();
01314             }
01315 
01316             insertmarker = itemRect (it ? it : after);
01317             level = after->depth();
01318         }
01319         else if (parent)
01320         {
01321             insertmarker = itemRect (parent);
01322             level = parent->depth() + 1;
01323         }
01324         insertmarker.setLeft( treeStepSize() * ( level + (rootIsDecorated() ? 1 : 0) ) + itemMargin() );
01325         insertmarker.setRight (viewport()->width());
01326         insertmarker.setTop (insertmarker.bottom() - d->mDropVisualizerWidth/2 + 1);
01327         insertmarker.setBottom (insertmarker.bottom() + d->mDropVisualizerWidth/2);
01328     }
01329 
01330     // This is not used anymore, at least by KListView itself (see viewportPaintEvent)
01331     // Remove for KDE 4.0.
01332     if (p)
01333         p->fillRect(insertmarker, Dense4Pattern);
01334 
01335     return insertmarker;
01336 }
01337 
01338 QRect KListView::drawItemHighlighter(QPainter *painter, QListViewItem *item)
01339 {
01340   QRect r;
01341 
01342   if (item)
01343   {
01344     r = itemRect(item);
01345     r.setLeft(r.left()+(item->depth()+(rootIsDecorated() ? 1 : 0))*treeStepSize());
01346     if (painter)
01347       style().drawPrimitive(QStyle::PE_FocusRect, painter, r, colorGroup(),
01348                             QStyle::Style_FocusAtBorder, colorGroup().highlight());
01349   }
01350 
01351   return r;
01352 }
01353 
01354 void KListView::cleanItemHighlighter ()
01355 {
01356   if (d->mOldDropHighlighter.isValid())
01357   {
01358     QRect rect=d->mOldDropHighlighter;
01359     d->mOldDropHighlighter = QRect();
01360     viewport()->repaint(rect, true);
01361   }
01362 }
01363 
01364 void KListView::rename(QListViewItem *item, int c)
01365 {
01366   if (d->renameable.contains(c))
01367   {
01368     ensureItemVisible(item);
01369     d->editor->load(item,c);
01370   }
01371 }
01372 
01373 bool KListView::isRenameable (int col) const
01374 {
01375   return d->renameable.contains(col);
01376 }
01377 
01378 void KListView::setRenameable (int col, bool renameable)
01379 {
01380   if (col>=header()->count()) return;
01381 
01382   d->renameable.remove(col);
01383   if (renameable)
01384     d->renameable+=col;
01385 }
01386 
01387 void KListView::doneEditing(QListViewItem *item, int row)
01388 {
01389   emit itemRenamed(item, item->text(row), row);
01390   emit itemRenamed(item);
01391 }
01392 
01393 bool KListView::acceptDrag(QDropEvent* e) const
01394 {
01395   return acceptDrops() && itemsMovable() && (e->source()==viewport());
01396 }
01397 
01398 void KListView::setCreateChildren(bool b)
01399 {
01400         d->createChildren=b;
01401 }
01402 
01403 bool KListView::createChildren() const
01404 {
01405         return d->createChildren;
01406 }
01407 
01408 
01409 int KListView::tooltipColumn() const
01410 {
01411         return d->tooltipColumn;
01412 }
01413 
01414 void KListView::setTooltipColumn(int column)
01415 {
01416         d->tooltipColumn=column;
01417 }
01418 
01419 void KListView::setDropHighlighter(bool b)
01420 {
01421         d->dropHighlighter=b;
01422 }
01423 
01424 bool KListView::dropHighlighter() const
01425 {
01426         return d->dropHighlighter;
01427 }
01428 
01429 bool KListView::showTooltip(QListViewItem *item, const QPoint &, int column) const
01430 {
01431         return ((column==tooltipColumn()) && !tooltip(item, column).isEmpty());
01432 }
01433 
01434 QString KListView::tooltip(QListViewItem *item, int column) const
01435 {
01436         return item->text(column);
01437 }
01438 
01439 void KListView::setTabOrderedRenaming(bool b)
01440 {
01441     d->tabRename = b;
01442 }
01443 
01444 bool KListView::tabOrderedRenaming() const
01445 {
01446     return d->tabRename;
01447 }
01448 
01449 void KListView::keyPressEvent (QKeyEvent* e)
01450 {
01451   //don't we need a contextMenuModifier too ? (aleXXX)
01452   if (e->key() == d->contextMenuKey)
01453         {
01454           emit menuShortCutPressed (this, currentItem());
01455           return;
01456         }
01457 
01458   if (d->selectionMode != FileManager)
01459         QListView::keyPressEvent (e);
01460   else
01461         fileManagerKeyPressEvent (e);
01462 }
01463 
01464 void KListView::activateAutomaticSelection()
01465 {
01466    d->selectedBySimpleMove=true;
01467    d->selectedUsingMouse=false;
01468    if (currentItem())
01469    {
01470       currentItem()->setSelected(true);
01471       currentItem()->repaint();
01472       emit selectionChanged();
01473    };
01474 }
01475 
01476 void KListView::deactivateAutomaticSelection()
01477 {
01478    d->selectedBySimpleMove=false;
01479 }
01480 
01481 bool KListView::automaticSelection() const
01482 {
01483    return d->selectedBySimpleMove;
01484 }
01485 
01486 void KListView::fileManagerKeyPressEvent (QKeyEvent* e)
01487 {
01488    //don't care whether it's on the keypad or not
01489     int e_state=(e->state() & ~Keypad);
01490 
01491     int oldSelectionDirection(d->selectionDirection);
01492 
01493     if ((e->key()!=Key_Shift) && (e->key()!=Key_Control)
01494         && (e->key()!=Key_Meta) && (e->key()!=Key_Alt))
01495     {
01496        if ((e_state==ShiftButton) && (!d->wasShiftEvent) && (!d->selectedBySimpleMove))
01497           selectAll(false);
01498        d->selectionDirection=0;
01499        d->wasShiftEvent = (e_state == ShiftButton);
01500     };
01501 
01502     //d->wasShiftEvent = (e_state == ShiftButton);
01503 
01504 
01505     QListViewItem* item = currentItem();
01506     if (!item) return;
01507 
01508     QListViewItem* repaintItem1 = item;
01509     QListViewItem* repaintItem2 = 0L;
01510     QListViewItem* visItem = 0L;
01511 
01512     QListViewItem* nextItem = 0L;
01513     int items = 0;
01514 
01515     bool shiftOrCtrl((e_state==ControlButton) || (e_state==ShiftButton));
01516     int selectedItems(0);
01517     for (QListViewItem *tmpItem=firstChild(); tmpItem; tmpItem=tmpItem->nextSibling())
01518        if (tmpItem->isSelected()) selectedItems++;
01519 
01520     if (((!selectedItems) || ((selectedItems==1) && (d->selectedUsingMouse)))
01521         && (e_state==NoButton)
01522         && ((e->key()==Key_Down)
01523         || (e->key()==Key_Up)
01524         || (e->key()==Key_Next)
01525         || (e->key()==Key_Prior)
01526         || (e->key()==Key_Home)
01527         || (e->key()==Key_End)))
01528     {
01529        d->selectedBySimpleMove=true;
01530        d->selectedUsingMouse=false;
01531     }
01532     else if (selectedItems>1)
01533        d->selectedBySimpleMove=false;
01534 
01535     bool emitSelectionChanged(false);
01536 
01537     switch (e->key())
01538     {
01539     case Key_Escape:
01540        selectAll(false);
01541        emitSelectionChanged=true;
01542        break;
01543 
01544     case Key_Space:
01545        //toggle selection of current item
01546        if (d->selectedBySimpleMove)
01547           d->selectedBySimpleMove=false;
01548        item->setSelected(!item->isSelected());
01549        emitSelectionChanged=true;
01550        break;
01551 
01552     case Key_Insert:
01553        //toggle selection of current item and move to the next item
01554        if (d->selectedBySimpleMove)
01555        {
01556           d->selectedBySimpleMove=false;
01557           if (!item->isSelected()) item->setSelected(true);
01558        }
01559        else
01560        {
01561           item->setSelected(!item->isSelected());
01562        };
01563 
01564        nextItem=item->itemBelow();
01565 
01566        if (nextItem)
01567        {
01568           repaintItem2=nextItem;
01569           visItem=nextItem;
01570           setCurrentItem(nextItem);
01571        };
01572        d->selectionDirection=1;
01573        emitSelectionChanged=true;
01574        break;
01575 
01576     case Key_Down:
01577        nextItem=item->itemBelow();
01578        //toggle selection of current item and move to the next item
01579        if (shiftOrCtrl)
01580        {
01581           d->selectionDirection=1;
01582           if (d->selectedBySimpleMove)
01583              d->selectedBySimpleMove=false;
01584           else
01585           {
01586              if (oldSelectionDirection!=-1)
01587              {
01588                 item->setSelected(!item->isSelected());
01589                 emitSelectionChanged=true;
01590              };
01591           };
01592        }
01593        else if ((d->selectedBySimpleMove) && (nextItem))
01594        {
01595           item->setSelected(false);
01596           emitSelectionChanged=true;
01597        };
01598 
01599        if (nextItem)
01600        {
01601           if (d->selectedBySimpleMove)
01602              nextItem->setSelected(true);
01603           repaintItem2=nextItem;
01604           visItem=nextItem;
01605           setCurrentItem(nextItem);
01606        };
01607        break;
01608 
01609     case Key_Up:
01610        nextItem=item->itemAbove();
01611        d->selectionDirection=-1;
01612        //move to the prev. item and toggle selection of this one
01613        // => No, can't select the last item, with this. For symmetry, let's
01614        // toggle selection and THEN move up, just like we do in down (David)
01615        if (shiftOrCtrl)
01616        {
01617           if (d->selectedBySimpleMove)
01618              d->selectedBySimpleMove=false;
01619           else
01620           {
01621              if (oldSelectionDirection!=1)
01622              {
01623                 item->setSelected(!item->isSelected());
01624                 emitSelectionChanged=true;
01625              };
01626           }
01627        }
01628        else if ((d->selectedBySimpleMove) && (nextItem))
01629        {
01630           item->setSelected(false);
01631           emitSelectionChanged=true;
01632        };
01633 
01634        if (nextItem)
01635        {
01636           if (d->selectedBySimpleMove)
01637              nextItem->setSelected(true);
01638           repaintItem2=nextItem;
01639           visItem=nextItem;
01640           setCurrentItem(nextItem);
01641        };
01642        break;
01643 
01644     case Key_End:
01645        //move to the last item and toggle selection of all items inbetween
01646        nextItem=item;
01647        if (d->selectedBySimpleMove)
01648           item->setSelected(false);
01649        if (shiftOrCtrl)
01650           d->selectedBySimpleMove=false;
01651 
01652        while(nextItem)
01653        {
01654           if (shiftOrCtrl)
01655              nextItem->setSelected(!nextItem->isSelected());
01656           if (!nextItem->itemBelow())
01657           {
01658              if (d->selectedBySimpleMove)
01659                 nextItem->setSelected(true);
01660              repaintItem2=nextItem;
01661              visItem=nextItem;
01662              setCurrentItem(nextItem);
01663           }
01664           nextItem=nextItem->itemBelow();
01665        }
01666        emitSelectionChanged=true;
01667        break;
01668 
01669     case Key_Home:
01670        // move to the first item and toggle selection of all items inbetween
01671        nextItem = firstChild();
01672        visItem = nextItem;
01673        repaintItem2 = visItem;
01674        if (d->selectedBySimpleMove)
01675           item->setSelected(false);
01676        if (shiftOrCtrl)
01677        {
01678           d->selectedBySimpleMove=false;
01679 
01680           while ( nextItem != item )
01681           {
01682              nextItem->setSelected( !nextItem->isSelected() );
01683              nextItem = nextItem->itemBelow();
01684           }
01685           item->setSelected( !item->isSelected() );
01686        }
01687        setCurrentItem( firstChild() );
01688        emitSelectionChanged=true;
01689        break;
01690 
01691     case Key_Next:
01692        items=visibleHeight()/item->height();
01693        nextItem=item;
01694        if (d->selectedBySimpleMove)
01695           item->setSelected(false);
01696        if (shiftOrCtrl)
01697        {
01698           d->selectedBySimpleMove=false;
01699           d->selectionDirection=1;
01700        };
01701 
01702        for (int i=0; i<items; i++)
01703        {
01704           if (shiftOrCtrl)
01705              nextItem->setSelected(!nextItem->isSelected());
01706           //the end
01707           if ((i==items-1) || (!nextItem->itemBelow()))
01708 
01709           {
01710              if (shiftOrCtrl)
01711                 nextItem->setSelected(!nextItem->isSelected());
01712              if (d->selectedBySimpleMove)
01713                 nextItem->setSelected(true);
01714              ensureItemVisible(nextItem);
01715              setCurrentItem(nextItem);
01716              update();
01717              if ((shiftOrCtrl) || (d->selectedBySimpleMove))
01718              {
01719                 emit selectionChanged();
01720              }
01721              return;
01722           }
01723           nextItem=nextItem->itemBelow();
01724        }
01725        break;
01726 
01727     case Key_Prior:
01728        items=visibleHeight()/item->height();
01729        nextItem=item;
01730        if (d->selectedBySimpleMove)
01731           item->setSelected(false);
01732        if (shiftOrCtrl)
01733        {
01734           d->selectionDirection=-1;
01735           d->selectedBySimpleMove=false;
01736        };
01737 
01738        for (int i=0; i<items; i++)
01739        {
01740           if ((nextItem!=item) &&(shiftOrCtrl))
01741              nextItem->setSelected(!nextItem->isSelected());
01742           //the end
01743           if ((i==items-1) || (!nextItem->itemAbove()))
01744 
01745           {
01746              if (d->selectedBySimpleMove)
01747                 nextItem->setSelected(true);
01748              ensureItemVisible(nextItem);
01749              setCurrentItem(nextItem);
01750              update();
01751              if ((shiftOrCtrl) || (d->selectedBySimpleMove))
01752              {
01753                 emit selectionChanged();
01754              }
01755              return;
01756           }
01757           nextItem=nextItem->itemAbove();
01758        }
01759        break;
01760 
01761     case Key_Minus:
01762        if ( item->isOpen() )
01763           setOpen( item, false );
01764        break;
01765     case Key_Plus:
01766        if (  !item->isOpen() && (item->isExpandable() || item->childCount()) )
01767           setOpen( item, true );
01768        break;
01769     default:
01770        bool realKey = ((e->key()!=Key_Shift) && (e->key()!=Key_Control)
01771                         && (e->key()!=Key_Meta) && (e->key()!=Key_Alt));
01772 
01773        bool selectCurrentItem = (d->selectedBySimpleMove) && (item->isSelected());
01774        if (realKey && selectCurrentItem)
01775           item->setSelected(false);
01776        //this is mainly for the "goto filename beginning with pressed char" feature (aleXXX)
01777        QListView::SelectionMode oldSelectionMode = selectionMode();
01778        setSelectionMode (QListView::Multi);
01779        QListView::keyPressEvent (e);
01780        setSelectionMode (oldSelectionMode);
01781        if (realKey && selectCurrentItem)
01782        {
01783           currentItem()->setSelected(true);
01784           emitSelectionChanged=true;
01785        }
01786        repaintItem2=currentItem();
01787        if (realKey)
01788           visItem=currentItem();
01789        break;
01790     }
01791 
01792     if (visItem)
01793        ensureItemVisible(visItem);
01794 
01795     QRect ir;
01796     if (repaintItem1)
01797        ir = ir.unite( itemRect(repaintItem1) );
01798     if (repaintItem2)
01799        ir = ir.unite( itemRect(repaintItem2) );
01800 
01801     if ( !ir.isEmpty() )
01802     {                 // rectangle to be repainted
01803        if ( ir.x() < 0 )
01804           ir.moveBy( -ir.x(), 0 );
01805        viewport()->repaint( ir, false );
01806     }
01807     /*if (repaintItem1)
01808        repaintItem1->repaint();
01809     if (repaintItem2)
01810        repaintItem2->repaint();*/
01811     update();
01812     if (emitSelectionChanged)
01813        emit selectionChanged();
01814 }
01815 
01816 void KListView::setSelectionModeExt (SelectionModeExt mode)
01817 {
01818     d->selectionMode = mode;
01819 
01820     switch (mode)
01821     {
01822     case Single:
01823     case Multi:
01824     case Extended:
01825     case NoSelection:
01826         setSelectionMode (static_cast<QListView::SelectionMode>(static_cast<int>(mode)));
01827         break;
01828 
01829     case FileManager:
01830         setSelectionMode (QListView::Extended);
01831         break;
01832 
01833     default:
01834         kdWarning () << "Warning: illegal selection mode " << int(mode) << " set!" << endl;
01835         break;
01836     }
01837 }
01838 
01839 KListView::SelectionModeExt KListView::selectionModeExt () const
01840 {
01841   return d->selectionMode;
01842 }
01843 
01844 int KListView::itemIndex( const QListViewItem *item ) const
01845 {
01846     if ( !item )
01847         return -1;
01848 
01849     if ( item == firstChild() )
01850         return 0;
01851     else {
01852         QListViewItemIterator it(firstChild());
01853         uint j = 0;
01854         for (; it.current() && it.current() != item; ++it, ++j );
01855 
01856         if( !it.current() )
01857           return -1;
01858 
01859         return j;
01860     }
01861 }
01862 
01863 QListViewItem* KListView::itemAtIndex(int index)
01864 {
01865    if (index<0)
01866       return 0;
01867 
01868    int j(0);
01869    for (QListViewItemIterator it=firstChild(); it.current(); ++it)
01870    {
01871       if (j==index)
01872          return it.current();
01873       ++j;
01874    };
01875    return 0;
01876 }
01877 
01878 
01879 void KListView::emitContextMenu (KListView*, QListViewItem* i)
01880 {
01881   QPoint p;
01882 
01883   if (i)
01884         p = viewport()->mapToGlobal(itemRect(i).center());
01885   else
01886         p = mapToGlobal(rect().center());
01887 
01888   emit contextMenu (this, i, p);
01889 }
01890 
01891 void KListView::emitContextMenu (QListViewItem* i, const QPoint& p, int)
01892 {
01893   emit contextMenu (this, i, p);
01894 }
01895 
01896 void KListView::setAcceptDrops (bool val)
01897 {
01898   QListView::setAcceptDrops (val);
01899   viewport()->setAcceptDrops (val);
01900 }
01901 
01902 int KListView::dropVisualizerWidth () const
01903 {
01904         return d->mDropVisualizerWidth;
01905 }
01906 
01907 
01908 void KListView::viewportPaintEvent(QPaintEvent *e)
01909 {
01910   d->paintAbove = 0;
01911   d->paintCurrent = 0;
01912   d->paintBelow = 0;
01913   d->painting = true;
01914 
01915   QListView::viewportPaintEvent(e);
01916 
01917   if (d->mOldDropVisualizer.isValid() && e->rect().intersects(d->mOldDropVisualizer))
01918     {
01919       QPainter painter(viewport());
01920 
01921       // This is where we actually draw the drop-visualizer
01922       painter.fillRect(d->mOldDropVisualizer, Dense4Pattern);
01923     }
01924   if (d->mOldDropHighlighter.isValid() && e->rect().intersects(d->mOldDropHighlighter))
01925     {
01926       QPainter painter(viewport());
01927 
01928       // This is where we actually draw the drop-highlighter
01929       style().drawPrimitive(QStyle::PE_FocusRect, &painter, d->mOldDropHighlighter, colorGroup(),
01930                             QStyle::Style_FocusAtBorder);
01931     }
01932   d->painting = false;
01933 }
01934 
01935 void KListView::setFullWidth()
01936 {
01937   setFullWidth(true);
01938 }
01939 
01940 void KListView::setFullWidth(bool fullWidth)
01941 {
01942   d->fullWidth = fullWidth;
01943   header()->setStretchEnabled(fullWidth, columns()-1);
01944 }
01945 
01946 bool KListView::fullWidth() const
01947 {
01948   return d->fullWidth;
01949 }
01950 
01951 int KListView::addColumn(const QString& label, int width)
01952 {
01953   int result = QListView::addColumn(label, width);
01954   if (d->fullWidth) {
01955     header()->setStretchEnabled(false, columns()-2);
01956     header()->setStretchEnabled(true, columns()-1);
01957   }
01958   return result;
01959 }
01960 
01961 int KListView::addColumn(const QIconSet& iconset, const QString& label, int width)
01962 {
01963   int result = QListView::addColumn(iconset, label, width);
01964   if (d->fullWidth) {
01965     header()->setStretchEnabled(false, columns()-2);
01966     header()->setStretchEnabled(true, columns()-1);
01967   }
01968   return result;
01969 }
01970 
01971 void KListView::removeColumn(int index)
01972 {
01973   QListView::removeColumn(index);
01974   if (d->fullWidth && index == columns()) header()->setStretchEnabled(true, columns()-1);
01975 }
01976 
01977 void KListView::viewportResizeEvent(QResizeEvent* e)
01978 {
01979   QListView::viewportResizeEvent(e);
01980 }
01981 
01982 const QColor &KListView::alternateBackground() const
01983 {
01984   return d->alternateBackground;
01985 }
01986 
01987 void KListView::setAlternateBackground(const QColor &c)
01988 {
01989   d->alternateBackground = c;
01990   repaint();
01991 }
01992 
01993 void KListView::setShadeSortColumn(bool shadeSortColumn)
01994 {
01995   d->shadeSortColumn = shadeSortColumn;
01996   repaint();
01997 }
01998 
01999 bool KListView::shadeSortColumn() const
02000 {
02001   return d->shadeSortColumn;
02002 }
02003 
02004 void KListView::saveLayout(KConfig *config, const QString &group) const
02005 {
02006   KConfigGroupSaver saver(config, group);
02007   QStringList widths, order;
02008 
02009   const int colCount = columns();
02010   QHeader* const thisHeader = header();
02011   for (int i = 0; i < colCount; ++i)
02012   {
02013     widths << QString::number(columnWidth(i));
02014     order << QString::number(thisHeader->mapToIndex(i));
02015   }
02016   config->writeEntry("ColumnWidths", widths);
02017   config->writeEntry("ColumnOrder", order);
02018   config->writeEntry("SortColumn", d->sortColumn);
02019   config->writeEntry("SortAscending", d->sortAscending);
02020 }
02021 
02022 void KListView::restoreLayout(KConfig *config, const QString &group)
02023 {
02024   KConfigGroupSaver saver(config, group);
02025   QStringList cols = config->readListEntry("ColumnWidths");
02026   int i = 0;
02027   { // scope the iterators
02028     QStringList::ConstIterator it = cols.constBegin();
02029     const QStringList::ConstIterator itEnd = cols.constEnd();
02030     for (; it != itEnd; ++it)
02031       setColumnWidth(i++, (*it).toInt());
02032   }
02033 
02034   // move sections in the correct sequence: from lowest to highest index position
02035   // otherwise we move a section from an index, which modifies
02036   // all index numbers to the right of the moved one
02037   cols = config->readListEntry("ColumnOrder");
02038   const int colCount = columns();
02039   for (i = 0; i < colCount; ++i)   // final index positions from lowest to highest
02040   {
02041     QStringList::ConstIterator it = cols.constBegin();
02042     const QStringList::ConstIterator itEnd = cols.constEnd();
02043 
02044     int section = 0;
02045     for (; (it != itEnd) && ((*it).toInt() != i); ++it, ++section) ;
02046 
02047     if ( it != itEnd ) {
02048       // found the section to move to position i
02049       header()->moveSection(section, i);
02050     }
02051   }
02052 
02053   if (config->hasKey("SortColumn"))
02054     setSorting(config->readNumEntry("SortColumn"), config->readBoolEntry("SortAscending", true));
02055 }
02056 
02057 void KListView::setSorting(int column, bool ascending)
02058 {
02059   QListViewItem *selected = 0;
02060 
02061   if (selectionMode() == QListView::Single) {
02062     selected = selectedItem();
02063     if (selected && !selected->isVisible())
02064       selected = 0;
02065   }
02066   else if (selectionMode() != QListView::NoSelection) {
02067     QListViewItem *item = firstChild();
02068     while (item && !selected) {
02069       if (item->isSelected() && item->isVisible())
02070     selected = item;
02071       item = item->itemBelow();
02072     }
02073   }
02074 
02075   d->sortColumn = column;
02076   d->sortAscending = ascending;
02077   QListView::setSorting(column, ascending);
02078 
02079   if (selected)
02080     ensureItemVisible(selected);
02081 
02082   QListViewItem* item = firstChild();
02083   while ( item ) {
02084     KListViewItem *kItem = dynamic_cast<KListViewItem*>(item);
02085     if (kItem) kItem->m_known = false;
02086     item = item->itemBelow();
02087   }
02088 }
02089 
02090 int KListView::columnSorted(void) const
02091 {
02092   return d->sortColumn;
02093 }
02094 
02095 bool KListView::ascendingSort(void) const
02096 {
02097   return d->sortAscending;
02098 }
02099 
02100 void KListView::takeItem(QListViewItem *item)
02101 {
02102   if(item && item == d->editor->currentItem())
02103     d->editor->terminate();
02104 
02105   QListView::takeItem(item);
02106 }
02107 
02108 void KListView::disableAutoSelection()
02109 {
02110   if ( d->disableAutoSelection )
02111     return;
02112 
02113   d->disableAutoSelection = true;
02114   d->autoSelect.stop();
02115   d->autoSelectDelay = -1;
02116 }
02117 
02118 void KListView::resetAutoSelection()
02119 {
02120   if ( !d->disableAutoSelection )
02121     return;
02122 
02123   d->disableAutoSelection = false;
02124   d->autoSelectDelay = KGlobalSettings::autoSelectDelay();
02125 }
02126 
02127 void KListView::doubleClicked( QListViewItem *item, const QPoint &pos, int c )
02128 {
02129   emit QListView::doubleClicked( item, pos, c );
02130 }
02131 
02132 KListViewItem::KListViewItem(QListView *parent)
02133   : QListViewItem(parent)
02134 {
02135   init();
02136 }
02137 
02138 KListViewItem::KListViewItem(QListViewItem *parent)
02139   : QListViewItem(parent)
02140 {
02141   init();
02142 }
02143 
02144 KListViewItem::KListViewItem(QListView *parent, QListViewItem *after)
02145   : QListViewItem(parent, after)
02146 {
02147   init();
02148 }
02149 
02150 KListViewItem::KListViewItem(QListViewItem *parent, QListViewItem *after)
02151   : QListViewItem(parent, after)
02152 {
02153   init();
02154 }
02155 
02156 KListViewItem::KListViewItem(QListView *parent,
02157     QString label1, QString label2, QString label3, QString label4,
02158     QString label5, QString label6, QString label7, QString label8)
02159   : QListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8)
02160 {
02161   init();
02162 }
02163 
02164 KListViewItem::KListViewItem(QListViewItem *parent,
02165     QString label1, QString label2, QString label3, QString label4,
02166     QString label5, QString label6, QString label7, QString label8)
02167   : QListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8)
02168 {
02169   init();
02170 }
02171 
02172 KListViewItem::KListViewItem(QListView *parent, QListViewItem *after,
02173     QString label1, QString label2, QString label3, QString label4,
02174     QString label5, QString label6, QString label7, QString label8)
02175   : QListViewItem(parent, after, label1, label2, label3, label4, label5, label6, label7, label8)
02176 {
02177   init();
02178 }
02179 
02180 KListViewItem::KListViewItem(QListViewItem *parent, QListViewItem *after,
02181     QString label1, QString label2, QString label3, QString label4,
02182     QString label5, QString label6, QString label7, QString label8)
02183   : QListViewItem(parent, after, label1, label2, label3, label4, label5, label6, label7, label8)
02184 {
02185   init();
02186 }
02187 
02188 KListViewItem::~KListViewItem()
02189 {
02190   if(listView())
02191     emit static_cast<KListView *>(listView())->itemRemoved(this);
02192 }
02193 
02194 void KListViewItem::init()
02195 {
02196   m_odd = m_known = false;
02197   KListView *lv = static_cast<KListView *>(listView());
02198   setDragEnabled( dragEnabled() || lv->dragEnabled() );
02199   emit lv->itemAdded(this);
02200 }
02201 
02202 void KListViewItem::insertItem(QListViewItem *item)
02203 {
02204   QListViewItem::insertItem(item);
02205   if(listView())
02206     emit static_cast<KListView *>(listView())->itemAdded(item);
02207 }
02208 
02209 void KListViewItem::takeItem(QListViewItem *item)
02210 {
02211   QListViewItem::takeItem(item);
02212   if(listView())
02213     emit static_cast<KListView *>(listView())->itemRemoved(item);
02214 }
02215 
02216 const QColor &KListViewItem::backgroundColor()
02217 {
02218   if (isAlternate())
02219     return static_cast< KListView* >(listView())->alternateBackground();
02220   return listView()->viewport()->colorGroup().base();
02221 }
02222 
02223 QColor KListViewItem::backgroundColor(int column)
02224 {
02225   KListView* view = static_cast< KListView* >(listView());
02226   QColor color = isAlternate() ?
02227                  view->alternateBackground() :
02228                  view->viewport()->colorGroup().base();
02229 
02230   // calculate a different color if the current column is sorted (only if more than 1 column)
02231   if ( (view->columns() > 1) && view->shadeSortColumn() && (column == view->columnSorted()) )
02232   {
02233     if ( color == Qt::black )
02234       color = QColor(55, 55, 55);  // dark gray
02235     else
02236     {
02237       int h,s,v;
02238       color.hsv(&h, &s, &v);
02239       if ( v > 175 )
02240         color = color.dark(104);
02241       else
02242         color = color.light(120);
02243     }
02244   }
02245 
02246   return color;
02247 }
02248 
02249 bool KListViewItem::isAlternate()
02250 {
02251   KListView* const lv = static_cast<KListView *>(listView());
02252   if (lv && lv->alternateBackground().isValid())
02253   {
02254     KListViewItem *above;
02255 
02256     KListView::KListViewPrivate* const lvD = lv->d;
02257 
02258     // Ok, there's some weirdness here that requires explanation as this is a
02259     // speed hack.  itemAbove() is a O(n) operation (though this isn't
02260     // immediately clear) so we want to call it as infrequently as possible --
02261     // especially in the case of painting a cell.
02262     //
02263     // So, in the case that we *are* painting a cell:  (1) we're assuming that
02264     // said painting is happening top to bottem -- this assumption is present
02265     // elsewhere in the implementation of this class, (2) itemBelow() is fast --
02266     // roughly constant time.
02267     //
02268     // Given these assumptions we can do a mixture of caching and telling the
02269     // next item that the when that item is the current item that the now
02270     // current item will be the item above it.
02271     //
02272     // Ideally this will make checking to see if the item above the current item
02273     // is the alternate color a constant time operation rather than 0(n).
02274 
02275     if (lvD->painting) {
02276       if (lvD->paintCurrent != this)
02277       {
02278         lvD->paintAbove = lvD->paintBelow == this ? lvD->paintCurrent : itemAbove();
02279         lvD->paintCurrent = this;
02280         lvD->paintBelow = itemBelow();
02281       }
02282 
02283       above = dynamic_cast<KListViewItem *>(lvD->paintAbove);
02284     }
02285     else
02286     {
02287       above = dynamic_cast<KListViewItem *>(itemAbove());
02288     }
02289 
02290     m_known = above ? above->m_known : true;
02291     if (m_known)
02292     {
02293        m_odd = above ? !above->m_odd : false;
02294     }
02295     else
02296     {
02297        KListViewItem *item;
02298        bool previous = true;
02299        if (parent())
02300        {
02301           item = dynamic_cast<KListViewItem *>(parent());
02302           if (item)
02303              previous = item->m_odd;
02304           item = dynamic_cast<KListViewItem *>(parent()->firstChild());
02305        }
02306        else
02307        {
02308           item = dynamic_cast<KListViewItem *>(lv->firstChild());
02309        }
02310 
02311        while(item)
02312        {
02313           item->m_odd = previous = !previous;
02314           item->m_known = true;
02315           item = dynamic_cast<KListViewItem *>(item->nextSibling());
02316        }
02317     }
02318     return m_odd;
02319   }
02320   return false;
02321 }
02322 
02323 void KListViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment)
02324 {
02325   QColorGroup _cg = cg;
02326   const QPixmap *pm = listView()->viewport()->backgroundPixmap();
02327 
02328   if (pm && !pm->isNull())
02329   {
02330     _cg.setBrush(QColorGroup::Base, QBrush(backgroundColor(column), *pm));
02331     QPoint o = p->brushOrigin();
02332     p->setBrushOrigin( o.x()-listView()->contentsX(), o.y()-listView()->contentsY() );
02333   }
02334   else
02335   {
02336     _cg.setColor((listView()->viewport()->backgroundMode() == Qt::FixedColor) ?
02337                  QColorGroup::Background : QColorGroup::Base,
02338                  backgroundColor(column));
02339   }
02340   QListViewItem::paintCell(p, _cg, column, width, alignment);
02341 }
02342 
02343 void KListView::virtual_hook( int, void* )
02344 { /*BASE::virtual_hook( id, data );*/ }
02345 
02346 #include "klistview.moc"
02347 #include "klistviewlineedit.moc"
02348 
02349 // vim: noet
KDE Logo
This file is part of the documentation for kdeui Library Version 3.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Sep 15 10:27:01 2005 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003