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