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