• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeui
 

tdeui

tdecompletionbox.cpp

00001 /* This file is part of the KDE libraries
00002 
00003    Copyright (c) 2000,2001,2002 Carsten Pfeiffer <pfeiffer@kde.org>
00004    Copyright (c) 2000 Stefan Schimanski <1Stein@gmx.de>
00005    Copyright (c) 2000,2001,2002,2003,2004 Dawit Alemayehu <adawit@kde.org>
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Library General Public
00009    License (LGPL) as published by the Free Software Foundation; either
00010    version 2 of the License, or (at your option) any later version.
00011 
00012    This library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Library General Public License for more details.
00016 
00017    You should have received a copy of the GNU Library General Public License
00018    along with this library; see the file COPYING.LIB.  If not, write to
00019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020    Boston, MA 02110-1301, USA.
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; // necessary to set the focus back
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     // grmbl, just TQListBox workarounds :[ Thanks Volker.
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(); // Only on TAB!!
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                         // If there is no selected item and we've popped up above
00138                         // our parent, select the first item when they press up.
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();  // Consume the Enter event
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                 // Override any acceleartors that match
00187                 // the key sequences we use here...
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             // parent loses focus or gets a click -> we hide
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     // any mouse-click on something else than "this" makes us hide
00232     else if ( type == TQEvent::MouseButtonPress ) {
00233         TQMouseEvent *ev = TQT_TQMOUSEEVENT( e );
00234         if ( !rect().contains( ev->pos() )) // this widget
00235             hide();
00236 
00237         if ( !d->emitSelected && currentItem() && !::tqqt_cast<TQScrollBar*>(o) )
00238         {
00239           emit highlighted( currentText() );
00240           hide();
00241           ev->accept();  // Consume the mouse click event...
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         // Are we above our parent? If so we must keep bottom edge anchored.
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     // ### we shouldn't need to call this, but without this, the scrollbars
00309     // are pretty b0rked.
00310     //triggerUpdate( true );
00311 
00312     // Workaround for I'm not sure whose bug - if this TDECompletionBox' parent
00313     // is in a layout, that layout will detect inserting new child (posted
00314     // ChildInserted event), and will trigger relayout (post LayoutHint event).
00315     // TQWidget::show() sends also posted ChildInserted events for the parent,
00316     // and later all LayoutHint events, which causes layout updating.
00317     // The problem is, TDECompletionBox::eventFilter() detects resizing
00318     // of the parent, and calls hide() - and this hide() happen in the middle
00319     // of show(), causing inconsistent state. I'll try to submit a Qt patch too.
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     //If we're inside a combox, Qt by default makes the dropdown
00342     // as wide as the combo, and gives the style a chance
00343     // to adjust it. Do that here as well, for consistency
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         //Expand to the combo width
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         //We need to adjust our horizontal position to also be WRT to the combo
00357         x += comboCorner.x() -  parentCorner.x();
00358 
00359         //The same with vertical one
00360         y += cb->height() - d->m_parent->height() +
00361              comboCorner.y() - parentCorner.y();
00362 
00363         //Ask the style to refine this a bit
00364         TQRect styleAdj = style().querySubControlMetrics(TQStyle::CC_ComboBox,
00365                                     cb, TQStyle::SC_ComboBoxListBoxPopup,
00366                                     TQStyleOption(x, y, w, h));
00367         //TQCommonStyle returns TQRect() by default, so this is what we get if the
00368         //style doesn't implement this
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     //Returns true if dirty.
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         //Keep track of whether we need to change anything,
00488         //so we can avoid a repaint for identical updates,
00489         //to reduce flicker
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                 //Inserting an item is a way of making this dirty
00504                 insertItem( new TQListBoxText( *it ) );
00505             }
00506         }
00507 
00508         //If there is an unused item, mark as dirty -> less items now
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"

tdeui

Skip menu "tdeui"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdeui

Skip menu "tdeui"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeui by doxygen 1.7.1
This website is maintained by Timothy Pearson.