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