Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ocombobox.cpp

Go to the documentation of this file.
00001 /*
00002   This file                  Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
00003     is part of the           Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
00004        Opie Project          Copyright (C) 2000 Dawit Alemayehu <adawit@kde.org>
00005 
00006               =.             Originally part of the KDE Project
00007             .=l.
00008            .>+-=
00009  _;:,     .>    :=|.         This program is free software; you can
00010 .> <`_,   >  .   <=          redistribute it and/or  modify it under
00011 :`=1 )Y*s>-.--   :           the terms of the GNU Library General Public
00012 .="- .-=="i,     .._         License as published by the Free Software
00013  - .   .-<_>     .<>         Foundation; either version 2 of the License,
00014      ._= =}       :          or (at your option) any later version.
00015     .%`+i>       _;_.
00016     .i_,=:_.      -<s.       This program is distributed in the hope that
00017      +  .  -:.       =       it will be useful,  but WITHOUT ANY WARRANTY;
00018     : ..    .:,     . . .    without even the implied warranty of
00019     =_        +     =;=|`    MERCHANTABILITY or FITNESS FOR A
00020   _.=:.       :    :=>`:     PARTICULAR PURPOSE. See the GNU
00021 ..}^=.=       =       ;      Library General Public License for more
00022 ++=   -.     .`     .:       details.
00023  :     =  ...= . :.=-
00024  -.   .:....=;==+<;          You should have received a copy of the GNU
00025   -_. . .   )=.  =           Library General Public License along with
00026     --        :-=`           this library; see the file COPYING.LIB.
00027                              If not, write to the Free Software Foundation,
00028                              Inc., 59 Temple Place - Suite 330,
00029                              Boston, MA 02111-1307, USA.
00030 
00031 */
00032 
00033 /* QT */
00034 
00035 #include <qclipboard.h>
00036 #include <qlistbox.h>
00037 #include <qpopupmenu.h>
00038 
00039 /* OPIE */
00040 
00041 #include <opie2/ocompletionbox.h>
00042 #include <opie2/olineedit.h>
00043 #include <opie2/opixmapprovider.h>
00044 #include <opie2/ocombobox.h>
00045 
00046 /*======================================================================================
00047  * OComboBoxPrivate
00048  *======================================================================================*/
00049 
00050 class OComboBox::OComboBoxPrivate
00051 {
00052 public:
00053     OComboBoxPrivate()
00054     {
00055         olineEdit = 0L;
00056     }
00057     ~OComboBoxPrivate()
00058     {
00059     }
00060 
00061     OLineEdit *olineEdit;
00062 };
00063 
00064 /*======================================================================================
00065  * OComboBox
00066  *======================================================================================*/
00067 
00068 OComboBox::OComboBox( QWidget *parent, const char *name )
00069     : QComboBox( parent, name )
00070 {
00071     init();
00072 }
00073 
00074 OComboBox::OComboBox( bool rw, QWidget *parent, const char *name )
00075     : QComboBox( rw, parent, name )
00076 {
00077     init();
00078 
00079     if ( rw )
00080     {
00081         OLineEdit *edit = new OLineEdit( this, "combo lineedit" );
00082         setLineEdit( edit );
00083     }
00084 }
00085 
00086 OComboBox::~OComboBox()
00087 {
00088     delete d;
00089 }
00090 
00091 void OComboBox::init()
00092 {
00093     d = new OComboBoxPrivate;
00094 
00095     // Permanently set some parameters in the parent object.
00096     QComboBox::setAutoCompletion( false );
00097 
00098     // Initialize enable popup menu to false.
00099     // Below it will be enabled if the widget
00100     // is editable.
00101     m_bEnableMenu = false;
00102 
00103     m_trapReturnKey = false;
00104 
00105     // Enable context menu by default if widget
00106     // is editable.
00107     setContextMenuEnabled( true );
00108 
00109     // for wheelscrolling
00110     installEventFilter( this );
00111     if ( lineEdit() )
00112         lineEdit()->installEventFilter( this );
00113 }
00114 
00115 
00116 bool OComboBox::contains( const QString& _text ) const
00117 {
00118     if ( _text.isEmpty() )
00119         return false;
00120 
00121     for (int i = 0; i < count(); i++ ) {
00122         if ( text(i) == _text )
00123             return true;
00124     }
00125     return false;
00126 }
00127 
00128 void OComboBox::setAutoCompletion( bool autocomplete )
00129 {
00130     if ( d->olineEdit )
00131     {
00132         if ( autocomplete )
00133         {
00134             d->olineEdit->setCompletionMode( OGlobalSettings::CompletionAuto );
00135             setCompletionMode( OGlobalSettings::CompletionAuto );
00136         }
00137         else
00138         {
00139             d->olineEdit->setCompletionMode( OGlobalSettings::completionMode() );
00140             setCompletionMode( OGlobalSettings::completionMode() );
00141         }
00142     }
00143 }
00144 
00145 void OComboBox::setContextMenuEnabled( bool showMenu )
00146 {
00147     if( d->olineEdit )
00148     {
00149         d->olineEdit->setContextMenuEnabled( showMenu );
00150         m_bEnableMenu = showMenu;
00151     }
00152 }
00153 
00154 /*
00155 void OComboBox::setURLDropsEnabled( bool enable )
00156 {
00157     if ( d->olineEdit )
00158         d->olineEdit->setURLDropsEnabled( enable );
00159 }
00160 
00161 bool OComboBox::isURLDropsEnabled() const
00162 {
00163     return d->olineEdit && d->olineEdit->isURLDropsEnabled();
00164 }
00165 */
00166 
00167 void OComboBox::setCompletedText( const QString& text, bool marked )
00168 {
00169     if ( d->olineEdit )
00170         d->olineEdit->setCompletedText( text, marked );
00171 }
00172 
00173 void OComboBox::setCompletedText( const QString& text )
00174 {
00175     if ( d->olineEdit )
00176         d->olineEdit->setCompletedText( text );
00177 }
00178 
00179 void OComboBox::makeCompletion( const QString& text )
00180 {
00181     if( d->olineEdit )
00182         d->olineEdit->makeCompletion( text );
00183 
00184     else // read-only combo completion
00185     {
00186         if( text.isNull() || !listBox() )
00187             return;
00188 
00189         int index = listBox()->index( listBox()->findItem( text ) );
00190         if( index >= 0 ) {
00191             setCurrentItem( index );
00192         }
00193     }
00194 }
00195 
00196 void OComboBox::rotateText( OCompletionBase::KeyBindingType type )
00197 {
00198     if ( d->olineEdit )
00199         d->olineEdit->rotateText( type );
00200 }
00201 
00202 bool OComboBox::eventFilter( QObject* o, QEvent* ev )
00203 {
00204     QLineEdit *edit = lineEdit();
00205 
00206     int type = ev->type();
00207 
00208     if ( o == edit )
00209     {
00210         //OCursor::autoHideEventFilter( edit, ev );
00211 
00212         if ( type == QEvent::KeyPress )
00213         {
00214             QKeyEvent *e = static_cast<QKeyEvent *>( ev );
00215 
00216             if ( e->key() == Key_Return || e->key() == Key_Enter)
00217             {
00218                 // On Return pressed event, emit both
00219                 // returnPressed(const QString&) and returnPressed() signals
00220                 emit returnPressed();
00221                 emit returnPressed( currentText() );
00222                 if ( d->olineEdit && d->olineEdit->completionBox(false) &&
00223                      d->olineEdit->completionBox()->isVisible() )
00224                     d->olineEdit->completionBox()->hide();
00225 
00226                 return m_trapReturnKey;
00227             }
00228         }
00229     }
00230 
00231 
00232     // wheel-scrolling changes the current item
00233     if ( type == QEvent::Wheel ) {
00234         if ( !listBox() || listBox()->isHidden() ) {
00235             QWheelEvent *e = static_cast<QWheelEvent*>( ev );
00236             static const int WHEEL_DELTA = 120;
00237             int skipItems = e->delta() / WHEEL_DELTA;
00238             if ( e->state() & ControlButton ) // fast skipping
00239                 skipItems *= 10;
00240 
00241             int newItem = currentItem() - skipItems;
00242 
00243             if ( newItem < 0 )
00244                 newItem = 0;
00245             else if ( newItem >= count() )
00246                 newItem = count() -1;
00247 
00248             setCurrentItem( newItem );
00249             if ( !text( newItem ).isNull() )
00250                 emit activated( text( newItem ) );
00251             emit activated( newItem );
00252             e->accept();
00253             return true;
00254         }
00255     }
00256 
00257     return QComboBox::eventFilter( o, ev );
00258 }
00259 
00260 void OComboBox::setTrapReturnKey( bool grab )
00261 {
00262     m_trapReturnKey = grab;
00263 }
00264 
00265 bool OComboBox::trapReturnKey() const
00266 {
00267     return m_trapReturnKey;
00268 }
00269 
00270 /*
00271 void OComboBox::setEditURL( const OURL& url )
00272 {
00273     QComboBox::setEditText( url.prettyURL() );
00274 }
00275 
00276 void OComboBox::insertURL( const OURL& url, int index )
00277 {
00278     QComboBox::insertItem( url.prettyURL(), index );
00279 }
00280 
00281 void OComboBox::insertURL( const QPixmap& pixmap, const OURL& url, int index )
00282 {
00283     QComboBox::insertItem( pixmap, url.prettyURL(), index );
00284 }
00285 
00286 void OComboBox::changeURL( const OURL& url, int index )
00287 {
00288     QComboBox::changeItem( url.prettyURL(), index );
00289 }
00290 
00291 void OComboBox::changeURL( const QPixmap& pixmap, const OURL& url, int index )
00292 {
00293     QComboBox::changeItem( pixmap, url.prettyURL(), index );
00294 }
00295 */
00296 
00297 
00298 void OComboBox::setCompletedItems( const QStringList& items )
00299 {
00300     if ( d->olineEdit )
00301         d->olineEdit->setCompletedItems( items );
00302 }
00303 
00304 
00305 OCompletionBox * OComboBox::completionBox( bool create )
00306 {
00307     if ( d->olineEdit )
00308         return d->olineEdit->completionBox( create );
00309     return 0;
00310 }
00311 
00312 // QWidget::create() turns off mouse-Tracking which would break auto-hiding
00313 void OComboBox::create( WId id, bool initializeWindow, bool destroyOldWindow )
00314 {
00315     QComboBox::create( id, initializeWindow, destroyOldWindow );
00316     //OCursor::setAutoHideCursor( lineEdit(), true, true );
00317 }
00318 
00319 void OComboBox::setLineEdit( OLineEdit *edit )
00320 {
00321     #if QT_VERSION >= 0x030000
00322     QComboBox::setLineEdit( edit );
00323     if ( !edit->inherits( "OLineEdit" ) )
00324         d->olineEdit = 0;
00325     else
00326         d->olineEdit = static_cast<OLineEdit*>( edit );
00327     setDelegate( d->olineEdit );
00328 
00329     // forward some signals. We only emit returnPressed() ourselves.
00330     if ( d->olineEdit ) {
00331         connect( d->olineEdit, SIGNAL( completion(const QString&)),
00332                  SIGNAL( completion(const QString&)) );
00333         connect( d->olineEdit, SIGNAL( substringCompletion(const QString&)),
00334                  SIGNAL( substringCompletion(const QString&)) );
00335         connect( d->olineEdit,
00336                  SIGNAL( textRotation(OCompletionBase::KeyBindingType)),
00337                  SIGNAL( textRotation(OCompletionBase::KeyBindingType)) );
00338         connect( d->olineEdit,
00339                  SIGNAL( completionModeChanged(OGlobalSettings::Completion)),
00340                  SIGNAL( completionModeChanged(OGlobalSettings::Completion)));
00341 
00342         connect( d->olineEdit,
00343                  SIGNAL( aboutToShowContextMenu(QPopupMenu*)),
00344                  SIGNAL( aboutToShowContextMenu(QPopupMenu*)) );
00345     }
00346     #else
00347     #warning OComboBox is not fully functional with Qt2
00348     #endif
00349 }
00350 
00351 // Temporary functions until QT3 appears. - Seth Chaiklin 20 may 2001
00352 void OComboBox::deleteWordForward()
00353 {
00354     lineEdit()->cursorWordForward(TRUE);
00355     #if QT_VERSION >= 0x030000
00356     if ( lineEdit()->hasSelectedText() )
00357     #else
00358     if ( lineEdit()->hasMarkedText() )
00359     #endif
00360     {
00361         lineEdit()->del();
00362     }
00363 }
00364 
00365 void OComboBox::deleteWordBack()
00366 {
00367     lineEdit()->cursorWordBackward(TRUE);
00368     #if QT_VERSION >= 0x030000
00369     if ( lineEdit()->hasSelectedText() )
00370     #else
00371     if ( lineEdit()->hasMarkedText() )
00372     #endif
00373     {
00374         lineEdit()->del();
00375     }
00376 }
00377 
00378 void OComboBox::setCurrentItem( const QString& item, bool insert, int index )
00379 {
00380     int sel = -1;
00381     for (int i = 0; i < count(); ++i)
00382         if (text(i) == item)
00383         {
00384             sel = i;
00385             break;
00386         }
00387     if (sel == -1 && insert)
00388     {
00389         insertItem(item, index);
00390         if (index >= 0)
00391             sel = index;
00392         else
00393             sel = count() - 1;
00394     }
00395     setCurrentItem(sel);
00396 }
00397 
00398 void OComboBox::setCurrentItem(int index)
00399 {
00400     QComboBox::setCurrentItem(index);
00401 }
00402 
00403 
00404 /*======================================================================================
00405  * OHistoryCombo
00406  *======================================================================================*/
00407 
00408 // we are always read-write
00409 OHistoryCombo::OHistoryCombo( QWidget *parent, const char *name )
00410     : OComboBox( true, parent, name )
00411 {
00412     init( true ); // using completion
00413 }
00414 
00415 // we are always read-write
00416 OHistoryCombo::OHistoryCombo( bool useCompletion,
00417                               QWidget *parent, const char *name )
00418     : OComboBox( true, parent, name )
00419 {
00420     init( useCompletion );
00421 }
00422 
00423 void OHistoryCombo::init( bool useCompletion )
00424 {
00425     if ( useCompletion )
00426         completionObject()->setOrder( OCompletion::Weighted );
00427 
00428     setInsertionPolicy( NoInsertion );
00429     myIterateIndex = -1;
00430     myRotated = false;
00431     myPixProvider = 0L;
00432 
00433     connect( this, SIGNAL(aboutToShowContextMenu(QPopupMenu*)),
00434              SLOT(addContextMenuItems(QPopupMenu*)) );
00435     connect( this, SIGNAL( activated(int) ), SLOT( slotReset() ));
00436     connect( this, SIGNAL( returnPressed(const QString&) ), SLOT(slotReset()));
00437 }
00438 
00439 OHistoryCombo::~OHistoryCombo()
00440 {
00441     delete myPixProvider;
00442 }
00443 
00444 void OHistoryCombo::setHistoryItems( QStringList items,
00445                                      bool setCompletionList )
00446 {
00447     OComboBox::clear();
00448 
00449     // limit to maxCount()
00450     while ( (int) items.count() > maxCount() && !items.isEmpty() )
00451         items.remove( items.begin() );
00452 
00453     insertItems( items );
00454 
00455     if ( setCompletionList && useCompletion() ) {
00456         // we don't have any weighting information here ;(
00457         OCompletion *comp = completionObject();
00458         comp->setOrder( OCompletion::Insertion );
00459         comp->setItems( items );
00460         comp->setOrder( OCompletion::Weighted );
00461     }
00462 
00463     clearEdit();
00464 }
00465 
00466 QStringList OHistoryCombo::historyItems() const
00467 {
00468     QStringList list;
00469     for ( int i = 0; i < count(); i++ )
00470         list.append( text( i ) );
00471 
00472     return list;
00473 }
00474 
00475 void OHistoryCombo::clearHistory()
00476 {
00477     OComboBox::clear();
00478     if ( useCompletion() )
00479         completionObject()->clear();
00480 }
00481 
00482 void OHistoryCombo::addContextMenuItems( QPopupMenu* menu )
00483 {
00484     if ( menu &&!lineEdit()->text().isEmpty())
00485     {
00486         menu->insertSeparator();
00487         menu->insertItem( tr("Empty Contents"), this, SLOT( slotClear()));
00488     }
00489 }
00490 
00491 void OHistoryCombo::addToHistory( const QString& item )
00492 {
00493     if ( item.isEmpty() || (count() > 0 && item == text(0) ))
00494         return;
00495 
00496     // remove all existing items before adding
00497     if ( !duplicatesEnabled() ) {
00498         for ( int i = 0; i < count(); i++ ) {
00499             if ( text( i ) == item )
00500                 removeItem( i );
00501         }
00502     }
00503 
00504     // now add the item
00505     if ( myPixProvider )
00506         //insertItem( myPixProvider->pixmapFor(item, KIcon::SizeSmall), item, 0);
00507         insertItem( myPixProvider->pixmapFor(item, 16), item, 0);
00508     else
00509         insertItem( item, 0 );
00510 
00511     int last;
00512     QString rmItem;
00513 
00514     bool useComp = useCompletion();
00515     while ( count() > maxCount() && count() > 0 ) {
00516         // remove the last item, as long as we are longer than maxCount()
00517         // remove the removed item from the completionObject if it isn't
00518         // anymore available at all in the combobox.
00519         last = count() - 1;
00520         rmItem = text( last );
00521         removeItem( last );
00522         if ( useComp && !contains( rmItem ) )
00523             completionObject()->removeItem( rmItem );
00524     }
00525 
00526     if ( useComp )
00527         completionObject()->addItem( item );
00528 }
00529 
00530 bool OHistoryCombo::removeFromHistory( const QString& item )
00531 {
00532     if ( item.isEmpty() )
00533         return false;
00534 
00535     bool removed = false;
00536     QString temp = currentText();
00537     for ( int i = 0; i < count(); i++ ) {
00538         while ( item == text( i ) ) {
00539             removed = true;
00540             removeItem( i );
00541         }
00542     }
00543 
00544     if ( removed && useCompletion() )
00545         completionObject()->removeItem( item );
00546 
00547     setEditText( temp );
00548     return removed;
00549 }
00550 
00551 void OHistoryCombo::keyPressEvent( QKeyEvent *e )
00552 {
00553     // save the current text in the lineedit
00554     if ( myIterateIndex == -1 )
00555         myText = currentText();
00556 
00557     // going up in the history, rotating when reaching QListBox::count()
00558     //if ( OStdAccel::isEqual( e, OStdAccel::rotateUp() ) ) {
00559     if ( e->key() == Qt::Key_Up ) {
00560         myIterateIndex++;
00561 
00562         // skip duplicates/empty items
00563         while ( myIterateIndex < count()-1 &&
00564                 (currentText() == text( myIterateIndex ) ||
00565                 text( myIterateIndex ).isEmpty()) )
00566             myIterateIndex++;
00567 
00568         if ( myIterateIndex >= count() ) {
00569             myRotated = true;
00570             myIterateIndex = -1;
00571 
00572             // if the typed text is the same as the first item, skip the first
00573             if ( myText == text(0) )
00574                 myIterateIndex = 0;
00575 
00576             setEditText( myText );
00577         }
00578         else
00579             setEditText( text( myIterateIndex ));
00580     }
00581 
00582 
00583     // going down in the history, no rotation possible. Last item will be
00584     // the text that was in the lineedit before Up was called.
00585     //else if ( OStdAccel::isEqual( e, OStdAccel::rotateDown() ) ) {
00586     else if ( e->key() == Qt::Key_Down ) {
00587         myIterateIndex--;
00588 
00589         // skip duplicates/empty items
00590         while ( myIterateIndex >= 0 &&
00591                 (currentText() == text( myIterateIndex ) ||
00592                 text( myIterateIndex ).isEmpty()) )
00593             myIterateIndex--;
00594 
00595 
00596         if ( myIterateIndex < 0 ) {
00597             if ( myRotated && myIterateIndex == -2 ) {
00598                 myRotated = false;
00599                 myIterateIndex = count() - 1;
00600                 setEditText( text(myIterateIndex) );
00601             }
00602             else { // bottom of history
00603                 if ( myIterateIndex == -2 ) {
00604                     qDebug( "ONotifyClient is not implemented yet." );
00605                     //ONotifyClient::event( ONotifyClient::notification,
00606                     //                  i18n("No further item in the history."));
00607                 }
00608 
00609                 myIterateIndex = -1;
00610                 if ( currentText() != myText )
00611                     setEditText( myText );
00612             }
00613         }
00614         else
00615             setEditText( text( myIterateIndex ));
00616     }
00617 
00618     else
00619         OComboBox::keyPressEvent( e );
00620 }
00621 
00622 void OHistoryCombo::slotReset()
00623 {
00624     myIterateIndex = -1;
00625     myRotated = false;
00626 }
00627 
00628 
00629 void OHistoryCombo::setPixmapProvider( OPixmapProvider *prov )
00630 {
00631     if ( myPixProvider == prov )
00632         return;
00633 
00634     delete myPixProvider;
00635     myPixProvider = prov;
00636 
00637     // re-insert all the items with/without pixmap
00638     // I would prefer to use changeItem(), but that doesn't honour the pixmap
00639     // when using an editable combobox (what we do)
00640     if ( count() > 0 ) {
00641         QStringList items( historyItems() );
00642         clear();
00643         insertItems( items );
00644     }
00645 }
00646 
00647 void OHistoryCombo::insertItems( const QStringList& items )
00648 {
00649     QStringList::ConstIterator it = items.begin();
00650     QString item;
00651     while ( it != items.end() ) {
00652         item = *it;
00653         if ( !item.isEmpty() ) { // only insert non-empty items
00654             if ( myPixProvider )
00655                 // insertItem( myPixProvider->pixmapFor(item, OIcon::SizeSmall), item );
00656                 insertItem( myPixProvider->pixmapFor(item, 16), item );
00657             else
00658                 insertItem( item );
00659         }
00660         ++it;
00661     }
00662 }
00663 
00664 void OHistoryCombo::slotClear()
00665 {
00666     clearHistory();
00667     emit cleared();
00668 }
00669 

Generated on Sat Nov 5 16:16:29 2005 for OPIE by  doxygen 1.4.2