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 } 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 } 00097 00098 00099 bool KComboBox::contains( const QString& _text ) const 00100 { 00101 if ( _text.isEmpty() ) 00102 return false; 00103 00104 for (int i = 0; i < count(); i++ ) 00105 { 00106 if ( text(i) == _text ) 00107 return true; 00108 } 00109 return false; 00110 } 00111 00112 void KComboBox::setAutoCompletion( bool autocomplete ) 00113 { 00114 if ( d->klineEdit ) 00115 { 00116 if ( autocomplete ) 00117 { 00118 d->klineEdit->setCompletionMode( KGlobalSettings::CompletionAuto ); 00119 setCompletionMode( KGlobalSettings::CompletionAuto ); 00120 } 00121 else 00122 { 00123 d->klineEdit->setCompletionMode( KGlobalSettings::completionMode() ); 00124 setCompletionMode( KGlobalSettings::completionMode() ); 00125 } 00126 } 00127 } 00128 00129 void KComboBox::setContextMenuEnabled( bool showMenu ) 00130 { 00131 if( d->klineEdit ) 00132 d->klineEdit->setContextMenuEnabled( showMenu ); 00133 } 00134 00135 00136 void KComboBox::setURLDropsEnabled( bool enable ) 00137 { 00138 if ( d->klineEdit ) 00139 d->klineEdit->setURLDropsEnabled( enable ); 00140 } 00141 00142 bool KComboBox::isURLDropsEnabled() const 00143 { 00144 return d->klineEdit && d->klineEdit->isURLDropsEnabled(); 00145 } 00146 00147 00148 void KComboBox::setCompletedText( const QString& text, bool marked ) 00149 { 00150 if ( d->klineEdit ) 00151 d->klineEdit->setCompletedText( text, marked ); 00152 } 00153 00154 void KComboBox::setCompletedText( const QString& text ) 00155 { 00156 if ( d->klineEdit ) 00157 d->klineEdit->setCompletedText( text ); 00158 } 00159 00160 void KComboBox::makeCompletion( const QString& text ) 00161 { 00162 if( d->klineEdit ) 00163 d->klineEdit->makeCompletion( text ); 00164 00165 else // read-only combo completion 00166 { 00167 if( text.isNull() || !listBox() ) 00168 return; 00169 00170 int index = listBox()->index( listBox()->findItem( text ) ); 00171 if( index >= 0 ) 00172 setCurrentItem( index ); 00173 } 00174 } 00175 00176 void KComboBox::rotateText( KCompletionBase::KeyBindingType type ) 00177 { 00178 if ( d->klineEdit ) 00179 d->klineEdit->rotateText( type ); 00180 } 00181 00182 // not needed anymore 00183 bool KComboBox::eventFilter( QObject* o, QEvent* ev ) 00184 { 00185 return QComboBox::eventFilter( o, ev ); 00186 } 00187 00188 void KComboBox::setTrapReturnKey( bool grab ) 00189 { 00190 if ( d->klineEdit ) 00191 d->klineEdit->setTrapReturnKey( grab ); 00192 else 00193 qWarning("KComboBox::setTrapReturnKey not supported with a non-KLineEdit."); 00194 } 00195 00196 bool KComboBox::trapReturnKey() const 00197 { 00198 return d->klineEdit && d->klineEdit->trapReturnKey(); 00199 } 00200 00201 00202 void KComboBox::setEditURL( const KURL& url ) 00203 { 00204 QComboBox::setEditText( url.prettyURL() ); 00205 } 00206 00207 void KComboBox::insertURL( const KURL& url, int index ) 00208 { 00209 QComboBox::insertItem( url.prettyURL(), index ); 00210 } 00211 00212 void KComboBox::insertURL( const QPixmap& pixmap, const KURL& url, int index ) 00213 { 00214 QComboBox::insertItem( pixmap, url.prettyURL(), index ); 00215 } 00216 00217 void KComboBox::changeURL( const KURL& url, int index ) 00218 { 00219 QComboBox::changeItem( url.prettyURL(), index ); 00220 } 00221 00222 void KComboBox::changeURL( const QPixmap& pixmap, const KURL& url, int index ) 00223 { 00224 QComboBox::changeItem( pixmap, url.prettyURL(), index ); 00225 } 00226 00227 void KComboBox::setCompletedItems( const QStringList& items ) 00228 { 00229 if ( d->klineEdit ) 00230 d->klineEdit->setCompletedItems( items ); 00231 } 00232 00233 KCompletionBox * KComboBox::completionBox( bool create ) 00234 { 00235 if ( d->klineEdit ) 00236 return d->klineEdit->completionBox( create ); 00237 return 0; 00238 } 00239 00240 // QWidget::create() turns off mouse-Tracking which would break auto-hiding 00241 void KComboBox::create( WId id, bool initializeWindow, bool destroyOldWindow ) 00242 { 00243 QComboBox::create( id, initializeWindow, destroyOldWindow ); 00244 KCursor::setAutoHideCursor( lineEdit(), true, true ); 00245 } 00246 00247 void KComboBox::wheelEvent( QWheelEvent *ev ) 00248 { 00249 // Not necessary anymore 00250 QComboBox::wheelEvent( ev ); 00251 } 00252 00253 void KComboBox::setLineEdit( QLineEdit *edit ) 00254 { 00255 if ( !editable() && edit && 00256 qstrcmp( edit->className(), "QLineEdit" ) == 0 ) 00257 { 00258 // uic generates code that creates a read-only KComboBox and then 00259 // calls combo->setEditable( true ), which causes QComboBox to set up 00260 // a dumb QLineEdit instead of our nice KLineEdit. 00261 // As some KComboBox features rely on the KLineEdit, we reject 00262 // this order here. 00263 delete edit; 00264 edit = new KLineEdit( this, "combo edit" ); 00265 } 00266 00267 QComboBox::setLineEdit( edit ); 00268 d->klineEdit = dynamic_cast<KLineEdit*>( edit ); 00269 setDelegate( d->klineEdit ); 00270 00271 // Connect the returnPressed signal for both Q[K]LineEdits' 00272 if (edit) 00273 connect( edit, SIGNAL( returnPressed() ), SIGNAL( returnPressed() )); 00274 00275 if ( d->klineEdit ) 00276 { 00277 // someone calling KComboBox::setEditable( false ) destroys our 00278 // lineedit without us noticing. And KCompletionBase::delegate would 00279 // be a dangling pointer then, so prevent that. Note: only do this 00280 // when it is a KLineEdit! 00281 connect( edit, SIGNAL( destroyed() ), SLOT( lineEditDeleted() )); 00282 00283 connect( d->klineEdit, SIGNAL( returnPressed( const QString& )), 00284 SIGNAL( returnPressed( const QString& ) )); 00285 00286 connect( d->klineEdit, SIGNAL( completion( const QString& )), 00287 SIGNAL( completion( const QString& )) ); 00288 00289 connect( d->klineEdit, SIGNAL( substringCompletion( const QString& )), 00290 SIGNAL( substringCompletion( const QString& )) ); 00291 00292 connect( d->klineEdit, 00293 SIGNAL( textRotation( KCompletionBase::KeyBindingType )), 00294 SIGNAL( textRotation( KCompletionBase::KeyBindingType )) ); 00295 00296 connect( d->klineEdit, 00297 SIGNAL( completionModeChanged( KGlobalSettings::Completion )), 00298 SIGNAL( completionModeChanged( KGlobalSettings::Completion))); 00299 00300 connect( d->klineEdit, 00301 SIGNAL( aboutToShowContextMenu( QPopupMenu * )), 00302 SIGNAL( aboutToShowContextMenu( QPopupMenu * )) ); 00303 00304 connect( d->klineEdit, 00305 SIGNAL( completionBoxActivated( const QString& )), 00306 SIGNAL( activated( const QString& )) ); 00307 } 00308 } 00309 00310 void KComboBox::setCurrentItem( const QString& item, bool insert, int index ) 00311 { 00312 int sel = -1; 00313 00314 for (int i = 0; i < count(); ++i) 00315 { 00316 if (text(i) == item) 00317 { 00318 sel = i; 00319 break; 00320 } 00321 } 00322 00323 if (sel == -1 && insert) 00324 { 00325 insertItem(item, index); 00326 if (index >= 0) 00327 sel = index; 00328 else 00329 sel = count() - 1; 00330 } 00331 setCurrentItem(sel); 00332 } 00333 00334 void KComboBox::lineEditDeleted() 00335 { 00336 // yes, we need those ugly casts due to the multiple inheritance 00337 // sender() is guaranteed to be a KLineEdit (see the connect() to the 00338 // destroyed() signal 00339 const KCompletionBase *base = static_cast<const KCompletionBase*>( static_cast<const KLineEdit*>( sender() )); 00340 00341 // is it our delegate, that is destroyed? 00342 if ( base == delegate() ) 00343 setDelegate( 0L ); 00344 } 00345 00346 00347 // ********************************************************************* 00348 // ********************************************************************* 00349 00350 00351 // we are always read-write 00352 KHistoryCombo::KHistoryCombo( QWidget *parent, const char *name ) 00353 : KComboBox( true, parent, name ) 00354 { 00355 init( true ); // using completion 00356 } 00357 00358 // we are always read-write 00359 KHistoryCombo::KHistoryCombo( bool useCompletion, 00360 QWidget *parent, const char *name ) 00361 : KComboBox( true, parent, name ) 00362 { 00363 init( useCompletion ); 00364 } 00365 00366 void KHistoryCombo::init( bool useCompletion ) 00367 { 00368 if ( useCompletion ) 00369 completionObject()->setOrder( KCompletion::Weighted ); 00370 00371 setInsertionPolicy( NoInsertion ); 00372 myIterateIndex = -1; 00373 myRotated = false; 00374 myPixProvider = 0L; 00375 00376 // obey HISTCONTROL setting 00377 QCString histControl = getenv("HISTCONTROL"); 00378 if ( histControl == "ignoredups" || histControl == "ignoreboth" ) 00379 setDuplicatesEnabled( false ); 00380 00381 connect( this, SIGNAL(aboutToShowContextMenu(QPopupMenu*)), 00382 SLOT(addContextMenuItems(QPopupMenu*)) ); 00383 connect( this, SIGNAL( activated(int) ), SLOT( slotReset() )); 00384 connect( this, SIGNAL( returnPressed(const QString&) ), SLOT(slotReset())); 00385 } 00386 00387 KHistoryCombo::~KHistoryCombo() 00388 { 00389 delete myPixProvider; 00390 } 00391 00392 void KHistoryCombo::setHistoryItems( QStringList items, 00393 bool setCompletionList ) 00394 { 00395 KComboBox::clear(); 00396 00397 // limit to maxCount() 00398 while ( (int) items.count() > maxCount() && !items.isEmpty() ) 00399 items.remove( items.begin() ); 00400 00401 insertItems( items ); 00402 00403 if ( setCompletionList && useCompletion() ) { 00404 // we don't have any weighting information here ;( 00405 KCompletion *comp = completionObject(); 00406 comp->setOrder( KCompletion::Insertion ); 00407 comp->setItems( items ); 00408 comp->setOrder( KCompletion::Weighted ); 00409 } 00410 00411 clearEdit(); 00412 } 00413 00414 QStringList KHistoryCombo::historyItems() const 00415 { 00416 QStringList list; 00417 for ( int i = 0; i < count(); i++ ) 00418 list.append( text( i ) ); 00419 00420 return list; 00421 } 00422 00423 void KHistoryCombo::clearHistory() 00424 { 00425 QString temp = currentText(); 00426 KComboBox::clear(); 00427 if ( useCompletion() ) 00428 completionObject()->clear(); 00429 setEditText( temp ); 00430 } 00431 00432 void KHistoryCombo::addContextMenuItems( QPopupMenu* menu ) 00433 { 00434 if ( menu ) 00435 { 00436 menu->insertSeparator(); 00437 int id = menu->insertItem( SmallIcon("history_clear"), i18n("Clear &History"), this, SLOT( slotClear())); 00438 if (!count()) 00439 menu->setItemEnabled(id, false); 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 ( count() > 0 && 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( winId(), 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 KKey event_key( e ); 00578 00579 // going up in the history, rotating when reaching QListBox::count() 00580 if ( KKey(KStdAccel::rotateUp().keyCodeQt()) == event_key ) 00581 rotateUp(); 00582 00583 // going down in the history, no rotation possible. Last item will be 00584 // the text that was in the lineedit before Up was called. 00585 else if ( KKey(KStdAccel::rotateDown().keyCodeQt()) == event_key ) 00586 rotateDown(); 00587 else 00588 KComboBox::keyPressEvent( e ); 00589 } 00590 00591 void KHistoryCombo::wheelEvent( QWheelEvent *ev ) 00592 { 00593 // Pass to poppable listbox if it's up 00594 QListBox *lb = listBox(); 00595 if ( lb && lb->isVisible() ) 00596 { 00597 QApplication::sendEvent( lb, ev ); 00598 return; 00599 } 00600 // Otherwise make it change the text without emitting activated 00601 if ( ev->delta() > 0 ) { 00602 rotateUp(); 00603 } else { 00604 rotateDown(); 00605 } 00606 ev->accept(); 00607 } 00608 00609 void KHistoryCombo::slotReset() 00610 { 00611 myIterateIndex = -1; 00612 myRotated = false; 00613 } 00614 00615 00616 void KHistoryCombo::setPixmapProvider( KPixmapProvider *prov ) 00617 { 00618 if ( myPixProvider == prov ) 00619 return; 00620 00621 delete myPixProvider; 00622 myPixProvider = prov; 00623 00624 // re-insert all the items with/without pixmap 00625 // I would prefer to use changeItem(), but that doesn't honor the pixmap 00626 // when using an editable combobox (what we do) 00627 if ( count() > 0 ) { 00628 QStringList items( historyItems() ); 00629 clear(); 00630 insertItems( items ); 00631 } 00632 } 00633 00634 void KHistoryCombo::insertItems( const QStringList& items ) 00635 { 00636 QStringList::ConstIterator it = items.begin(); 00637 QString item; 00638 while ( it != items.end() ) { 00639 item = *it; 00640 if ( !item.isEmpty() ) { // only insert non-empty items 00641 if ( myPixProvider ) 00642 insertItem( myPixProvider->pixmapFor(item, KIcon::SizeSmall), 00643 item ); 00644 else 00645 insertItem( item ); 00646 } 00647 ++it; 00648 } 00649 } 00650 00651 void KHistoryCombo::slotClear() 00652 { 00653 clearHistory(); 00654 emit cleared(); 00655 } 00656 00657 void KComboBox::virtual_hook( int id, void* data ) 00658 { KCompletionBase::virtual_hook( id, data ); } 00659 00660 void KHistoryCombo::virtual_hook( int id, void* data ) 00661 { KComboBox::virtual_hook( id, data ); } 00662 00663 #include "kcombobox.moc"
KDE Logo
This file is part of the documentation for kdeui Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Oct 8 11:14:24 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003