/* This file Copyright (C) 2003 Michael 'Mickey' Lauer is part of the Copyright (C) 2000 Carsten Pfeiffer Opie Project Copyright (C) 2000 Dawit Alemayehu =. Originally part of the KDE Project .=l.            .>+-=  _;:,     .>    :=|. This program is free software; you can .> <`_,   >  .   <= redistribute it and/or modify it under :`=1 )Y*s>-.--   : the terms of the GNU Library General Public .="- .-=="i,     .._ License as published by the Free Software  - .   .-<_>     .<> Foundation; either version 2 of the License,      ._= =}       : or (at your option) any later version.     .%`+i>       _;_.     .i_,=:_.      -`: PARTICULAR PURPOSE. See the GNU ..}^=.=       =       ; Library General Public License for more ++=   -.     .`     .: details.  :     =  ...= . :.=-  -.   .:....=;==+<; You should have received a copy of the GNU   -_. . .   )=.  = Library General Public License along with     --        :-=` this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* QT */ #include #include #include /* OPIE */ #include #include #include #include /*====================================================================================== * OComboBoxPrivate *======================================================================================*/ class OComboBox::OComboBoxPrivate { public: OComboBoxPrivate() { olineEdit = 0L; } ~OComboBoxPrivate() { } OLineEdit *olineEdit; }; /*====================================================================================== * OComboBox *======================================================================================*/ OComboBox::OComboBox( QWidget *parent, const char *name ) : QComboBox( parent, name ) { init(); } OComboBox::OComboBox( bool rw, QWidget *parent, const char *name ) : QComboBox( rw, parent, name ) { init(); if ( rw ) { OLineEdit *edit = new OLineEdit( this, "combo lineedit" ); setLineEdit( edit ); } } OComboBox::~OComboBox() { delete d; } void OComboBox::init() { d = new OComboBoxPrivate; // Permanently set some parameters in the parent object. QComboBox::setAutoCompletion( false ); // Initialize enable popup menu to false. // Below it will be enabled if the widget // is editable. m_bEnableMenu = false; m_trapReturnKey = false; // Enable context menu by default if widget // is editable. setContextMenuEnabled( true ); // for wheelscrolling installEventFilter( this ); if ( lineEdit() ) lineEdit()->installEventFilter( this ); } bool OComboBox::contains( const QString& _text ) const { if ( _text.isEmpty() ) return false; for (int i = 0; i < count(); i++ ) { if ( text(i) == _text ) return true; } return false; } void OComboBox::setAutoCompletion( bool autocomplete ) { if ( d->olineEdit ) { if ( autocomplete ) { d->olineEdit->setCompletionMode( OGlobalSettings::CompletionAuto ); setCompletionMode( OGlobalSettings::CompletionAuto ); } else { d->olineEdit->setCompletionMode( OGlobalSettings::completionMode() ); setCompletionMode( OGlobalSettings::completionMode() ); } } } void OComboBox::setContextMenuEnabled( bool showMenu ) { if( d->olineEdit ) { d->olineEdit->setContextMenuEnabled( showMenu ); m_bEnableMenu = showMenu; } } /* void OComboBox::setURLDropsEnabled( bool enable ) { if ( d->olineEdit ) d->olineEdit->setURLDropsEnabled( enable ); } bool OComboBox::isURLDropsEnabled() const { return d->olineEdit && d->olineEdit->isURLDropsEnabled(); } */ void OComboBox::setCompletedText( const QString& text, bool marked ) { if ( d->olineEdit ) d->olineEdit->setCompletedText( text, marked ); } void OComboBox::setCompletedText( const QString& text ) { if ( d->olineEdit ) d->olineEdit->setCompletedText( text ); } void OComboBox::makeCompletion( const QString& text ) { if( d->olineEdit ) d->olineEdit->makeCompletion( text ); else // read-only combo completion { if( text.isNull() || !listBox() ) return; int index = listBox()->index( listBox()->findItem( text ) ); if( index >= 0 ) { setCurrentItem( index ); } } } void OComboBox::rotateText( OCompletionBase::KeyBindingType type ) { if ( d->olineEdit ) d->olineEdit->rotateText( type ); } bool OComboBox::eventFilter( QObject* o, QEvent* ev ) { QLineEdit *edit = lineEdit(); int type = ev->type(); if ( o == edit ) { //OCursor::autoHideEventFilter( edit, ev ); if ( type == QEvent::KeyPress ) { QKeyEvent *e = static_cast( ev ); if ( e->key() == Key_Return || e->key() == Key_Enter) { // On Return pressed event, emit both // returnPressed(const QString&) and returnPressed() signals emit returnPressed(); emit returnPressed( currentText() ); if ( d->olineEdit && d->olineEdit->completionBox(false) && d->olineEdit->completionBox()->isVisible() ) d->olineEdit->completionBox()->hide(); return m_trapReturnKey; } } } // wheel-scrolling changes the current item if ( type == QEvent::Wheel ) { if ( !listBox() || listBox()->isHidden() ) { QWheelEvent *e = static_cast( ev ); static const int WHEEL_DELTA = 120; int skipItems = e->delta() / WHEEL_DELTA; if ( e->state() & ControlButton ) // fast skipping skipItems *= 10; int newItem = currentItem() - skipItems; if ( newItem < 0 ) newItem = 0; else if ( newItem >= count() ) newItem = count() -1; setCurrentItem( newItem ); if ( !text( newItem ).isNull() ) emit activated( text( newItem ) ); emit activated( newItem ); e->accept(); return true; } } return QComboBox::eventFilter( o, ev ); } void OComboBox::setTrapReturnKey( bool grab ) { m_trapReturnKey = grab; } bool OComboBox::trapReturnKey() const { return m_trapReturnKey; } /* void OComboBox::setEditURL( const OURL& url ) { QComboBox::setEditText( url.prettyURL() ); } void OComboBox::insertURL( const OURL& url, int index ) { QComboBox::insertItem( url.prettyURL(), index ); } void OComboBox::insertURL( const QPixmap& pixmap, const OURL& url, int index ) { QComboBox::insertItem( pixmap, url.prettyURL(), index ); } void OComboBox::changeURL( const OURL& url, int index ) { QComboBox::changeItem( url.prettyURL(), index ); } void OComboBox::changeURL( const QPixmap& pixmap, const OURL& url, int index ) { QComboBox::changeItem( pixmap, url.prettyURL(), index ); } */ void OComboBox::setCompletedItems( const QStringList& items ) { if ( d->olineEdit ) d->olineEdit->setCompletedItems( items ); } OCompletionBox * OComboBox::completionBox( bool create ) { if ( d->olineEdit ) return d->olineEdit->completionBox( create ); return 0; } // QWidget::create() turns off mouse-Tracking which would break auto-hiding void OComboBox::create( WId id, bool initializeWindow, bool destroyOldWindow ) { QComboBox::create( id, initializeWindow, destroyOldWindow ); //OCursor::setAutoHideCursor( lineEdit(), true, true ); } void OComboBox::setLineEdit( OLineEdit *edit ) { #if QT_VERSION >= 0x030000 QComboBox::setLineEdit( edit ); if ( !edit->inherits( "OLineEdit" ) ) d->olineEdit = 0; else d->olineEdit = static_cast( edit ); setDelegate( d->olineEdit ); // forward some signals. We only emit returnPressed() ourselves. if ( d->olineEdit ) { connect( d->olineEdit, SIGNAL( completion(const QString&)), SIGNAL( completion(const QString&)) ); connect( d->olineEdit, SIGNAL( substringCompletion(const QString&)), SIGNAL( substringCompletion(const QString&)) ); connect( d->olineEdit, SIGNAL( textRotation(OCompletionBase::KeyBindingType)), SIGNAL( textRotation(OCompletionBase::KeyBindingType)) ); connect( d->olineEdit, SIGNAL( completionModeChanged(OGlobalSettings::Completion)), SIGNAL( completionModeChanged(OGlobalSettings::Completion))); connect( d->olineEdit, SIGNAL( aboutToShowContextMenu(QPopupMenu*)), SIGNAL( aboutToShowContextMenu(QPopupMenu*)) ); } #else #warning OComboBox is not fully functional with Qt2 #endif } // Temporary functions until QT3 appears. - Seth Chaiklin 20 may 2001 void OComboBox::deleteWordForward() { lineEdit()->cursorWordForward(TRUE); #if QT_VERSION >= 0x030000 if ( lineEdit()->hasSelectedText() ) #else if ( lineEdit()->hasMarkedText() ) #endif { lineEdit()->del(); } } void OComboBox::deleteWordBack() { lineEdit()->cursorWordBackward(TRUE); #if QT_VERSION >= 0x030000 if ( lineEdit()->hasSelectedText() ) #else if ( lineEdit()->hasMarkedText() ) #endif { lineEdit()->del(); } } void OComboBox::setCurrentItem( const QString& item, bool insert, int index ) { int sel = -1; for (int i = 0; i < count(); ++i) if (text(i) == item) { sel = i; break; } if (sel == -1 && insert) { insertItem(item, index); if (index >= 0) sel = index; else sel = count() - 1; } setCurrentItem(sel); } void OComboBox::setCurrentItem(int index) { QComboBox::setCurrentItem(index); } /*====================================================================================== * OHistoryCombo *======================================================================================*/ // we are always read-write OHistoryCombo::OHistoryCombo( QWidget *parent, const char *name ) : OComboBox( true, parent, name ) { init( true ); // using completion } // we are always read-write OHistoryCombo::OHistoryCombo( bool useCompletion, QWidget *parent, const char *name ) : OComboBox( true, parent, name ) { init( useCompletion ); } void OHistoryCombo::init( bool useCompletion ) { if ( useCompletion ) completionObject()->setOrder( OCompletion::Weighted ); setInsertionPolicy( NoInsertion ); myIterateIndex = -1; myRotated = false; myPixProvider = 0L; connect( this, SIGNAL(aboutToShowContextMenu(QPopupMenu*)), SLOT(addContextMenuItems(QPopupMenu*)) ); connect( this, SIGNAL( activated(int) ), SLOT( slotReset() )); connect( this, SIGNAL( returnPressed(const QString&) ), SLOT(slotReset())); } OHistoryCombo::~OHistoryCombo() { delete myPixProvider; } void OHistoryCombo::setHistoryItems( QStringList items, bool setCompletionList ) { OComboBox::clear(); // limit to maxCount() while ( (int) items.count() > maxCount() && !items.isEmpty() ) items.remove( items.begin() ); insertItems( items ); if ( setCompletionList && useCompletion() ) { // we don't have any weighting information here ;( OCompletion *comp = completionObject(); comp->setOrder( OCompletion::Insertion ); comp->setItems( items ); comp->setOrder( OCompletion::Weighted ); } clearEdit(); } QStringList OHistoryCombo::historyItems() const { QStringList list; for ( int i = 0; i < count(); i++ ) list.append( text( i ) ); return list; } void OHistoryCombo::clearHistory() { OComboBox::clear(); if ( useCompletion() ) completionObject()->clear(); } void OHistoryCombo::addContextMenuItems( QPopupMenu* menu ) { if ( menu &&!lineEdit()->text().isEmpty()) { menu->insertSeparator(); menu->insertItem( tr("Empty Contents"), this, SLOT( slotClear())); } } void OHistoryCombo::addToHistory( const QString& item ) { if ( item.isEmpty() || (count() > 0 && item == text(0) )) return; // remove all existing items before adding if ( !duplicatesEnabled() ) { for ( int i = 0; i < count(); i++ ) { if ( text( i ) == item ) removeItem( i ); } } // now add the item if ( myPixProvider ) //insertItem( myPixProvider->pixmapFor(item, KIcon::SizeSmall), item, 0); insertItem( myPixProvider->pixmapFor(item, 16), item, 0); else insertItem( item, 0 ); int last; QString rmItem; bool useComp = useCompletion(); while ( count() > maxCount() && count() > 0 ) { // remove the last item, as long as we are longer than maxCount() // remove the removed item from the completionObject if it isn't // anymore available at all in the combobox. last = count() - 1; rmItem = text( last ); removeItem( last ); if ( useComp && !contains( rmItem ) ) completionObject()->removeItem( rmItem ); } if ( useComp ) completionObject()->addItem( item ); } bool OHistoryCombo::removeFromHistory( const QString& item ) { if ( item.isEmpty() ) return false; bool removed = false; QString temp = currentText(); for ( int i = 0; i < count(); i++ ) { while ( item == text( i ) ) { removed = true; removeItem( i ); } } if ( removed && useCompletion() ) completionObject()->removeItem( item ); setEditText( temp ); return removed; } void OHistoryCombo::keyPressEvent( QKeyEvent *e ) { // save the current text in the lineedit if ( myIterateIndex == -1 ) myText = currentText(); // going up in the history, rotating when reaching QListBox::count() //if ( OStdAccel::isEqual( e, OStdAccel::rotateUp() ) ) { if ( e->key() == Qt::Key_Up ) { myIterateIndex++; // skip duplicates/empty items while ( myIterateIndex < count()-1 && (currentText() == text( myIterateIndex ) || text( myIterateIndex ).isEmpty()) ) myIterateIndex++; if ( myIterateIndex >= count() ) { myRotated = true; myIterateIndex = -1; // if the typed text is the same as the first item, skip the first if ( myText == text(0) ) myIterateIndex = 0; setEditText( myText ); } else setEditText( text( myIterateIndex )); } // going down in the history, no rotation possible. Last item will be // the text that was in the lineedit before Up was called. //else if ( OStdAccel::isEqual( e, OStdAccel::rotateDown() ) ) { else if ( e->key() == Qt::Key_Down ) { myIterateIndex--; // skip duplicates/empty items while ( myIterateIndex >= 0 && (currentText() == text( myIterateIndex ) || text( myIterateIndex ).isEmpty()) ) myIterateIndex--; if ( myIterateIndex < 0 ) { if ( myRotated && myIterateIndex == -2 ) { myRotated = false; myIterateIndex = count() - 1; setEditText( text(myIterateIndex) ); } else { // bottom of history if ( myIterateIndex == -2 ) { qDebug( "ONotifyClient is not implemented yet." ); //ONotifyClient::event( ONotifyClient::notification, // i18n("No further item in the history.")); } myIterateIndex = -1; if ( currentText() != myText ) setEditText( myText ); } } else setEditText( text( myIterateIndex )); } else OComboBox::keyPressEvent( e ); } void OHistoryCombo::slotReset() { myIterateIndex = -1; myRotated = false; } void OHistoryCombo::setPixmapProvider( OPixmapProvider *prov ) { if ( myPixProvider == prov ) return; delete myPixProvider; myPixProvider = prov; // re-insert all the items with/without pixmap // I would prefer to use changeItem(), but that doesn't honour the pixmap // when using an editable combobox (what we do) if ( count() > 0 ) { QStringList items( historyItems() ); clear(); insertItems( items ); } } void OHistoryCombo::insertItems( const QStringList& items ) { QStringList::ConstIterator it = items.begin(); QString item; while ( it != items.end() ) { item = *it; if ( !item.isEmpty() ) { // only insert non-empty items if ( myPixProvider ) // insertItem( myPixProvider->pixmapFor(item, OIcon::SizeSmall), item ); insertItem( myPixProvider->pixmapFor(item, 16), item ); else insertItem( item ); } ++it; } } void OHistoryCombo::slotClear() { clearHistory(); emit cleared(); }