00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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>
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
00088 QComboBox::setAutoCompletion( false );
00089
00090
00091
00092 setContextMenuEnabled( true );
00093
00094
00095
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
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
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
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
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
00259
00260
00261
00262
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
00272 if (edit)
00273 connect( edit, SIGNAL( returnPressed() ), SIGNAL( returnPressed() ));
00274
00275 if ( d->klineEdit )
00276 {
00277
00278
00279
00280
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
00337
00338
00339 const KCompletionBase *base = static_cast<const KCompletionBase*>( static_cast<const KLineEdit*>( sender() ));
00340
00341
00342 if ( base == delegate() )
00343 setDelegate( 0L );
00344 }
00345
00346
00347
00348
00349
00350
00351
00352 KHistoryCombo::KHistoryCombo( QWidget *parent, const char *name )
00353 : KComboBox( true, parent, name )
00354 {
00355 init( true );
00356 }
00357
00358
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
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
00398 while ( (int) items.count() > maxCount() && !items.isEmpty() )
00399 items.remove( items.begin() );
00400
00401 insertItems( items );
00402
00403 if ( setCompletionList && useCompletion() ) {
00404
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( 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
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
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
00476
00477
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
00513 if ( myIterateIndex == -1 )
00514 myText = currentText();
00515
00516 myIterateIndex++;
00517
00518
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
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
00541 if ( myIterateIndex == -1 )
00542 myText = currentText();
00543
00544 myIterateIndex--;
00545
00546
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 {
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
00580 if ( KKey(KStdAccel::rotateUp().keyCodeQt()) == event_key )
00581 rotateUp();
00582
00583
00584
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
00594 QListBox *lb = listBox();
00595 if ( lb && lb->isVisible() )
00596 {
00597 QApplication::sendEvent( lb, ev );
00598 return;
00599 }
00600
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
00625
00626
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() ) {
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"