• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kdeui

kcombobox.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00020    Boston, MA 02110-1301, 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     // Set a default history size to something reasonable, Qt sets it to INT_MAX by default
00365     setMaxCount( 50 );
00366 
00367     if ( useCompletion )
00368         completionObject()->setOrder( KCompletion::Weighted );
00369 
00370     setInsertionPolicy( NoInsertion );
00371     myIterateIndex = -1;
00372     myRotated = false;
00373     myPixProvider = 0L;
00374 
00375     // obey HISTCONTROL setting
00376     QCString histControl = getenv("HISTCONTROL");
00377     if ( histControl == "ignoredups" || histControl == "ignoreboth" )
00378         setDuplicatesEnabled( false );
00379 
00380     connect( this, SIGNAL(aboutToShowContextMenu(QPopupMenu*)),
00381              SLOT(addContextMenuItems(QPopupMenu*)) );
00382     connect( this, SIGNAL( activated(int) ), SLOT( slotReset() ));
00383     connect( this, SIGNAL( returnPressed(const QString&) ), SLOT(slotReset()));
00384 }
00385 
00386 KHistoryCombo::~KHistoryCombo()
00387 {
00388     delete myPixProvider;
00389 }
00390 
00391 void KHistoryCombo::setHistoryItems( QStringList items,
00392                                      bool setCompletionList )
00393 {
00394     KComboBox::clear();
00395 
00396     // limit to maxCount()
00397     const int itemCount = items.count(); 
00398     const int toRemove = itemCount - maxCount();
00399 
00400     if (toRemove >= itemCount) {
00401         items.clear();
00402     } else {
00403         for (int i = 0; i < toRemove; ++i) 
00404             items.pop_front();
00405     }
00406 
00407     insertItems( items );
00408 
00409     if ( setCompletionList && useCompletion() ) {
00410         // we don't have any weighting information here ;(
00411         KCompletion *comp = completionObject();
00412         comp->setOrder( KCompletion::Insertion );
00413         comp->setItems( items );
00414         comp->setOrder( KCompletion::Weighted );
00415     }
00416 
00417     clearEdit();
00418 }
00419 
00420 QStringList KHistoryCombo::historyItems() const
00421 {
00422     QStringList list;
00423     const int itemCount = count();
00424     for ( int i = 0; i < itemCount; ++i )
00425         list.append( text( i ) );
00426 
00427     return list;
00428 }
00429 
00430 void KHistoryCombo::clearHistory()
00431 {
00432     const QString temp = currentText();
00433     KComboBox::clear();
00434     if ( useCompletion() )
00435         completionObject()->clear();
00436     setEditText( temp );
00437 }
00438 
00439 void KHistoryCombo::addContextMenuItems( QPopupMenu* menu )
00440 {
00441     if ( menu )
00442     {
00443         menu->insertSeparator();
00444         int id = menu->insertItem( SmallIconSet("history_clear"), i18n("Clear &History"), this, SLOT( slotClear()));
00445         if (!count())
00446            menu->setItemEnabled(id, false);
00447     }
00448 }
00449 
00450 void KHistoryCombo::addToHistory( const QString& item )
00451 {
00452     if ( item.isEmpty() || (count() > 0 && item == text(0) )) {
00453         return;
00454     }
00455 
00456     bool wasCurrent = false;
00457     // remove all existing items before adding
00458     if ( !duplicatesEnabled() ) {
00459         int i = 0;
00460         int itemCount = count();
00461         while ( i < itemCount ) {
00462             if ( text( i ) == item ) {
00463                 if ( !wasCurrent )
00464                   wasCurrent = ( i == currentItem() );
00465                 removeItem( i );
00466                 --itemCount;
00467             } else {
00468                 ++i;
00469             }
00470         }
00471     }
00472 
00473     // now add the item
00474     if ( myPixProvider )
00475         insertItem( myPixProvider->pixmapFor(item, KIcon::SizeSmall), item, 0);
00476     else
00477         insertItem( item, 0 );
00478 
00479     if ( wasCurrent )
00480         setCurrentItem( 0 );
00481 
00482     const bool useComp = useCompletion();
00483 
00484     const int last = count() - 1; // last valid index
00485     const int mc = maxCount();
00486     const int stopAt = QMAX(mc, 0);
00487 
00488     for (int rmIndex = last; rmIndex >= stopAt; --rmIndex) {
00489         // remove the last item, as long as we are longer than maxCount()
00490         // remove the removed item from the completionObject if it isn't
00491         // anymore available at all in the combobox.
00492         const QString rmItem = text( rmIndex );
00493         removeItem( rmIndex );
00494         if ( useComp && !contains( rmItem ) )
00495             completionObject()->removeItem( rmItem );
00496     }
00497 
00498     if ( useComp )
00499         completionObject()->addItem( item );
00500 }
00501 
00502 bool KHistoryCombo::removeFromHistory( const QString& item )
00503 {
00504     if ( item.isEmpty() )
00505         return false;
00506 
00507     bool removed = false;
00508     const QString temp = currentText();
00509     int i = 0;
00510     int itemCount = count();
00511     while ( i < itemCount ) {
00512         if ( item == text( i ) ) {
00513             removed = true;
00514             removeItem( i );
00515             --itemCount;
00516         } else {
00517             ++i;
00518         }
00519     }
00520 
00521     if ( removed && useCompletion() )
00522         completionObject()->removeItem( item );
00523 
00524     setEditText( temp );
00525     return removed;
00526 }
00527 
00528 void KHistoryCombo::rotateUp()
00529 {
00530     // save the current text in the lineedit
00531     if ( myIterateIndex == -1 )
00532         myText = currentText();
00533 
00534     ++myIterateIndex;
00535 
00536     // skip duplicates/empty items
00537     const int last = count() - 1; // last valid index
00538     const QString currText = currentText();
00539 
00540     while ( myIterateIndex < last &&
00541             (currText == text( myIterateIndex ) ||
00542              text( myIterateIndex ).isEmpty()) )
00543         ++myIterateIndex;
00544 
00545     if ( myIterateIndex >= count() ) {
00546         myRotated = true;
00547         myIterateIndex = -1;
00548 
00549         // if the typed text is the same as the first item, skip the first
00550         if ( count() > 0 && myText == text(0) )
00551             myIterateIndex = 0;
00552 
00553         setEditText( myText );
00554     }
00555     else
00556         setEditText( text( myIterateIndex ));
00557 }
00558 
00559 void KHistoryCombo::rotateDown()
00560 {
00561     // save the current text in the lineedit
00562     if ( myIterateIndex == -1 )
00563         myText = currentText();
00564 
00565     --myIterateIndex;
00566 
00567     const QString currText = currentText();
00568     // skip duplicates/empty items
00569     while ( myIterateIndex >= 0 &&
00570             (currText == text( myIterateIndex ) ||
00571              text( myIterateIndex ).isEmpty()) )
00572         --myIterateIndex;
00573 
00574 
00575     if ( myIterateIndex < 0 ) {
00576         if ( myRotated && myIterateIndex == -2 ) {
00577             myRotated = false;
00578             myIterateIndex = count() - 1;
00579             setEditText( text(myIterateIndex) );
00580         }
00581         else { // bottom of history
00582             if ( myIterateIndex == -2 ) {
00583                 KNotifyClient::event( (int)winId(), KNotifyClient::notification,
00584                                       i18n("No further item in the history."));
00585             }
00586 
00587             myIterateIndex = -1;
00588             if ( currentText() != myText )
00589                 setEditText( myText );
00590         }
00591     }
00592     else
00593         setEditText( text( myIterateIndex ));
00594 
00595 }
00596 
00597 void KHistoryCombo::keyPressEvent( QKeyEvent *e )
00598 {
00599     KKey event_key( e );
00600 
00601     // going up in the history, rotating when reaching QListBox::count()
00602     if ( KStdAccel::rotateUp().contains(event_key) )
00603         rotateUp();
00604 
00605     // going down in the history, no rotation possible. Last item will be
00606     // the text that was in the lineedit before Up was called.
00607     else if ( KStdAccel::rotateDown().contains(event_key) )
00608         rotateDown();
00609     else
00610         KComboBox::keyPressEvent( e );
00611 }
00612 
00613 void KHistoryCombo::wheelEvent( QWheelEvent *ev )
00614 {
00615     // Pass to poppable listbox if it's up
00616     QListBox* const lb = listBox();
00617     if ( lb && lb->isVisible() )
00618     {
00619         QApplication::sendEvent( lb, ev );
00620         return;
00621     }
00622     // Otherwise make it change the text without emitting activated
00623     if ( ev->delta() > 0 ) {
00624         rotateUp();
00625     } else {
00626         rotateDown();
00627     }
00628     ev->accept();
00629 }
00630 
00631 void KHistoryCombo::slotReset()
00632 {
00633     myIterateIndex = -1;
00634     myRotated = false;
00635 }
00636 
00637 
00638 void KHistoryCombo::setPixmapProvider( KPixmapProvider *prov )
00639 {
00640     if ( myPixProvider == prov )
00641         return;
00642 
00643     delete myPixProvider;
00644     myPixProvider = prov;
00645 
00646     // re-insert all the items with/without pixmap
00647     // I would prefer to use changeItem(), but that doesn't honor the pixmap
00648     // when using an editable combobox (what we do)
00649     if ( count() > 0 ) {
00650         QStringList items( historyItems() );
00651         clear();
00652         insertItems( items );
00653     }
00654 }
00655 
00656 void KHistoryCombo::insertItems( const QStringList& items )
00657 {
00658     QStringList::ConstIterator it = items.constBegin();
00659     const QStringList::ConstIterator itEnd = items.constEnd();
00660 
00661     while ( it != itEnd ) {
00662         const QString item = *it;
00663         if ( !item.isEmpty() ) { // only insert non-empty items
00664             if ( myPixProvider )
00665                 insertItem( myPixProvider->pixmapFor(item, KIcon::SizeSmall),
00666                             item );
00667             else
00668                 insertItem( item );
00669         }
00670         ++it;
00671     }
00672 }
00673 
00674 void KHistoryCombo::slotClear()
00675 {
00676     clearHistory();
00677     emit cleared();
00678 }
00679 
00680 void KComboBox::virtual_hook( int id, void* data )
00681 { KCompletionBase::virtual_hook( id, data ); }
00682 
00683 void KHistoryCombo::virtual_hook( int id, void* data )
00684 { KComboBox::virtual_hook( id, data ); }
00685 
00686 #include "kcombobox.moc"

kdeui

Skip menu "kdeui"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal