KDevelop API Documentation

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+2;
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.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 23 00:03:53 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003