kcombobox.cpp Source File (kdeui Library)

| # kdeui Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kcombobox.cpp

    00001 /* This file is part of the KDE libraries
    00002
    00003    Copyright (c) 2000,2001 Dawit Alemayehu <adawit@kde.org>
    00004    Copyright (c) 2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
    00005    Copyright (c) 2000 Stefan Schimanski <1Stein@gmx.de>
    00006
    00007    This library is free software; you can redistribute it and/or
    00008    modify it under the terms of the GNU Lesser General Public
    00009    License (LGPL) as published by the Free Software Foundation; either
    00010    version 2 of the License, or (at your option) any later version.
    00011
    00012    This library is distributed in the hope that it will be useful,
    00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00015    Lesser General Public License for more details.
    00016
    00017    You should have received a copy of the GNU Lesser General Public License
    00018    along with this library; see the file COPYING.LIB.  If not, write to
    00019    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00020    Boston, MA 02111-1307, USA.
    00021 */
    00022
    00023 #include <stdlib.h>
    00024
    00025 #include <qclipboard.h>
    00026 #include <qlistbox.h>
    00027 #include <qpopupmenu.h>
    00028 #include <qapplication.h>
    00029
    00030 #include <kcompletionbox.h>
    00031 #include <kcursor.h>
    00032 #include <kiconloader.h>
    00033 #include <kicontheme.h>
    00034 #include <klineedit.h>
    00035 #include <klocale.h>
    00036 #include <knotifyclient.h>
    00037 #include <kpixmapprovider.h>
    00038 #include <kstdaccel.h>
    00039 #include <kurl.h>
    00040 #include <kurldrag.h>
    00041
    00042 #include <kdebug.h>
    00043
    00044 #include "kcombobox.h"
    00045
    00046 class KComboBox::KComboBoxPrivate
    00047 {
    00048 public:
    00049     KComboBoxPrivate()
    00050     {
    00051         klineEdit = 0L;
    00052     }
    00053     ~KComboBoxPrivate()
    00054     {
    00055     }
    00056
    00057     KLineEdit *klineEdit;
    00058 };
    00059
    00060 KComboBox::KComboBox( QWidget *parent, const char *name )
    00061     : QComboBox( parent, name )
    00062 {
    00063     init();
    00064 }
    00065
    00066 KComboBox::KComboBox( bool rw, QWidget *parent, const char *name )
    00067     : QComboBox( rw, parent, name )
    00068 {
    00069     init();
    00070
    00071     if ( rw )
    00072     {
    00073         KLineEdit *edit = new KLineEdit( this, "combo lineedit" );
    00074         setLineEdit( edit );
    00075     }
    00076 }
    00077
    00078 KComboBox::~KComboBox()
    00079 {
    00080     delete d;
    00081 }
    00082
    00083 void KComboBox::init()
    00084 {
    00085     d = new KComboBoxPrivate;
    00086
    00087     // Permanently set some parameters in the parent object.
    00088     QComboBox::setAutoCompletion( false );
    00089
    00090     // Enable context menu by default if widget
    00091     // is editable.
    00092     setContextMenuEnabled( true );
    00093
    00094     // for wheelscrolling
    00095     installEventFilter( this );
    00096     if ( lineEdit() )
    00097     {
    00098         connect( lineEdit(), SIGNAL( returnPressed() ),
    00099                  this, SIGNAL( returnPressed() ));
    00100     }
    00101 }
    00102
    00103
    00104 bool KComboBox::contains( const QString& _text ) const
    00105 {
    00106     if ( _text.isEmpty() )
    00107         return false;
    00108
    00109     for (int i = 0; i < count(); i++ )
    00110     {
    00111         if ( text(i) == _text )
    00112             return true;
    00113     }
    00114     return false;
    00115 }
    00116
    00117 void KComboBox::setAutoCompletion( bool autocomplete )
    00118 {
    00119     if ( d->klineEdit )
    00120     {
    00121         if ( autocomplete )
    00122         {
    00123             d->klineEdit->setCompletionMode( KGlobalSettings::CompletionAuto );
    00124             setCompletionMode( KGlobalSettings::CompletionAuto );
    00125         }
    00126         else
    00127         {
    00128             d->klineEdit->setCompletionMode( KGlobalSettings::completionMode() );
    00129             setCompletionMode( KGlobalSettings::completionMode() );
    00130         }
    00131     }
    00132 }
    00133
    00134 void KComboBox::setContextMenuEnabled( bool showMenu )
    00135 {
    00136     if( d->klineEdit )
    00137         d->klineEdit->setContextMenuEnabled( showMenu );
    00138 }
    00139
    00140
    00141 void KComboBox::setURLDropsEnabled( bool enable )
    00142 {
    00143     if ( d->klineEdit )
    00144         d->klineEdit->setURLDropsEnabled( enable );
    00145 }
    00146
    00147 bool KComboBox::isURLDropsEnabled() const
    00148 {
    00149     return d->klineEdit && d->klineEdit->isURLDropsEnabled();
    00150 }
    00151
    00152
    00153 void KComboBox::setCompletedText( const QString& text, bool marked )
    00154 {
    00155     if ( d->klineEdit )
    00156         d->klineEdit->setCompletedText( text, marked );
    00157 }
    00158
    00159 void KComboBox::setCompletedText( const QString& text )
    00160 {
    00161     if ( d->klineEdit )
    00162         d->klineEdit->setCompletedText( text );
    00163 }
    00164
    00165 void KComboBox::makeCompletion( const QString& text )
    00166 {
    00167     if( d->klineEdit )
    00168         d->klineEdit->makeCompletion( text );
    00169
    00170     else // read-only combo completion
    00171     {
    00172         if( text.isNull() || !listBox() )
    00173             return;
    00174
    00175         int index = listBox()->index( listBox()->findItem( text ) );
    00176         if( index >= 0 )
    00177             setCurrentItem( index );
    00178     }
    00179 }
    00180
    00181 void KComboBox::rotateText( KCompletionBase::KeyBindingType type )
    00182 {
    00183     if ( d->klineEdit )
    00184         d->klineEdit->rotateText( type );
    00185 }
    00186
    00187 // not needed anymore
    00188 bool KComboBox::eventFilter( QObject* o, QEvent* ev )
    00189 {
    00190     return QComboBox::eventFilter( o, ev );
    00191 }
    00192
    00193 void KComboBox::setTrapReturnKey( bool grab )
    00194 {
    00195     if ( d->klineEdit )
    00196         d->klineEdit->setTrapReturnKey( grab );
    00197     else
    00198         qWarning("KComboBox::setTrapReturnKey not supported with a non-KLineEdit.");
    00199 }
    00200
    00201 bool KComboBox::trapReturnKey() const
    00202 {
    00203     return d->klineEdit && d->klineEdit->trapReturnKey();
    00204 }
    00205
    00206
    00207 void KComboBox::setEditURL( const KURL& url )
    00208 {
    00209     QComboBox::setEditText( url.prettyURL() );
    00210 }
    00211
    00212 void KComboBox::insertURL( const KURL& url, int index )
    00213 {
    00214     QComboBox::insertItem( url.prettyURL(), index );
    00215 }
    00216
    00217 void KComboBox::insertURL( const QPixmap& pixmap, const KURL& url, int index )
    00218 {
    00219     QComboBox::insertItem( pixmap, url.prettyURL(), index );
    00220 }
    00221
    00222 void KComboBox::changeURL( const KURL& url, int index )
    00223 {
    00224     QComboBox::changeItem( url.prettyURL(), index );
    00225 }
    00226
    00227 void KComboBox::changeURL( const QPixmap& pixmap, const KURL& url, int index )
    00228 {
    00229     QComboBox::changeItem( pixmap, url.prettyURL(), index );
    00230 }
    00231
    00232 void KComboBox::setCompletedItems( const QStringList& items )
    00233 {
    00234     if ( d->klineEdit )
    00235         d->klineEdit->setCompletedItems( items );
    00236 }
    00237
    00238 KCompletionBox * KComboBox::completionBox( bool create )
    00239 {
    00240     if ( d->klineEdit )
    00241         return d->klineEdit->completionBox( create );
    00242     return 0;
    00243 }
    00244
    00245 // QWidget::create() turns off mouse-Tracking which would break auto-hiding
    00246 void KComboBox::create( WId id, bool initializeWindow, bool destroyOldWindow )
    00247 {
    00248     QComboBox::create( id, initializeWindow, destroyOldWindow );
    00249     KCursor::setAutoHideCursor( lineEdit(), true, true );
    00250 }
    00251
    00252 void KComboBox::wheelEvent( QWheelEvent *ev )
    00253 {
    00254     // Not necessary anymore
    00255     QComboBox::wheelEvent( ev );
    00256 }
    00257
    00258 void KComboBox::setLineEdit( QLineEdit *edit )
    00259 {
    00260     if ( !editable() && edit &&
    00261          qstrcmp( edit->className(), "QLineEdit" ) == 0 )
    00262     {
    00263         // uic generates code that creates a read-only QComboBox and then
    00264         // calls combo->setEditable( true ), which causes QComboBox to set up
    00265         // a dumb QLineEdit instead of our nice KLineEdit.
    00266         // As some KComboBox features rely on the KLineEdit, we reject
    00267         // this order here.
    00268         delete edit;
    00269         edit = new KLineEdit( this, "combo edit" );
    00270     }
    00271
    00272     QComboBox::setLineEdit( edit );
    00273     d->klineEdit = dynamic_cast<KLineEdit*>( edit );
    00274     setDelegate( d->klineEdit );
    00275
    00276     // forward some signals.
    00277     if ( edit )
    00278         connect( edit, SIGNAL( returnPressed() ), SIGNAL( returnPressed() ));
    00279
    00280     if ( d->klineEdit )
    00281     {
    00282         // someone calling KComboBox::setEditable( false ) destroys our
    00283         // lineedit without us noticing. And KCompletionBase::delegate would
    00284         // be a dangling pointer then, so prevent that. Note: only do this
    00285         // when it is a KLineEdit!
    00286         connect( edit, SIGNAL( destroyed() ), SLOT( lineEditDeleted() ));
    00287
    00288         connect( d->klineEdit, SIGNAL( returnPressed( const QString& )),
    00289                  SIGNAL( returnPressed( const QString& ) ));
    00290
    00291         connect( d->klineEdit, SIGNAL( completion( const QString& )),
    00292                  SIGNAL( completion( const QString& )) );
    00293
    00294         connect( d->klineEdit, SIGNAL( substringCompletion( const QString& )),
    00295                  SIGNAL( substringCompletion( const QString& )) );
    00296
    00297         connect( d->klineEdit,
    00298                  SIGNAL( textRotation( KCompletionBase::KeyBindingType )),
    00299                  SIGNAL( textRotation( KCompletionBase::KeyBindingType )) );
    00300
    00301         connect( d->klineEdit,
    00302                  SIGNAL( completionModeChanged( KGlobalSettings::Completion )),
    00303                  SIGNAL( completionModeChanged( KGlobalSettings::Completion)));
    00304
    00305         connect( d->klineEdit,
    00306                  SIGNAL( aboutToShowContextMenu( QPopupMenu * )),
    00307                  SIGNAL( aboutToShowContextMenu( QPopupMenu * )) );
    00308
    00309         connect( d->klineEdit,
    00310                  SIGNAL( completionBoxActivated( const QString& )),
    00311                  SIGNAL( activated( const QString& )) );
    00312     }
    00313 }
    00314
    00315 void KComboBox::setCurrentItem( const QString& item, bool insert, int index )
    00316 {
    00317     int sel = -1;
    00318
    00319     for (int i = 0; i < count(); ++i)
    00320     {
    00321         if (text(i) == item)
    00322         {
    00323             sel = i;
    00324             break;
    00325         }
    00326     }
    00327
    00328     if (sel == -1 && insert)
    00329     {
    00330         insertItem(item, index);
    00331         if (index >= 0)
    00332             sel = index;
    00333         else
    00334             sel = count() - 1;
    00335     }
    00336     setCurrentItem(sel);
    00337 }
    00338
    00339 void KComboBox::lineEditDeleted()
    00340 {
    00341     // yes, we need those ugly casts due to the multiple inheritance
    00342     // sender() is guaranteed to be a KLineEdit (see the connect() to the
    00343     // destroyed() signal
    00344     const KCompletionBase *base = static_cast<const KCompletionBase*>( static_cast<const KLineEdit*>( sender() ));
    00345
    00346     // is it our delegate, that is destroyed?
    00347     if ( base == delegate() )
    00348         setDelegate( 0L );
    00349 }
    00350
    00351 // *********************************************************************
    00352 // *********************************************************************
    00353
    00354
    00355 // we are always read-write
    00356 KHistoryCombo::KHistoryCombo( QWidget *parent, const char *name )
    00357     : KComboBox( true, parent, name )
    00358 {
    00359     init( true ); // using completion
    00360 }
    00361
    00362 // we are always read-write
    00363 KHistoryCombo::KHistoryCombo( bool useCompletion,
    00364                               QWidget *parent, const char *name )
    00365     : KComboBox( true, parent, name )
    00366 {
    00367     init( useCompletion );
    00368 }
    00369
    00370 void KHistoryCombo::init( bool useCompletion )
    00371 {
    00372     if ( useCompletion )
    00373         completionObject()->setOrder( KCompletion::Weighted );
    00374
    00375     setInsertionPolicy( NoInsertion );
    00376     myIterateIndex = -1;
    00377     myRotated = false;
    00378     myPixProvider = 0L;
    00379
    00380     // obey HISTCONTROL setting
    00381     QCString histControl = getenv("HISTCONTROL");
    00382     if ( histControl == "ignoredups" || histControl == "ignoreboth" )
    00383         setDuplicatesEnabled( false );
    00384
    00385     connect( this, SIGNAL(aboutToShowContextMenu(QPopupMenu*)),
    00386              SLOT(addContextMenuItems(QPopupMenu*)) );
    00387     connect( this, SIGNAL( activated(int) ), SLOT( slotReset() ));
    00388     connect( this, SIGNAL( returnPressed(const QString&) ), SLOT(slotReset()));
    00389 }
    00390
    00391 KHistoryCombo::~KHistoryCombo()
    00392 {
    00393     delete myPixProvider;
    00394 }
    00395
    00396 void KHistoryCombo::setHistoryItems( QStringList items,
    00397                                      bool setCompletionList )
    00398 {
    00399     KComboBox::clear();
    00400
    00401     // limit to maxCount()
    00402     while ( (int) items.count() > maxCount() && !items.isEmpty() )
    00403         items.remove( items.begin() );
    00404
    00405     insertItems( items );
    00406
    00407     if ( setCompletionList && useCompletion() ) {
    00408         // we don't have any weighting information here ;(
    00409         KCompletion *comp = completionObject();
    00410         comp->setOrder( KCompletion::Insertion );
    00411         comp->setItems( items );
    00412         comp->setOrder( KCompletion::Weighted );
    00413     }
    00414
    00415     clearEdit();
    00416 }
    00417
    00418 QStringList KHistoryCombo::historyItems() const
    00419 {
    00420     QStringList list;
    00421     for ( int i = 0; i < count(); i++ )
    00422         list.append( text( i ) );
    00423
    00424     return list;
    00425 }
    00426
    00427 void KHistoryCombo::clearHistory()
    00428 {
    00429     KComboBox::clear();
    00430     if ( useCompletion() )
    00431         completionObject()->clear();
    00432 }
    00433
    00434 void KHistoryCombo::addContextMenuItems( QPopupMenu* menu )
    00435 {
    00436     if ( menu &&!lineEdit()->text().isEmpty())
    00437     {
    00438         menu->insertSeparator();
    00439         menu->insertItem( i18n("Empty Contents"), this, SLOT( slotClear()));
    00440     }
    00441 }
    00442
    00443 void KHistoryCombo::addToHistory( const QString& item )
    00444 {
    00445     if ( item.isEmpty() || (count() > 0 && item == text(0) )) {
    00446         return;
    00447     }
    00448
    00449     bool wasCurrent = false;
    00450     // remove all existing items before adding
    00451     if ( !duplicatesEnabled() ) {
    00452         for ( int i = 0; i < count(); i++ ) {
    00453             if ( text( i ) == item ) {
    00454                 if ( !wasCurrent )
    00455                   wasCurrent = ( i == currentItem() );
    00456                 removeItem( i );
    00457             }
    00458         }
    00459     }
    00460
    00461     // now add the item
    00462     if ( myPixProvider )
    00463         insertItem( myPixProvider->pixmapFor(item, KIcon::SizeSmall), item, 0);
    00464     else
    00465         insertItem( item, 0 );
    00466
    00467     if ( wasCurrent )
    00468         setCurrentItem( 0 );
    00469
    00470     int last;
    00471     QString rmItem;
    00472
    00473     bool useComp = useCompletion();
    00474     while ( count() > maxCount() && count() > 0 ) {
    00475         // remove the last item, as long as we are longer than maxCount()
    00476         // remove the removed item from the completionObject if it isn't
    00477         // anymore available at all in the combobox.
    00478         last = count() - 1;
    00479         rmItem = text( last );
    00480         removeItem( last );
    00481         if ( useComp && !contains( rmItem ) )
    00482             completionObject()->removeItem( rmItem );
    00483     }
    00484
    00485     if ( useComp )
    00486         completionObject()->addItem( item );
    00487 }
    00488
    00489 bool KHistoryCombo::removeFromHistory( const QString& item )
    00490 {
    00491     if ( item.isEmpty() )
    00492         return false;
    00493
    00494     bool removed = false;
    00495     QString temp = currentText();
    00496     for ( int i = 0; i < count(); i++ ) {
    00497         while ( item == text( i ) ) {
    00498             removed = true;
    00499             removeItem( i );
    00500         }
    00501     }
    00502
    00503     if ( removed && useCompletion() )
    00504         completionObject()->removeItem( item );
    00505
    00506     setEditText( temp );
    00507     return removed;
    00508 }
    00509
    00510 void KHistoryCombo::rotateUp()
    00511 {
    00512     // save the current text in the lineedit
    00513     if ( myIterateIndex == -1 )
    00514         myText = currentText();
    00515
    00516     myIterateIndex++;
    00517
    00518     // skip duplicates/empty items
    00519     while ( myIterateIndex < count()-1 &&
    00520             (currentText() == text( myIterateIndex ) ||
    00521              text( myIterateIndex ).isEmpty()) )
    00522         myIterateIndex++;
    00523
    00524     if ( myIterateIndex >= count() ) {
    00525         myRotated = true;
    00526         myIterateIndex = -1;
    00527
    00528         // if the typed text is the same as the first item, skip the first
    00529         if ( myText == text(0) )
    00530             myIterateIndex = 0;
    00531
    00532         setEditText( myText );
    00533     }
    00534     else
    00535         setEditText( text( myIterateIndex ));
    00536 }
    00537
    00538 void KHistoryCombo::rotateDown()
    00539 {
    00540     // save the current text in the lineedit
    00541     if ( myIterateIndex == -1 )
    00542         myText = currentText();
    00543
    00544     myIterateIndex--;
    00545
    00546     // skip duplicates/empty items
    00547     while ( myIterateIndex >= 0 &&
    00548             (currentText() == text( myIterateIndex ) ||
    00549              text( myIterateIndex ).isEmpty()) )
    00550         myIterateIndex--;
    00551
    00552
    00553     if ( myIterateIndex < 0 ) {
    00554         if ( myRotated && myIterateIndex == -2 ) {
    00555             myRotated = false;
    00556             myIterateIndex = count() - 1;
    00557             setEditText( text(myIterateIndex) );
    00558         }
    00559         else { // bottom of history
    00560             if ( myIterateIndex == -2 ) {
    00561                 KNotifyClient::event( KNotifyClient::notification,
    00562                                       i18n("No further item in the history."));
    00563             }
    00564
    00565             myIterateIndex = -1;
    00566             if ( currentText() != myText )
    00567                 setEditText( myText );
    00568         }
    00569     }
    00570     else
    00571         setEditText( text( myIterateIndex ));
    00572
    00573 }
    00574
    00575 void KHistoryCombo::keyPressEvent( QKeyEvent *e )
    00576 {
    00577     // going up in the history, rotating when reaching QListBox::count()
    00578     if ( KStdAccel::isEqual( e, KStdAccel::rotateUp() ) ) {
    00579         rotateUp();
    00580     }
    00581     // going down in the history, no rotation possible. Last item will be
    00582     // the text that was in the lineedit before Up was called.
    00583     else if ( KStdAccel::isEqual( e, KStdAccel::rotateDown() ) ) {
    00584         rotateDown();
    00585     }
    00586     else
    00587         KComboBox::keyPressEvent( e );
    00588 }
    00589
    00590 void KHistoryCombo::wheelEvent( QWheelEvent *ev )
    00591 {
    00592     // Pass to poppable listbox if it's up
    00593     QListBox *lb = listBox();
    00594     if ( lb && lb->isVisible() )
    00595     {
    00596         QApplication::sendEvent( lb, ev );
    00597         return;
    00598     }
    00599     // Otherwise make it change the text without emitting activated
    00600     if ( ev->delta() > 0 ) {
    00601         rotateUp();
    00602     } else {
    00603         rotateDown();
    00604     }
    00605     ev->accept();
    00606 }
    00607
    00608 void KHistoryCombo::slotReset()
    00609 {
    00610     myIterateIndex = -1;
    00611     myRotated = false;
    00612 }
    00613
    00614
    00615 void KHistoryCombo::setPixmapProvider( KPixmapProvider *prov )
    00616 {
    00617     if ( myPixProvider == prov )
    00618         return;
    00619
    00620     delete myPixProvider;
    00621     myPixProvider = prov;
    00622
    00623     // re-insert all the items with/without pixmap
    00624     // I would prefer to use changeItem(), but that doesn't honour the pixmap
    00625     // when using an editable combobox (what we do)
    00626     if ( count() > 0 ) {
    00627         QStringList items( historyItems() );
    00628         clear();
    00629         insertItems( items );
    00630     }
    00631 }
    00632
    00633 void KHistoryCombo::insertItems( const QStringList& items )
    00634 {
    00635     QStringList::ConstIterator it = items.begin();
    00636     QString item;
    00637     while ( it != items.end() ) {
    00638         item = *it;
    00639         if ( !item.isEmpty() ) { // only insert non-empty items
    00640             if ( myPixProvider )
    00641                 insertItem( myPixProvider->pixmapFor(item, KIcon::SizeSmall),
    00642                             item );
    00643             else
    00644                 insertItem( item );
    00645         }
    00646         ++it;
    00647     }
    00648 }
    00649
    00650 void KHistoryCombo::slotClear()
    00651 {
    00652     clearHistory();
    00653     emit cleared();
    00654 }
    00655
    00656 void KComboBox::virtual_hook( int id, void* data )
    00657 { KCompletionBase::virtual_hook( id, data ); }
    00658
    00659 void KHistoryCombo::virtual_hook( int id, void* data )
    00660 { KComboBox::virtual_hook( id, data ); }
    00661
    00662 #include "kcombobox.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:56:22 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001