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 <tqapplication.h>
00025 #include <tqcombobox.h>
00026 #include <tqevent.h>
00027 #include <tqstyle.h>
00028
00029 #include <kdebug.h>
00030 #include <tdeconfig.h>
00031 #include <knotifyclient.h>
00032 #include <tdeglobalsettings.h>
00033
00034 #include "tdecompletionbox.h"
00035
00036 class TDECompletionBox::TDECompletionBoxPrivate
00037 {
00038 public:
00039 TQWidget *m_parent;
00040 TQString cancelText;
00041 bool tabHandling;
00042 bool down_workaround;
00043 bool upwardBox;
00044 bool emitSelected;
00045 };
00046
00047 TDECompletionBox::TDECompletionBox( TQWidget *parent, const char *name )
00048 :TDEListBox( parent, name, (WFlags)WType_Popup ), d(new TDECompletionBoxPrivate)
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( TQFrame::Box | TQFrame::Plain );
00060
00061 if ( parent )
00062 setFocusProxy( parent );
00063 else
00064 setFocusPolicy( TQ_NoFocus );
00065
00066 setVScrollBarMode( Auto );
00067 setHScrollBarMode( AlwaysOff );
00068
00069 connect( this, TQT_SIGNAL( doubleClicked( TQListBoxItem * )),
00070 TQT_SLOT( slotActivated( TQListBoxItem * )) );
00071
00072
00073 connect( this, TQT_SIGNAL( currentChanged( TQListBoxItem * )),
00074 TQT_SLOT( slotCurrentChanged() ));
00075 connect( this, TQT_SIGNAL( clicked( TQListBoxItem * )),
00076 TQT_SLOT( slotItemClicked( TQListBoxItem * )) );
00077 }
00078
00079 TDECompletionBox::~TDECompletionBox()
00080 {
00081 d->m_parent = 0L;
00082 delete d;
00083 }
00084
00085 TQStringList TDECompletionBox::items() const
00086 {
00087 TQStringList list;
00088
00089 const TQListBoxItem* currItem = firstItem();
00090
00091 while (currItem) {
00092 list.append(currItem->text());
00093 currItem = currItem->next();
00094 }
00095
00096 return list;
00097 }
00098
00099 void TDECompletionBox::slotActivated( TQListBoxItem *item )
00100 {
00101 if ( !item )
00102 return;
00103
00104 hide();
00105 emit activated( item->text() );
00106 }
00107
00108 bool TDECompletionBox::eventFilter( TQObject *o, TQEvent *e )
00109 {
00110 int type = e->type();
00111
00112 if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(d->m_parent) ) {
00113 if ( isVisible() ) {
00114 if ( type == TQEvent::KeyPress ) {
00115 TQKeyEvent *ev = TQT_TQKEYEVENT( e );
00116 switch ( ev->key() ) {
00117 case Key_BackTab:
00118 if ( d->tabHandling && (ev->state() == Qt::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() == Qt::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( TQPoint( 0, 0 ) ).y() >
00141 d->m_parent->mapToGlobal( TQPoint( 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 == TQEvent::AccelOverride ) {
00186
00187
00188 TQKeyEvent *ev = TQT_TQKEYEVENT( 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() == Qt::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 == TQEvent::FocusOut || type == TQEvent::Resize ||
00224 type == TQEvent::Close || type == TQEvent::Hide ||
00225 type == TQEvent::Move ) {
00226 hide();
00227 }
00228 }
00229 }
00230
00231
00232 else if ( type == TQEvent::MouseButtonPress ) {
00233 TQMouseEvent *ev = TQT_TQMOUSEEVENT( e );
00234 if ( !rect().contains( ev->pos() ))
00235 hide();
00236
00237 if ( !d->emitSelected && currentItem() && !::tqqt_cast<TQScrollBar*>(o) )
00238 {
00239 emit highlighted( currentText() );
00240 hide();
00241 ev->accept();
00242 return true;
00243 }
00244 }
00245
00246 return TDEListBox::eventFilter( o, e );
00247 }
00248
00249
00250 void TDECompletionBox::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 TDECompletionBox::sizeAndPosition()
00269 {
00270 int currentGeom = height();
00271 TQPoint currentPos = pos();
00272 TQRect geom = calculateGeometry();
00273 resize( geom.size() );
00274
00275 int x = currentPos.x(), y = currentPos.y();
00276 if ( d->m_parent ) {
00277 if ( !isVisible() ) {
00278 TQRect screenSize = TDEGlobalSettings::desktopGeometry(d->m_parent);
00279
00280 TQPoint orig = d->m_parent->mapToGlobal( TQPoint(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 TDECompletionBox::show()
00301 {
00302 d->upwardBox = false;
00303 if ( d->m_parent ) {
00304 sizeAndPosition();
00305 tqApp->installEventFilter( this );
00306 }
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 tqApp->sendPostedEvents();
00321 TDEListBox::show();
00322 }
00323
00324 void TDECompletionBox::hide()
00325 {
00326 if ( d->m_parent )
00327 tqApp->removeEventFilter( this );
00328 d->cancelText = TQString::null;
00329 TDEListBox::hide();
00330 }
00331
00332 TQRect TDECompletionBox::calculateGeometry() const
00333 {
00334 int x = 0, y = 0;
00335 int ih = itemHeight();
00336 int h = TQMIN( 15 * ih, (int) count() * ih ) + 2*frameWidth();
00337
00338 int w = (d->m_parent) ? d->m_parent->width() : TDEListBox::minimumSizeHint().width();
00339 w = TQMAX( TDEListBox::minimumSizeHint().width(), w );
00340
00341
00342
00343
00344 const TQObject* combo;
00345 if ( d->m_parent && (combo = d->m_parent->parent() ) &&
00346 combo->inherits(TQCOMBOBOX_OBJECT_NAME_STRING) )
00347 {
00348 const TQComboBox* cb = static_cast<const TQComboBox*>(TQT_TQWIDGET_CONST(combo));
00349
00350
00351 w = TQMAX( w, cb->width() );
00352
00353 TQPoint parentCorner = d->m_parent->mapToGlobal(TQPoint(0, 0));
00354 TQPoint comboCorner = cb->mapToGlobal(TQPoint(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 TQRect styleAdj = style().querySubControlMetrics(TQStyle::CC_ComboBox,
00365 cb, TQStyle::SC_ComboBoxListBoxPopup,
00366 TQStyleOption(x, y, w, h));
00367
00368
00369 if (!styleAdj.isNull())
00370 return styleAdj;
00371
00372 }
00373 return TQRect(x, y, w, h);
00374 }
00375
00376 TQSize TDECompletionBox::sizeHint() const
00377 {
00378 return calculateGeometry().size();
00379 }
00380
00381 void TDECompletionBox::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 TDECompletionBox::up()
00397 {
00398 if ( currentItem() > 0 )
00399 setCurrentItem( currentItem() - 1 );
00400 }
00401
00402 void TDECompletionBox::pageDown()
00403 {
00404 int i = currentItem() + numItemsVisible();
00405 i = i > (int)count() - 1 ? (int)count() - 1 : i;
00406 setCurrentItem( i );
00407 }
00408
00409 void TDECompletionBox::pageUp()
00410 {
00411 int i = currentItem() - numItemsVisible();
00412 i = i < 0 ? 0 : i;
00413 setCurrentItem( i );
00414 }
00415
00416 void TDECompletionBox::home()
00417 {
00418 setCurrentItem( 0 );
00419 }
00420
00421 void TDECompletionBox::end()
00422 {
00423 setCurrentItem( count() -1 );
00424 }
00425
00426 void TDECompletionBox::setTabHandling( bool enable )
00427 {
00428 d->tabHandling = enable;
00429 }
00430
00431 bool TDECompletionBox::isTabHandling() const
00432 {
00433 return d->tabHandling;
00434 }
00435
00436 void TDECompletionBox::setCancelledText( const TQString& text )
00437 {
00438 d->cancelText = text;
00439 }
00440
00441 TQString TDECompletionBox::cancelledText() const
00442 {
00443 return d->cancelText;
00444 }
00445
00446 void TDECompletionBox::canceled()
00447 {
00448 if ( !d->cancelText.isNull() )
00449 emit userCancelled( d->cancelText );
00450 if ( isVisible() )
00451 hide();
00452 }
00453
00454 class TDECompletionBoxItem : public TQListBoxItem
00455 {
00456 public:
00457
00458 bool reuse( const TQString& newText )
00459 {
00460 if ( text() == newText )
00461 return false;
00462 setText( newText );
00463 return true;
00464 }
00465 };
00466
00467
00468 void TDECompletionBox::insertItems( const TQStringList& 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 TDECompletionBox::setItems( const TQStringList& items )
00478 {
00479 bool block = signalsBlocked();
00480 blockSignals( true );
00481
00482 TQListBoxItem* item = firstItem();
00483 if ( !item ) {
00484 insertStringList( items );
00485 }
00486 else {
00487
00488
00489
00490 bool dirty = false;
00491
00492 TQStringList::ConstIterator it = items.constBegin();
00493 const TQStringList::ConstIterator itEnd = items.constEnd();
00494
00495 for ( ; it != itEnd; ++it) {
00496 if ( item ) {
00497 const bool changed = ((TDECompletionBoxItem*)item)->reuse( *it );
00498 dirty = dirty || changed;
00499 item = item->next();
00500 }
00501 else {
00502 dirty = true;
00503
00504 insertItem( new TQListBoxText( *it ) );
00505 }
00506 }
00507
00508
00509 if ( item ) {
00510 dirty = true;
00511 }
00512
00513 TQListBoxItem* 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 TDECompletionBox::slotCurrentChanged()
00531 {
00532 d->down_workaround = false;
00533 }
00534
00535 void TDECompletionBox::slotItemClicked( TQListBoxItem *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 TDECompletionBox::setActivateOnSelect(bool state)
00550 {
00551 d->emitSelected = state;
00552 }
00553
00554 bool TDECompletionBox::activateOnSelect() const
00555 {
00556 return d->emitSelected;
00557 }
00558
00559 void TDECompletionBox::virtual_hook( int id, void* data )
00560 { TDEListBox::virtual_hook( id, data ); }
00561
00562 #include "tdecompletionbox.moc"