summaryrefslogtreecommitdiff
path: root/libopie2/qt3/opieui/ocompletionbox.cpp
Unidiff
Diffstat (limited to 'libopie2/qt3/opieui/ocompletionbox.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/qt3/opieui/ocompletionbox.cpp408
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 @@
1/*
2 This file Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
3 is part of the Copyright (C) 2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
4 Opie Project Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
5 Copyright (C) 2000,2001 Dawit Alemayehu <adawit@kde.org>
6 =.
7 .=l. Originally part of the KDE Project
8           .>+-=
9 _;:,     .>    :=|. This program is free software; you can
10.> <`_,   >  .   <= redistribute it and/or modify it under
11:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
12.="- .-=="i,     .._ License as published by the Free Software
13 - .   .-<_>     .<> Foundation; either version 2 of the License,
14     ._= =}       : or (at your option) any later version.
15    .%`+i>       _;_.
16    .i_,=:_.      -<s. This program is distributed in the hope that
17     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
18    : ..    .:,     . . . without even the implied warranty of
19    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
20  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
21..}^=.=       =       ; Library General Public License for more
22++=   -.     .`     .: details.
23 :     =  ...= . :.=-
24 -.   .:....=;==+<; You should have received a copy of the GNU
25  -_. . .   )=.  = Library General Public License along with
26    --        :-=` this library; see the file COPYING.LIB.
27 If not, write to the Free Software Foundation,
28 Inc., 59 Temple Place - Suite 330,
29 Boston, MA 02111-1307, USA.
30
31*/
32
33#include <qapplication.h>
34#include <qevent.h>
35#include <qstyle.h>
36
37#include <opie2/ocompletionbox.h>
38
39#define OListBox QListBox
40
41class OCompletionBox::OCompletionBoxPrivate
42{
43public:
44 QWidget *m_parent; // necessary to set the focus back
45 QString cancelText;
46 bool tabHandling;
47 bool down_workaround;
48};
49
50OCompletionBox::OCompletionBox( QWidget *parent, const char *name )
51 :OListBox( parent, name, WType_Popup )
52{
53 d = new OCompletionBoxPrivate;
54 d->m_parent = parent;
55 d->tabHandling = true;
56 d->down_workaround = false;
57
58 setColumnMode( 1 );
59 setLineWidth( 1 );
60 setFrameStyle( QFrame::Box | QFrame::Plain );
61
62 if ( parent )
63 setFocusProxy( parent );
64 else
65 setFocusPolicy( NoFocus );
66
67 setVScrollBarMode( Auto );
68 setHScrollBarMode( AlwaysOff );
69
70 connect( this, SIGNAL( doubleClicked( QListBoxItem * )),
71 SLOT( slotActivated( QListBoxItem * )) );
72
73 // grmbl, just QListBox workarounds :[ Thanks Volker.
74 connect( this, SIGNAL( currentChanged( QListBoxItem * )),
75 SLOT( slotCurrentChanged() ));
76 connect( this, SIGNAL( clicked( QListBoxItem * )),
77 SLOT( slotItemClicked( QListBoxItem * )) );
78}
79
80OCompletionBox::~OCompletionBox()
81{
82 d->m_parent = 0L;
83 delete d;
84}
85
86QStringList OCompletionBox::items() const
87{
88 QStringList list;
89 for ( uint i = 0; i < count(); i++ ) {
90 list.append( text( i ) );
91 }
92 return list;
93}
94
95void OCompletionBox::slotActivated( QListBoxItem *item )
96{
97 if ( !item )
98 return;
99
100 hide();
101 emit activated( item->text() );
102}
103
104bool OCompletionBox::eventFilter( QObject *o, QEvent *e )
105{
106 int type = e->type();
107
108 if ( o == d->m_parent ) {
109 if ( isVisible() ) {
110 if ( type == QEvent::KeyPress ) {
111 QKeyEvent *ev = static_cast<QKeyEvent *>( e );
112 switch ( ev->key() ) {
113 case Key_BackTab:
114 if ( d->tabHandling ) {
115 up();
116 ev->accept();
117 return true;
118 }
119 break;
120 case Key_Tab:
121 if ( d->tabHandling ) {
122 down(); // Only on TAB!!
123 ev->accept();
124 return true;
125 }
126 break;
127 case Key_Down:
128 down();
129 ev->accept();
130 return true;
131 case Key_Up:
132 up();
133 ev->accept();
134 return true;
135 case Key_Prior:
136 pageUp();
137 ev->accept();
138 return true;
139 case Key_Next:
140 pageDown();
141 ev->accept();
142 return true;
143 case Key_Escape:
144 cancelled();
145 ev->accept();
146 return true;
147 case Key_Enter:
148 case Key_Return:
149 if ( ev->state() & ShiftButton ) {
150 hide();
151 ev->accept(); // Consume the Enter event
152 return true;
153 }
154 break;
155 default:
156 break;
157 }
158 }
159 else if ( type == QEvent::AccelOverride ) {
160 // Override any acceleartors that match
161 // the key sequences we use here...
162 QKeyEvent *ev = static_cast<QKeyEvent *>( e );
163 switch ( ev->key() ) {
164 case Key_Tab:
165 case Key_BackTab:
166 case Key_Down:
167 case Key_Up:
168 case Key_Prior:
169 case Key_Next:
170 case Key_Escape:
171 case Key_Enter:
172 case Key_Return:
173 ev->accept();
174 return true;
175 break;
176 default:
177 break;
178 }
179 }
180
181 // parent loses focus or gets a click -> we hide
182 else if ( type == QEvent::FocusOut || type == QEvent::Resize ||
183 type == QEvent::Close || type == QEvent::Hide ||
184 type == QEvent::Move ) {
185 hide();
186 }
187 else if ( type == QEvent::Move )
188 move( d->m_parent->mapToGlobal(QPoint(0, d->m_parent->height())));
189 else if ( type == QEvent::Resize )
190 resize( sizeHint() );
191 }
192 }
193
194 // any mouse-click on something else than "this" makes us hide
195 else if ( type == QEvent::MouseButtonPress ) {
196 QMouseEvent *ev = static_cast<QMouseEvent *>( e );
197 if ( !rect().contains( ev->pos() )) // this widget
198 hide();
199 }
200
201 return OListBox::eventFilter( o, e );
202}
203
204
205void OCompletionBox::popup()
206{
207 if ( count() == 0 )
208 hide();
209 else {
210 ensureCurrentVisible();
211 bool block = signalsBlocked();
212 blockSignals( true );
213 setCurrentItem( 0 );
214 blockSignals( block );
215 clearSelection();
216 if ( !isVisible() )
217 show();
218 else if ( size().height() < sizeHint().height() )
219 resize( sizeHint() );
220 }
221}
222
223void OCompletionBox::show()
224{
225 resize( sizeHint() );
226
227 if ( d->m_parent )
228 {
229 //QDesktopWidget *screen = QApplication::desktop();
230 QWidget *screen = QApplication::desktop();
231
232 QPoint orig = d->m_parent->mapToGlobal( QPoint(0, d->m_parent->height()) );
233 int x = orig.x();
234 int y = orig.y();
235
236 if ( x + width() > screen->width() )
237 x = screen->width() - width();
238 if (y + height() > screen->height() )
239 y = y - height() - d->m_parent->height();
240
241 move( x, y);
242 qApp->installEventFilter( this );
243 }
244
245 // ### we shouldn't need to call this, but without this, the scrollbars
246 // are pretty b0rked.
247 //triggerUpdate( true );
248
249 OListBox::show();
250}
251
252void OCompletionBox::hide()
253{
254 if ( d->m_parent )
255 qApp->removeEventFilter( this );
256 d->cancelText = QString::null;
257 OListBox::hide();
258}
259
260QSize OCompletionBox::sizeHint() const
261{
262 int ih = itemHeight();
263 int h = QMIN( 15 * ih, (int) count() * ih ) +1;
264 h = QMAX( h, OListBox::minimumSizeHint().height() );
265
266 int w = (d->m_parent) ? d->m_parent->width() : OListBox::minimumSizeHint().width();
267 w = QMAX( OListBox::minimumSizeHint().width(), w );
268 return QSize( w, h );
269}
270
271void OCompletionBox::down()
272{
273 int i = currentItem();
274
275 if ( i == 0 && d->down_workaround ) {
276 d->down_workaround = false;
277 setCurrentItem( 0 );
278 setSelected( 0, true );
279 emit highlighted( currentText() );
280 }
281
282 else if ( i < (int) count() - 1 )
283 setCurrentItem( i + 1 );
284}
285
286void OCompletionBox::up()
287{
288 if ( currentItem() > 0 )
289 setCurrentItem( currentItem() - 1 );
290}
291
292void OCompletionBox::pageDown()
293{
294 int i = currentItem() + numItemsVisible();
295 i = i > (int)count() - 1 ? (int)count() - 1 : i;
296 setCurrentItem( i );
297}
298
299void OCompletionBox::pageUp()
300{
301 int i = currentItem() - numItemsVisible();
302 i = i < 0 ? 0 : i;
303 setCurrentItem( i );
304}
305
306void OCompletionBox::home()
307{
308 setCurrentItem( 0 );
309}
310
311void OCompletionBox::end()
312{
313 setCurrentItem( count() -1 );
314}
315
316void OCompletionBox::setTabHandling( bool enable )
317{
318 d->tabHandling = enable;
319}
320
321bool OCompletionBox::isTabHandling() const
322{
323 return d->tabHandling;
324}
325
326void OCompletionBox::setCancelledText( const QString& text )
327{
328 d->cancelText = text;
329}
330
331QString OCompletionBox::cancelledText() const
332{
333 return d->cancelText;
334}
335
336void OCompletionBox::cancelled()
337{
338 if ( !d->cancelText.isNull() )
339 emit userCancelled( d->cancelText );
340 if ( isVisible() )
341 hide();
342}
343
344class OCompletionBoxItem : public QListBoxItem
345{
346public:
347 void reuse( const QString &text ) { setText( text ); }
348};
349
350
351void OCompletionBox::insertItems( const QStringList& items, int index )
352{
353 bool block = signalsBlocked();
354 blockSignals( true );
355 insertStringList( items, index );
356 blockSignals( block );
357 d->down_workaround = true;
358}
359
360void OCompletionBox::setItems( const QStringList& items )
361{
362 bool block = signalsBlocked();
363 blockSignals( true );
364
365 QListBoxItem* item = firstItem();
366 if ( !item ) {
367 insertStringList( items );
368 }
369 else {
370 for ( QStringList::ConstIterator it = items.begin(); it != items.end(); it++) {
371 if ( item ) {
372 ((OCompletionBoxItem*)item)->reuse( *it );
373 item = item->next();
374 }
375 else {
376 insertItem( new QListBoxText( *it ) );
377 }
378 }
379 QListBoxItem* tmp = item;
380 while ( (item = tmp ) ) {
381 tmp = item->next();
382 delete item;
383 }
384 triggerUpdate( false );
385 }
386
387 blockSignals( block );
388 d->down_workaround = true;
389}
390
391void OCompletionBox::slotCurrentChanged()
392{
393 d->down_workaround = false;
394}
395
396void OCompletionBox::slotItemClicked( QListBoxItem *item )
397{
398 if ( item )
399 {
400 if ( d->down_workaround ) {
401 d->down_workaround = false;
402 emit highlighted( item->text() );
403 }
404
405 hide();
406 emit activated( item->text() );
407 }
408}