00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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;
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
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 )
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
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
00239 d->updateLinedGeometry();
00240 }
00241 if ( d->listView() ) {
00242 d->listView()->setCurrentItem( item );
00243 } else {
00244 internalHighlight( item );
00245
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
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
00288
00289
00290
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
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
00326 d->updateLinedGeometry();
00327 }
00328 emit activated( item );
00329 emit activated( t );
00330
00331
00332 }
00333
00340 void QComboView::internalHighlight( QListViewItem * item )
00341 {
00342 if (!item)
00343 {
00344 d->current = 0;
00345 if ( d->ed ) {
00346
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();
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
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
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
00480
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 );
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
00537
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
00679 myChild = myChild->nextSibling();
00680 }
00681 return count;
00682 }
00683
00689 static int listHeight( QListView *l, int )
00690 {
00691
00692
00693
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
00709
00710 return prefH+2;
00711 }
00712
00719 void QComboView::popup()
00720 {
00721 if ( !childCount() )
00722 return;
00723
00724
00725 QListView* lb = d->listView();
00726 lb->triggerUpdate( );
00727 lb->installEventFilter( this );
00728 lb->viewport()->installEventFilter( this );
00729 d->mouseWasInsidePopup = FALSE;
00730
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();
00740 int sy = screen.y();
00741 int sw = screen.width();
00742 int sh = screen.height();
00743 QPoint pos = mapToGlobal( QPoint(0,height()) );
00744
00745 int x = pos.x();
00746 int y = pos.y();
00747
00748
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
00774 if ( currentLBItem && currentLBItem->isSelectable() && !currentLBItem->isSelected() )
00775 lb->setSelected( currentLBItem, TRUE );
00776 lb->blockSignals( block );
00777 lb->setVScrollBarMode(QScrollView::Auto);
00778
00779
00780
00781
00782
00783
00784
00785
00786
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
00906 QPoint pos = e->pos();
00907 if ( d->listView()->rect().contains( pos ) )
00908 d->mouseWasInsidePopup = TRUE;
00909
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
00932 QWidget *mouseW = QApplication::widgetAt( e->globalPos(), TRUE );
00933
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
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
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
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
01020
01021
01022
01023 if (!start)
01024 start = listView()->firstChild();
01025 if (!start)
01026 return 0;
01027
01028
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
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
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
01105
01106
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
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
01228
01229 d->listView()->setFrameStyle( QFrame::Box | QFrame::Plain );
01230 d->listView()->setLineWidth( 1 );
01231
01232
01233 d->listView()->resize( 100, 10 );
01234
01235 if (d->listView()->firstChild())
01236 d->current = d->listView()->firstChild();
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
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();
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
01384
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
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