KDevelop API Documentation

lib/widgets/qcomboview.cpp

Go to the documentation of this file.
00001 /********************************************************************** 00002 ** 00003 ** 00004 ** Implementation of QComboView widget class 00005 ** 00006 ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. 00007 ** Copyright (C) 2003 Alexander Dymo <cloudtemple@mksat.net> 00008 ** 00009 ** This file may be distributed and/or modified under the terms of the 00010 ** GNU General Public License version 2 as published by the Free Software 00011 ** Foundation and appearing in the file LICENSE.GPL included in the 00012 ** packaging of this file. 00013 ** 00014 **********************************************************************/ 00015 00016 #include "qcomboview.h" 00017 #include <kdeversion.h> 00018 #ifndef QT_NO_COMBOBOX 00019 #include "qpopupmenu.h" 00020 #include "qlistview.h" 00021 #include "qpainter.h" 00022 #include "qdrawutil.h" 00023 #include "qstrlist.h" 00024 #include "qpixmap.h" 00025 #include "qtimer.h" 00026 #include "qapplication.h" 00027 #include "qlineedit.h" 00028 #include "qbitmap.h" 00029 #include "private/qeffects_p.h" 00030 #include "qstringlist.h" 00031 #include "qcombobox.h" 00032 #include "qstyle.h" 00033 #include "qheader.h" 00034 #include <limits.h> 00035 00036 class QComboViewData 00037 { 00038 public: 00039 QComboViewData( QComboView *cb ): current(0), lView( 0 ), combo( cb ) 00040 { 00041 duplicatesEnabled = TRUE; 00042 cb->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) ); 00043 } 00044 00045 inline QListView * listView() { return lView; } 00046 void updateLinedGeometry(); 00047 00048 void setListView( QListView *l ) { lView = l ; 00049 l->setMouseTracking( TRUE );} 00050 00051 QListViewItem *current; 00052 int maxCount; 00053 int sizeLimit; 00054 QComboView::Policy p; 00055 bool autoresize; 00056 bool poppedUp; 00057 bool mouseWasInsidePopup; 00058 bool arrowPressed; 00059 bool arrowDown; 00060 bool discardNextMousePress; 00061 bool shortClick; 00062 bool useCompletion; 00063 bool completeNow; 00064 int completeAt; 00065 bool duplicatesEnabled; 00066 int fullHeight, currHeight; 00067 00068 QLineEdit * ed; // /bin/ed rules! 00069 QTimer *completionTimer; 00070 00071 QSize sizeHint; 00072 00073 private: 00074 bool usinglView; 00075 QListView *lView; 00076 QComboView *combo; 00077 00078 }; 00079 00080 void QComboViewData::updateLinedGeometry() 00081 { 00082 if ( !ed || !combo ) 00083 return; 00084 QRect r = QStyle::visualRect( combo->style().querySubControlMetrics(QStyle::CC_ComboBox, combo, 00085 QStyle::SC_ComboBoxEditField), combo ); 00086 00087 // qWarning("updateLinedGeometry(): currentItem is %d", combo->currentItem() == 0 ? 0 : 1); 00088 const QPixmap *pix = combo->currentItem() ? combo->currentItem()->pixmap(0) : 0; 00089 if ( pix && pix->width() < r.width() ) 00090 r.setLeft( r.left() + pix->width() + 4 ); 00091 if ( r != ed->geometry() ) 00092 ed->setGeometry( r ); 00093 } 00094 00095 static inline bool checkInsertIndex( const char *method, const char * name, 00096 int count, int *index) 00097 { 00098 bool range_err = (*index > count); 00099 #if defined(QT_CHECK_RANGE) 00100 if ( range_err ) 00101 qWarning( "QComboView::%s: (%s) Index %d out of range", 00102 method, name ? name : "<no name>", *index ); 00103 #else 00104 Q_UNUSED( method ) 00105 Q_UNUSED( name ) 00106 #endif 00107 if ( *index < 0 ) // append 00108 *index = count; 00109 return !range_err; 00110 } 00111 00112 00113 static inline bool checkIndex( const char *method, const char * name, 00114 int count, int index ) 00115 { 00116 bool range_err = (index >= count); 00117 #if defined(QT_CHECK_RANGE) 00118 if ( range_err ) 00119 qWarning( "QComboView::%s: (%s) Index %i out of range", 00120 method, name ? name : "<no name>", index ); 00121 #else 00122 Q_UNUSED( method ) 00123 Q_UNUSED( name ) 00124 #endif 00125 return !range_err; 00126 } 00127 00128 00141 QComboView::QComboView( bool rw, QWidget *parent, const char *name ) 00142 : QWidget( parent, name, WResizeNoErase ) 00143 { 00144 d = new QComboViewData( this ); 00145 setUpListView(); 00146 00147 d->current = 0; 00148 d->maxCount = INT_MAX; 00149 setSizeLimit(10); 00150 d->p = AtBottom; 00151 d->autoresize = FALSE; 00152 d->poppedUp = FALSE; 00153 d->arrowDown = FALSE; 00154 d->discardNextMousePress = FALSE; 00155 d->shortClick = FALSE; 00156 d->useCompletion = FALSE; 00157 d->completeAt = 0; 00158 d->completeNow = FALSE; 00159 d->completionTimer = new QTimer( this ); 00160 00161 setFocusPolicy( StrongFocus ); 00162 00163 d->ed = 0; 00164 if ( rw ) 00165 setUpLineEdit(); 00166 setBackgroundMode( PaletteButton, PaletteBase ); 00167 } 00168 00169 00170 00175 QComboView::~QComboView() 00176 { 00177 delete d; 00178 } 00179 00180 void QComboView::setDuplicatesEnabled( bool enable ) 00181 { 00182 d->duplicatesEnabled = enable; 00183 } 00184 00185 bool QComboView::duplicatesEnabled() const 00186 { 00187 return d->duplicatesEnabled; 00188 } 00189 00190 int QComboView::childCount() const 00191 { 00192 return d->listView()->childCount(); 00193 } 00194 00195 00200 void QComboView::clear() 00201 { 00202 d->listView()->resize( 0, 0 ); 00203 d->listView()->clear(); 00204 00205 d->current = 0; 00206 if ( d->ed ) { 00207 d->ed->setText( QString::fromLatin1("") ); 00208 d->updateLinedGeometry(); 00209 } 00210 currentChanged(); 00211 } 00212 00213 QListViewItem *QComboView::currentItem() const 00214 { 00215 return d->current; 00216 } 00217 00218 void QComboView::setCurrentItem( QListViewItem *item ) 00219 { 00220 if ( item == d->current && !d->ed ) { 00221 return; 00222 } 00223 00224 if (!item) 00225 { 00226 d->current = 0; 00227 if ( d->ed ) { 00228 // d->ed->setText( "" ); 00229 d->updateLinedGeometry(); 00230 } 00231 return; 00232 } 00233 00234 d->current = item; 00235 d->completeAt = 0; 00236 if ( d->ed ) { 00237 d->ed->setText( item->text(0) ); 00238 // qWarning("setCurrentItem( %s )", item->text(0).latin1()); 00239 d->updateLinedGeometry(); 00240 } 00241 if ( d->listView() ) { 00242 d->listView()->setCurrentItem( item ); 00243 } else { 00244 internalHighlight( item ); 00245 // internalActivate( item ); ### this leads to weird behavior, as in 3.0.1 00246 } 00247 00248 currentChanged(); 00249 00250 d->listView()->ensureItemVisible(item); 00251 } 00252 00253 bool QComboView::autoResize() const 00254 { 00255 return d->autoresize; 00256 } 00257 00258 void QComboView::setAutoResize( bool enable ) 00259 { 00260 if ( (bool)d->autoresize != enable ) { 00261 d->autoresize = enable; 00262 if ( enable ) 00263 adjustSize(); 00264 } 00265 } 00266 00267 00275 QSize QComboView::sizeHint() const 00276 { 00277 if ( isVisible() && d->sizeHint.isValid() ) 00278 return d->sizeHint; 00279 00280 constPolish(); 00281 // int i, w; 00282 QFontMetrics fm = fontMetrics(); 00283 00284 int maxW = childCount() ? 18 : 7 * fm.width(QChar('x')) + 18; 00285 int maxH = QMAX( fm.lineSpacing(), 14 ) + 2; 00286 00287 /* for( i = 0; i < count(); i++ ) { 00288 w = d->listView()->item( i )->width( d->listView() ); 00289 if ( w > maxW ) 00290 maxW = w; 00291 } 00292 */ 00293 d->sizeHint = (style().sizeFromContents(QStyle::CT_ComboBox, this, 00294 QSize(maxW, maxH)).expandedTo(QApplication::globalStrut())); 00295 00296 return d->sizeHint; 00297 } 00298 00299 00306 void QComboView::internalActivate( QListViewItem * item ) 00307 { 00308 if (!item) 00309 { 00310 d->current = 0; 00311 if ( d->ed ) { 00312 // d->ed->setText( "" ); 00313 d->updateLinedGeometry(); 00314 } 00315 return; 00316 } 00317 popDownListView(); 00318 d->poppedUp = FALSE; 00319 00320 d->current = item; 00321 00322 QString t( item->text(0) ); 00323 if ( d->ed ) { 00324 d->ed->setText( t ); 00325 // qWarning("internalActivate( %s )", item->text(0).latin1()); 00326 d->updateLinedGeometry(); 00327 } 00328 emit activated( item ); 00329 emit activated( t ); 00330 00331 // item->setOpen(true); 00332 } 00333 00340 void QComboView::internalHighlight( QListViewItem * item ) 00341 { 00342 if (!item) 00343 { 00344 d->current = 0; 00345 if ( d->ed ) { 00346 // d->ed->setText( "" ); 00347 d->updateLinedGeometry(); 00348 } 00349 return; 00350 } 00351 emit highlighted( item ); 00352 QString t = item->text(0); 00353 if ( !t.isNull() ) 00354 emit highlighted( t ); 00355 } 00356 00362 void QComboView::internalClickTimeout() 00363 { 00364 d->shortClick = FALSE; 00365 } 00366 00372 void QComboView::setPalette( const QPalette &palette ) 00373 { 00374 QWidget::setPalette( palette ); 00375 if( d ) { 00376 if(d->listView()) 00377 d->listView()->setPalette( palette ); 00378 } 00379 } 00380 00386 void QComboView::setFont( const QFont &font ) 00387 { 00388 d->sizeHint = QSize(); // invalidate size hint 00389 QWidget::setFont( font ); 00390 d->listView()->setFont( font ); 00391 if (d->ed) 00392 d->ed->setFont( font ); 00393 if ( d->autoresize ) 00394 adjustSize(); 00395 } 00396 00397 00401 void QComboView::resizeEvent( QResizeEvent * e ) 00402 { 00403 if ( d->ed ) 00404 d->updateLinedGeometry(); 00405 d->listView()->resize( width(), d->listView()->height() ); 00406 QWidget::resizeEvent( e ); 00407 } 00408 00412 void QComboView::paintEvent( QPaintEvent * ) 00413 { 00414 QPainter p( this ); 00415 const QColorGroup & g = colorGroup(); 00416 p.setPen(g.text()); 00417 00418 QStyle::SFlags flags = QStyle::Style_Default; 00419 if (isEnabled()) 00420 flags |= QStyle::Style_Enabled; 00421 if (hasFocus()) 00422 flags |= QStyle::Style_HasFocus; 00423 00424 if ( width() < 5 || height() < 5 ) { 00425 qDrawShadePanel( &p, rect(), g, FALSE, 2, 00426 &g.brush( QColorGroup::Button ) ); 00427 return; 00428 } 00429 00430 // bool reverse = QApplication::reverseLayout(); 00431 style().drawComplexControl( QStyle::CC_ComboBox, &p, this, rect(), g, 00432 flags, QStyle::SC_All, 00433 (d->arrowDown ? 00434 QStyle::SC_ComboBoxArrow : 00435 QStyle::SC_None )); 00436 00437 QRect re = style().querySubControlMetrics( QStyle::CC_ComboBox, this, 00438 QStyle::SC_ComboBoxEditField ); 00439 re = QStyle::visualRect(re, this); 00440 p.setClipRect( re ); 00441 00442 if ( !d->ed ) { 00443 QListViewItem * item = d->current; 00444 if ( item ) { 00445 // we calculate the QListBoxTexts height (ignoring strut) 00446 int itemh = d->listView()->fontMetrics().lineSpacing() + 2; 00447 p.translate( re.x(), re.y() + (re.height() - itemh)/2 ); 00448 item->paintCell( &p, d->listView()->colorGroup(), 0, width(), AlignLeft | AlignVCenter ); 00449 } 00450 } else if ( d->listView() && d->listView()->currentItem( ) && d->current ) { 00451 QListViewItem * item = d->current ; 00452 const QPixmap *pix = item->pixmap(0); 00453 if ( pix ) { 00454 p.fillRect( re.x(), re.y(), pix->width() + 4, re.height(), 00455 colorGroup().brush( QColorGroup::Base ) ); 00456 p.drawPixmap( re.x() + 2, re.y() + 00457 ( re.height() - pix->height() ) / 2, *pix ); 00458 } 00459 } 00460 p.setClipping( FALSE ); 00461 } 00462 00463 00467 void QComboView::mousePressEvent( QMouseEvent *e ) 00468 { 00469 if ( e->button() != LeftButton ) 00470 return; 00471 if ( d->discardNextMousePress ) { 00472 d->discardNextMousePress = FALSE; 00473 return; 00474 } 00475 QRect arrowRect = style().querySubControlMetrics( QStyle::CC_ComboBox, this, 00476 QStyle::SC_ComboBoxArrow); 00477 arrowRect = QStyle::visualRect(arrowRect, this); 00478 00479 // Correction for motif style, where arrow is smaller 00480 // and thus has a rect that doesn't fit the button. 00481 arrowRect.setHeight( QMAX( height() - (2 * arrowRect.y()), arrowRect.height() ) ); 00482 00483 if ( childCount() && ( !editable() || arrowRect.contains( e->pos() ) ) ) { 00484 d->arrowPressed = FALSE; 00485 listView()->blockSignals( TRUE ); 00486 qApp->sendEvent( listView(), e ); // trigger the listbox's autoscroll 00487 listView()->blockSignals( FALSE ); 00488 popup(); 00489 if ( arrowRect.contains( e->pos() ) ) { 00490 d->arrowPressed = TRUE; 00491 d->arrowDown = TRUE; 00492 repaint( FALSE ); 00493 } 00494 QTimer::singleShot( 200, this, SLOT(internalClickTimeout())); 00495 d->shortClick = TRUE; 00496 } 00497 } 00498 00502 void QComboView::mouseMoveEvent( QMouseEvent * ) 00503 { 00504 } 00505 00509 void QComboView::mouseReleaseEvent( QMouseEvent * ) 00510 { 00511 } 00512 00516 void QComboView::mouseDoubleClickEvent( QMouseEvent *e ) 00517 { 00518 mousePressEvent( e ); 00519 } 00520 00521 00525 void QComboView::keyPressEvent( QKeyEvent *e ) 00526 { 00527 QListViewItem *c = currentItem(); 00528 if ( ( e->key() == Key_F4 && e->state() == 0 ) || 00529 ( e->key() == Key_Down && (e->state() & AltButton) ) || 00530 ( !d->ed && e->key() == Key_Space ) ) { 00531 if ( childCount() ) { 00532 popup(); 00533 } 00534 return; 00535 } else if ( e->key() == Key_Up ) { 00536 /* if ((!c) && (listView()->firstChild())) 00537 setCurrentItem(listView()->firstChild());*/ 00538 if (c && c->itemAbove() ) 00539 setCurrentItem( c->itemAbove() ); 00540 else 00541 return; 00542 } else if ( e->key() == Key_Down ) { 00543 if ((!c) && (listView()->firstChild())) 00544 { 00545 setCurrentItem(listView()->firstChild()); 00546 return; 00547 } 00548 if ( c && c->itemBelow() ) 00549 setCurrentItem( c->itemBelow() ); 00550 else 00551 return; 00552 } else if ( e->key() == Key_Home && ( !d->ed || !d->ed->hasFocus() ) ) { 00553 if (listView()->firstChild()) 00554 setCurrentItem( listView()->firstChild() ); 00555 else 00556 return; 00557 } else if ( e->key() == Key_End && ( !d->ed || !d->ed->hasFocus() ) ) { 00558 if (listView()->lastItem()) 00559 setCurrentItem( listView()->lastItem() ); 00560 else 00561 return; 00562 } else if ( !d->ed && e->ascii() >= 32 && !e->text().isEmpty() ) { 00563 if ( !d->completionTimer->isActive() ) { 00564 d->completeAt = 0; 00565 c = completionIndex( e->text(), c->itemBelow() ); 00566 if ( c ) { 00567 setCurrentItem( c ); 00568 d->completeAt = e->text().length(); 00569 } 00570 else 00571 return; 00572 } else { 00573 d->completionTimer->stop(); 00574 QString ct = currentText().left( d->completeAt ) + e->text(); 00575 c = completionIndex( ct, c ); 00576 if ( c == 0 && d->completeAt > 0 ) { 00577 c = completionIndex( e->text(), listView()->firstChild() ); 00578 ct = e->text(); 00579 } 00580 d->completeAt = 0; 00581 if ( c ) { 00582 setCurrentItem( c ); 00583 d->completeAt = ct.length(); 00584 } 00585 else 00586 return; 00587 } 00588 d->completionTimer->start( 400, TRUE ); 00589 } else { 00590 e->ignore(); 00591 return; 00592 } 00593 00594 c = currentItem(); 00595 if ( childCount() && c && !c->text(0).isNull() ) 00596 emit activated( c->text(0) ); 00597 emit activated( c ); 00598 } 00599 00600 QString QComboView::currentText() const 00601 { 00602 if ( d->ed ) 00603 return d->ed->text(); 00604 else if ( d->current ) 00605 return currentItem()->text(0); 00606 else 00607 return QString::null; 00608 } 00609 00613 void QComboView::focusInEvent( QFocusEvent * e ) 00614 { 00615 QWidget::focusInEvent( e ); 00616 d->completeNow = FALSE; 00617 d->completeAt = 0; 00618 00619 emit focusGranted(); 00620 } 00621 00625 void QComboView::focusOutEvent( QFocusEvent * e ) 00626 { 00627 QWidget::focusOutEvent( e ); 00628 d->completeNow = FALSE; 00629 d->completeAt = 0; 00630 00631 emit focusLost(); 00632 } 00633 00637 void QComboView::wheelEvent( QWheelEvent *e ) 00638 { 00639 if ( d->poppedUp ) { 00640 QApplication::sendEvent( d->listView(), e ); 00641 } else { 00642 if ( e->delta() > 0 ) { 00643 QListViewItem *c = currentItem(); 00644 if ( c && c->itemAbove() ) { 00645 setCurrentItem( c->itemAbove() ); 00646 emit activated( currentItem() ); 00647 emit activated( currentText() ); 00648 } 00649 } else { 00650 QListViewItem *c = currentItem(); 00651 if ( c && c->itemBelow() ) { 00652 setCurrentItem( c->itemBelow() ); 00653 emit activated( currentItem() ); 00654 emit activated( currentText() ); 00655 } 00656 } 00657 e->accept(); 00658 } 00659 } 00660 00661 int childCount(QListViewItem *it) 00662 { 00663 int count = 1; 00664 QListViewItem * myChild = it->firstChild(); 00665 while( myChild ) { 00666 count += childCount(myChild); 00667 myChild = myChild->nextSibling(); 00668 } 00669 return count; 00670 } 00671 00672 int childCount(QListView *lv) 00673 { 00674 int count = 0; 00675 QListViewItem * myChild = lv->firstChild(); 00676 while( myChild ) { 00677 count += childCount(myChild); 00678 // count += 1; 00679 myChild = myChild->nextSibling(); 00680 } 00681 return count; 00682 } 00683 00689 static int listHeight( QListView *l, int /*sl*/ ) 00690 { 00691 /* if ( l->childCount() > 0 ) 00692 return QMIN( l->childCount(), (uint)sl) * l->firstChild()->height(); 00693 else*/ 00694 00695 int prefH = 0; 00696 int ch = childCount(l); 00697 ch = QMIN(ch, 10); 00698 if (l->firstChild()) 00699 { 00700 prefH = ch * l->firstChild()->height(); 00701 } 00702 else 00703 prefH = l->sizeHint().height(); 00704 00705 if (l->header()->isVisible()) 00706 prefH += l->header()->sizeHint().height(); 00707 00708 // return prefH < l->sizeHint().height() ? prefH : l->sizeHint().height(); 00709 00710 return prefH; 00711 } 00712 00719 void QComboView::popup() 00720 { 00721 if ( !childCount() ) 00722 return; 00723 00724 // Send all listbox events to eventFilter(): 00725 QListView* lb = d->listView(); 00726 lb->triggerUpdate( ); 00727 lb->installEventFilter( this ); 00728 lb->viewport()->installEventFilter( this ); 00729 d->mouseWasInsidePopup = FALSE; 00730 // int w = lb->variableWidth() ? lb->sizeHint().width() : width(); 00731 int w = width(); 00732 int h = listHeight( lb, d->sizeLimit ); 00733 #if KDE_VERSION > 305 00734 QRect screen = QApplication::desktop()->availableGeometry( const_cast<QComboView*>(this) ); 00735 #else 00736 QRect screen = geometry(); 00737 #endif 00738 00739 int sx = screen.x(); // screen pos 00740 int sy = screen.y(); 00741 int sw = screen.width(); // screen width 00742 int sh = screen.height(); // screen height 00743 QPoint pos = mapToGlobal( QPoint(0,height()) ); 00744 // ## Similar code is in QPopupMenu 00745 int x = pos.x(); 00746 int y = pos.y(); 00747 00748 // the complete widget must be visible 00749 if ( x + w > sx + sw ) 00750 x = sx+sw - w; 00751 if ( x < sx ) 00752 x = sx; 00753 if (y + h > sy+sh && y - h - height() >= 0 ) 00754 y = y - h - height(); 00755 #if KDE_VERSION >= 310 00756 QRect rect = 00757 style().querySubControlMetrics( QStyle::CC_ComboBox, this, 00758 QStyle::SC_ComboBoxListBoxPopup, 00759 QStyleOption( x, y, w, h ) ); 00760 if ( rect.isNull() ) 00761 rect.setRect( x, y, w, h ); 00762 #else 00763 QRect rect; 00764 rect.setRect( x, y, w, h ); 00765 #endif 00766 lb->setGeometry( rect ); 00767 00768 lb->raise(); 00769 bool block = lb->signalsBlocked(); 00770 lb->blockSignals( TRUE ); 00771 QListViewItem *currentLBItem = d->current ; 00772 lb->setCurrentItem( currentLBItem ); 00773 // set the current item to also be the selected item if it isn't already 00774 if ( currentLBItem && currentLBItem->isSelectable() && !currentLBItem->isSelected() ) 00775 lb->setSelected( currentLBItem, TRUE ); 00776 lb->blockSignals( block ); 00777 lb->setVScrollBarMode(QScrollView::Auto); 00778 00779 //#ifndef QT_NO_EFFECTS 00780 /* if ( QApplication::isEffectEnabled( UI_AnimateCombo ) ) { 00781 if ( lb->y() < mapToGlobal(QPoint(0,0)).y() ) 00782 qScrollEffect( lb, QEffects::UpScroll ); 00783 else 00784 qScrollEffect( lb ); 00785 } else*/ 00786 //#endif 00787 lb->show(); 00788 d->poppedUp = TRUE; 00789 } 00790 00791 00795 void QComboView::updateMask() 00796 { 00797 QBitmap bm( size() ); 00798 bm.fill( color0 ); 00799 00800 { 00801 QPainter p( &bm, this ); 00802 style().drawComplexControlMask(QStyle::CC_ComboBox, &p, this, rect()); 00803 } 00804 00805 setMask( bm ); 00806 } 00807 00812 void QComboView::popDownListView() 00813 { 00814 d->listView()->removeEventFilter( this ); 00815 d->listView()->viewport()->removeEventFilter( this ); 00816 d->listView()->hide(); 00817 d->listView()->setCurrentItem( d->current ); 00818 if ( d->arrowDown ) { 00819 d->arrowDown = FALSE; 00820 repaint( FALSE ); 00821 } 00822 d->poppedUp = FALSE; 00823 } 00824 00825 00831 void QComboView::reIndex() 00832 { 00833 } 00834 00840 void QComboView::currentChanged() 00841 { 00842 if ( d->autoresize ) 00843 adjustSize(); 00844 update(); 00845 } 00846 00858 bool QComboView::eventFilter( QObject *object, QEvent *event ) 00859 { 00860 if ( !event ) 00861 return TRUE; 00862 else if ( object == d->ed ) { 00863 if ( event->type() == QEvent::KeyPress ) { 00864 bool isAccepted = ( (QKeyEvent*)event )->isAccepted(); 00865 keyPressEvent( (QKeyEvent *)event ); 00866 if ( ((QKeyEvent *)event)->isAccepted() ) { 00867 d->completeNow = FALSE; 00868 return TRUE; 00869 } else if ( ((QKeyEvent *)event)->key() != Key_End ) { 00870 d->completeNow = TRUE; 00871 d->completeAt = d->ed->cursorPosition(); 00872 } 00873 if ( isAccepted ) 00874 ( (QKeyEvent*)event )->accept(); 00875 else 00876 ( (QKeyEvent*)event )->ignore(); 00877 } else if ( event->type() == QEvent::KeyRelease ) { 00878 d->completeNow = FALSE; 00879 keyReleaseEvent( (QKeyEvent *)event ); 00880 return ((QKeyEvent *)event)->isAccepted(); 00881 } else if ( event->type() == QEvent::FocusIn ) { 00882 focusInEvent( (QFocusEvent *)event ); 00883 } else if ( event->type() == QEvent::FocusOut ) { 00884 focusOutEvent( (QFocusEvent *)event ); 00885 } else if ( d->useCompletion && d->completeNow ) { 00886 if ( !d->ed->text().isNull() && 00887 d->ed->cursorPosition() > d->completeAt && 00888 d->ed->cursorPosition() == (int)d->ed->text().length() ) { 00889 d->completeNow = FALSE; 00890 QString ct( d->ed->text() ); 00891 QListViewItem *i = completionIndex( ct, currentItem() ); 00892 if ( i ) { 00893 QString it = i->text(0); 00894 d->ed->validateAndSet( it, ct.length(), 00895 ct.length(), it.length() ); 00896 } 00897 } 00898 } 00899 } else if ( ( object == d->listView() || 00900 object == d->listView()->viewport() )) { 00901 QMouseEvent *e = (QMouseEvent*)event; 00902 switch( event->type() ) { 00903 case QEvent::MouseMove: 00904 if ( !d->mouseWasInsidePopup ) { 00905 // qWarning("!d->mouseWasInsidePopup"); 00906 QPoint pos = e->pos(); 00907 if ( d->listView()->rect().contains( pos ) ) 00908 d->mouseWasInsidePopup = TRUE; 00909 // Check if arrow button should toggle 00910 if ( d->arrowPressed ) { 00911 QPoint comboPos; 00912 comboPos = mapFromGlobal( d->listView()->mapToGlobal(pos) ); 00913 QRect arrowRect = 00914 style().querySubControlMetrics( QStyle::CC_ComboBox, this, 00915 QStyle::SC_ComboBoxArrow); 00916 arrowRect = QStyle::visualRect(arrowRect, this); 00917 if ( arrowRect.contains( comboPos ) ) { 00918 if ( !d->arrowDown ) { 00919 d->arrowDown = TRUE; 00920 repaint( FALSE ); 00921 } 00922 } else { 00923 if ( d->arrowDown ) { 00924 d->arrowDown = FALSE; 00925 repaint( FALSE ); 00926 } 00927 } 00928 } 00929 } else if ((e->state() & ( RightButton | LeftButton | MidButton ) ) == 0 && 00930 style().styleHint(QStyle::SH_ComboBox_ListMouseTracking, this)) { 00931 // qWarning("event filter:: emu"); 00932 QWidget *mouseW = QApplication::widgetAt( e->globalPos(), TRUE ); 00933 // if ( mouseW == d->listView()->viewport() ) { //### 00934 if ( mouseW == d->listView()->viewport() ) { 00935 QListViewItem *sel = d->listView()->itemAt(e->pos()); 00936 if (sel) 00937 { 00938 d->listView()->setCurrentItem(sel); 00939 d->listView()->setSelected(sel, true); 00940 } 00941 return TRUE; 00942 } 00943 } 00944 00945 break; 00946 case QEvent::MouseButtonRelease: 00947 if ( d->listView()->rect().contains( e->pos() ) ) { 00948 QMouseEvent tmp( QEvent::MouseButtonDblClick, 00949 e->pos(), e->button(), e->state() ) ; 00950 // will hide popup 00951 QApplication::sendEvent( object, &tmp ); 00952 return TRUE; 00953 } else { 00954 if ( d->mouseWasInsidePopup ) { 00955 popDownListView(); 00956 } else { 00957 d->arrowPressed = FALSE; 00958 if ( d->arrowDown ) { 00959 d->arrowDown = FALSE; 00960 repaint( FALSE ); 00961 } 00962 } 00963 } 00964 break; 00965 case QEvent::MouseButtonDblClick: 00966 case QEvent::MouseButtonPress: 00967 if ( !d->listView()->rect().contains( e->pos() ) ) { 00968 QPoint globalPos = d->listView()->mapToGlobal(e->pos()); 00969 if ( QApplication::widgetAt( globalPos, TRUE ) == this ) { 00970 d->discardNextMousePress = TRUE; 00971 // avoid popping up again 00972 } 00973 popDownListView(); 00974 return TRUE; 00975 } 00976 break; 00977 case QEvent::KeyPress: 00978 switch( ((QKeyEvent *)event)->key() ) { 00979 case Key_Up: 00980 case Key_Down: 00981 if ( !(((QKeyEvent *)event)->state() & AltButton) ) 00982 break; 00983 case Key_F4: 00984 case Key_Escape: 00985 if ( d->poppedUp ) { 00986 popDownListView(); 00987 return TRUE; 00988 } 00989 break; 00990 case Key_Enter: 00991 case Key_Return: 00992 // work around QDialog's enter handling 00993 return FALSE; 00994 default: 00995 break; 00996 } 00997 break; 00998 case QEvent::Hide: 00999 popDownListView(); 01000 break; 01001 default: 01002 break; 01003 } 01004 } 01005 return QWidget::eventFilter( object, event ); 01006 } 01007 01008 01015 QListViewItem *QComboView::completionIndex( const QString & prefix, 01016 QListViewItem *startingAt ) const 01017 { 01018 QListViewItem *start = startingAt; 01019 /* if ( start < 0 || start >= count() ) 01020 start = 0; 01021 if ( start >= count() ) 01022 return -1;*/ 01023 if (!start) 01024 start = listView()->firstChild(); 01025 if (!start) 01026 return 0; 01027 /* if (!start->itemBelow()) 01028 return 0;*/ 01029 QString match = prefix.lower(); 01030 if ( match.length() < 1 ) 01031 return start; 01032 01033 QString current; 01034 QListViewItem *i = start; 01035 do { 01036 current = i->text(0).lower(); 01037 if ( current.startsWith( match ) ) 01038 return i; 01039 i = i->itemBelow(); 01040 if ( i ) 01041 i = listView()->firstChild(); 01042 } while ( i != start ); 01043 return 0; 01044 } 01045 01046 01047 int QComboView::sizeLimit() const 01048 { 01049 return d ? d->sizeLimit : INT_MAX; 01050 } 01051 01052 void QComboView::setSizeLimit( int lines ) 01053 { 01054 d->sizeLimit = lines; 01055 } 01056 01057 01058 /*int QComboView::maxCount() const 01059 { 01060 return d ? d->maxCount : INT_MAX; 01061 } 01062 01063 void QComboView::setMaxCount( int count ) 01064 { 01065 int l = this->count(); 01066 while( --l > count ) 01067 removeItem( l ); 01068 d->maxCount = count; 01069 } 01070 */ 01071 QComboView::Policy QComboView::insertionPolicy() const 01072 { 01073 return d->p; 01074 } 01075 01076 void QComboView::setInsertionPolicy( Policy policy ) 01077 { 01078 d->p = policy; 01079 } 01080 01081 01082 01087 void QComboView::returnPressed() 01088 { 01089 QString s( d->ed->text() ); 01090 01091 if ( s.isEmpty() ) 01092 return; 01093 01094 QListViewItem *c = 0; 01095 bool doInsert = TRUE; 01096 if ( !d->duplicatesEnabled ) { 01097 c = listView()->findItem(s, 0); 01098 if ( c ) 01099 doInsert = FALSE; 01100 } 01101 01102 if ( doInsert ) { 01103 if ( insertionPolicy() != NoInsertion ) { 01104 /* int cnt = count(); 01105 while ( cnt >= d->maxCount ) { 01106 removeItem( --cnt ); 01107 }*/ 01108 } 01109 01110 switch ( insertionPolicy() ) { 01111 case AtCurrent: 01112 if ( s != currentItem()->text(0) ) 01113 currentItem()->setText(0, s); 01114 emit activated( currentItem() ); 01115 emit activated( s ); 01116 return; 01117 case NoInsertion: 01118 emit activated( s ); 01119 return; 01120 case AtTop: 01121 c = 0; 01122 return; 01123 // break; 01124 case AtBottom: 01125 c = new QListViewItem(listView(), listView()->lastItem(), s); 01126 break; 01127 case BeforeCurrent: 01128 if (currentItem() && currentItem()->itemAbove()) 01129 c = new QListViewItem(listView(), currentItem()->itemAbove(), s); 01130 else 01131 { 01132 c = 0; 01133 return; 01134 } 01135 break; 01136 case AfterCurrent: 01137 if (currentItem() && currentItem()->itemBelow()) 01138 c = new QListViewItem(listView(), currentItem()->itemBelow(), s); 01139 else 01140 { 01141 c = 0; 01142 return; 01143 } 01144 break; 01145 } 01146 } 01147 01148 if (c) 01149 { 01150 setCurrentItem( c ); 01151 emit activated( c ); 01152 emit activated( s ); 01153 } 01154 } 01155 01156 01160 void QComboView::setEnabled( bool enable ) 01161 { 01162 QWidget::setEnabled( enable ); 01163 } 01164 01165 01166 01176 void QComboView::setValidator( const QValidator * v ) 01177 { 01178 if ( d && d->ed ) 01179 d->ed->setValidator( v ); 01180 } 01181 01182 01190 const QValidator * QComboView::validator() const 01191 { 01192 return d && d->ed ? d->ed->validator() : 0; 01193 } 01194 01195 01200 void QComboView::clearValidator() 01201 { 01202 if ( d && d->ed ) 01203 d->ed->setValidator( 0 ); 01204 } 01205 01206 01217 void QComboView::setListView( QListView * newListView ) 01218 { 01219 clear(); 01220 01221 delete d->listView(); 01222 01223 newListView->reparent( this, WType_Popup, QPoint(0,0), FALSE ); 01224 d->setListView( newListView ); 01225 d->listView()->setFont( font() ); 01226 d->listView()->setPalette( palette() ); 01227 /* d->listView()->setVScrollBarMode(QScrollView::AlwaysOff); 01228 d->listView()->setHScrollBarMode(QScrollView::AlwaysOff);*/ 01229 d->listView()->setFrameStyle( QFrame::Box | QFrame::Plain ); 01230 d->listView()->setLineWidth( 1 ); 01231 /* d->listView()->setRootIsDecorated( true ); 01232 d->listView()->setAllColumnsShowFocus(true);*/ 01233 d->listView()->resize( 100, 10 ); 01234 01235 if (d->listView()->firstChild()) 01236 d->current = d->listView()->firstChild(); 01237 01238 // d->listView()->header()->hide(); 01239 01240 01241 /* d->listView()->setFont( font() ); 01242 d->listView()->setPalette( palette() ); 01243 d->listView()->setVScrollBarMode( QScrollView::AlwaysOff ); 01244 d->listView()->setHScrollBarMode( QScrollView::AlwaysOff ); 01245 d->listView()->setFrameStyle( QFrame::Box | QFrame::Plain ); 01246 d->listView()->setLineWidth( 1 ); 01247 d->listView()->setRootIsDecorated( true ); 01248 d->listView()->setAllColumnsShowFocus(true); 01249 d->listView()->addColumn(""); 01250 d->listView()->resize( 100, 10 ); 01251 */ 01252 01253 connect( d->listView(), SIGNAL(returnPressed(QListViewItem*)), 01254 SLOT(internalActivate(QListViewItem*))); 01255 connect( d->listView(), SIGNAL(doubleClicked(QListViewItem*)), 01256 SLOT(internalActivate(QListViewItem*))); 01257 connect( d->listView(), SIGNAL(doubleClicked(QListViewItem*)), 01258 SLOT(checkState(QListViewItem*))); 01259 connect( d->listView(), SIGNAL(currentChanged(QListViewItem*)), 01260 SLOT(internalHighlight(QListViewItem*))); 01261 connect( d->listView(), SIGNAL(selectionChanged(QListViewItem*)), 01262 SLOT(internalHighlight(QListViewItem*))); 01263 } 01264 01265 01274 QListView * QComboView::listView() const 01275 { 01276 return d ? d->listView() : 0; 01277 } 01278 01284 QLineEdit* QComboView::lineEdit() const 01285 { 01286 return d->ed; 01287 } 01288 01289 01290 01303 void QComboView::clearEdit() 01304 { 01305 if ( d && d->ed ) 01306 d->ed->clear(); 01307 } 01308 01309 01321 void QComboView::setEditText( const QString &newText ) 01322 { 01323 if ( d && d->ed ) { 01324 d->updateLinedGeometry(); 01325 d->ed->setText( newText ); 01326 } 01327 } 01328 01329 void QComboView::setAutoCompletion( bool enable ) 01330 { 01331 d->useCompletion = enable; 01332 d->completeNow = FALSE; 01333 } 01334 01335 01336 bool QComboView::autoCompletion() const 01337 { 01338 return d->useCompletion; 01339 } 01340 01343 void QComboView::styleChange( QStyle& s ) 01344 { 01345 d->sizeHint = QSize(); // invalidate size hint... 01346 if ( d->ed ) 01347 d->updateLinedGeometry(); 01348 QWidget::styleChange( s ); 01349 } 01350 01351 bool QComboView::editable() const 01352 { 01353 return d->ed != 0; 01354 } 01355 01356 void QComboView::setEditable( bool y ) 01357 { 01358 if ( y == editable() ) 01359 return; 01360 if ( y ) { 01361 setUpListView(); 01362 setUpLineEdit(); 01363 d->ed->show(); 01364 if ( currentItem() ) 01365 setEditText( currentText() ); 01366 } else { 01367 delete d->ed; 01368 d->ed = 0; 01369 } 01370 01371 setFocusPolicy( StrongFocus ); 01372 updateGeometry(); 01373 update(); 01374 } 01375 01376 01377 void QComboView::setUpListView() 01378 { 01379 d->setListView( new QListView( this, "in-combo", WType_Popup ) ); 01380 01381 d->listView()->setFont( font() ); 01382 d->listView()->setPalette( palette() ); 01383 /* d->listView()->setVScrollBarMode( QScrollView::AlwaysOff ); 01384 d->listView()->setHScrollBarMode( QScrollView::AlwaysOff );*/ 01385 d->listView()->setFrameStyle( QFrame::Box | QFrame::Plain ); 01386 d->listView()->setLineWidth( 1 ); 01387 d->listView()->setRootIsDecorated( false ); 01388 d->listView()->setAllColumnsShowFocus(true); 01389 d->listView()->addColumn(""); 01390 d->listView()->resize( 100, 10 ); 01391 d->listView()->setResizeMode(QListView::LastColumn); 01392 01393 if (d->listView()->firstChild()) 01394 d->current = d->listView()->firstChild(); 01395 01396 d->listView()->header()->hide(); 01397 01398 connect( d->listView(), SIGNAL(returnPressed(QListViewItem*)), 01399 SLOT(internalActivate(QListViewItem*))); 01400 connect( d->listView(), SIGNAL(doubleClicked(QListViewItem*)), 01401 SLOT(internalActivate(QListViewItem*))); 01402 connect( d->listView(), SIGNAL(doubleClicked(QListViewItem*)), 01403 SLOT(checkState(QListViewItem*))); 01404 connect( d->listView(), SIGNAL(currentChanged(QListViewItem*)), 01405 SLOT(internalHighlight(QListViewItem*))); 01406 connect( d->listView(), SIGNAL(selectionChanged(QListViewItem*)), 01407 SLOT(internalHighlight(QListViewItem*))); 01408 } 01409 01410 01411 void QComboView::setUpLineEdit() 01412 { 01413 if ( !d->ed ) 01414 setLineEdit( new QLineEdit( this, "combo edit" ) ); 01415 } 01416 01421 void QComboView::setLineEdit( QLineEdit *edit ) 01422 { 01423 if ( !edit ) { 01424 #if defined(QT_CHECK_NULL) 01425 Q_ASSERT( edit != 0 ); 01426 #endif 01427 return; 01428 } 01429 01430 edit->setText( currentText() ); 01431 if ( d->ed ) { 01432 int start = 0, end = 0; 01433 d->ed->getSelection( &start, &end ); 01434 edit->setSelection( start, end ); 01435 edit->setCursorPosition( d->ed->cursorPosition() ); 01436 edit->setEdited( d->ed->edited() ); 01437 delete d->ed; 01438 } 01439 01440 d->ed = edit; 01441 01442 if ( edit->parent() != this ) { 01443 edit->reparent( this, QPoint(0,0), FALSE ); 01444 edit->setFont( font() ); 01445 } 01446 01447 connect (edit, SIGNAL( textChanged( const QString& ) ), 01448 this, SIGNAL( textChanged( const QString& ) ) ); 01449 connect( edit, SIGNAL(returnPressed()), SLOT(returnPressed()) ); 01450 01451 edit->setFrame( FALSE ); 01452 d->updateLinedGeometry(); 01453 edit->installEventFilter( this ); 01454 setFocusProxy( edit ); 01455 setFocusPolicy( StrongFocus ); 01456 01457 setUpListView(); 01458 01459 if ( isVisible() ) 01460 edit->show(); 01461 01462 updateGeometry(); 01463 update(); 01464 } 01465 01466 void QComboView::setCurrentText( const QString& txt ) 01467 { 01468 QListViewItem *i; 01469 i = listView()->findItem(txt, 0); 01470 if ( i ) 01471 setCurrentItem( i ); 01472 else if ( d->ed ) 01473 d->ed->setText( txt ); 01474 else if (currentItem()) 01475 currentItem()->setText(0, txt); 01476 } 01477 01478 void QComboView::checkState( QListViewItem * item) 01479 { 01480 item->setOpen(!item->isOpen()); 01481 } 01482 01483 void QComboView::setCurrentActiveItem( QListViewItem * item ) 01484 { 01485 if ( item == d->current && !d->ed ) { 01486 return; 01487 } 01488 01489 d->current = item; 01490 d->completeAt = 0; 01491 if ( d->ed ) { 01492 d->ed->setText( item->text(0) ); 01493 // qWarning("setCurrentActiveItem( %s )", item->text(0).latin1()); 01494 d->updateLinedGeometry(); 01495 } 01496 if ( d->listView() ) { 01497 d->listView()->setCurrentItem( item ); 01498 emit activated( item ); 01499 emit activated( item->text(0) ); 01500 } else { 01501 internalHighlight( item ); 01502 internalActivate( item ); 01503 } 01504 01505 currentChanged(); 01506 01507 d->listView()->ensureItemVisible(item); 01508 } 01509 01510 #include "qcomboview.moc" 01511 01512 #endif // QT_NO_COMBOBOX 01513
KDE Logo
This file is part of the documentation for KDevelop Version 3.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Oct 6 17:39:09 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003