kdeui Library API Documentation

klistview.cpp

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