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() : 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
00085 QComboBox::setAutoCompletion( false );
00086
00087
00088
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
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
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
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
00245 QComboBox::wheelEvent( ev );
00246 }
00247
00248 void KComboBox::setLineEdit( QLineEdit *edit )
00249 {
00250 if ( !editable() && edit &&
00251 !qstrcmp( edit->className(), "QLineEdit" ) )
00252 {
00253
00254
00255
00256
00257
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
00267 if (edit)
00268 connect( edit, SIGNAL( returnPressed() ), SIGNAL( returnPressed() ));
00269
00270 if ( d->klineEdit )
00271 {
00272
00273
00274
00275
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
00333
00334
00335 const KCompletionBase *base = static_cast<const KCompletionBase*>( static_cast<const KLineEdit*>( sender() ));
00336
00337
00338 if ( base == delegate() )
00339 setDelegate( 0L );
00340 }
00341
00342
00343
00344
00345
00346
00347
00348 KHistoryCombo::KHistoryCombo( QWidget *parent, const char *name )
00349 : KComboBox( true, parent, name ), d(0)
00350 {
00351 init( true );
00352 }
00353
00354
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
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
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
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
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
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
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;
00485 const int mc = maxCount();
00486 const int stopAt = QMAX(mc, 0);
00487
00488 for (int rmIndex = last; rmIndex >= stopAt; --rmIndex) {
00489
00490
00491
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
00531 if ( myIterateIndex == -1 )
00532 myText = currentText();
00533
00534 ++myIterateIndex;
00535
00536
00537 const int last = count() - 1;
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
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
00562 if ( myIterateIndex == -1 )
00563 myText = currentText();
00564
00565 --myIterateIndex;
00566
00567 const QString currText = currentText();
00568
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 {
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
00602 if ( KStdAccel::rotateUp().contains(event_key) )
00603 rotateUp();
00604
00605
00606
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
00616 QListBox* const lb = listBox();
00617 if ( lb && lb->isVisible() )
00618 {
00619 QApplication::sendEvent( lb, ev );
00620 return;
00621 }
00622
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
00647
00648
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() ) {
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"