kcompletionbox.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <qapplication.h>
00025 #include <qcombobox.h>
00026 #include <qevent.h>
00027 #include <qstyle.h>
00028
00029 #include <kdebug.h>
00030 #include <kconfig.h>
00031 #include <knotifyclient.h>
00032 #include <kglobalsettings.h>
00033
00034 #include "kcompletionbox.h"
00035
00036 class KCompletionBox::KCompletionBoxPrivate
00037 {
00038 public:
00039 QWidget *m_parent;
00040 QString cancelText;
00041 bool tabHandling;
00042 bool down_workaround;
00043 bool upwardBox;
00044 };
00045
00046 KCompletionBox::KCompletionBox( QWidget *parent, const char *name )
00047 :KListBox( parent, name, WType_Popup ), d(new KCompletionBoxPrivate)
00048 {
00049
00050 d->m_parent = parent;
00051 d->tabHandling = true;
00052 d->down_workaround = false;
00053 d->upwardBox = false;
00054
00055 setColumnMode( 1 );
00056 setLineWidth( 1 );
00057 setFrameStyle( QFrame::Box | QFrame::Plain );
00058
00059 if ( parent )
00060 setFocusProxy( parent );
00061 else
00062 setFocusPolicy( NoFocus );
00063
00064 setVScrollBarMode( Auto );
00065 setHScrollBarMode( AlwaysOff );
00066
00067 connect( this, SIGNAL( doubleClicked( QListBoxItem * )),
00068 SLOT( slotActivated( QListBoxItem * )) );
00069
00070
00071 connect( this, SIGNAL( currentChanged( QListBoxItem * )),
00072 SLOT( slotCurrentChanged() ));
00073 connect( this, SIGNAL( clicked( QListBoxItem * )),
00074 SLOT( slotItemClicked( QListBoxItem * )) );
00075 }
00076
00077 KCompletionBox::~KCompletionBox()
00078 {
00079 d->m_parent = 0L;
00080 delete d;
00081 }
00082
00083 QStringList KCompletionBox::items() const
00084 {
00085 QStringList list;
00086
00087 const QListBoxItem* currItem = firstItem();
00088
00089 while (currItem) {
00090 list.append(currItem->text());
00091 currItem = currItem->next();
00092 }
00093
00094 return list;
00095 }
00096
00097 void KCompletionBox::slotActivated( QListBoxItem *item )
00098 {
00099 if ( !item )
00100 return;
00101
00102 hide();
00103 emit activated( item->text() );
00104 }
00105
00106 bool KCompletionBox::eventFilter( QObject *o, QEvent *e )
00107 {
00108 int type = e->type();
00109
00110 if ( o == d->m_parent ) {
00111 if ( isVisible() ) {
00112 if ( type == QEvent::KeyPress ) {
00113 QKeyEvent *ev = static_cast<QKeyEvent *>( e );
00114 switch ( ev->key() ) {
00115 case Key_BackTab:
00116 if ( d->tabHandling && (ev->state() == NoButton ||
00117 (ev->state() & ShiftButton)) ) {
00118 up();
00119 ev->accept();
00120 return true;
00121 }
00122 break;
00123 case Key_Tab:
00124 if ( d->tabHandling && (ev->state() == NoButton) ) {
00125 down();
00126 ev->accept();
00127 return true;
00128 }
00129 break;
00130 case Key_Down:
00131 down();
00132 ev->accept();
00133 return true;
00134 case Key_Up:
00135
00136
00137
00138
00139 if ( selectedItem() ||
00140 mapToGlobal( QPoint( 0, 0 ) ).y() >
00141 d->m_parent->mapToGlobal( QPoint( 0, 0 ) ).y() )
00142 up();
00143 else
00144 down();
00145
00146 ev->accept();
00147 return true;
00148 case Key_Prior:
00149 pageUp();
00150 ev->accept();
00151 return true;
00152 case Key_Next:
00153 pageDown();
00154 ev->accept();
00155 return true;
00156 case Key_Escape:
00157 canceled();
00158 ev->accept();
00159 return true;
00160 case Key_Enter:
00161 case Key_Return:
00162 if ( ev->state() & ShiftButton ) {
00163 hide();
00164 ev->accept();
00165 return true;
00166 }
00167 break;
00168 case Key_End:
00169 if ( ev->state() & ControlButton )
00170 {
00171 end();
00172 ev->accept();
00173 return true;
00174 }
00175 case Key_Home:
00176 if ( ev->state() & ControlButton )
00177 {
00178 home();
00179 ev->accept();
00180 return true;
00181 }
00182 default:
00183 break;
00184 }
00185 }
00186 else if ( type == QEvent::AccelOverride ) {
00187
00188
00189 QKeyEvent *ev = static_cast<QKeyEvent *>( e );
00190 switch ( ev->key() ) {
00191 case Key_Down:
00192 case Key_Up:
00193 case Key_Prior:
00194 case Key_Next:
00195 case Key_Escape:
00196 case Key_Enter:
00197 case Key_Return:
00198 ev->accept();
00199 return true;
00200 break;
00201 case Key_Tab:
00202 case Key_BackTab:
00203 if ( ev->state() == NoButton ||
00204 (ev->state() & ShiftButton))
00205 {
00206 ev->accept();
00207 return true;
00208 }
00209 break;
00210 case Key_Home:
00211 case Key_End:
00212 if ( ev->state() & ControlButton )
00213 {
00214 ev->accept();
00215 return true;
00216 }
00217 break;
00218 default:
00219 break;
00220 }
00221 }
00222
00223
00224 else if ( type == QEvent::FocusOut || type == QEvent::Resize ||
00225 type == QEvent::Close || type == QEvent::Hide ||
00226 type == QEvent::Move ) {
00227 hide();
00228 }
00229 }
00230 }
00231
00232
00233 else if ( type == QEvent::MouseButtonPress ) {
00234 QMouseEvent *ev = static_cast<QMouseEvent *>( e );
00235 if ( !rect().contains( ev->pos() ))
00236 hide();
00237 }
00238
00239 return KListBox::eventFilter( o, e );
00240 }
00241
00242
00243 void KCompletionBox::popup()
00244 {
00245 if ( count() == 0 )
00246 hide();
00247 else {
00248 ensureCurrentVisible();
00249 bool block = signalsBlocked();
00250 blockSignals( true );
00251 setCurrentItem( 0 );
00252 blockSignals( block );
00253 clearSelection();
00254 if ( !isVisible() )
00255 show();
00256 else if ( size().height() != sizeHint().height() )
00257 sizeAndPosition();
00258 }
00259 }
00260
00261 void KCompletionBox::sizeAndPosition()
00262 {
00263 int currentGeom = height();
00264 QPoint currentPos = pos();
00265 QRect geom = calculateGeometry();
00266 resize( geom.size() );
00267
00268 int x = currentPos.x(), y = currentPos.y();
00269 if ( d->m_parent ) {
00270 if ( !isVisible() ) {
00271 QRect screenSize = KGlobalSettings::desktopGeometry(d->m_parent);
00272
00273 QPoint orig = d->m_parent->mapToGlobal( QPoint(0, d->m_parent->height()) );
00274 x = orig.x() + geom.x();
00275 y = orig.y() + geom.y();
00276
00277 if ( x + width() > screenSize.right() )
00278 x = screenSize.right() - width();
00279 if (y + height() > screenSize.bottom() ) {
00280 y = y - height() - d->m_parent->height();
00281 d->upwardBox = true;
00282 }
00283 }
00284 else {
00285
00286 if (d->upwardBox)
00287 y += (currentGeom-height());
00288 }
00289 move( x, y);
00290 }
00291 }
00292
00293 void KCompletionBox::show()
00294 {
00295 d->upwardBox = false;
00296 if ( d->m_parent ) {
00297 sizeAndPosition();
00298 qApp->installEventFilter( this );
00299 }
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313 qApp->sendPostedEvents();
00314 KListBox::show();
00315 }
00316
00317 void KCompletionBox::hide()
00318 {
00319 if ( d->m_parent )
00320 qApp->removeEventFilter( this );
00321 d->cancelText = QString::null;
00322 KListBox::hide();
00323 }
00324
00325 QRect KCompletionBox::calculateGeometry() const
00326 {
00327 int x = 0, y = 0;
00328 int ih = itemHeight();
00329 int h = QMIN( 15 * ih, (int) count() * ih ) + 2*frameWidth();
00330
00331 int w = (d->m_parent) ? d->m_parent->width() : KListBox::minimumSizeHint().width();
00332 w = QMAX( KListBox::minimumSizeHint().width(), w );
00333
00334
00335
00336
00337 const QObject* combo;
00338 if ( d->m_parent && (combo = d->m_parent->parent() ) &&
00339 combo->inherits("QComboBox") )
00340 {
00341 const QComboBox* cb = static_cast<const QComboBox*>(combo);
00342
00343
00344 w = QMAX( w, cb->width() );
00345
00346 QPoint parentCorner = d->m_parent->mapToGlobal(QPoint(0, 0));
00347 QPoint comboCorner = cb->mapToGlobal(QPoint(0, 0));
00348
00349
00350 x += comboCorner.x() - parentCorner.x();
00351
00352
00353 y += cb->height() - d->m_parent->height() +
00354 comboCorner.y() - parentCorner.y();
00355
00356
00357 QRect styleAdj = style().querySubControlMetrics(QStyle::CC_ComboBox,
00358 cb, QStyle::SC_ComboBoxListBoxPopup,
00359 QStyleOption(x, y, w, h));
00360
00361
00362 if (!styleAdj.isNull())
00363 return styleAdj;
00364
00365 }
00366 return QRect(x, y, w, h);
00367 }
00368
00369 QSize KCompletionBox::sizeHint() const
00370 {
00371 return calculateGeometry().size();
00372 }
00373
00374 void KCompletionBox::down()
00375 {
00376 int i = currentItem();
00377
00378 if ( i == 0 && d->down_workaround ) {
00379 d->down_workaround = false;
00380 setCurrentItem( 0 );
00381 setSelected( 0, true );
00382 emit highlighted( currentText() );
00383 }
00384
00385 else if ( i < (int) count() - 1 )
00386 setCurrentItem( i + 1 );
00387 }
00388
00389 void KCompletionBox::up()
00390 {
00391 if ( currentItem() > 0 )
00392 setCurrentItem( currentItem() - 1 );
00393 }
00394
00395 void KCompletionBox::pageDown()
00396 {
00397 int i = currentItem() + numItemsVisible();
00398 i = i > (int)count() - 1 ? (int)count() - 1 : i;
00399 setCurrentItem( i );
00400 }
00401
00402 void KCompletionBox::pageUp()
00403 {
00404 int i = currentItem() - numItemsVisible();
00405 i = i < 0 ? 0 : i;
00406 setCurrentItem( i );
00407 }
00408
00409 void KCompletionBox::home()
00410 {
00411 setCurrentItem( 0 );
00412 }
00413
00414 void KCompletionBox::end()
00415 {
00416 setCurrentItem( count() -1 );
00417 }
00418
00419 void KCompletionBox::setTabHandling( bool enable )
00420 {
00421 d->tabHandling = enable;
00422 }
00423
00424 bool KCompletionBox::isTabHandling() const
00425 {
00426 return d->tabHandling;
00427 }
00428
00429 void KCompletionBox::setCancelledText( const QString& text )
00430 {
00431 d->cancelText = text;
00432 }
00433
00434 QString KCompletionBox::cancelledText() const
00435 {
00436 return d->cancelText;
00437 }
00438
00439 void KCompletionBox::canceled()
00440 {
00441 if ( !d->cancelText.isNull() )
00442 emit userCancelled( d->cancelText );
00443 if ( isVisible() )
00444 hide();
00445 }
00446
00447 class KCompletionBoxItem : public QListBoxItem
00448 {
00449 public:
00450
00451 bool reuse( const QString& newText )
00452 {
00453 if ( text() == newText )
00454 return false;
00455 setText( newText );
00456 return true;
00457 }
00458 };
00459
00460
00461 void KCompletionBox::insertItems( const QStringList& items, int index )
00462 {
00463 bool block = signalsBlocked();
00464 blockSignals( true );
00465 insertStringList( items, index );
00466 blockSignals( block );
00467 d->down_workaround = true;
00468 }
00469
00470 void KCompletionBox::setItems( const QStringList& items )
00471 {
00472 bool block = signalsBlocked();
00473 blockSignals( true );
00474
00475 QListBoxItem* item = firstItem();
00476 if ( !item ) {
00477 insertStringList( items );
00478 }
00479 else {
00480
00481
00482
00483 bool dirty = false;
00484
00485 QStringList::ConstIterator it = items.constBegin();
00486 const QStringList::ConstIterator itEnd = items.constEnd();
00487
00488 for ( ; it != itEnd; ++it) {
00489 if ( item ) {
00490 const bool changed = ((KCompletionBoxItem*)item)->reuse( *it );
00491 dirty = dirty || changed;
00492 item = item->next();
00493 }
00494 else {
00495 dirty = true;
00496
00497 insertItem( new QListBoxText( *it ) );
00498 }
00499 }
00500
00501
00502 if ( item ) {
00503 dirty = true;
00504 }
00505
00506 QListBoxItem* tmp = item;
00507 while ( (item = tmp ) ) {
00508 tmp = item->next();
00509 delete item;
00510 }
00511
00512 if (dirty)
00513 triggerUpdate( false );
00514 }
00515
00516 if ( isVisible() && size().height() != sizeHint().height() )
00517 sizeAndPosition();
00518
00519 blockSignals( block );
00520 d->down_workaround = true;
00521 }
00522
00523 void KCompletionBox::slotCurrentChanged()
00524 {
00525 d->down_workaround = false;
00526 }
00527
00528 void KCompletionBox::slotItemClicked( QListBoxItem *item )
00529 {
00530 if ( item )
00531 {
00532 if ( d->down_workaround ) {
00533 d->down_workaround = false;
00534 emit highlighted( item->text() );
00535 }
00536
00537 hide();
00538 emit activated( item->text() );
00539 }
00540 }
00541
00542 void KCompletionBox::virtual_hook( int id, void* data )
00543 { KListBox::virtual_hook( id, data ); }
00544
00545 #include "kcompletionbox.moc"
This file is part of the documentation for kdeui Library Version 3.4.0.