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