Diffstat (limited to 'libopie2/qt3/opieui/ocompletionbox.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | libopie2/qt3/opieui/ocompletionbox.cpp | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/libopie2/qt3/opieui/ocompletionbox.cpp b/libopie2/qt3/opieui/ocompletionbox.cpp new file mode 100644 index 0000000..b594b8e --- a/dev/null +++ b/libopie2/qt3/opieui/ocompletionbox.cpp @@ -0,0 +1,408 @@ +/* + This file Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + is part of the Copyright (C) 2000,2001 Carsten Pfeiffer <pfeiffer@kde.org> + Opie Project Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de> + Copyright (C) 2000,2001 Dawit Alemayehu <adawit@kde.org> + =. + .=l. Originally part of the KDE Project + .>+-= + _;:, .> :=|. 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_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: 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. + +*/ + +#include <qapplication.h> +#include <qevent.h> +#include <qstyle.h> + +#include <opie2/ocompletionbox.h> + +#define OListBox QListBox + +class OCompletionBox::OCompletionBoxPrivate +{ +public: + QWidget *m_parent; // necessary to set the focus back + QString cancelText; + bool tabHandling; + bool down_workaround; +}; + +OCompletionBox::OCompletionBox( QWidget *parent, const char *name ) + :OListBox( parent, name, WType_Popup ) +{ + d = new OCompletionBoxPrivate; + d->m_parent = parent; + d->tabHandling = true; + d->down_workaround = false; + + setColumnMode( 1 ); + setLineWidth( 1 ); + setFrameStyle( QFrame::Box | QFrame::Plain ); + + if ( parent ) + setFocusProxy( parent ); + else + setFocusPolicy( NoFocus ); + + setVScrollBarMode( Auto ); + setHScrollBarMode( AlwaysOff ); + + connect( this, SIGNAL( doubleClicked( QListBoxItem * )), + SLOT( slotActivated( QListBoxItem * )) ); + + // grmbl, just QListBox workarounds :[ Thanks Volker. + connect( this, SIGNAL( currentChanged( QListBoxItem * )), + SLOT( slotCurrentChanged() )); + connect( this, SIGNAL( clicked( QListBoxItem * )), + SLOT( slotItemClicked( QListBoxItem * )) ); +} + +OCompletionBox::~OCompletionBox() +{ + d->m_parent = 0L; + delete d; +} + +QStringList OCompletionBox::items() const +{ + QStringList list; + for ( uint i = 0; i < count(); i++ ) { + list.append( text( i ) ); + } + return list; +} + +void OCompletionBox::slotActivated( QListBoxItem *item ) +{ + if ( !item ) + return; + + hide(); + emit activated( item->text() ); +} + +bool OCompletionBox::eventFilter( QObject *o, QEvent *e ) +{ + int type = e->type(); + + if ( o == d->m_parent ) { + if ( isVisible() ) { + if ( type == QEvent::KeyPress ) { + QKeyEvent *ev = static_cast<QKeyEvent *>( e ); + switch ( ev->key() ) { + case Key_BackTab: + if ( d->tabHandling ) { + up(); + ev->accept(); + return true; + } + break; + case Key_Tab: + if ( d->tabHandling ) { + down(); // Only on TAB!! + ev->accept(); + return true; + } + break; + case Key_Down: + down(); + ev->accept(); + return true; + case Key_Up: + up(); + ev->accept(); + return true; + case Key_Prior: + pageUp(); + ev->accept(); + return true; + case Key_Next: + pageDown(); + ev->accept(); + return true; + case Key_Escape: + cancelled(); + ev->accept(); + return true; + case Key_Enter: + case Key_Return: + if ( ev->state() & ShiftButton ) { + hide(); + ev->accept(); // Consume the Enter event + return true; + } + break; + default: + break; + } + } + else if ( type == QEvent::AccelOverride ) { + // Override any acceleartors that match + // the key sequences we use here... + QKeyEvent *ev = static_cast<QKeyEvent *>( e ); + switch ( ev->key() ) { + case Key_Tab: + case Key_BackTab: + case Key_Down: + case Key_Up: + case Key_Prior: + case Key_Next: + case Key_Escape: + case Key_Enter: + case Key_Return: + ev->accept(); + return true; + break; + default: + break; + } + } + + // parent loses focus or gets a click -> we hide + else if ( type == QEvent::FocusOut || type == QEvent::Resize || + type == QEvent::Close || type == QEvent::Hide || + type == QEvent::Move ) { + hide(); + } + else if ( type == QEvent::Move ) + move( d->m_parent->mapToGlobal(QPoint(0, d->m_parent->height()))); + else if ( type == QEvent::Resize ) + resize( sizeHint() ); + } + } + + // any mouse-click on something else than "this" makes us hide + else if ( type == QEvent::MouseButtonPress ) { + QMouseEvent *ev = static_cast<QMouseEvent *>( e ); + if ( !rect().contains( ev->pos() )) // this widget + hide(); + } + + return OListBox::eventFilter( o, e ); +} + + +void OCompletionBox::popup() +{ + if ( count() == 0 ) + hide(); + else { + ensureCurrentVisible(); + bool block = signalsBlocked(); + blockSignals( true ); + setCurrentItem( 0 ); + blockSignals( block ); + clearSelection(); + if ( !isVisible() ) + show(); + else if ( size().height() < sizeHint().height() ) + resize( sizeHint() ); + } +} + +void OCompletionBox::show() +{ + resize( sizeHint() ); + + if ( d->m_parent ) + { + //QDesktopWidget *screen = QApplication::desktop(); + QWidget *screen = QApplication::desktop(); + + QPoint orig = d->m_parent->mapToGlobal( QPoint(0, d->m_parent->height()) ); + int x = orig.x(); + int y = orig.y(); + + if ( x + width() > screen->width() ) + x = screen->width() - width(); + if (y + height() > screen->height() ) + y = y - height() - d->m_parent->height(); + + move( x, y); + qApp->installEventFilter( this ); + } + + // ### we shouldn't need to call this, but without this, the scrollbars + // are pretty b0rked. + //triggerUpdate( true ); + + OListBox::show(); +} + +void OCompletionBox::hide() +{ + if ( d->m_parent ) + qApp->removeEventFilter( this ); + d->cancelText = QString::null; + OListBox::hide(); +} + +QSize OCompletionBox::sizeHint() const +{ + int ih = itemHeight(); + int h = QMIN( 15 * ih, (int) count() * ih ) +1; + h = QMAX( h, OListBox::minimumSizeHint().height() ); + + int w = (d->m_parent) ? d->m_parent->width() : OListBox::minimumSizeHint().width(); + w = QMAX( OListBox::minimumSizeHint().width(), w ); + return QSize( w, h ); +} + +void OCompletionBox::down() +{ + int i = currentItem(); + + if ( i == 0 && d->down_workaround ) { + d->down_workaround = false; + setCurrentItem( 0 ); + setSelected( 0, true ); + emit highlighted( currentText() ); + } + + else if ( i < (int) count() - 1 ) + setCurrentItem( i + 1 ); +} + +void OCompletionBox::up() +{ + if ( currentItem() > 0 ) + setCurrentItem( currentItem() - 1 ); +} + +void OCompletionBox::pageDown() +{ + int i = currentItem() + numItemsVisible(); + i = i > (int)count() - 1 ? (int)count() - 1 : i; + setCurrentItem( i ); +} + +void OCompletionBox::pageUp() +{ + int i = currentItem() - numItemsVisible(); + i = i < 0 ? 0 : i; + setCurrentItem( i ); +} + +void OCompletionBox::home() +{ + setCurrentItem( 0 ); +} + +void OCompletionBox::end() +{ + setCurrentItem( count() -1 ); +} + +void OCompletionBox::setTabHandling( bool enable ) +{ + d->tabHandling = enable; +} + +bool OCompletionBox::isTabHandling() const +{ + return d->tabHandling; +} + +void OCompletionBox::setCancelledText( const QString& text ) +{ + d->cancelText = text; +} + +QString OCompletionBox::cancelledText() const +{ + return d->cancelText; +} + +void OCompletionBox::cancelled() +{ + if ( !d->cancelText.isNull() ) + emit userCancelled( d->cancelText ); + if ( isVisible() ) + hide(); +} + +class OCompletionBoxItem : public QListBoxItem +{ +public: + void reuse( const QString &text ) { setText( text ); } +}; + + +void OCompletionBox::insertItems( const QStringList& items, int index ) +{ + bool block = signalsBlocked(); + blockSignals( true ); + insertStringList( items, index ); + blockSignals( block ); + d->down_workaround = true; +} + +void OCompletionBox::setItems( const QStringList& items ) +{ + bool block = signalsBlocked(); + blockSignals( true ); + + QListBoxItem* item = firstItem(); + if ( !item ) { + insertStringList( items ); + } + else { + for ( QStringList::ConstIterator it = items.begin(); it != items.end(); it++) { + if ( item ) { + ((OCompletionBoxItem*)item)->reuse( *it ); + item = item->next(); + } + else { + insertItem( new QListBoxText( *it ) ); + } + } + QListBoxItem* tmp = item; + while ( (item = tmp ) ) { + tmp = item->next(); + delete item; + } + triggerUpdate( false ); + } + + blockSignals( block ); + d->down_workaround = true; +} + +void OCompletionBox::slotCurrentChanged() +{ + d->down_workaround = false; +} + +void OCompletionBox::slotItemClicked( QListBoxItem *item ) +{ + if ( item ) + { + if ( d->down_workaround ) { + d->down_workaround = false; + emit highlighted( item->text() ); + } + + hide(); + emit activated( item->text() ); + } +} |