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