kdeui Library API Documentation

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