# kdeui Library API Documentation

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

This file is part of the documentation for kdeui Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:20:14 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003