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