author | mickeyl <mickeyl> | 2003-03-28 15:11:52 (UTC) |
---|---|---|
committer | mickeyl <mickeyl> | 2003-03-28 15:11:52 (UTC) |
commit | 11304d02942e9fa493e4e80943a828f9c65f6772 (patch) (unidiff) | |
tree | a0223c10c067e1afc70d15c2b82be3f3c15e41ae /libopie2/qt3/opieui | |
parent | b271d575fa05cf570a1a829136517761bd47e69b (diff) | |
download | opie-11304d02942e9fa493e4e80943a828f9c65f6772.zip opie-11304d02942e9fa493e4e80943a828f9c65f6772.tar.gz opie-11304d02942e9fa493e4e80943a828f9c65f6772.tar.bz2 |
skeleton and the start of libopie2, please read README, ROADMAP and STATUS and comment...
-rw-r--r-- | libopie2/qt3/opieui/ocombobox.cpp | 666 | ||||
-rw-r--r-- | libopie2/qt3/opieui/ocombobox.h | 790 | ||||
-rw-r--r-- | libopie2/qt3/opieui/ocompletionbox.cpp | 408 | ||||
-rw-r--r-- | libopie2/qt3/opieui/ocompletionbox.h | 232 | ||||
-rw-r--r-- | libopie2/qt3/opieui/oeditlistbox.cpp | 416 | ||||
-rw-r--r-- | libopie2/qt3/opieui/oeditlistbox.h | 250 | ||||
-rw-r--r-- | libopie2/qt3/opieui/ojanuswidget.cpp | 1116 | ||||
-rw-r--r-- | libopie2/qt3/opieui/ojanuswidget.h | 551 | ||||
-rw-r--r-- | libopie2/qt3/opieui/olineedit.cpp | 729 | ||||
-rw-r--r-- | libopie2/qt3/opieui/olineedit.h | 498 |
10 files changed, 5656 insertions, 0 deletions
diff --git a/libopie2/qt3/opieui/ocombobox.cpp b/libopie2/qt3/opieui/ocombobox.cpp new file mode 100644 index 0000000..a1dd5f5 --- a/dev/null +++ b/libopie2/qt3/opieui/ocombobox.cpp | |||
@@ -0,0 +1,666 @@ | |||
1 | /* | ||
2 | This file Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> | ||
3 | is part of the Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org> | ||
4 | Opie Project Copyright (C) 2000 Dawit Alemayehu <adawit@kde.org> | ||
5 | |||
6 | =. Originally part of the KDE Project | ||
7 | .=l. | ||
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 | /* QT */ | ||
34 | |||
35 | #include <qclipboard.h> | ||
36 | #include <qlistbox.h> | ||
37 | #include <qpopupmenu.h> | ||
38 | |||
39 | /* OPIE */ | ||
40 | |||
41 | #include <opie2/ocompletionbox.h> | ||
42 | #include <opie2/olineedit.h> | ||
43 | #include <opie2/opixmapprovider.h> | ||
44 | #include <opie2/ocombobox.h> | ||
45 | |||
46 | /*====================================================================================== | ||
47 | * OComboBoxPrivate | ||
48 | *======================================================================================*/ | ||
49 | |||
50 | class OComboBox::OComboBoxPrivate | ||
51 | { | ||
52 | public: | ||
53 | OComboBoxPrivate() | ||
54 | { | ||
55 | olineEdit = 0L; | ||
56 | } | ||
57 | ~OComboBoxPrivate() | ||
58 | { | ||
59 | } | ||
60 | |||
61 | OLineEdit *olineEdit; | ||
62 | }; | ||
63 | |||
64 | /*====================================================================================== | ||
65 | * OComboBox | ||
66 | *======================================================================================*/ | ||
67 | |||
68 | OComboBox::OComboBox( QWidget *parent, const char *name ) | ||
69 | : QComboBox( parent, name ) | ||
70 | { | ||
71 | init(); | ||
72 | } | ||
73 | |||
74 | OComboBox::OComboBox( bool rw, QWidget *parent, const char *name ) | ||
75 | : QComboBox( rw, parent, name ) | ||
76 | { | ||
77 | init(); | ||
78 | |||
79 | if ( rw ) | ||
80 | { | ||
81 | OLineEdit *edit = new OLineEdit( this, "combo lineedit" ); | ||
82 | setLineEdit( edit ); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | OComboBox::~OComboBox() | ||
87 | { | ||
88 | delete d; | ||
89 | } | ||
90 | |||
91 | void OComboBox::init() | ||
92 | { | ||
93 | d = new OComboBoxPrivate; | ||
94 | |||
95 | // Permanently set some parameters in the parent object. | ||
96 | QComboBox::setAutoCompletion( false ); | ||
97 | |||
98 | // Initialize enable popup menu to false. | ||
99 | // Below it will be enabled if the widget | ||
100 | // is editable. | ||
101 | m_bEnableMenu = false; | ||
102 | |||
103 | m_trapReturnKey = false; | ||
104 | |||
105 | // Enable context menu by default if widget | ||
106 | // is editable. | ||
107 | setContextMenuEnabled( true ); | ||
108 | |||
109 | // for wheelscrolling | ||
110 | installEventFilter( this ); | ||
111 | if ( lineEdit() ) | ||
112 | lineEdit()->installEventFilter( this ); | ||
113 | } | ||
114 | |||
115 | |||
116 | bool OComboBox::contains( const QString& _text ) const | ||
117 | { | ||
118 | if ( _text.isEmpty() ) | ||
119 | return false; | ||
120 | |||
121 | for (int i = 0; i < count(); i++ ) { | ||
122 | if ( text(i) == _text ) | ||
123 | return true; | ||
124 | } | ||
125 | return false; | ||
126 | } | ||
127 | |||
128 | void OComboBox::setAutoCompletion( bool autocomplete ) | ||
129 | { | ||
130 | if ( d->olineEdit ) | ||
131 | { | ||
132 | if ( autocomplete ) | ||
133 | { | ||
134 | d->olineEdit->setCompletionMode( OGlobalSettings::CompletionAuto ); | ||
135 | setCompletionMode( OGlobalSettings::CompletionAuto ); | ||
136 | } | ||
137 | else | ||
138 | { | ||
139 | d->olineEdit->setCompletionMode( OGlobalSettings::completionMode() ); | ||
140 | setCompletionMode( OGlobalSettings::completionMode() ); | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | void OComboBox::setContextMenuEnabled( bool showMenu ) | ||
146 | { | ||
147 | if( d->olineEdit ) | ||
148 | { | ||
149 | d->olineEdit->setContextMenuEnabled( showMenu ); | ||
150 | m_bEnableMenu = showMenu; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | void OComboBox::setURLDropsEnabled( bool enable ) | ||
156 | { | ||
157 | if ( d->olineEdit ) | ||
158 | d->olineEdit->setURLDropsEnabled( enable ); | ||
159 | } | ||
160 | |||
161 | bool OComboBox::isURLDropsEnabled() const | ||
162 | { | ||
163 | return d->olineEdit && d->olineEdit->isURLDropsEnabled(); | ||
164 | } | ||
165 | */ | ||
166 | |||
167 | void OComboBox::setCompletedText( const QString& text, bool marked ) | ||
168 | { | ||
169 | if ( d->olineEdit ) | ||
170 | d->olineEdit->setCompletedText( text, marked ); | ||
171 | } | ||
172 | |||
173 | void OComboBox::setCompletedText( const QString& text ) | ||
174 | { | ||
175 | if ( d->olineEdit ) | ||
176 | d->olineEdit->setCompletedText( text ); | ||
177 | } | ||
178 | |||
179 | void OComboBox::makeCompletion( const QString& text ) | ||
180 | { | ||
181 | if( d->olineEdit ) | ||
182 | d->olineEdit->makeCompletion( text ); | ||
183 | |||
184 | else // read-only combo completion | ||
185 | { | ||
186 | if( text.isNull() || !listBox() ) | ||
187 | return; | ||
188 | |||
189 | int index = listBox()->index( listBox()->findItem( text ) ); | ||
190 | if( index >= 0 ) { | ||
191 | setCurrentItem( index ); | ||
192 | } | ||
193 | } | ||
194 | } | ||
195 | |||
196 | void OComboBox::rotateText( OCompletionBase::KeyBindingType type ) | ||
197 | { | ||
198 | if ( d->olineEdit ) | ||
199 | d->olineEdit->rotateText( type ); | ||
200 | } | ||
201 | |||
202 | bool OComboBox::eventFilter( QObject* o, QEvent* ev ) | ||
203 | { | ||
204 | QLineEdit *edit = lineEdit(); | ||
205 | |||
206 | int type = ev->type(); | ||
207 | |||
208 | if ( o == edit ) | ||
209 | { | ||
210 | //OCursor::autoHideEventFilter( edit, ev ); | ||
211 | |||
212 | if ( type == QEvent::KeyPress ) | ||
213 | { | ||
214 | QKeyEvent *e = static_cast<QKeyEvent *>( ev ); | ||
215 | |||
216 | if ( e->key() == Key_Return || e->key() == Key_Enter) | ||
217 | { | ||
218 | // On Return pressed event, emit both | ||
219 | // returnPressed(const QString&) and returnPressed() signals | ||
220 | emit returnPressed(); | ||
221 | emit returnPressed( currentText() ); | ||
222 | if ( d->olineEdit && d->olineEdit->completionBox(false) && | ||
223 | d->olineEdit->completionBox()->isVisible() ) | ||
224 | d->olineEdit->completionBox()->hide(); | ||
225 | |||
226 | return m_trapReturnKey; | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | |||
231 | |||
232 | // wheel-scrolling changes the current item | ||
233 | if ( type == QEvent::Wheel ) { | ||
234 | if ( !listBox() || listBox()->isHidden() ) { | ||
235 | QWheelEvent *e = static_cast<QWheelEvent*>( ev ); | ||
236 | static const int WHEEL_DELTA = 120; | ||
237 | int skipItems = e->delta() / WHEEL_DELTA; | ||
238 | if ( e->state() & ControlButton ) // fast skipping | ||
239 | skipItems *= 10; | ||
240 | |||
241 | int newItem = currentItem() - skipItems; | ||
242 | |||
243 | if ( newItem < 0 ) | ||
244 | newItem = 0; | ||
245 | else if ( newItem >= count() ) | ||
246 | newItem = count() -1; | ||
247 | |||
248 | setCurrentItem( newItem ); | ||
249 | if ( !text( newItem ).isNull() ) | ||
250 | emit activated( text( newItem ) ); | ||
251 | emit activated( newItem ); | ||
252 | e->accept(); | ||
253 | return true; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | return QComboBox::eventFilter( o, ev ); | ||
258 | } | ||
259 | |||
260 | void OComboBox::setTrapReturnKey( bool grab ) | ||
261 | { | ||
262 | m_trapReturnKey = grab; | ||
263 | } | ||
264 | |||
265 | bool OComboBox::trapReturnKey() const | ||
266 | { | ||
267 | return m_trapReturnKey; | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | void OComboBox::setEditURL( const OURL& url ) | ||
272 | { | ||
273 | QComboBox::setEditText( url.prettyURL() ); | ||
274 | } | ||
275 | |||
276 | void OComboBox::insertURL( const OURL& url, int index ) | ||
277 | { | ||
278 | QComboBox::insertItem( url.prettyURL(), index ); | ||
279 | } | ||
280 | |||
281 | void OComboBox::insertURL( const QPixmap& pixmap, const OURL& url, int index ) | ||
282 | { | ||
283 | QComboBox::insertItem( pixmap, url.prettyURL(), index ); | ||
284 | } | ||
285 | |||
286 | void OComboBox::changeURL( const OURL& url, int index ) | ||
287 | { | ||
288 | QComboBox::changeItem( url.prettyURL(), index ); | ||
289 | } | ||
290 | |||
291 | void OComboBox::changeURL( const QPixmap& pixmap, const OURL& url, int index ) | ||
292 | { | ||
293 | QComboBox::changeItem( pixmap, url.prettyURL(), index ); | ||
294 | } | ||
295 | */ | ||
296 | |||
297 | |||
298 | void OComboBox::setCompletedItems( const QStringList& items ) | ||
299 | { | ||
300 | if ( d->olineEdit ) | ||
301 | d->olineEdit->setCompletedItems( items ); | ||
302 | } | ||
303 | |||
304 | |||
305 | OCompletionBox * OComboBox::completionBox( bool create ) | ||
306 | { | ||
307 | if ( d->olineEdit ) | ||
308 | return d->olineEdit->completionBox( create ); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | // QWidget::create() turns off mouse-Tracking which would break auto-hiding | ||
313 | void OComboBox::create( WId id, bool initializeWindow, bool destroyOldWindow ) | ||
314 | { | ||
315 | QComboBox::create( id, initializeWindow, destroyOldWindow ); | ||
316 | //OCursor::setAutoHideCursor( lineEdit(), true, true ); | ||
317 | } | ||
318 | |||
319 | void OComboBox::setLineEdit( OLineEdit *edit ) | ||
320 | { | ||
321 | #if QT_VERSION > 290 | ||
322 | QComboBox::setLineEdit( edit ); | ||
323 | d->olineEdit = dynamic_cast<OLineEdit*>( edit ); | ||
324 | setDelegate( d->olineEdit ); | ||
325 | |||
326 | // forward some signals. We only emit returnPressed() ourselves. | ||
327 | if ( d->olineEdit ) { | ||
328 | connect( d->olineEdit, SIGNAL( completion( const QString& )), | ||
329 | SIGNAL( completion( const QString& )) ); | ||
330 | connect( d->olineEdit, SIGNAL( substringCompletion( const QString& )), | ||
331 | SIGNAL( substringCompletion( const QString& )) ); | ||
332 | connect( d->olineEdit, | ||
333 | SIGNAL( textRotation( OCompletionBase::KeyBindingType )), | ||
334 | SIGNAL( textRotation( OCompletionBase::KeyBindingType )) ); | ||
335 | connect( d->olineEdit, | ||
336 | SIGNAL( completionModeChanged( OGlobalSettings::Completion )), | ||
337 | SIGNAL( completionModeChanged( OGlobalSettings::Completion))); | ||
338 | |||
339 | connect( d->olineEdit, | ||
340 | SIGNAL( aboutToShowContextMenu( QPopupMenu * )), | ||
341 | SIGNAL( aboutToShowContextMenu( QPopupMenu * )) ); | ||
342 | } | ||
343 | #else | ||
344 | #warning OComboBox is not fully functional with Qt2 | ||
345 | #endif | ||
346 | } | ||
347 | |||
348 | // Temporary functions until QT3 appears. - Seth Chaiklin 20 may 2001 | ||
349 | void OComboBox::deleteWordForward() | ||
350 | { | ||
351 | lineEdit()->cursorWordForward(TRUE); | ||
352 | #if QT_VERSION > 290 | ||
353 | if ( lineEdit()->hasSelectedText() ) | ||
354 | #else | ||
355 | if ( lineEdit()->hasMarkedText() ) | ||
356 | #endif | ||
357 | { | ||
358 | lineEdit()->del(); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | void OComboBox::deleteWordBack() | ||
363 | { | ||
364 | lineEdit()->cursorWordBackward(TRUE); | ||
365 | #if QT_VERSION > 290 | ||
366 | if ( lineEdit()->hasSelectedText() ) | ||
367 | #else | ||
368 | if ( lineEdit()->hasMarkedText() ) | ||
369 | #endif | ||
370 | { | ||
371 | lineEdit()->del(); | ||
372 | } | ||
373 | } | ||
374 | |||
375 | void OComboBox::setCurrentItem( const QString& item, bool insert, int index ) | ||
376 | { | ||
377 | int sel = -1; | ||
378 | for (int i = 0; i < count(); ++i) | ||
379 | if (text(i) == item) | ||
380 | { | ||
381 | sel = i; | ||
382 | break; | ||
383 | } | ||
384 | if (sel == -1 && insert) | ||
385 | { | ||
386 | insertItem(item, index); | ||
387 | if (index >= 0) | ||
388 | sel = index; | ||
389 | else | ||
390 | sel = count() - 1; | ||
391 | } | ||
392 | setCurrentItem(sel); | ||
393 | } | ||
394 | |||
395 | void OComboBox::setCurrentItem(int index) | ||
396 | { | ||
397 | QComboBox::setCurrentItem(index); | ||
398 | } | ||
399 | |||
400 | |||
401 | /*====================================================================================== | ||
402 | * OHistoryCombo | ||
403 | *======================================================================================*/ | ||
404 | |||
405 | // we are always read-write | ||
406 | OHistoryCombo::OHistoryCombo( QWidget *parent, const char *name ) | ||
407 | : OComboBox( true, parent, name ) | ||
408 | { | ||
409 | init( true ); // using completion | ||
410 | } | ||
411 | |||
412 | // we are always read-write | ||
413 | OHistoryCombo::OHistoryCombo( bool useCompletion, | ||
414 | QWidget *parent, const char *name ) | ||
415 | : OComboBox( true, parent, name ) | ||
416 | { | ||
417 | init( useCompletion ); | ||
418 | } | ||
419 | |||
420 | void OHistoryCombo::init( bool useCompletion ) | ||
421 | { | ||
422 | if ( useCompletion ) | ||
423 | completionObject()->setOrder( OCompletion::Weighted ); | ||
424 | |||
425 | setInsertionPolicy( NoInsertion ); | ||
426 | myIterateIndex = -1; | ||
427 | myRotated = false; | ||
428 | myPixProvider = 0L; | ||
429 | |||
430 | connect( this, SIGNAL(aboutToShowContextMenu(QPopupMenu*)), | ||
431 | SLOT(addContextMenuItems(QPopupMenu*)) ); | ||
432 | connect( this, SIGNAL( activated(int) ), SLOT( slotReset() )); | ||
433 | connect( this, SIGNAL( returnPressed(const QString&) ), SLOT(slotReset())); | ||
434 | } | ||
435 | |||
436 | OHistoryCombo::~OHistoryCombo() | ||
437 | { | ||
438 | delete myPixProvider; | ||
439 | } | ||
440 | |||
441 | void OHistoryCombo::setHistoryItems( QStringList items, | ||
442 | bool setCompletionList ) | ||
443 | { | ||
444 | OComboBox::clear(); | ||
445 | |||
446 | // limit to maxCount() | ||
447 | while ( (int) items.count() > maxCount() && !items.isEmpty() ) | ||
448 | items.remove( items.begin() ); | ||
449 | |||
450 | insertItems( items ); | ||
451 | |||
452 | if ( setCompletionList && useCompletion() ) { | ||
453 | // we don't have any weighting information here ;( | ||
454 | OCompletion *comp = completionObject(); | ||
455 | comp->setOrder( OCompletion::Insertion ); | ||
456 | comp->setItems( items ); | ||
457 | comp->setOrder( OCompletion::Weighted ); | ||
458 | } | ||
459 | |||
460 | clearEdit(); | ||
461 | } | ||
462 | |||
463 | QStringList OHistoryCombo::historyItems() const | ||
464 | { | ||
465 | QStringList list; | ||
466 | for ( int i = 0; i < count(); i++ ) | ||
467 | list.append( text( i ) ); | ||
468 | |||
469 | return list; | ||
470 | } | ||
471 | |||
472 | void OHistoryCombo::clearHistory() | ||
473 | { | ||
474 | OComboBox::clear(); | ||
475 | if ( useCompletion() ) | ||
476 | completionObject()->clear(); | ||
477 | } | ||
478 | |||
479 | void OHistoryCombo::addContextMenuItems( QPopupMenu* menu ) | ||
480 | { | ||
481 | if ( menu &&!lineEdit()->text().isEmpty()) | ||
482 | { | ||
483 | menu->insertSeparator(); | ||
484 | menu->insertItem( tr("Empty Contents"), this, SLOT( slotClear())); | ||
485 | } | ||
486 | } | ||
487 | |||
488 | void OHistoryCombo::addToHistory( const QString& item ) | ||
489 | { | ||
490 | if ( item.isEmpty() || (count() > 0 && item == text(0) )) | ||
491 | return; | ||
492 | |||
493 | // remove all existing items before adding | ||
494 | if ( !duplicatesEnabled() ) { | ||
495 | for ( int i = 0; i < count(); i++ ) { | ||
496 | if ( text( i ) == item ) | ||
497 | removeItem( i ); | ||
498 | } | ||
499 | } | ||
500 | |||
501 | // now add the item | ||
502 | if ( myPixProvider ) | ||
503 | //insertItem( myPixProvider->pixmapFor(item, KIcon::SizeSmall), item, 0); | ||
504 | insertItem( myPixProvider->pixmapFor(item, 16), item, 0); | ||
505 | else | ||
506 | insertItem( item, 0 ); | ||
507 | |||
508 | int last; | ||
509 | QString rmItem; | ||
510 | |||
511 | bool useComp = useCompletion(); | ||
512 | while ( count() > maxCount() && count() > 0 ) { | ||
513 | // remove the last item, as long as we are longer than maxCount() | ||
514 | // remove the removed item from the completionObject if it isn't | ||
515 | // anymore available at all in the combobox. | ||
516 | last = count() - 1; | ||
517 | rmItem = text( last ); | ||
518 | removeItem( last ); | ||
519 | if ( useComp && !contains( rmItem ) ) | ||
520 | completionObject()->removeItem( rmItem ); | ||
521 | } | ||
522 | |||
523 | if ( useComp ) | ||
524 | completionObject()->addItem( item ); | ||
525 | } | ||
526 | |||
527 | bool OHistoryCombo::removeFromHistory( const QString& item ) | ||
528 | { | ||
529 | if ( item.isEmpty() ) | ||
530 | return false; | ||
531 | |||
532 | bool removed = false; | ||
533 | QString temp = currentText(); | ||
534 | for ( int i = 0; i < count(); i++ ) { | ||
535 | while ( item == text( i ) ) { | ||
536 | removed = true; | ||
537 | removeItem( i ); | ||
538 | } | ||
539 | } | ||
540 | |||
541 | if ( removed && useCompletion() ) | ||
542 | completionObject()->removeItem( item ); | ||
543 | |||
544 | setEditText( temp ); | ||
545 | return removed; | ||
546 | } | ||
547 | |||
548 | void OHistoryCombo::keyPressEvent( QKeyEvent *e ) | ||
549 | { | ||
550 | // save the current text in the lineedit | ||
551 | if ( myIterateIndex == -1 ) | ||
552 | myText = currentText(); | ||
553 | |||
554 | // going up in the history, rotating when reaching QListBox::count() | ||
555 | //if ( OStdAccel::isEqual( e, OStdAccel::rotateUp() ) ) { | ||
556 | if ( e->key() == Qt::Key_Up ) { | ||
557 | myIterateIndex++; | ||
558 | |||
559 | // skip duplicates/empty items | ||
560 | while ( myIterateIndex < count()-1 && | ||
561 | (currentText() == text( myIterateIndex ) || | ||
562 | text( myIterateIndex ).isEmpty()) ) | ||
563 | myIterateIndex++; | ||
564 | |||
565 | if ( myIterateIndex >= count() ) { | ||
566 | myRotated = true; | ||
567 | myIterateIndex = -1; | ||
568 | |||
569 | // if the typed text is the same as the first item, skip the first | ||
570 | if ( myText == text(0) ) | ||
571 | myIterateIndex = 0; | ||
572 | |||
573 | setEditText( myText ); | ||
574 | } | ||
575 | else | ||
576 | setEditText( text( myIterateIndex )); | ||
577 | } | ||
578 | |||
579 | |||
580 | // going down in the history, no rotation possible. Last item will be | ||
581 | // the text that was in the lineedit before Up was called. | ||
582 | //else if ( OStdAccel::isEqual( e, OStdAccel::rotateDown() ) ) { | ||
583 | else if ( e->key() == Qt::Key_Down ) { | ||
584 | myIterateIndex--; | ||
585 | |||
586 | // skip duplicates/empty items | ||
587 | while ( myIterateIndex >= 0 && | ||
588 | (currentText() == text( myIterateIndex ) || | ||
589 | text( myIterateIndex ).isEmpty()) ) | ||
590 | myIterateIndex--; | ||
591 | |||
592 | |||
593 | if ( myIterateIndex < 0 ) { | ||
594 | if ( myRotated && myIterateIndex == -2 ) { | ||
595 | myRotated = false; | ||
596 | myIterateIndex = count() - 1; | ||
597 | setEditText( text(myIterateIndex) ); | ||
598 | } | ||
599 | else { // bottom of history | ||
600 | if ( myIterateIndex == -2 ) { | ||
601 | qDebug( "ONotifyClient is not implemented yet." ); | ||
602 | //ONotifyClient::event( ONotifyClient::notification, | ||
603 | // i18n("No further item in the history.")); | ||
604 | } | ||
605 | |||
606 | myIterateIndex = -1; | ||
607 | if ( currentText() != myText ) | ||
608 | setEditText( myText ); | ||
609 | } | ||
610 | } | ||
611 | else | ||
612 | setEditText( text( myIterateIndex )); | ||
613 | } | ||
614 | |||
615 | else | ||
616 | OComboBox::keyPressEvent( e ); | ||
617 | } | ||
618 | |||
619 | void OHistoryCombo::slotReset() | ||
620 | { | ||
621 | myIterateIndex = -1; | ||
622 | myRotated = false; | ||
623 | } | ||
624 | |||
625 | |||
626 | void OHistoryCombo::setPixmapProvider( OPixmapProvider *prov ) | ||
627 | { | ||
628 | if ( myPixProvider == prov ) | ||
629 | return; | ||
630 | |||
631 | delete myPixProvider; | ||
632 | myPixProvider = prov; | ||
633 | |||
634 | // re-insert all the items with/without pixmap | ||
635 | // I would prefer to use changeItem(), but that doesn't honour the pixmap | ||
636 | // when using an editable combobox (what we do) | ||
637 | if ( count() > 0 ) { | ||
638 | QStringList items( historyItems() ); | ||
639 | clear(); | ||
640 | insertItems( items ); | ||
641 | } | ||
642 | } | ||
643 | |||
644 | void OHistoryCombo::insertItems( const QStringList& items ) | ||
645 | { | ||
646 | QStringList::ConstIterator it = items.begin(); | ||
647 | QString item; | ||
648 | while ( it != items.end() ) { | ||
649 | item = *it; | ||
650 | if ( !item.isEmpty() ) { // only insert non-empty items | ||
651 | if ( myPixProvider ) | ||
652 | // insertItem( myPixProvider->pixmapFor(item, OIcon::SizeSmall), item ); | ||
653 | insertItem( myPixProvider->pixmapFor(item, 16), item ); | ||
654 | else | ||
655 | insertItem( item ); | ||
656 | } | ||
657 | ++it; | ||
658 | } | ||
659 | } | ||
660 | |||
661 | void OHistoryCombo::slotClear() | ||
662 | { | ||
663 | clearHistory(); | ||
664 | emit cleared(); | ||
665 | } | ||
666 | |||
diff --git a/libopie2/qt3/opieui/ocombobox.h b/libopie2/qt3/opieui/ocombobox.h new file mode 100644 index 0000000..4e35b61 --- a/dev/null +++ b/libopie2/qt3/opieui/ocombobox.h | |||
@@ -0,0 +1,790 @@ | |||
1 | /* | ||
2 | This file Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> | ||
3 | is part of the Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org> | ||
4 | Opie Project Copyright (C) 2000 Dawit Alemayehu <adawit@kde.org> | ||
5 | |||
6 | =. Originally part of the KDE projects | ||
7 | .=l. | ||
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 | #ifndef OCOMBOBOX_H | ||
34 | #define OCOMBOBOX_H | ||
35 | |||
36 | /* QT */ | ||
37 | |||
38 | #include <qcombobox.h> | ||
39 | |||
40 | /* OPIE */ | ||
41 | |||
42 | #include <opie2/olineedit.h> | ||
43 | #include <opie2/ocompletion.h> | ||
44 | #include <opie2/ocompletionbase.h> | ||
45 | |||
46 | /* FORWARDS */ | ||
47 | |||
48 | class QListBoxItem; | ||
49 | class QPopupMenu; | ||
50 | class OCompletionBox; | ||
51 | typedef QString OURL; | ||
52 | |||
53 | /** | ||
54 | * A combined button, line-edit and a popup list widget. | ||
55 | * | ||
56 | * @sect Detail | ||
57 | * | ||
58 | * This widget inherits from @ref QComboBox and implements | ||
59 | * the following additional functionalities: a completion | ||
60 | * object that provides both automatic and manual text | ||
61 | * completion as well as text rotation features, configurable | ||
62 | * key-bindings to activate these features, and a popup-menu | ||
63 | * item that can be used to allow the user to set text completion | ||
64 | * modes on the fly based on their preference. | ||
65 | * | ||
66 | * To support these new features OComboBox also emits a few | ||
67 | * more additional signals as well. The main ones are the | ||
68 | * @ref completion( const QString& ) and @ref textRotation( KeyBindingType ) | ||
69 | * signals. The completion signal is intended to be connected to a slot | ||
70 | * that will assist the user in filling out the remaining text while | ||
71 | * the rotation signals is intended to be used to traverse through all | ||
72 | * possible matches whenever text completion results in multiple matches. | ||
73 | * The @ref returnPressed() and @ref returnPressed( const QString& ) | ||
74 | * signal is emitted when the user presses the Enter/Return key. | ||
75 | * | ||
76 | * This widget by default creates a completion object when you invoke | ||
77 | * the @ref completionObject( bool ) member function for the first time | ||
78 | * or use @ref setCompletionObject( OCompletion*, bool ) to assign your | ||
79 | * own completion object. Additionally, to make this widget more functional, | ||
80 | * OComboBox will by default handle the text rotation and completion | ||
81 | * events internally whenever a completion object is created through either | ||
82 | * one of the methods mentioned above. If you do not need this functionality, | ||
83 | * simply use @ref OCompletionBase::setHandleSignals( bool ) or alternatively | ||
84 | * set the boolean parameter in the above methods to FALSE. | ||
85 | * | ||
86 | * The default key-bindings for completion and rotation is determined | ||
87 | * from the global settings in @ref OStdAccel. These values, however, | ||
88 | * can be overriden locally by invoking @ref OCompletionBase::setKeyBinding(). | ||
89 | * The values can easily be reverted back to the default setting, by simply | ||
90 | * calling @ref useGlobalSettings(). An alternate method would be to default | ||
91 | * individual key-bindings by usning @ref setKeyBinding() with the default | ||
92 | * second argument. | ||
93 | * | ||
94 | * Note that if this widget is not editable ( i.e. select-only ), then only | ||
95 | * one completion mode, @p CompletionAuto, will work. All the other modes are | ||
96 | * simply ignored. The @p CompletionAuto mode in this case allows you to | ||
97 | * automatically select an item from the list by trying to match the pressed | ||
98 | * keycode with the first letter of the enteries in the combo box. | ||
99 | * | ||
100 | * @sect Useage | ||
101 | * | ||
102 | * To enable the basic completion feature: | ||
103 | * | ||
104 | * <pre> | ||
105 | * OComboBox *combo = new OComboBox( true, this, "mywidget" ); | ||
106 | * OCompletion *comp = combo->completionObject(); | ||
107 | * // Connect to the return pressed signal - optional | ||
108 | * connect(combo,SIGNAL(returnPressed(const QString&)),comp,SLOT(addItem(const QString&)); | ||
109 | * </pre> | ||
110 | * | ||
111 | * To use your own completion object: | ||
112 | * | ||
113 | * <pre> | ||
114 | * OComboBox *combo = new OComboBox( this,"mywidget" ); | ||
115 | * OURLCompletion *comp = new OURLCompletion(); | ||
116 | * combo->setCompletionObject( comp ); | ||
117 | * // Connect to the return pressed signal - optional | ||
118 | * connect(combo,SIGNAL(returnPressed(const QString&)),comp,SLOT(addItem(const QString&)); | ||
119 | * </pre> | ||
120 | * | ||
121 | * Note that you have to either delete the allocated completion object | ||
122 | * when you don't need it anymore, or call | ||
123 | * setAutoDeleteCompletionObject( true ); | ||
124 | * | ||
125 | * Miscellaneous function calls: | ||
126 | * | ||
127 | * <pre> | ||
128 | * // Tell the widget not to handle completion and rotation | ||
129 | * combo->setHandleSignals( false ); | ||
130 | * // Set your own completion key for manual completions. | ||
131 | * combo->setKeyBinding( OCompletionBase::TextCompletion, Qt::End ); | ||
132 | * // Hide the context (popup) menu | ||
133 | * combo->setContextMenuEnabled( false ); | ||
134 | * // Temporarly disable signal emition | ||
135 | * combo->disableSignals(); | ||
136 | * // Default the all key-bindings to their system-wide settings. | ||
137 | * combo->useGlobalKeyBindings(); | ||
138 | * </pre> | ||
139 | * | ||
140 | * @short An enhanced combo box. | ||
141 | * @author Dawit Alemayehu <adawit@kde.org> | ||
142 | */ | ||
143 | class OComboBox : public QComboBox, public OCompletionBase | ||
144 | { | ||
145 | Q_OBJECT | ||
146 | |||
147 | //Q_PROPERTY( bool autoCompletion READ autoCompletion WRITE setAutoCompletion ) | ||
148 | //Q_PROPERTY( bool contextMenuEnabled READ isContextMenuEnabled WRITE setContextMenuEnabled ) | ||
149 | //Q_PROPERTY( bool urlDropsEnabled READ isURLDropsEnabled WRITE setURLDropsEnabled ) | ||
150 | |||
151 | public: | ||
152 | |||
153 | /** | ||
154 | * Constructs a read-only or rather select-only combo box with a | ||
155 | * parent object and a name. | ||
156 | * | ||
157 | * @param parent The parent object of this widget | ||
158 | * @param name The name of this widget | ||
159 | */ | ||
160 | OComboBox( QWidget *parent=0, const char *name=0 ); | ||
161 | |||
162 | /** | ||
163 | * Constructs a "read-write" or "read-only" combo box depending on | ||
164 | * the value of the first argument( @p rw ) with a parent, a | ||
165 | * name. | ||
166 | * | ||
167 | * @param rw When @p true, widget will be editable. | ||
168 | * @param parent The parent object of this widget. | ||
169 | * @param name The name of this widget. | ||
170 | */ | ||
171 | OComboBox( bool rw, QWidget *parent=0, const char *name=0 ); | ||
172 | |||
173 | /** | ||
174 | * Destructor. | ||
175 | */ | ||
176 | virtual ~OComboBox(); | ||
177 | |||
178 | /** | ||
179 | * Sets @p url into the edit field of the combobox. It uses | ||
180 | * @ref OURL::prettyURL() so that the url is properly decoded for | ||
181 | * displaying. | ||
182 | */ | ||
183 | //void setEditURL( const OURL& url ); | ||
184 | |||
185 | /** | ||
186 | * Inserts @p url at position @p index into the combobox. The item will | ||
187 | * be appended if @p index is negative. @ref OURL::prettyURL() is used | ||
188 | * so that the url is properly decoded for displaying. | ||
189 | */ | ||
190 | //void insertURL( const OURL& url, int index = -1 ); | ||
191 | |||
192 | /** | ||
193 | * Inserts @p url with the pixmap &p pixmap at position @p index into | ||
194 | * the combobox. The item will be appended if @p index is negative. | ||
195 | * @ref OURL::prettyURL() is used so that the url is properly decoded | ||
196 | * for displaying. | ||
197 | */ | ||
198 | //void insertURL( const QPixmap& pixmap, const OURL& url, int index = -1 ); | ||
199 | |||
200 | /** | ||
201 | * Replaces the item at position @p index with @p url. | ||
202 | * @ref OURL::prettyURL() is used so that the url is properly decoded | ||
203 | * for displaying. | ||
204 | */ | ||
205 | //void changeURL( const OURL& url, int index ); | ||
206 | |||
207 | /** | ||
208 | * Replaces the item at position @p index with @p url and pixmap @p pixmap. | ||
209 | * @ref OURL::prettyURL() is used so that the url is properly decoded | ||
210 | * for displaying. | ||
211 | */ | ||
212 | //void changeURL( const QPixmap& pixmap, const OURL& url, int index ); | ||
213 | |||
214 | /** | ||
215 | * Returns the current cursor position. | ||
216 | * | ||
217 | * This method always returns a -1 if the combo-box is @em not | ||
218 | * editable (read-write). | ||
219 | * | ||
220 | * @return Current cursor position. | ||
221 | */ | ||
222 | int cursorPosition() const { return ( lineEdit() ) ? lineEdit()->cursorPosition() : -1; } | ||
223 | |||
224 | /** | ||
225 | * Re-implemented from @ref QComboBox. | ||
226 | * | ||
227 | * If @p true, the completion mode will be set to automatic. | ||
228 | * Otherwise, it is defaulted to the global setting. This | ||
229 | * method has been replaced by the more comprehensive | ||
230 | * @ref setCompletionMode(). | ||
231 | * | ||
232 | * @param autocomplete Flag to enable/disable automatic completion mode. | ||
233 | */ | ||
234 | virtual void setAutoCompletion( bool autocomplete ); | ||
235 | |||
236 | /** | ||
237 | * Re-implemented from QComboBox. | ||
238 | * | ||
239 | * Returns @p true if the current completion mode is set | ||
240 | * to automatic. See its more comprehensive replacement | ||
241 | * @ref completionMode(). | ||
242 | * | ||
243 | * @return @p true when completion mode is automatic. | ||
244 | */ | ||
245 | bool autoCompletion() const { | ||
246 | return completionMode() == OGlobalSettings::CompletionAuto; | ||
247 | } | ||
248 | |||
249 | /** | ||
250 | * Enables or disable the popup (context) menu. | ||
251 | * | ||
252 | * This method only works if this widget is editable, i.e. | ||
253 | * read-write and allows you to enable/disable the context | ||
254 | * menu. It does nothing if invoked for a none-editable | ||
255 | * combo-box. Note that by default the mode changer item | ||
256 | * is made visiable whenever the context menu is enabled. | ||
257 | * Use @ref hideModechanger() if you want to hide this | ||
258 | * item. Also by default, the context menu is created if | ||
259 | * this widget is editable. Call this function with the | ||
260 | * argument set to false to disable the popup menu. | ||
261 | * | ||
262 | * @param showMenu If @p true, show the context menu. | ||
263 | * @param showMode If @p true, show the mode changer. | ||
264 | */ | ||
265 | virtual void setContextMenuEnabled( bool showMenu ); | ||
266 | |||
267 | /** | ||
268 | * Returns @p true when the context menu is enabled. | ||
269 | */ | ||
270 | bool isContextMenuEnabled() const { return m_bEnableMenu; } | ||
271 | |||
272 | /** | ||
273 | * Enables/Disables handling of URL drops. If enabled and the user | ||
274 | * drops an URL, the decoded URL will be inserted. Otherwise the default | ||
275 | * behaviour of QComboBox is used, which inserts the encoded URL. | ||
276 | * | ||
277 | * @param enable If @p true, insert decoded URLs | ||
278 | */ | ||
279 | //void setURLDropsEnabled( bool enable ); | ||
280 | |||
281 | /** | ||
282 | * Returns @p true when decoded URL drops are enabled | ||
283 | */ | ||
284 | //bool isURLDropsEnabled() const; | ||
285 | |||
286 | /** | ||
287 | * Convenience method which iterates over all items and checks if | ||
288 | * any of them is equal to @p text. | ||
289 | * | ||
290 | * If @p text is an empty string, @p false | ||
291 | * is returned. | ||
292 | * | ||
293 | * @return @p true if an item with the string @p text is in the combobox. | ||
294 | */ | ||
295 | bool contains( const QString& text ) const; | ||
296 | |||
297 | /** | ||
298 | * By default, OComboBox recognizes Key_Return and Key_Enter | ||
299 | * and emits | ||
300 | * the @ref returnPressed() signals, but it also lets the event pass, | ||
301 | * for example causing a dialog's default-button to be called. | ||
302 | * | ||
303 | * Call this method with @p trap equal to true to make OComboBox | ||
304 | * stop these | ||
305 | * events. The signals will still be emitted of course. | ||
306 | * | ||
307 | * Only affects read-writable comboboxes. | ||
308 | * | ||
309 | * @see setTrapReturnKey() | ||
310 | */ | ||
311 | void setTrapReturnKey( bool trap ); | ||
312 | |||
313 | /** | ||
314 | * @return @p true if keyevents of Key_Return or Key_Enter will | ||
315 | * be stopped or if they will be propagated. | ||
316 | * | ||
317 | * @see setTrapReturnKey () | ||
318 | */ | ||
319 | bool trapReturnKey() const; | ||
320 | |||
321 | /** | ||
322 | * Re-implemented for internal reasons. API not affected. | ||
323 | * | ||
324 | * @reimplemented | ||
325 | */ | ||
326 | virtual bool eventFilter( QObject *, QEvent * ); | ||
327 | |||
328 | /** | ||
329 | * @returns the completion-box, that is used in completion mode | ||
330 | * @ref OGlobalSettings::CompletionPopup and @ref OGlobalSettings::CompletionPopupAuto. | ||
331 | * This method will create a completion-box by calling | ||
332 | * @ref OLineEdit::completionBox, if none is there, yet. | ||
333 | * | ||
334 | * @param create Set this to false if you don't want the box to be created | ||
335 | * i.e. to test if it is available. | ||
336 | */ | ||
337 | OCompletionBox * completionBox( bool create = true ); | ||
338 | |||
339 | virtual void setLineEdit( OLineEdit * ); | ||
340 | |||
341 | signals: | ||
342 | /** | ||
343 | * Emitted when the user presses the Enter key. | ||
344 | * | ||
345 | * Note that this signal is only | ||
346 | * emitted if this widget is editable. | ||
347 | */ | ||
348 | void returnPressed(); | ||
349 | |||
350 | /** | ||
351 | * Emitted when the user presses | ||
352 | * the Enter key. | ||
353 | * | ||
354 | * The argument is the current | ||
355 | * text being edited. This signal is just like | ||
356 | * @ref returnPressed() except it contains the | ||
357 | * current text as its argument. | ||
358 | * | ||
359 | * Note that this signal is only emitted if this | ||
360 | * widget is editable. | ||
361 | */ | ||
362 | void returnPressed( const QString& ); | ||
363 | |||
364 | /** | ||
365 | * This signal is emitted when the completion key | ||
366 | * is pressed. | ||
367 | * | ||
368 | * The argument is the current text | ||
369 | * being edited. | ||
370 | * | ||
371 | * Note that this signal is @em not available if this | ||
372 | * widget is non-editable or the completion mode is | ||
373 | * set to @p OGlobalSettings::CompletionNone. | ||
374 | */ | ||
375 | void completion( const QString& ); | ||
376 | |||
377 | /** | ||
378 | * Emitted when the shortcut for substring completion is pressed. | ||
379 | */ | ||
380 | void substringCompletion( const QString& ); | ||
381 | |||
382 | /** | ||
383 | * Emitted when the text rotation key-bindings are pressed. | ||
384 | * | ||
385 | * The argument indicates which key-binding was pressed. | ||
386 | * In this case this can be either one of four values: | ||
387 | * @p PrevCompletionMatch, @p NextCompletionMatch, @p RotateUp or | ||
388 | * @p RotateDown. See @ref OCompletionBase::setKeyBinding() for | ||
389 | * details. | ||
390 | * | ||
391 | * Note that this signal is @em NOT emitted if the completion | ||
392 | * mode is set to CompletionNone. | ||
393 | */ | ||
394 | void textRotation( OCompletionBase::KeyBindingType ); | ||
395 | |||
396 | /** | ||
397 | * Emitted when the user changed the completion mode by using the | ||
398 | * popupmenu. | ||
399 | */ | ||
400 | void completionModeChanged( OGlobalSettings::Completion ); | ||
401 | |||
402 | /** | ||
403 | * Emitted before the context menu is displayed. | ||
404 | * | ||
405 | * The signal allows you to add your own entries into the | ||
406 | * the context menu that is created on demand. | ||
407 | * | ||
408 | * NOTE: Do not store the pointer to the QPopupMenu | ||
409 | * provided through since it is created and deleted | ||
410 | * on demand. | ||
411 | * | ||
412 | * @param the context menu about to be displayed | ||
413 | */ | ||
414 | void aboutToShowContextMenu( QPopupMenu * ); | ||
415 | |||
416 | public slots: | ||
417 | |||
418 | /** | ||
419 | * Iterates through all possible matches of the completed text | ||
420 | * or the history list. | ||
421 | * | ||
422 | * Depending on the value of the argument, this function either | ||
423 | * iterates through the history list of this widget or the all | ||
424 | * possible matches in whenever multiple matches result from a | ||
425 | * text completion request. Note that the all-possible-match | ||
426 | * iteration will not work if there are no previous matches, i.e. | ||
427 | * no text has been completed and the *nix shell history list | ||
428 | * rotation is only available if the insertion policy for this | ||
429 | * widget is set either @p QComobBox::AtTop or @p QComboBox::AtBottom. | ||
430 | * For other insertion modes whatever has been typed by the user | ||
431 | * when the rotation event was initiated will be lost. | ||
432 | * | ||
433 | * @param type The key-binding invoked. | ||
434 | */ | ||
435 | void rotateText( OCompletionBase::KeyBindingType /* type */ ); | ||
436 | |||
437 | /** | ||
438 | * Sets the completed text in the line-edit appropriately. | ||
439 | * | ||
440 | * This function is an implementation for | ||
441 | * @ref OCompletionBase::setCompletedText. | ||
442 | */ | ||
443 | virtual void setCompletedText( const QString& ); | ||
444 | |||
445 | /** | ||
446 | * Sets @p items into the completion-box if @ref completionMode() is | ||
447 | * CompletionPopup. The popup will be shown immediately. | ||
448 | */ | ||
449 | void setCompletedItems( const QStringList& items ); | ||
450 | |||
451 | public: | ||
452 | /** | ||
453 | * Selects the first item that matches @p item. If there is no such item, | ||
454 | * it is inserted at position @p index if @p insert is true. Otherwise, | ||
455 | * no item is selected. | ||
456 | */ | ||
457 | void setCurrentItem( const QString& item, bool insert = false, int index = -1 ); | ||
458 | void setCurrentItem(int index); | ||
459 | |||
460 | protected slots: | ||
461 | |||
462 | /** | ||
463 | * @deprecated. | ||
464 | */ | ||
465 | virtual void itemSelected( QListBoxItem* ) {}; | ||
466 | |||
467 | /** | ||
468 | * Completes text according to the completion mode. | ||
469 | * | ||
470 | * Note: this method is @p not invoked if the completion mode is | ||
471 | * set to CompletionNone. Also if the mode is set to @p CompletionShell | ||
472 | * and multiple matches are found, this method will complete the | ||
473 | * text to the first match with a beep to inidicate that there are | ||
474 | * more matches. Then any successive completion key event iterates | ||
475 | * through the remaining matches. This way the rotation functionality | ||
476 | * is left to iterate through the list as usual. | ||
477 | */ | ||
478 | virtual void makeCompletion( const QString& ); | ||
479 | |||
480 | protected: | ||
481 | /* | ||
482 | * This function simply sets the lineedit text and | ||
483 | * highlights the text appropriately if the boolean | ||
484 | * value is set to true. | ||
485 | * | ||
486 | * @param | ||
487 | * @param | ||
488 | */ | ||
489 | virtual void setCompletedText( const QString& /* */, bool /*marked*/ ); | ||
490 | |||
491 | /** | ||
492 | * Reimplemented for internal reasons, the API is not affected. | ||
493 | */ | ||
494 | virtual void create( WId = 0, bool initializeWindow = true, | ||
495 | bool destroyOldWindow = true ); | ||
496 | |||
497 | private: | ||
498 | // Constants that represent the ID's of the popup menu. | ||
499 | // TODO: See if we can replace this mess with OActionMenu | ||
500 | // in the future though this is working lovely. | ||
501 | enum MenuID { | ||
502 | Default=0, | ||
503 | Cut, | ||
504 | Copy, | ||
505 | Paste, | ||
506 | Clear, | ||
507 | Unselect, | ||
508 | SelectAll, | ||
509 | NoCompletion, | ||
510 | AutoCompletion, | ||
511 | ShellCompletion, | ||
512 | PopupCompletion, | ||
513 | SemiAutoCompletion | ||
514 | }; | ||
515 | |||
516 | /** | ||
517 | * Initializes the variables upon construction. | ||
518 | */ | ||
519 | void init(); | ||
520 | /** | ||
521 | * Temporary functions to delete words back and foward until | ||
522 | * alternatives are available in QT3 (Seth Chaiklin, 21 may 2001) | ||
523 | */ | ||
524 | void deleteWordBack(); | ||
525 | void deleteWordForward(); | ||
526 | |||
527 | bool m_bEnableMenu; | ||
528 | |||
529 | // indicating if we should stop return-key events from propagating | ||
530 | bool m_trapReturnKey; | ||
531 | |||
532 | //protected: | ||
533 | // virtual void virtual_hook( int id, void* data ); | ||
534 | private: | ||
535 | class OComboBoxPrivate; | ||
536 | OComboBoxPrivate *d; | ||
537 | }; | ||
538 | |||
539 | |||
540 | class OPixmapProvider; | ||
541 | |||
542 | /** | ||
543 | * A combobox which implements a history like a unix shell. You can navigate | ||
544 | * through all the items by using the Up or Down arrows (configurable of | ||
545 | * course). Additionally, weighted completion is available. So you should | ||
546 | * load and save the completion list to preserve the weighting between | ||
547 | * sessions. | ||
548 | * | ||
549 | * @author Carsten Pfeiffer <pfeiffer@kde.org> | ||
550 | * @short A combobox for offering a history and completion | ||
551 | */ | ||
552 | class OHistoryCombo : public OComboBox | ||
553 | { | ||
554 | Q_OBJECT | ||
555 | Q_PROPERTY( QStringList historyItems READ historyItems WRITE setHistoryItems ) | ||
556 | |||
557 | public: | ||
558 | /** | ||
559 | * Constructs a "read-write" combobox. A read-only history combobox | ||
560 | * doesn't make much sense, so it is only available as read-write. | ||
561 | * Completion will be used automatically for the items in the combo. | ||
562 | * | ||
563 | * The insertion-policy is set to NoInsertion, you have to add the items | ||
564 | * yourself via the slot @ref addToHistory. If you want every item added, | ||
565 | * use | ||
566 | * | ||
567 | * <pre> | ||
568 | * connect( combo, SIGNAL( activated( const QString& )), | ||
569 | * combo, SLOT( addToHistory( const QString& ))); | ||
570 | * </pre> | ||
571 | * | ||
572 | * Use @ref QComboBox::setMaxCount() to limit the history. | ||
573 | * | ||
574 | * @p parent the parent object of this widget. | ||
575 | * @p name the name of this widget. | ||
576 | */ | ||
577 | OHistoryCombo( QWidget *parent = 0L, const char *name = 0L ); | ||
578 | |||
579 | // ### merge these two constructors | ||
580 | /** | ||
581 | * Same as the previous constructor, but additionally has the option | ||
582 | * to specify whether you want to let OHistoryCombo handle completion | ||
583 | * or not. If set to @p true, OHistoryCombo will sync the completion to the | ||
584 | * contents of the combobox. | ||
585 | */ | ||
586 | OHistoryCombo( bool useCompletion, | ||
587 | QWidget *parent = 0L, const char *name = 0L ); | ||
588 | |||
589 | /** | ||
590 | * Destructs the combo, the completion-object and the pixmap-provider | ||
591 | */ | ||
592 | ~OHistoryCombo(); | ||
593 | |||
594 | /** | ||
595 | * Inserts @p items into the combobox. @p items might get | ||
596 | * truncated if it is longer than @ref maxCount() | ||
597 | * | ||
598 | * @see #historyItems | ||
599 | */ | ||
600 | inline void setHistoryItems( QStringList items ) { | ||
601 | setHistoryItems(items, false); | ||
602 | } | ||
603 | |||
604 | /** | ||
605 | * Inserts @p items into the combobox. @p items might get | ||
606 | * truncated if it is longer than @ref maxCount() | ||
607 | * | ||
608 | * Set @p setCompletionList to true, if you don't have a list of | ||
609 | * completions. This tells OHistoryCombo to use all the items for the | ||
610 | * completion object as well. | ||
611 | * You won't have the benefit of weighted completion though, so normally | ||
612 | * you should do something like | ||
613 | * <pre> | ||
614 | * OConfig *config = kapp->config(); | ||
615 | * QStringList list; | ||
616 | * | ||
617 | * // load the history and completion list after creating the history combo | ||
618 | * list = config->readListEntry( "Completion list" ); | ||
619 | * combo->completionObject()->setItems( list ); | ||
620 | * list = config->readListEntry( "History list" ); | ||
621 | * combo->setHistoryItems( list ); | ||
622 | * | ||
623 | * [...] | ||
624 | * | ||
625 | * // save the history and completion list when the history combo is | ||
626 | * // destroyed | ||
627 | * list = combo->completionObject()->items() | ||
628 | * config->writeEntry( "Completion list", list ); | ||
629 | * list = combo->historyItems(); | ||
630 | * config->writeEntry( "History list", list ); | ||
631 | * </pre> | ||
632 | * | ||
633 | * Be sure to use different names for saving with OConfig if you have more | ||
634 | * than one OHistoryCombo. | ||
635 | * | ||
636 | * Note: When @p setCompletionList is true, the items are inserted into the | ||
637 | * OCompletion object with mode OCompletion::Insertion and the mode is set | ||
638 | * to OCompletion::Weighted afterwards. | ||
639 | * | ||
640 | * @see #historyItems | ||
641 | * @see OComboBox::completionObject | ||
642 | * @see OCompletion::setItems | ||
643 | * @see OCompletion::items | ||
644 | */ | ||
645 | void setHistoryItems( QStringList items, bool setCompletionList ); | ||
646 | |||
647 | /** | ||
648 | * Returns the list of history items. Empty, when this is not a read-write | ||
649 | * combobox. | ||
650 | * | ||
651 | * @see #setHistoryItems | ||
652 | */ | ||
653 | QStringList historyItems() const; | ||
654 | |||
655 | /** | ||
656 | * Removes all items named @p item. | ||
657 | * | ||
658 | * @return @p true if at least one item was removed. | ||
659 | * | ||
660 | * @see #addToHistory | ||
661 | */ | ||
662 | bool removeFromHistory( const QString& item ); | ||
663 | |||
664 | /** | ||
665 | * Sets a pixmap provider, so that items in the combobox can have a pixmap. | ||
666 | * @ref OPixmapProvider is just an abstract class with the one pure virtual | ||
667 | * method @ref OPixmapProvider::pixmapFor(). This method is called whenever | ||
668 | * an item is added to the OHistoryComboBox. Implement it to return your | ||
669 | * own custom pixmaps, or use the @ref OURLPixmapProvider from libkio, | ||
670 | * which uses @ref OMimeType::pixmapForURL to resolve icons. | ||
671 | * | ||
672 | * Set @p prov to 0L if you want to disable pixmaps. Default no pixmaps. | ||
673 | * | ||
674 | * @see #pixmapProvider | ||
675 | */ | ||
676 | void setPixmapProvider( OPixmapProvider *prov ); | ||
677 | |||
678 | /** | ||
679 | * @returns the current pixmap provider. | ||
680 | * @see #setPixmapProvider | ||
681 | * @see OPixmapProvider | ||
682 | */ | ||
683 | OPixmapProvider * pixmapProvider() const { return myPixProvider; } | ||
684 | |||
685 | /** | ||
686 | * Resets the current position of the up/down history. Call this | ||
687 | * when you manually call @ref setCurrentItem() or @ref clearEdit(). | ||
688 | */ | ||
689 | void reset() { slotReset(); } | ||
690 | |||
691 | public slots: | ||
692 | /** | ||
693 | * Adds an item to the end of the history list and to the completion list. | ||
694 | * If @ref maxCount() is reached, the first item of the list will be | ||
695 | * removed. | ||
696 | * | ||
697 | * If the last inserted item is the same as @p item, it will not be | ||
698 | * inserted again. | ||
699 | * | ||
700 | * If @ref duplicatesEnabled() is false, any equal existing item will be | ||
701 | * removed before @p item is added. | ||
702 | * | ||
703 | * Note: By using this method and not the Q and OComboBox insertItem() | ||
704 | * methods, you make sure that the combobox stays in sync with the | ||
705 | * completion. It would be annoying if completion would give an item | ||
706 | * not in the combobox, and vice versa. | ||
707 | * | ||
708 | * @see #removeFromHistory | ||
709 | * @see QComboBox::setDuplicatesEnabled | ||
710 | */ | ||
711 | void addToHistory( const QString& item ); | ||
712 | |||
713 | /** | ||
714 | * Clears the history and the completion list. | ||
715 | */ | ||
716 | void clearHistory(); | ||
717 | |||
718 | signals: | ||
719 | /** | ||
720 | * Emitted when the history was cleared by the entry in the popup menu. | ||
721 | */ | ||
722 | void cleared(); | ||
723 | |||
724 | protected: | ||
725 | /** | ||
726 | * Handling key-events, the shortcuts to rotate the items. | ||
727 | */ | ||
728 | virtual void keyPressEvent( QKeyEvent * ); | ||
729 | |||
730 | |||
731 | /** | ||
732 | * Inserts @p items into the combo, honouring @ref pixmapProvider() | ||
733 | * Does not update the completionObject. | ||
734 | * | ||
735 | * Note: @ref duplicatesEnabled() is not honored here. | ||
736 | * | ||
737 | * Called from @ref setHistoryItems() and @ref setPixmapProvider() | ||
738 | */ | ||
739 | void insertItems( const QStringList& items ); | ||
740 | |||
741 | /** | ||
742 | * @returns if we can modify the completion object or not. | ||
743 | */ | ||
744 | bool useCompletion() const { return compObj() != 0L; } | ||
745 | |||
746 | private slots: | ||
747 | /** | ||
748 | * Resets the iterate index to -1 | ||
749 | */ | ||
750 | void slotReset(); | ||
751 | |||
752 | /** | ||
753 | * Called from the popupmenu, | ||
754 | * calls clearHistory() and emits cleared() | ||
755 | */ | ||
756 | void slotClear(); | ||
757 | |||
758 | /** | ||
759 | * Appends our own context menu entry. | ||
760 | */ | ||
761 | void addContextMenuItems( QPopupMenu* ); | ||
762 | |||
763 | private: | ||
764 | void init( bool useCompletion ); | ||
765 | |||
766 | /** | ||
767 | * The current position (index) in the combobox, used for Up and Down | ||
768 | */ | ||
769 | int myIterateIndex; | ||
770 | |||
771 | /** | ||
772 | * The text typed before Up or Down was pressed. | ||
773 | */ | ||
774 | QString myText; | ||
775 | |||
776 | /** | ||
777 | * Indicates that the user at least once rotated Up through the entire list | ||
778 | * Needed to allow going back after rotation. | ||
779 | */ | ||
780 | bool myRotated; | ||
781 | OPixmapProvider *myPixProvider; | ||
782 | |||
783 | private: | ||
784 | class OHistoryComboPrivate; | ||
785 | OHistoryComboPrivate *d; | ||
786 | }; | ||
787 | |||
788 | |||
789 | #endif | ||
790 | |||
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 | |||
41 | class OCompletionBox::OCompletionBoxPrivate | ||
42 | { | ||
43 | public: | ||
44 | QWidget *m_parent; // necessary to set the focus back | ||
45 | QString cancelText; | ||
46 | bool tabHandling; | ||
47 | bool down_workaround; | ||
48 | }; | ||
49 | |||
50 | OCompletionBox::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 | |||
80 | OCompletionBox::~OCompletionBox() | ||
81 | { | ||
82 | d->m_parent = 0L; | ||
83 | delete d; | ||
84 | } | ||
85 | |||
86 | QStringList 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 | |||
95 | void OCompletionBox::slotActivated( QListBoxItem *item ) | ||
96 | { | ||
97 | if ( !item ) | ||
98 | return; | ||
99 | |||
100 | hide(); | ||
101 | emit activated( item->text() ); | ||
102 | } | ||
103 | |||
104 | bool 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 | |||
205 | void 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 | |||
223 | void 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 | |||
252 | void OCompletionBox::hide() | ||
253 | { | ||
254 | if ( d->m_parent ) | ||
255 | qApp->removeEventFilter( this ); | ||
256 | d->cancelText = QString::null; | ||
257 | OListBox::hide(); | ||
258 | } | ||
259 | |||
260 | QSize 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 | |||
271 | void 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 | |||
286 | void OCompletionBox::up() | ||
287 | { | ||
288 | if ( currentItem() > 0 ) | ||
289 | setCurrentItem( currentItem() - 1 ); | ||
290 | } | ||
291 | |||
292 | void OCompletionBox::pageDown() | ||
293 | { | ||
294 | int i = currentItem() + numItemsVisible(); | ||
295 | i = i > (int)count() - 1 ? (int)count() - 1 : i; | ||
296 | setCurrentItem( i ); | ||
297 | } | ||
298 | |||
299 | void OCompletionBox::pageUp() | ||
300 | { | ||
301 | int i = currentItem() - numItemsVisible(); | ||
302 | i = i < 0 ? 0 : i; | ||
303 | setCurrentItem( i ); | ||
304 | } | ||
305 | |||
306 | void OCompletionBox::home() | ||
307 | { | ||
308 | setCurrentItem( 0 ); | ||
309 | } | ||
310 | |||
311 | void OCompletionBox::end() | ||
312 | { | ||
313 | setCurrentItem( count() -1 ); | ||
314 | } | ||
315 | |||
316 | void OCompletionBox::setTabHandling( bool enable ) | ||
317 | { | ||
318 | d->tabHandling = enable; | ||
319 | } | ||
320 | |||
321 | bool OCompletionBox::isTabHandling() const | ||
322 | { | ||
323 | return d->tabHandling; | ||
324 | } | ||
325 | |||
326 | void OCompletionBox::setCancelledText( const QString& text ) | ||
327 | { | ||
328 | d->cancelText = text; | ||
329 | } | ||
330 | |||
331 | QString OCompletionBox::cancelledText() const | ||
332 | { | ||
333 | return d->cancelText; | ||
334 | } | ||
335 | |||
336 | void OCompletionBox::cancelled() | ||
337 | { | ||
338 | if ( !d->cancelText.isNull() ) | ||
339 | emit userCancelled( d->cancelText ); | ||
340 | if ( isVisible() ) | ||
341 | hide(); | ||
342 | } | ||
343 | |||
344 | class OCompletionBoxItem : public QListBoxItem | ||
345 | { | ||
346 | public: | ||
347 | void reuse( const QString &text ) { setText( text ); } | ||
348 | }; | ||
349 | |||
350 | |||
351 | void 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 | |||
360 | void 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 | |||
391 | void OCompletionBox::slotCurrentChanged() | ||
392 | { | ||
393 | d->down_workaround = false; | ||
394 | } | ||
395 | |||
396 | void 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 | } | ||
diff --git a/libopie2/qt3/opieui/ocompletionbox.h b/libopie2/qt3/opieui/ocompletionbox.h new file mode 100644 index 0000000..54d9ef5 --- a/dev/null +++ b/libopie2/qt3/opieui/ocompletionbox.h | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | This file Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> | ||
3 | is part of the Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org> | ||
4 | Opie Project Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de> | ||
5 | |||
6 | =. Originally part of the KDE Project | ||
7 | .=l. | ||
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 | #ifndef OCOMPLETIONBOX_H | ||
34 | #define OCOMPLETIONBOX_H | ||
35 | |||
36 | class QEvent; | ||
37 | #include <qstringlist.h> | ||
38 | #include <qlistbox.h> | ||
39 | |||
40 | // ML: Until we don't have an own OListBox, we use the QListBox | ||
41 | #define OListBox QListBox | ||
42 | |||
43 | /** | ||
44 | * A little utility class for "completion-widgets", like @ref OLineEdit or | ||
45 | * @ref OComboBox. OCompletionBox is a listbox, displayed as a rectangle without | ||
46 | * any window decoration, usually directly under the lineedit or combobox. | ||
47 | * It is filled with all possible matches for a completion, so the user | ||
48 | * can select the one he wants. | ||
49 | * | ||
50 | * It is used when OGlobalSettings::Completion == CompletionPopup or CompletionPopupAuto. | ||
51 | * | ||
52 | * @short A helper widget for "completion-widgets" (OLineEdit, OComboBox)) | ||
53 | * @short Adapted for the Opie project by Michael Lauer <mickey@tm.informatik.uni-frankfurt.de> | ||
54 | * @author Carsten Pfeiffer <pfeiffer@kde.org> | ||
55 | * | ||
56 | */ | ||
57 | class OCompletionBox : public OListBox | ||
58 | { | ||
59 | Q_OBJECT | ||
60 | Q_PROPERTY( bool isTabHandling READ isTabHandling WRITE setTabHandling ) | ||
61 | Q_PROPERTY(QString cancelledText READ cancelledText WRITE setCancelledText) | ||
62 | |||
63 | public: | ||
64 | /** | ||
65 | * Constructs a OCompletionBox. | ||
66 | * | ||
67 | * Notice: the parent needs to be always 0L, | ||
68 | * so you can't specify it in the constructor. Because of that, Qt's | ||
69 | * auto-deletion does not take place, so you have to explicitly delete | ||
70 | * this widget when you don't need it anymore. | ||
71 | * | ||
72 | * The parent widget is used to give the focus back when pressing the | ||
73 | * up-button on the very first item. | ||
74 | */ | ||
75 | OCompletionBox( QWidget *parent, const char *name = 0 ); | ||
76 | |||
77 | /** | ||
78 | * Destroys the box | ||
79 | */ | ||
80 | ~OCompletionBox(); | ||
81 | |||
82 | virtual QSize sizeHint() const; | ||
83 | |||
84 | public slots: | ||
85 | /** | ||
86 | * Returns a list of all items currently in the box. | ||
87 | */ | ||
88 | QStringList items() const; | ||
89 | |||
90 | /** | ||
91 | * Inserts @p items into the box. Does not clear the items before. | ||
92 | * @p index determines at which position @p items will be inserted. | ||
93 | * (defaults to appending them at the end) | ||
94 | */ | ||
95 | void insertItems( const QStringList& items, int index = -1 ); | ||
96 | |||
97 | /** | ||
98 | * Clears the box and inserts @p items. | ||
99 | */ | ||
100 | void setItems( const QStringList& items ); | ||
101 | |||
102 | /** | ||
103 | * Adjusts the size of the box to fit the width of the parent given in the | ||
104 | * constructor and pops it up at the most appropriate place, relative to | ||
105 | * the parent. | ||
106 | * | ||
107 | * Depending on the screensize and the position of the parent, this may | ||
108 | * be a different place, however the default is to pop it up and the | ||
109 | * lower left corner of the parent. | ||
110 | * | ||
111 | * Make sure to hide() the box when appropriate. | ||
112 | */ | ||
113 | virtual void popup(); | ||
114 | |||
115 | /** | ||
116 | * Makes this widget (when visible) capture Tab-key events to traverse the | ||
117 | * items in the dropdown list. | ||
118 | * | ||
119 | * Default off, as it conflicts with the usual behavior of Tab to traverse | ||
120 | * widgets. It is useful for cases like Konqueror's Location Bar, though. | ||
121 | * | ||
122 | * @see #isTabHandling | ||
123 | */ | ||
124 | void setTabHandling( bool enable ); | ||
125 | |||
126 | /** | ||
127 | * @returns true if this widget is handling Tab-key events to traverse the | ||
128 | * items in the dropdown list, otherwise false. | ||
129 | * | ||
130 | * Default is false. | ||
131 | * | ||
132 | * @see #setTabHandling | ||
133 | */ | ||
134 | bool isTabHandling() const; | ||
135 | |||
136 | /** | ||
137 | * Sets the text to be emitted if the user chooses not to | ||
138 | * pick from the available matches. | ||
139 | * | ||
140 | * If the cancelled text is not set through this function, the | ||
141 | * @ref userCancelled signal will not be emitted. | ||
142 | * | ||
143 | * @see userCancelled( const QString& ) | ||
144 | * @param txt the text to be emitted if the user cancels this box | ||
145 | */ | ||
146 | void setCancelledText( const QString& ); | ||
147 | |||
148 | /** | ||
149 | * @returns the text set via @ref setCancelledText() or QString::null. | ||
150 | */ | ||
151 | QString cancelledText() const; | ||
152 | |||
153 | /** | ||
154 | * Moves the selection one line down or select the first item if nothing is selected yet. | ||
155 | */ | ||
156 | void down(); | ||
157 | |||
158 | /** | ||
159 | * Moves the selection one line up or select the first item if nothing is selected yet. | ||
160 | */ | ||
161 | void up(); | ||
162 | |||
163 | /** | ||
164 | * Moves the selection one page down. | ||
165 | */ | ||
166 | void pageDown(); | ||
167 | |||
168 | /** | ||
169 | * Moves the selection one page up. | ||
170 | */ | ||
171 | void pageUp(); | ||
172 | |||
173 | /** | ||
174 | * Moves the selection up to the first item. | ||
175 | */ | ||
176 | void home(); | ||
177 | |||
178 | /** | ||
179 | * Moves the selection down to the last item. | ||
180 | */ | ||
181 | void end(); | ||
182 | |||
183 | /** | ||
184 | * Re-implemented for internal reasons. API is unaffected. | ||
185 | */ | ||
186 | virtual void show(); | ||
187 | |||
188 | /** | ||
189 | * Re-implemented for internal reasons. API is unaffected. | ||
190 | */ | ||
191 | virtual void hide(); | ||
192 | |||
193 | signals: | ||
194 | /** | ||
195 | * Emitted when an item was selected, contains the text of | ||
196 | * the selected item. | ||
197 | */ | ||
198 | void activated( const QString& ); | ||
199 | |||
200 | /** | ||
201 | * Emitted whenever the user chooses to ignore the available | ||
202 | * selections and close the this box. | ||
203 | */ | ||
204 | void userCancelled( const QString& ); | ||
205 | |||
206 | protected: | ||
207 | /** | ||
208 | * Reimplemented from OListBox to get events from the viewport (to hide | ||
209 | * this widget on mouse-click, Escape-presses, etc. | ||
210 | */ | ||
211 | virtual bool eventFilter( QObject *, QEvent * ); | ||
212 | |||
213 | protected slots: | ||
214 | /** | ||
215 | * Called when an item was activated. Emits | ||
216 | * @ref activated() with the item. | ||
217 | */ | ||
218 | virtual void slotActivated( QListBoxItem * ); | ||
219 | |||
220 | private slots: | ||
221 | void slotSetCurrentItem( QListBoxItem *i ) { setCurrentItem( i ); } // grrr | ||
222 | void slotCurrentChanged(); | ||
223 | void cancelled(); | ||
224 | void slotItemClicked( QListBoxItem * ); | ||
225 | |||
226 | private: | ||
227 | class OCompletionBoxPrivate; | ||
228 | OCompletionBoxPrivate* d; | ||
229 | }; | ||
230 | |||
231 | |||
232 | #endif // OCOMPLETIONBOX_H | ||
diff --git a/libopie2/qt3/opieui/oeditlistbox.cpp b/libopie2/qt3/opieui/oeditlistbox.cpp new file mode 100644 index 0000000..3c53552 --- a/dev/null +++ b/libopie2/qt3/opieui/oeditlistbox.cpp | |||
@@ -0,0 +1,416 @@ | |||
1 | /* This file is part of the KDE libraries | ||
2 | Copyright (C) 2000 David Faure <faure@kde.org>, Alexander Neundorf <neundorf@kde.org> | ||
3 | 2000, 2002 Carsten Pfeiffer <pfeiffer@kde.org> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to | ||
17 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /* QT */ | ||
22 | |||
23 | #include <qstringlist.h> | ||
24 | #include <qpushbutton.h> | ||
25 | #include <qlayout.h> | ||
26 | #include <qgroupbox.h> | ||
27 | #include <qlistbox.h> | ||
28 | #include <qwhatsthis.h> | ||
29 | #include <qlabel.h> | ||
30 | |||
31 | /* OPIE */ | ||
32 | |||
33 | #include <opie2/ocombobox.h> | ||
34 | #include <opie2/odialog.h> | ||
35 | #include <opie2/olineedit.h> | ||
36 | #include <opie2/oeditlistbox.h> | ||
37 | |||
38 | /* UNIX */ | ||
39 | |||
40 | #include <assert.h> | ||
41 | |||
42 | /*====================================================================================== | ||
43 | * OEditListBoxPrivate | ||
44 | *======================================================================================*/ | ||
45 | |||
46 | class OEditListBoxPrivate | ||
47 | { | ||
48 | public: | ||
49 | bool m_checkAtEntering; | ||
50 | int buttons; | ||
51 | }; | ||
52 | |||
53 | /*====================================================================================== | ||
54 | * OEditListBox | ||
55 | *======================================================================================*/ | ||
56 | |||
57 | OEditListBox::OEditListBox(QWidget *parent, const char *name, | ||
58 | bool checkAtEntering, int buttons ) | ||
59 | :QGroupBox(parent, name ) | ||
60 | { | ||
61 | init( checkAtEntering, buttons ); | ||
62 | } | ||
63 | |||
64 | OEditListBox::OEditListBox(const QString& title, QWidget *parent, | ||
65 | const char *name, bool checkAtEntering, int buttons) | ||
66 | :QGroupBox(title, parent, name ) | ||
67 | { | ||
68 | init( checkAtEntering, buttons ); | ||
69 | } | ||
70 | |||
71 | OEditListBox::OEditListBox(const QString& title, const CustomEditor& custom, | ||
72 | QWidget *parent, const char *name, | ||
73 | bool checkAtEntering, int buttons) | ||
74 | :QGroupBox(title, parent, name ) | ||
75 | { | ||
76 | m_lineEdit = custom.lineEdit(); | ||
77 | init( checkAtEntering, buttons, custom.representationWidget() ); | ||
78 | } | ||
79 | |||
80 | OEditListBox::~OEditListBox() | ||
81 | { | ||
82 | delete d; | ||
83 | d=0; | ||
84 | } | ||
85 | |||
86 | void OEditListBox::init( bool checkAtEntering, int buttons, | ||
87 | QWidget *representationWidget ) | ||
88 | { | ||
89 | d=new OEditListBoxPrivate; | ||
90 | d->m_checkAtEntering=checkAtEntering; | ||
91 | d->buttons = buttons; | ||
92 | |||
93 | int lostButtons = 0; | ||
94 | if ( (buttons & Add) == 0 ) | ||
95 | lostButtons++; | ||
96 | if ( (buttons & Remove) == 0 ) | ||
97 | lostButtons++; | ||
98 | if ( (buttons & UpDown) == 0 ) | ||
99 | lostButtons += 2; | ||
100 | |||
101 | |||
102 | servNewButton = servRemoveButton = servUpButton = servDownButton = 0L; | ||
103 | setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, | ||
104 | QSizePolicy::MinimumExpanding)); | ||
105 | |||
106 | QWidget * gb = this; | ||
107 | QGridLayout * grid = new QGridLayout(gb, 7 - lostButtons, 2, | ||
108 | ODialog::marginHint(), | ||
109 | ODialog::spacingHint()); | ||
110 | grid->addRowSpacing(0, fontMetrics().lineSpacing()); | ||
111 | for ( int i = 1; i < 7 - lostButtons; i++ ) | ||
112 | grid->setRowStretch(i, 1); | ||
113 | |||
114 | grid->setMargin(15); | ||
115 | |||
116 | if ( representationWidget ) | ||
117 | representationWidget->reparent( gb, QPoint(0,0) ); | ||
118 | else | ||
119 | m_lineEdit=new OLineEdit(gb); | ||
120 | |||
121 | m_listBox = new QListBox(gb); | ||
122 | |||
123 | QWidget *editingWidget = representationWidget ? | ||
124 | representationWidget : m_lineEdit; | ||
125 | grid->addMultiCellWidget(editingWidget,1,1,0,1); | ||
126 | grid->addMultiCellWidget(m_listBox, 2, 6 - lostButtons, 0, 0); | ||
127 | int row = 2; | ||
128 | if ( buttons & Add ) { | ||
129 | servNewButton = new QPushButton(tr("&Add"), gb); | ||
130 | servNewButton->setEnabled(false); | ||
131 | connect(servNewButton, SIGNAL(clicked()), SLOT(addItem())); | ||
132 | |||
133 | grid->addWidget(servNewButton, row++, 1); | ||
134 | } | ||
135 | |||
136 | if ( buttons & Remove ) { | ||
137 | servRemoveButton = new QPushButton(tr("&Remove"), gb); | ||
138 | servRemoveButton->setEnabled(false); | ||
139 | connect(servRemoveButton, SIGNAL(clicked()), SLOT(removeItem())); | ||
140 | |||
141 | grid->addWidget(servRemoveButton, row++, 1); | ||
142 | } | ||
143 | |||
144 | if ( buttons & UpDown ) { | ||
145 | servUpButton = new QPushButton(tr("Move &Up"), gb); | ||
146 | servUpButton->setEnabled(false); | ||
147 | connect(servUpButton, SIGNAL(clicked()), SLOT(moveItemUp())); | ||
148 | |||
149 | servDownButton = new QPushButton(tr("Move &Down"), gb); | ||
150 | servDownButton->setEnabled(false); | ||
151 | connect(servDownButton, SIGNAL(clicked()), SLOT(moveItemDown())); | ||
152 | |||
153 | grid->addWidget(servUpButton, row++, 1); | ||
154 | grid->addWidget(servDownButton, row++, 1); | ||
155 | } | ||
156 | |||
157 | connect(m_lineEdit,SIGNAL(textChanged(const QString&)),this,SLOT(typedSomething(const QString&))); | ||
158 | m_lineEdit->setTrapReturnKey(true); | ||
159 | connect(m_lineEdit,SIGNAL(returnPressed()),this,SLOT(addItem())); | ||
160 | connect(m_listBox, SIGNAL(highlighted(int)), SLOT(enableMoveButtons(int))); | ||
161 | |||
162 | // maybe supplied lineedit has some text already | ||
163 | typedSomething( m_lineEdit->text() ); | ||
164 | } | ||
165 | |||
166 | void OEditListBox::typedSomething(const QString& text) | ||
167 | { | ||
168 | if(currentItem() >= 0) { | ||
169 | if(currentText() != m_lineEdit->text()) | ||
170 | { | ||
171 | // IMHO changeItem() shouldn't do anything with the value | ||
172 | // of currentItem() ... like changing it or emitting signals ... | ||
173 | // but TT disagree with me on this one (it's been that way since ages ... grrr) | ||
174 | bool block = m_listBox->signalsBlocked(); | ||
175 | m_listBox->blockSignals( true ); | ||
176 | m_listBox->changeItem(text, currentItem()); | ||
177 | m_listBox->blockSignals( block ); | ||
178 | emit changed(); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | if ( !servNewButton ) | ||
183 | return; | ||
184 | |||
185 | if (!d->m_checkAtEntering) | ||
186 | servNewButton->setEnabled(!text.isEmpty()); | ||
187 | else | ||
188 | { | ||
189 | if (text.isEmpty()) | ||
190 | { | ||
191 | servNewButton->setEnabled(false); | ||
192 | } | ||
193 | else | ||
194 | { | ||
195 | #if QT_VERSION > 290 | ||
196 | StringComparisonMode mode = (StringComparisonMode) (ExactMatch | CaseSensitive ); | ||
197 | bool enable = (m_listBox->findItem( text, mode ) == 0L); | ||
198 | #else | ||
199 | bool enable = (m_listBox->findItem( text ) == 0L); | ||
200 | #endif | ||
201 | servNewButton->setEnabled( enable ); | ||
202 | } | ||
203 | } | ||
204 | } | ||
205 | |||
206 | void OEditListBox::moveItemUp() | ||
207 | { | ||
208 | if (!m_listBox->isEnabled()) | ||
209 | { | ||
210 | //ONotifyClient::beep(); | ||
211 | return; | ||
212 | } | ||
213 | |||
214 | unsigned int selIndex = m_listBox->currentItem(); | ||
215 | if (selIndex == 0) | ||
216 | { | ||
217 | //ONotifyClient::beep(); | ||
218 | return; | ||
219 | } | ||
220 | |||
221 | QListBoxItem *selItem = m_listBox->item(selIndex); | ||
222 | m_listBox->takeItem(selItem); | ||
223 | m_listBox->insertItem(selItem, selIndex-1); | ||
224 | m_listBox->setCurrentItem(selIndex - 1); | ||
225 | |||
226 | emit changed(); | ||
227 | } | ||
228 | |||
229 | void OEditListBox::moveItemDown() | ||
230 | { | ||
231 | if (!m_listBox->isEnabled()) | ||
232 | { | ||
233 | //ONotifyClient::beep(); | ||
234 | return; | ||
235 | } | ||
236 | |||
237 | unsigned int selIndex = m_listBox->currentItem(); | ||
238 | if (selIndex == m_listBox->count() - 1) | ||
239 | { | ||
240 | //ONotifyClient::beep(); | ||
241 | return; | ||
242 | } | ||
243 | |||
244 | QListBoxItem *selItem = m_listBox->item(selIndex); | ||
245 | m_listBox->takeItem(selItem); | ||
246 | m_listBox->insertItem(selItem, selIndex+1); | ||
247 | m_listBox->setCurrentItem(selIndex + 1); | ||
248 | |||
249 | emit changed(); | ||
250 | } | ||
251 | |||
252 | void OEditListBox::addItem() | ||
253 | { | ||
254 | // when m_checkAtEntering is true, the add-button is disabled, but this | ||
255 | // slot can still be called through Key_Return/Key_Enter. So we guard | ||
256 | // against this. | ||
257 | if ( !servNewButton || !servNewButton->isEnabled() ) | ||
258 | return; | ||
259 | |||
260 | const QString& currentTextLE=m_lineEdit->text(); | ||
261 | bool alreadyInList(false); | ||
262 | //if we didn't check for dupes at the inserting we have to do it now | ||
263 | if (!d->m_checkAtEntering) | ||
264 | { | ||
265 | // first check current item instead of dumb iterating the entire list | ||
266 | if ( m_listBox->currentText() == currentTextLE ) | ||
267 | alreadyInList = true; | ||
268 | else | ||
269 | { | ||
270 | #if QT_VERSION > 290 | ||
271 | StringComparisonMode mode = (StringComparisonMode) (ExactMatch | CaseSensitive ); | ||
272 | alreadyInList =(m_listBox->findItem(currentTextLE, mode) != 0); | ||
273 | #else | ||
274 | alreadyInList =(m_listBox->findItem(currentTextLE) != 0); | ||
275 | #endif | ||
276 | } | ||
277 | } | ||
278 | |||
279 | if ( servNewButton ) | ||
280 | servNewButton->setEnabled(false); | ||
281 | |||
282 | bool block = m_lineEdit->signalsBlocked(); | ||
283 | m_lineEdit->blockSignals(true); | ||
284 | m_lineEdit->clear(); | ||
285 | m_lineEdit->blockSignals(block); | ||
286 | |||
287 | m_listBox->setSelected(currentItem(), false); | ||
288 | |||
289 | if (!alreadyInList) | ||
290 | { | ||
291 | block = m_listBox->signalsBlocked(); | ||
292 | m_listBox->blockSignals( true ); | ||
293 | m_listBox->insertItem(currentTextLE); | ||
294 | m_listBox->blockSignals( block ); | ||
295 | emit changed(); | ||
296 | emit added( currentTextLE ); | ||
297 | } | ||
298 | } | ||
299 | |||
300 | int OEditListBox::currentItem() const | ||
301 | { | ||
302 | int nr = m_listBox->currentItem(); | ||
303 | #if QT_VERSION > 290 | ||
304 | if(nr >= 0 && !m_listBox->item(nr)->isSelected()) return -1; | ||
305 | #else | ||
306 | if(nr >= 0 && !m_listBox->isSelected(m_listBox->item(nr))) return -1; | ||
307 | #endif | ||
308 | return nr; | ||
309 | } | ||
310 | |||
311 | void OEditListBox::removeItem() | ||
312 | { | ||
313 | int selected = m_listBox->currentItem(); | ||
314 | |||
315 | if ( selected >= 0 ) | ||
316 | { | ||
317 | QString removedText = m_listBox->currentText(); | ||
318 | |||
319 | m_listBox->removeItem( selected ); | ||
320 | if ( count() > 0 ) | ||
321 | m_listBox->setSelected( QMIN( selected, count() - 1 ), true ); | ||
322 | |||
323 | emit changed(); | ||
324 | emit removed( removedText ); | ||
325 | } | ||
326 | |||
327 | if ( servRemoveButton && m_listBox->currentItem() == -1 ) | ||
328 | servRemoveButton->setEnabled(false); | ||
329 | } | ||
330 | |||
331 | void OEditListBox::enableMoveButtons(int index) | ||
332 | { | ||
333 | // Update the lineEdit when we select a different line. | ||
334 | if(currentText() != m_lineEdit->text()) | ||
335 | m_lineEdit->setText(currentText()); | ||
336 | |||
337 | bool moveEnabled = servUpButton && servDownButton; | ||
338 | |||
339 | if (moveEnabled ) | ||
340 | { | ||
341 | if (m_listBox->count() <= 1) | ||
342 | { | ||
343 | servUpButton->setEnabled(false); | ||
344 | servDownButton->setEnabled(false); | ||
345 | } | ||
346 | else if ((uint) index == (m_listBox->count() - 1)) | ||
347 | { | ||
348 | servUpButton->setEnabled(true); | ||
349 | servDownButton->setEnabled(false); | ||
350 | } | ||
351 | else if (index == 0) | ||
352 | { | ||
353 | servUpButton->setEnabled(false); | ||
354 | servDownButton->setEnabled(true); | ||
355 | } | ||
356 | else | ||
357 | { | ||
358 | servUpButton->setEnabled(true); | ||
359 | servDownButton->setEnabled(true); | ||
360 | } | ||
361 | } | ||
362 | |||
363 | if ( servRemoveButton ) | ||
364 | servRemoveButton->setEnabled(true); | ||
365 | } | ||
366 | |||
367 | void OEditListBox::clear() | ||
368 | { | ||
369 | m_lineEdit->clear(); | ||
370 | m_listBox->clear(); | ||
371 | emit changed(); | ||
372 | } | ||
373 | |||
374 | void OEditListBox::insertStringList(const QStringList& list, int index) | ||
375 | { | ||
376 | m_listBox->insertStringList(list,index); | ||
377 | } | ||
378 | |||
379 | void OEditListBox::insertStrList(const QStrList* list, int index) | ||
380 | { | ||
381 | m_listBox->insertStrList(list,index); | ||
382 | } | ||
383 | |||
384 | void OEditListBox::insertStrList(const QStrList& list, int index) | ||
385 | { | ||
386 | m_listBox->insertStrList(list,index); | ||
387 | } | ||
388 | |||
389 | void OEditListBox::insertStrList(const char ** list, int numStrings, int index) | ||
390 | { | ||
391 | m_listBox->insertStrList(list,numStrings,index); | ||
392 | } | ||
393 | |||
394 | QStringList OEditListBox::items() const | ||
395 | { | ||
396 | QStringList list; | ||
397 | for ( uint i = 0; i < m_listBox->count(); i++ ) | ||
398 | list.append( m_listBox->text( i )); | ||
399 | |||
400 | return list; | ||
401 | } | ||
402 | |||
403 | void OEditListBox::virtual_hook( int, void* ) | ||
404 | { /*BASE::virtual_hook( id, data );*/ } | ||
405 | |||
406 | |||
407 | /*====================================================================================== | ||
408 | * CustomEditor | ||
409 | *======================================================================================*/ | ||
410 | |||
411 | OEditListBox::CustomEditor::CustomEditor( OComboBox *combo ) | ||
412 | { | ||
413 | m_representationWidget = combo; | ||
414 | m_lineEdit = dynamic_cast<OLineEdit*>( combo->lineEdit() ); | ||
415 | assert( m_lineEdit ); | ||
416 | } | ||
diff --git a/libopie2/qt3/opieui/oeditlistbox.h b/libopie2/qt3/opieui/oeditlistbox.h new file mode 100644 index 0000000..63fab11 --- a/dev/null +++ b/libopie2/qt3/opieui/oeditlistbox.h | |||
@@ -0,0 +1,250 @@ | |||
1 | /* This file is part of the KDE libraries | ||
2 | Copyright (C) 2000 David Faure <faure@kde.org>, Alexander Neundorf <neundorf@kde.org> | ||
3 | |||
4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Library General Public | ||
6 | License as published by the Free Software Foundation; either | ||
7 | version 2 of the License, or (at your option) any later version. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this library; see the file COPYING.LIB. If not, write to | ||
16 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
17 | Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #ifndef OEDITLISTBOX_H | ||
21 | #define OEDITLISTBOX_H | ||
22 | |||
23 | #include <qgroupbox.h> | ||
24 | #include <qlistbox.h> | ||
25 | |||
26 | class OLineEdit; | ||
27 | class OComboBox; | ||
28 | class QPushButton; | ||
29 | |||
30 | #if QT_VERSION < 300 | ||
31 | enum StringComparisonMode { | ||
32 | CaseSensitive = 0x00001, // 0 0001 | ||
33 | BeginsWith = 0x00002, // 0 0010 | ||
34 | EndsWith = 0x00004, // 0 0100 | ||
35 | Contains = 0x00008, // 0 1000 | ||
36 | ExactMatch = 0x00010 // 1 0000 | ||
37 | }; | ||
38 | #endif | ||
39 | |||
40 | class OEditListBoxPrivate; | ||
41 | /** | ||
42 | * An editable listbox | ||
43 | * | ||
44 | * This class provides a editable listbox ;-), this means | ||
45 | * a listbox which is accompanied by a line edit to enter new | ||
46 | * items into the listbox and pushbuttons to add and remove | ||
47 | * items from the listbox and two buttons to move items up and down. | ||
48 | */ | ||
49 | class OEditListBox : public QGroupBox | ||
50 | { | ||
51 | Q_OBJECT | ||
52 | |||
53 | public: | ||
54 | /// @since 3.1 | ||
55 | class CustomEditor | ||
56 | { | ||
57 | public: | ||
58 | CustomEditor() | ||
59 | : m_representationWidget( 0L ), | ||
60 | m_lineEdit( 0L ) {} | ||
61 | CustomEditor( QWidget *repWidget, OLineEdit *edit ) | ||
62 | : m_representationWidget( repWidget ), | ||
63 | m_lineEdit( edit ) {} | ||
64 | CustomEditor( OComboBox *combo ); | ||
65 | |||
66 | void setRepresentationWidget( QWidget *repWidget ) { | ||
67 | m_representationWidget = repWidget; | ||
68 | } | ||
69 | void setLineEdit( OLineEdit *edit ) { | ||
70 | m_lineEdit = edit; | ||
71 | } | ||
72 | |||
73 | virtual QWidget *representationWidget() const { | ||
74 | return m_representationWidget; | ||
75 | } | ||
76 | virtual OLineEdit *lineEdit() const { | ||
77 | return m_lineEdit; | ||
78 | } | ||
79 | |||
80 | protected: | ||
81 | QWidget *m_representationWidget; | ||
82 | OLineEdit *m_lineEdit; | ||
83 | }; | ||
84 | |||
85 | public: | ||
86 | |||
87 | /** | ||
88 | * Enumeration of the buttons, the listbox offers. Specify them in the | ||
89 | * constructor in the buttons parameter. | ||
90 | */ | ||
91 | enum Button { Add = 1, Remove = 2, UpDown = 4, All = Add|Remove|UpDown }; | ||
92 | |||
93 | /** | ||
94 | * Create an editable listbox. | ||
95 | * | ||
96 | * If @p checkAtEntering is true, after every character you type | ||
97 | * in the line edit OEditListBox will enable or disable | ||
98 | * the Add-button, depending whether the current content of the | ||
99 | * line edit is already in the listbox. Maybe this can become a | ||
100 | * performance hit with large lists on slow machines. | ||
101 | * If @p checkAtEntering is false, | ||
102 | * it will be checked if you press the Add-button. It is not | ||
103 | * possible to enter items twice into the listbox. | ||
104 | */ | ||
105 | OEditListBox(QWidget *parent = 0, const char *name = 0, | ||
106 | bool checkAtEntering=false, int buttons = All ); | ||
107 | /** | ||
108 | * Create an editable listbox. | ||
109 | * | ||
110 | * The same as the other constructor, additionally it takes | ||
111 | * @title, which will be the title of the frame around the listbox. | ||
112 | */ | ||
113 | OEditListBox(const QString& title, QWidget *parent = 0, | ||
114 | const char *name = 0, bool checkAtEntering=false, | ||
115 | int buttons = All ); | ||
116 | |||
117 | /** | ||
118 | * Another constructor, which allows to use a custom editing widget | ||
119 | * instead of the standard OLineEdit widget. E.g. you can use a | ||
120 | * @ref OURLRequester or a @ref OComboBox as input widget. The custom | ||
121 | * editor must consist of a lineedit and optionally another widget that | ||
122 | * is used as representation. A OComboBox or a OURLRequester have a | ||
123 | * OLineEdit as child-widget for example, so the OComboBox is used as | ||
124 | * the representation widget. | ||
125 | * | ||
126 | * @see OURLRequester::customEditor() | ||
127 | * @since 3.1 | ||
128 | */ | ||
129 | OEditListBox( const QString& title, | ||
130 | const CustomEditor &customEditor, | ||
131 | QWidget *parent = 0, const char *name = 0, | ||
132 | bool checkAtEntering = false, int buttons = All ); | ||
133 | |||
134 | virtual ~OEditListBox(); | ||
135 | |||
136 | /** | ||
137 | * Return a pointer to the embedded QListBox. | ||
138 | */ | ||
139 | QListBox* listBox() const { return m_listBox; } | ||
140 | /** | ||
141 | * Return a pointer to the embedded QLineEdit. | ||
142 | */ | ||
143 | OLineEdit* lineEdit() const { return m_lineEdit; } | ||
144 | /** | ||
145 | * Return a pointer to the Add button | ||
146 | */ | ||
147 | QPushButton* addButton() const { return servNewButton; } | ||
148 | /** | ||
149 | * Return a pointer to the Remove button | ||
150 | */ | ||
151 | QPushButton* removeButton() const { return servRemoveButton; } | ||
152 | /** | ||
153 | * Return a pointer to the Up button | ||
154 | */ | ||
155 | QPushButton* upButton() const { return servUpButton; } | ||
156 | /** | ||
157 | * Return a pointer to the Down button | ||
158 | */ | ||
159 | QPushButton* downButton() const { return servDownButton; } | ||
160 | |||
161 | /** | ||
162 | * See @ref QListBox::count() | ||
163 | */ | ||
164 | int count() const { return int(m_listBox->count()); } | ||
165 | /** | ||
166 | * See @ref QListBox::insertStringList() | ||
167 | */ | ||
168 | void insertStringList(const QStringList& list, int index=-1); | ||
169 | /** | ||
170 | * See @ref QListBox::insertStringList() | ||
171 | */ | ||
172 | void insertStrList(const QStrList* list, int index=-1); | ||
173 | /** | ||
174 | * See @ref QListBox::insertStrList() | ||
175 | */ | ||
176 | void insertStrList(const QStrList& list, int index=-1); | ||
177 | /** | ||
178 | * See @ref QListBox::insertStrList() | ||
179 | */ | ||
180 | void insertStrList(const char ** list, int numStrings=-1, int index=-1); | ||
181 | /** | ||
182 | * See @ref QListBox::insertItem() | ||
183 | */ | ||
184 | void insertItem(const QString& text, int index=-1) {m_listBox->insertItem(text,index);} | ||
185 | /** | ||
186 | * Clears both the listbox and the line edit. | ||
187 | */ | ||
188 | void clear(); | ||
189 | /** | ||
190 | * See @ref QListBox::text() | ||
191 | */ | ||
192 | QString text(int index) const { return m_listBox->text(index); } | ||
193 | /** | ||
194 | * See @ref QListBox::currentItem() | ||
195 | */ | ||
196 | int currentItem() const; | ||
197 | /** | ||
198 | * See @ref QListBox::currentText() | ||
199 | */ | ||
200 | QString currentText() const { return m_listBox->currentText(); } | ||
201 | |||
202 | /** | ||
203 | * @returns a stringlist of all items in the listbox | ||
204 | */ | ||
205 | QStringList items() const; | ||
206 | |||
207 | signals: | ||
208 | void changed(); | ||
209 | |||
210 | /** | ||
211 | * This signal is emitted when the user adds a new string to the list, | ||
212 | * the parameter is the added string. | ||
213 | * @since 3.2 | ||
214 | */ | ||
215 | void added( const QString & text ); | ||
216 | |||
217 | /** | ||
218 | * This signal is emitted when the user removes a string from the list, | ||
219 | * the parameter is the removed string. | ||
220 | * @since 3.2 | ||
221 | */ | ||
222 | void removed( const QString & text ); | ||
223 | |||
224 | protected slots: | ||
225 | //the names should be self-explaining | ||
226 | void moveItemUp(); | ||
227 | void moveItemDown(); | ||
228 | void addItem(); | ||
229 | void removeItem(); | ||
230 | void enableMoveButtons(int index); | ||
231 | void typedSomething(const QString& text); | ||
232 | |||
233 | private: | ||
234 | QListBox *m_listBox; | ||
235 | QPushButton *servUpButton, *servDownButton; | ||
236 | QPushButton *servNewButton, *servRemoveButton; | ||
237 | OLineEdit *m_lineEdit; | ||
238 | |||
239 | //this is called in both ctors, to avoid code duplication | ||
240 | void init( bool checkAtEntering, int buttons, | ||
241 | QWidget *representationWidget = 0L ); | ||
242 | |||
243 | protected: | ||
244 | virtual void virtual_hook( int id, void* data ); | ||
245 | private: | ||
246 | //our lovely private d-pointer | ||
247 | OEditListBoxPrivate *d; | ||
248 | }; | ||
249 | |||
250 | #endif // OEDITLISTBOX | ||
diff --git a/libopie2/qt3/opieui/ojanuswidget.cpp b/libopie2/qt3/opieui/ojanuswidget.cpp new file mode 100644 index 0000000..0a037ff --- a/dev/null +++ b/libopie2/qt3/opieui/ojanuswidget.cpp | |||
@@ -0,0 +1,1116 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | |||
4 | Originally part of the KDE project | ||
5 | (C) 1999-2000 Espen Sand (espensa@online.no) | ||
6 | =. | ||
7 | .=l. | ||
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 | /* QT */ | ||
34 | |||
35 | #include <qbitmap.h> | ||
36 | #include <qgrid.h> | ||
37 | #include <qhbox.h> | ||
38 | #include <qheader.h> | ||
39 | #include <qlabel.h> | ||
40 | #include <qlayout.h> | ||
41 | #include <qobjectlist.h> | ||
42 | #include <qpixmap.h> | ||
43 | #include <qlistview.h> | ||
44 | #include <qsplitter.h> | ||
45 | #include <qtabwidget.h> | ||
46 | #include <qvbox.h> | ||
47 | #include <qwidgetstack.h> | ||
48 | #include <qpainter.h> | ||
49 | #include <qtimer.h> | ||
50 | #include <qstyle.h> | ||
51 | |||
52 | /* OPIE */ | ||
53 | |||
54 | #include <opie2/odialog.h> | ||
55 | #include <opie2/oseparator.h> | ||
56 | #include <opie2/ojanuswidget.h> | ||
57 | |||
58 | /*====================================================================================== | ||
59 | * IconListItem | ||
60 | *======================================================================================*/ | ||
61 | |||
62 | class OJanusWidget::IconListItem : public QListBoxItem | ||
63 | { | ||
64 | public: | ||
65 | IconListItem( QListBox *listbox, const QPixmap &pixmap, | ||
66 | const QString &text ); | ||
67 | virtual int height( const QListBox *lb ) const; | ||
68 | virtual int width( const QListBox *lb ) const; | ||
69 | int expandMinimumWidth( int width ); | ||
70 | |||
71 | protected: | ||
72 | const QPixmap &defaultPixmap(); | ||
73 | void paint( QPainter *painter ); | ||
74 | |||
75 | private: | ||
76 | QPixmap mPixmap; | ||
77 | int mMinimumWidth; | ||
78 | }; | ||
79 | |||
80 | template class QPtrList<QListViewItem>; | ||
81 | |||
82 | /*====================================================================================== | ||
83 | * OJanusWidget | ||
84 | *======================================================================================*/ | ||
85 | |||
86 | OJanusWidget::OJanusWidget( QWidget *parent, const char *name, int face ) | ||
87 | : QWidget( parent, name, 0 ), | ||
88 | mValid(false), mPageList(0), | ||
89 | mTitleList(0), mFace(face), mTitleLabel(0), mActivePageWidget(0), | ||
90 | mShowIconsInTreeList(false), d(0) | ||
91 | { | ||
92 | QVBoxLayout *topLayout = new QVBoxLayout( this ); | ||
93 | |||
94 | if( mFace == TreeList || mFace == IconList ) | ||
95 | { | ||
96 | mPageList = new QPtrList<QWidget>; | ||
97 | mTitleList = new QStringList(); | ||
98 | |||
99 | QFrame *page; | ||
100 | if( mFace == TreeList ) | ||
101 | { | ||
102 | QSplitter *splitter = new QSplitter( this ); | ||
103 | topLayout->addWidget( splitter, 10 ); | ||
104 | mTreeListResizeMode = QSplitter::KeepSize; | ||
105 | |||
106 | mTreeList = new QListView( splitter ); | ||
107 | mTreeList->addColumn( QString::fromLatin1("") ); | ||
108 | mTreeList->header()->hide(); | ||
109 | mTreeList->setRootIsDecorated(true); | ||
110 | mTreeList->setSorting( -1 ); | ||
111 | connect( mTreeList, SIGNAL(selectionChanged()), SLOT(slotShowPage()) ); | ||
112 | connect( mTreeList, SIGNAL(clicked(QListViewItem *)), SLOT(slotItemClicked(QListViewItem *))); | ||
113 | |||
114 | // | ||
115 | // Page area. Title at top with a separator below and a pagestack using | ||
116 | // all available space at bottom. | ||
117 | // | ||
118 | QFrame *p = new QFrame( splitter ); | ||
119 | |||
120 | QHBoxLayout *hbox = new QHBoxLayout( p, 0, 0 ); | ||
121 | hbox->addSpacing( ODialog::spacingHint() ); | ||
122 | |||
123 | page = new QFrame( p ); | ||
124 | hbox->addWidget( page, 10 ); | ||
125 | } | ||
126 | else | ||
127 | { | ||
128 | QHBoxLayout *hbox = new QHBoxLayout( topLayout ); | ||
129 | mIconList = new IconListBox( this ); | ||
130 | |||
131 | QFont listFont( mIconList->font() ); | ||
132 | listFont.setBold( true ); | ||
133 | mIconList->setFont( listFont ); | ||
134 | |||
135 | mIconList->verticalScrollBar()->installEventFilter( this ); | ||
136 | hbox->addWidget( mIconList ); | ||
137 | connect( mIconList, SIGNAL(selectionChanged()), SLOT(slotShowPage())); | ||
138 | hbox->addSpacing( ODialog::spacingHint() ); | ||
139 | page = new QFrame( this ); | ||
140 | hbox->addWidget( page, 10 ); | ||
141 | } | ||
142 | |||
143 | // | ||
144 | // Rest of page area. Title at top with a separator below and a | ||
145 | // pagestack using all available space at bottom. | ||
146 | // | ||
147 | |||
148 | QVBoxLayout *vbox = new QVBoxLayout( page, 0, ODialog::spacingHint() ); | ||
149 | |||
150 | mTitleLabel = new QLabel( QString::fromLatin1("Empty page"), page, "OJanusWidgetTitleLabel" ); | ||
151 | vbox->addWidget( mTitleLabel ); | ||
152 | |||
153 | QFont titleFont( mTitleLabel->font() ); | ||
154 | titleFont.setBold( true ); | ||
155 | mTitleLabel->setFont( titleFont ); | ||
156 | |||
157 | mTitleSep = new OSeparator( page ); | ||
158 | mTitleSep->setFrameStyle( QFrame::HLine|QFrame::Plain ); | ||
159 | vbox->addWidget( mTitleSep ); | ||
160 | |||
161 | mPageStack = new QWidgetStack( page ); | ||
162 | connect(mPageStack, SIGNAL(aboutToShow(QWidget *)), | ||
163 | this, SIGNAL(aboutToShowPage(QWidget *))); | ||
164 | vbox->addWidget( mPageStack, 10 ); | ||
165 | } | ||
166 | else if( mFace == Tabbed ) | ||
167 | { | ||
168 | mPageList = new QPtrList<QWidget>; | ||
169 | |||
170 | mTabControl = new QTabWidget( this ); | ||
171 | mTabControl->setMargin (ODialog::marginHint()); | ||
172 | topLayout->addWidget( mTabControl, 10 ); | ||
173 | } | ||
174 | else if( mFace == Swallow ) | ||
175 | { | ||
176 | mSwallowPage = new QWidget( this ); | ||
177 | topLayout->addWidget( mSwallowPage, 10 ); | ||
178 | } | ||
179 | else | ||
180 | { | ||
181 | mFace = Plain; | ||
182 | mPlainPage = new QFrame( this ); | ||
183 | topLayout->addWidget( mPlainPage, 10 ); | ||
184 | } | ||
185 | |||
186 | /* FIXME: Revise for Opie | ||
187 | if ( kapp ) | ||
188 | connect(kapp,SIGNAL(kdisplayFontChanged()),SLOT(slotFontChanged())); | ||
189 | */ | ||
190 | |||
191 | mValid = true; | ||
192 | |||
193 | setSwallowedWidget(0); // Set default size if 'mFace' is Swallow. | ||
194 | } | ||
195 | |||
196 | |||
197 | OJanusWidget::~OJanusWidget() | ||
198 | { | ||
199 | delete mPageList; | ||
200 | mPageList = 0; | ||
201 | delete mTitleList; | ||
202 | mTitleList = 0; | ||
203 | } | ||
204 | |||
205 | |||
206 | bool OJanusWidget::isValid() const | ||
207 | { | ||
208 | return( mValid ); | ||
209 | } | ||
210 | |||
211 | |||
212 | QFrame *OJanusWidget::plainPage() | ||
213 | { | ||
214 | return( mPlainPage ); | ||
215 | } | ||
216 | |||
217 | |||
218 | int OJanusWidget::face() const | ||
219 | { | ||
220 | return( mFace ); | ||
221 | } | ||
222 | |||
223 | QWidget *OJanusWidget::FindParent() | ||
224 | { | ||
225 | if( mFace == Tabbed ) { | ||
226 | return mTabControl; | ||
227 | } | ||
228 | else { | ||
229 | return this; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | QFrame *OJanusWidget::addPage( const QStringList &items, const QString &header, | ||
234 | const QPixmap &pixmap ) | ||
235 | { | ||
236 | if( mValid == false ) | ||
237 | { | ||
238 | qDebug( "addPage: Invalid object" ); | ||
239 | return( 0 ); | ||
240 | } | ||
241 | |||
242 | QFrame *page = new QFrame( FindParent(), "page" ); | ||
243 | addPageWidget( page, items, header, pixmap ); | ||
244 | |||
245 | return page; | ||
246 | } | ||
247 | |||
248 | void OJanusWidget::pageGone( QObject *obj ) | ||
249 | { | ||
250 | removePage( static_cast<QWidget*>( obj ) ); | ||
251 | } | ||
252 | |||
253 | void OJanusWidget::slotReopen( QListViewItem * item ) | ||
254 | { | ||
255 | if( item ) | ||
256 | item->setOpen( true ); | ||
257 | } | ||
258 | |||
259 | QFrame *OJanusWidget::addPage( const QString &itemName, const QString &header, | ||
260 | const QPixmap &pixmap ) | ||
261 | { | ||
262 | QStringList items; | ||
263 | items << itemName; | ||
264 | return addPage(items, header, pixmap); | ||
265 | } | ||
266 | |||
267 | |||
268 | |||
269 | QVBox *OJanusWidget::addVBoxPage( const QStringList &items, | ||
270 | const QString &header, | ||
271 | const QPixmap &pixmap ) | ||
272 | { | ||
273 | if( mValid == false ) | ||
274 | { | ||
275 | qDebug( "addPage: Invalid object" ); | ||
276 | return( 0 ); | ||
277 | } | ||
278 | |||
279 | QVBox *page = new QVBox(FindParent() , "page" ); | ||
280 | page->setSpacing( ODialog::spacingHint() ); | ||
281 | addPageWidget( page, items, header, pixmap ); | ||
282 | |||
283 | return page; | ||
284 | } | ||
285 | |||
286 | QVBox *OJanusWidget::addVBoxPage( const QString &itemName, | ||
287 | const QString &header, | ||
288 | const QPixmap &pixmap ) | ||
289 | { | ||
290 | QStringList items; | ||
291 | items << itemName; | ||
292 | return addVBoxPage(items, header, pixmap); | ||
293 | } | ||
294 | |||
295 | QHBox *OJanusWidget::addHBoxPage( const QStringList &items, | ||
296 | const QString &header, | ||
297 | const QPixmap &pixmap ) | ||
298 | { | ||
299 | if( mValid == false ) { | ||
300 | qDebug( "addPage: Invalid object" ); | ||
301 | return( 0 ); | ||
302 | } | ||
303 | |||
304 | QHBox *page = new QHBox(FindParent(), "page"); | ||
305 | page->setSpacing( ODialog::spacingHint() ); | ||
306 | addPageWidget( page, items, header, pixmap ); | ||
307 | |||
308 | return page; | ||
309 | } | ||
310 | |||
311 | QHBox *OJanusWidget::addHBoxPage( const QString &itemName, | ||
312 | const QString &header, | ||
313 | const QPixmap &pixmap ) | ||
314 | { | ||
315 | QStringList items; | ||
316 | items << itemName; | ||
317 | return addHBoxPage(items, header, pixmap); | ||
318 | } | ||
319 | |||
320 | QGrid *OJanusWidget::addGridPage( int n, Orientation dir, | ||
321 | const QStringList &items, | ||
322 | const QString &header, | ||
323 | const QPixmap &pixmap ) | ||
324 | { | ||
325 | if( mValid == false ) | ||
326 | { | ||
327 | qDebug( "addPage: Invalid object" ); | ||
328 | return( 0 ); | ||
329 | } | ||
330 | |||
331 | QGrid *page = new QGrid( n, dir, FindParent(), "page" ); | ||
332 | page->setSpacing( ODialog::spacingHint() ); | ||
333 | addPageWidget( page, items, header, pixmap ); | ||
334 | |||
335 | return page; | ||
336 | } | ||
337 | |||
338 | |||
339 | QGrid *OJanusWidget::addGridPage( int n, Orientation dir, | ||
340 | const QString &itemName, | ||
341 | const QString &header, | ||
342 | const QPixmap &pixmap ) | ||
343 | { | ||
344 | QStringList items; | ||
345 | items << itemName; | ||
346 | return addGridPage(n, dir, items, header, pixmap); | ||
347 | } | ||
348 | |||
349 | void OJanusWidget::InsertTreeListItem(const QStringList &items, const QPixmap &pixmap, QFrame *page) | ||
350 | { | ||
351 | bool isTop = true; | ||
352 | QListViewItem *curTop = 0, *child, *last, *newChild; | ||
353 | unsigned int index = 1; | ||
354 | QStringList curPath; | ||
355 | |||
356 | for ( QStringList::ConstIterator it = items.begin(); it != items.end(); ++it, index++ ) { | ||
357 | QString name = (*it); | ||
358 | bool isPath = ( index != items.count() ); | ||
359 | |||
360 | // Find the first child. | ||
361 | if (isTop) { | ||
362 | child = mTreeList->firstChild(); | ||
363 | } | ||
364 | else { | ||
365 | child = curTop->firstChild(); | ||
366 | } | ||
367 | |||
368 | // Now search for a child with the current Name, and if it we doesn't | ||
369 | // find it, then remember the location of the last child. | ||
370 | for (last = 0; child && child->text(0) != name ; last = child, child = child->nextSibling()); | ||
371 | |||
372 | if (last == 0 && child == 0) { | ||
373 | // This node didn't have any children at all, lets just insert the | ||
374 | // new child. | ||
375 | if (isTop) | ||
376 | newChild = new QListViewItem(mTreeList, name); | ||
377 | else | ||
378 | newChild = new QListViewItem(curTop, name); | ||
379 | |||
380 | } | ||
381 | else if (child != 0) { | ||
382 | // we found the given name in this child. | ||
383 | if (!isPath) { | ||
384 | qDebug( "The element inserted was already in the TreeList box!" ); | ||
385 | return; | ||
386 | } | ||
387 | else { | ||
388 | // Ok we found the folder | ||
389 | newChild = child; | ||
390 | } | ||
391 | } | ||
392 | else { | ||
393 | // the node had some children, but we didn't find the given name | ||
394 | if (isTop) | ||
395 | newChild = new QListViewItem(mTreeList, last, name); | ||
396 | else | ||
397 | newChild = new QListViewItem(curTop, last, name); | ||
398 | } | ||
399 | |||
400 | // Now make the element expandable if it is a path component, and make | ||
401 | // ready for next loop | ||
402 | if (isPath) { | ||
403 | newChild->setExpandable(true); | ||
404 | curTop = newChild; | ||
405 | isTop = false; | ||
406 | curPath << name; | ||
407 | |||
408 | QString key = curPath.join("_/_"); | ||
409 | if (mFolderIconMap.contains(key)) { | ||
410 | QPixmap p = mFolderIconMap[key]; | ||
411 | newChild->setPixmap(0,p); | ||
412 | } | ||
413 | } | ||
414 | else { | ||
415 | if (mShowIconsInTreeList) { | ||
416 | newChild->setPixmap(0, pixmap); | ||
417 | } | ||
418 | mTreeListToPageStack.insert(newChild, page); | ||
419 | } | ||
420 | } | ||
421 | } | ||
422 | |||
423 | void OJanusWidget::addPageWidget( QFrame *page, const QStringList &items, | ||
424 | const QString &header,const QPixmap &pixmap ) | ||
425 | { | ||
426 | connect(page, SIGNAL(destroyed(QObject*)), SLOT(pageGone(QObject*))); | ||
427 | |||
428 | if( mFace == Tabbed ) | ||
429 | { | ||
430 | mTabControl->addTab (page, items.last()); | ||
431 | mPageList->append (page); | ||
432 | } | ||
433 | else if( mFace == TreeList || mFace == IconList ) | ||
434 | { | ||
435 | mPageList->append( page ); | ||
436 | mPageStack->addWidget( page, 0 ); | ||
437 | |||
438 | if (items.count() == 0) { | ||
439 | qDebug( "Invalid QStringList, with zero items" ); | ||
440 | return; | ||
441 | } | ||
442 | |||
443 | if( mFace == TreeList ) | ||
444 | { | ||
445 | InsertTreeListItem(items, pixmap, page); | ||
446 | } | ||
447 | else // mFace == IconList | ||
448 | { | ||
449 | QString itemName = items.last(); | ||
450 | IconListItem *item = new IconListItem( mIconList, pixmap, itemName ); | ||
451 | // | ||
452 | // 2000-06-01 Espen Sand: If I do this with Qt 2.1.1 all sorts of | ||
453 | // strange things happen. With Qt <= 2.1 it worked but now I must | ||
454 | // either specify the listbox in the constructor on the item | ||
455 | // or as below, not both. | ||
456 | // mIconList->insertItem( item ); | ||
457 | // | ||
458 | mIconListToPageStack.insert(item, page); | ||
459 | mIconList->invalidateHeight(); | ||
460 | mIconList->invalidateWidth(); | ||
461 | |||
462 | if (mIconList->isVisible()) | ||
463 | mIconList->updateWidth(); | ||
464 | } | ||
465 | |||
466 | // | ||
467 | // Make sure the title label is sufficiently wide | ||
468 | // | ||
469 | QString lastName = items.last(); | ||
470 | const QString &title = (header != QString::null ? header : lastName); | ||
471 | QRect r = mTitleLabel->fontMetrics().boundingRect( title ); | ||
472 | if( mTitleLabel->minimumWidth() < r.width() ) | ||
473 | { | ||
474 | mTitleLabel->setMinimumWidth( r.width() ); | ||
475 | } | ||
476 | mTitleList->append( title ); | ||
477 | |||
478 | if( mTitleList->count() == 1 ) | ||
479 | { | ||
480 | showPage(0); | ||
481 | } | ||
482 | } | ||
483 | else | ||
484 | { | ||
485 | qDebug( "OJanusWidget::addPageWidget: can only add a page in Tabbed, TreeList or IconList modes" ); | ||
486 | } | ||
487 | |||
488 | } | ||
489 | |||
490 | void OJanusWidget::setFolderIcon(const QStringList &path, const QPixmap &pixmap) | ||
491 | { | ||
492 | QString key = path.join("_/_"); | ||
493 | mFolderIconMap.insert(key,pixmap); | ||
494 | } | ||
495 | |||
496 | |||
497 | |||
498 | bool OJanusWidget::setSwallowedWidget( QWidget *widget ) | ||
499 | { | ||
500 | if( mFace != Swallow || mValid == false ) | ||
501 | { | ||
502 | return( false ); | ||
503 | } | ||
504 | |||
505 | // | ||
506 | // Remove current layout and make a new. | ||
507 | // | ||
508 | if( mSwallowPage->layout() != 0 ) | ||
509 | { | ||
510 | delete mSwallowPage->layout(); | ||
511 | } | ||
512 | QGridLayout *gbox = new QGridLayout( mSwallowPage, 1, 1, 0 ); | ||
513 | |||
514 | // | ||
515 | // Hide old children | ||
516 | // | ||
517 | QObjectList *l = (QObjectList*)mSwallowPage->children(); // silence please | ||
518 | for( uint i=0; i < l->count(); i++ ) | ||
519 | { | ||
520 | QObject *o = l->at(i); | ||
521 | if( o->isWidgetType() ) | ||
522 | { | ||
523 | ((QWidget*)o)->hide(); | ||
524 | } | ||
525 | } | ||
526 | |||
527 | // | ||
528 | // Add new child or make default size | ||
529 | // | ||
530 | if( widget == 0 ) | ||
531 | { | ||
532 | gbox->addRowSpacing(0,100); | ||
533 | gbox->addColSpacing(0,100); | ||
534 | mSwallowPage->setMinimumSize(100,100); | ||
535 | } | ||
536 | else | ||
537 | { | ||
538 | if( widget->parent() != mSwallowPage ) | ||
539 | { | ||
540 | widget->reparent( mSwallowPage, 0, QPoint(0,0) ); | ||
541 | } | ||
542 | gbox->addWidget(widget, 0, 0 ); | ||
543 | gbox->activate(); | ||
544 | mSwallowPage->setMinimumSize( widget->minimumSize() ); | ||
545 | } | ||
546 | |||
547 | return( true ); | ||
548 | } | ||
549 | |||
550 | bool OJanusWidget::slotShowPage() | ||
551 | { | ||
552 | if( mValid == false ) | ||
553 | { | ||
554 | return( false ); | ||
555 | } | ||
556 | |||
557 | if( mFace == TreeList ) | ||
558 | { | ||
559 | QListViewItem *node = mTreeList->selectedItem(); | ||
560 | if( node == 0 ) { return( false ); } | ||
561 | |||
562 | QWidget *stackItem = mTreeListToPageStack[node]; | ||
563 | return showPage(stackItem); | ||
564 | } | ||
565 | else if( mFace == IconList ) | ||
566 | { | ||
567 | QListBoxItem *node = mIconList->item( mIconList->currentItem() ); | ||
568 | if( node == 0 ) { return( false ); } | ||
569 | QWidget *stackItem = mIconListToPageStack[node]; | ||
570 | return showPage(stackItem); | ||
571 | } | ||
572 | |||
573 | return( false ); | ||
574 | } | ||
575 | |||
576 | |||
577 | bool OJanusWidget::showPage( int index ) | ||
578 | { | ||
579 | if( mPageList == 0 || mValid == false ) | ||
580 | { | ||
581 | return( false ); | ||
582 | } | ||
583 | else | ||
584 | { | ||
585 | return showPage(mPageList->at(index)); | ||
586 | } | ||
587 | } | ||
588 | |||
589 | |||
590 | bool OJanusWidget::showPage( QWidget *w ) | ||
591 | { | ||
592 | if( w == 0 || mValid == false ) | ||
593 | { | ||
594 | return( false ); | ||
595 | } | ||
596 | |||
597 | if( mFace == TreeList || mFace == IconList ) | ||
598 | { | ||
599 | mPageStack->raiseWidget( w ); | ||
600 | mActivePageWidget = w; | ||
601 | |||
602 | int index = mPageList->findRef( w ); | ||
603 | mTitleLabel->setText( *mTitleList->at(index) ); | ||
604 | if( mFace == TreeList ) | ||
605 | { | ||
606 | QMap<QListViewItem *, QWidget *>::Iterator it; | ||
607 | for (it = mTreeListToPageStack.begin(); it != mTreeListToPageStack.end(); ++it){ | ||
608 | QListViewItem *key = it.key(); | ||
609 | QWidget *val = it.data(); | ||
610 | if (val == w) { | ||
611 | mTreeList->setSelected(key, true ); | ||
612 | break; | ||
613 | } | ||
614 | } | ||
615 | } | ||
616 | else | ||
617 | { | ||
618 | QMap<QListBoxItem *, QWidget *>::Iterator it; | ||
619 | for (it = mIconListToPageStack.begin(); it != mIconListToPageStack.end(); ++it){ | ||
620 | QListBoxItem *key = it.key(); | ||
621 | QWidget *val = it.data(); | ||
622 | if (val == w) { | ||
623 | mIconList->setSelected( key, true ); | ||
624 | break; | ||
625 | } | ||
626 | } | ||
627 | |||
628 | // | ||
629 | // 2000-02-13 Espen Sand | ||
630 | // Don't ask me why (because I don't know). If I select a page | ||
631 | // with the mouse the page is not updated until it receives an | ||
632 | // event. It seems this event get lost if the mouse is not moved | ||
633 | // when released. The timer ensures the update | ||
634 | // | ||
635 | QTimer::singleShot( 0, mActivePageWidget, SLOT(update()) ); | ||
636 | } | ||
637 | } | ||
638 | else if( mFace == Tabbed ) | ||
639 | { | ||
640 | mTabControl->showPage(w); | ||
641 | mActivePageWidget = w; | ||
642 | } | ||
643 | else | ||
644 | { | ||
645 | return( false ); | ||
646 | } | ||
647 | |||
648 | return( true ); | ||
649 | } | ||
650 | |||
651 | |||
652 | int OJanusWidget::activePageIndex() const | ||
653 | { | ||
654 | if( mFace == TreeList) { | ||
655 | QListViewItem *node = mTreeList->selectedItem(); | ||
656 | if( node == 0 ) { return -1; } | ||
657 | QWidget *stackItem = mTreeListToPageStack[node]; | ||
658 | return mPageList->findRef(stackItem); | ||
659 | } | ||
660 | else if (mFace == IconList) { | ||
661 | QListBoxItem *node = mIconList->item( mIconList->currentItem() ); | ||
662 | if( node == 0 ) { return( false ); } | ||
663 | QWidget *stackItem = mIconListToPageStack[node]; | ||
664 | return mPageList->findRef(stackItem); | ||
665 | } | ||
666 | else if( mFace == Tabbed ) { | ||
667 | QWidget *widget = mTabControl->currentPage(); | ||
668 | return( widget == 0 ? -1 : mPageList->findRef( widget ) ); | ||
669 | } | ||
670 | else { | ||
671 | return( -1 ); | ||
672 | } | ||
673 | } | ||
674 | |||
675 | |||
676 | int OJanusWidget::pageIndex( QWidget *widget ) const | ||
677 | { | ||
678 | if( widget == 0 ) | ||
679 | { | ||
680 | return( -1 ); | ||
681 | } | ||
682 | else if( mFace == TreeList || mFace == IconList ) | ||
683 | { | ||
684 | return( mPageList->findRef( widget ) ); | ||
685 | } | ||
686 | else if( mFace == Tabbed ) | ||
687 | { | ||
688 | // | ||
689 | // The user gets the real page widget with addVBoxPage(), addHBoxPage() | ||
690 | // and addGridPage() but not with addPage() which returns a child of | ||
691 | // the toplevel page. addPage() returns a QFrame so I check for that. | ||
692 | // | ||
693 | if( widget->isA("QFrame") ) | ||
694 | { | ||
695 | return( mPageList->findRef( widget->parentWidget() ) ); | ||
696 | } | ||
697 | else | ||
698 | { | ||
699 | return( mPageList->findRef( widget ) ); | ||
700 | } | ||
701 | } | ||
702 | else | ||
703 | { | ||
704 | return( -1 ); | ||
705 | } | ||
706 | } | ||
707 | |||
708 | void OJanusWidget::slotFontChanged() | ||
709 | { | ||
710 | #ifdef FIXME | ||
711 | |||
712 | if ( mTitleLabel != 0 ) | ||
713 | { | ||
714 | mTitleLabel->setFont( KGlobalSettings::generalFont() ); | ||
715 | QFont titleFont( mTitleLabel->font() ); | ||
716 | titleFont.setBold( true ); | ||
717 | mTitleLabel->setFont( titleFont ); | ||
718 | } | ||
719 | #endif | ||
720 | |||
721 | if( mFace == IconList ) | ||
722 | { | ||
723 | QFont listFont( mIconList->font() ); | ||
724 | listFont.setBold( true ); | ||
725 | mIconList->setFont( listFont ); | ||
726 | mIconList->invalidateHeight(); | ||
727 | mIconList->invalidateWidth(); | ||
728 | } | ||
729 | } | ||
730 | |||
731 | // makes the treelist behave like the list of kcontrol | ||
732 | void OJanusWidget::slotItemClicked(QListViewItem *it) | ||
733 | { | ||
734 | if(it && (it->childCount()>0)) | ||
735 | it->setOpen(!it->isOpen()); | ||
736 | } | ||
737 | |||
738 | void OJanusWidget::setFocus() | ||
739 | { | ||
740 | if( mValid == false ) { return; } | ||
741 | if( mFace == TreeList ) | ||
742 | { | ||
743 | mTreeList->setFocus(); | ||
744 | } | ||
745 | if( mFace == IconList ) | ||
746 | { | ||
747 | mIconList->setFocus(); | ||
748 | } | ||
749 | else if( mFace == Tabbed ) | ||
750 | { | ||
751 | mTabControl->setFocus(); | ||
752 | } | ||
753 | else if( mFace == Swallow ) | ||
754 | { | ||
755 | mSwallowPage->setFocus(); | ||
756 | } | ||
757 | else if( mFace == Plain ) | ||
758 | { | ||
759 | mPlainPage->setFocus(); | ||
760 | } | ||
761 | } | ||
762 | |||
763 | |||
764 | QSize OJanusWidget::minimumSizeHint() const | ||
765 | { | ||
766 | if( mFace == TreeList || mFace == IconList ) | ||
767 | { | ||
768 | QSize s1( ODialog::spacingHint(), ODialog::spacingHint()*2 ); | ||
769 | QSize s2(0,0); | ||
770 | QSize s3(0,0); | ||
771 | QSize s4( mPageStack->sizeHint() ); | ||
772 | |||
773 | if( mFace == TreeList ) | ||
774 | { | ||
775 | #if QT_VERSION < 300 | ||
776 | s1.rwidth() += style().splitterWidth(); | ||
777 | #else | ||
778 | s1.rwidth() += style().pixelMetric( QStyle::PM_SplitterWidth ); | ||
779 | #endif | ||
780 | s2 = mTreeList->minimumSize(); | ||
781 | } | ||
782 | else | ||
783 | { | ||
784 | mIconList->updateMinimumHeight(); | ||
785 | mIconList->updateWidth(); | ||
786 | s2 = mIconList->minimumSize(); | ||
787 | } | ||
788 | |||
789 | if( mTitleLabel->isVisible() == true ) | ||
790 | { | ||
791 | s3 += mTitleLabel->sizeHint(); | ||
792 | s3.rheight() += mTitleSep->minimumSize().height(); | ||
793 | } | ||
794 | |||
795 | // | ||
796 | // Select the tallest item. It has only effect in IconList mode | ||
797 | // | ||
798 | int h1 = s1.rheight() + s3.rheight() + s4.height(); | ||
799 | int h2 = QMAX( h1, s2.rheight() ); | ||
800 | |||
801 | return( QSize( s1.width()+s2.width()+QMAX(s3.width(),s4.width()), h2 ) ); | ||
802 | } | ||
803 | else if( mFace == Tabbed ) | ||
804 | { | ||
805 | return( mTabControl->sizeHint() ); | ||
806 | } | ||
807 | else if( mFace == Swallow ) | ||
808 | { | ||
809 | return( mSwallowPage->minimumSize() ); | ||
810 | } | ||
811 | else if( mFace == Plain ) | ||
812 | { | ||
813 | return( mPlainPage->sizeHint() ); | ||
814 | } | ||
815 | else | ||
816 | { | ||
817 | return( QSize( 100, 100 ) ); // Should never happen though. | ||
818 | } | ||
819 | |||
820 | } | ||
821 | |||
822 | |||
823 | QSize OJanusWidget::sizeHint() const | ||
824 | { | ||
825 | return( minimumSizeHint() ); | ||
826 | } | ||
827 | |||
828 | |||
829 | void OJanusWidget::setTreeListAutoResize( bool state ) | ||
830 | { | ||
831 | if( mFace == TreeList ) | ||
832 | { | ||
833 | mTreeListResizeMode = state == false ? | ||
834 | QSplitter::KeepSize : QSplitter::Stretch; | ||
835 | QSplitter *splitter = (QSplitter*)(mTreeList->parentWidget()); | ||
836 | splitter->setResizeMode( mTreeList, mTreeListResizeMode ); | ||
837 | } | ||
838 | } | ||
839 | |||
840 | |||
841 | void OJanusWidget::setIconListAllVisible( bool state ) | ||
842 | { | ||
843 | if( mFace == IconList ) | ||
844 | { | ||
845 | mIconList->setShowAll( state ); | ||
846 | } | ||
847 | } | ||
848 | |||
849 | void OJanusWidget::setShowIconsInTreeList( bool state ) | ||
850 | { | ||
851 | mShowIconsInTreeList = state; | ||
852 | } | ||
853 | |||
854 | void OJanusWidget::setRootIsDecorated( bool state ) | ||
855 | { | ||
856 | if( mFace == TreeList ) { | ||
857 | mTreeList->setRootIsDecorated(state); | ||
858 | } | ||
859 | } | ||
860 | |||
861 | void OJanusWidget::unfoldTreeList( bool persist ) | ||
862 | { | ||
863 | if( mFace == TreeList ) | ||
864 | { | ||
865 | if( persist ) | ||
866 | connect( mTreeList, SIGNAL( collapsed( QListViewItem * ) ), this, SLOT( slotReopen( QListViewItem * ) ) ); | ||
867 | else | ||
868 | disconnect( mTreeList, SIGNAL( collapsed( QListViewItem * ) ), this, SLOT( slotReopen( QListViewItem * ) ) ); | ||
869 | |||
870 | for( QListViewItem * item = mTreeList->firstChild(); item; item = item->itemBelow() ) | ||
871 | item->setOpen( true ); | ||
872 | } | ||
873 | } | ||
874 | |||
875 | void OJanusWidget::showEvent( QShowEvent * ) | ||
876 | { | ||
877 | if( mFace == TreeList ) | ||
878 | { | ||
879 | QSplitter *splitter = (QSplitter*)(mTreeList->parentWidget()); | ||
880 | splitter->setResizeMode( mTreeList, mTreeListResizeMode ); | ||
881 | } | ||
882 | } | ||
883 | |||
884 | |||
885 | // | ||
886 | // 2000-13-02 Espen Sand | ||
887 | // It should be obvious that this eventfilter must only be | ||
888 | // be installed on the vertical scrollbar of the mIconList. | ||
889 | // | ||
890 | bool OJanusWidget::eventFilter( QObject *o, QEvent *e ) | ||
891 | { | ||
892 | if( e->type() == QEvent::Show ) | ||
893 | { | ||
894 | IconListItem *item = (IconListItem*)mIconList->item(0); | ||
895 | if( item != 0 ) | ||
896 | { | ||
897 | int lw = item->width( mIconList ); | ||
898 | int sw = mIconList->verticalScrollBar()->sizeHint().width(); | ||
899 | mIconList->setFixedWidth( lw+sw+mIconList->frameWidth()*2 ); | ||
900 | } | ||
901 | } | ||
902 | else if( e->type() == QEvent::Hide ) | ||
903 | { | ||
904 | IconListItem *item = (IconListItem*)mIconList->item(0); | ||
905 | if( item != 0 ) | ||
906 | { | ||
907 | int lw = item->width( mIconList ); | ||
908 | mIconList->setFixedWidth( lw+mIconList->frameWidth()*2 ); | ||
909 | } | ||
910 | } | ||
911 | return QWidget::eventFilter( o, e ); | ||
912 | } | ||
913 | |||
914 | |||
915 | |||
916 | // | ||
917 | // Code for the icon list box | ||
918 | // | ||
919 | |||
920 | |||
921 | OJanusWidget::IconListBox::IconListBox( QWidget *parent, const char *name, | ||
922 | WFlags f ) | ||
923 | :QListBox( parent, name, f ), mShowAll(false), mHeightValid(false), | ||
924 | mWidthValid(false) | ||
925 | { | ||
926 | } | ||
927 | |||
928 | |||
929 | void OJanusWidget::IconListBox::updateMinimumHeight() | ||
930 | { | ||
931 | if( mShowAll == true && mHeightValid == false ) | ||
932 | { | ||
933 | int h = frameWidth()*2; | ||
934 | for( QListBoxItem *i = item(0); i != 0; i = i->next() ) | ||
935 | { | ||
936 | h += i->height( this ); | ||
937 | } | ||
938 | setMinimumHeight( h ); | ||
939 | mHeightValid = true; | ||
940 | } | ||
941 | } | ||
942 | |||
943 | |||
944 | void OJanusWidget::IconListBox::updateWidth() | ||
945 | { | ||
946 | if( mWidthValid == false ) | ||
947 | { | ||
948 | int maxWidth = 10; | ||
949 | for( QListBoxItem *i = item(0); i != 0; i = i->next() ) | ||
950 | { | ||
951 | int w = ((IconListItem *)i)->width(this); | ||
952 | maxWidth = QMAX( w, maxWidth ); | ||
953 | } | ||
954 | |||
955 | for( QListBoxItem *i = item(0); i != 0; i = i->next() ) | ||
956 | { | ||
957 | ((IconListItem *)i)->expandMinimumWidth( maxWidth ); | ||
958 | } | ||
959 | |||
960 | if( verticalScrollBar()->isVisible() ) | ||
961 | { | ||
962 | maxWidth += verticalScrollBar()->sizeHint().width(); | ||
963 | } | ||
964 | |||
965 | setFixedWidth( maxWidth + frameWidth()*2 ); | ||
966 | mWidthValid = true; | ||
967 | } | ||
968 | } | ||
969 | |||
970 | |||
971 | void OJanusWidget::IconListBox::invalidateHeight() | ||
972 | { | ||
973 | mHeightValid = false; | ||
974 | } | ||
975 | |||
976 | |||
977 | void OJanusWidget::IconListBox::invalidateWidth() | ||
978 | { | ||
979 | mWidthValid = false; | ||
980 | } | ||
981 | |||
982 | |||
983 | void OJanusWidget::IconListBox::setShowAll( bool showAll ) | ||
984 | { | ||
985 | mShowAll = showAll; | ||
986 | mHeightValid = false; | ||
987 | } | ||
988 | |||
989 | |||
990 | |||
991 | OJanusWidget::IconListItem::IconListItem( QListBox *listbox, const QPixmap &pixmap, | ||
992 | const QString &text ) | ||
993 | : QListBoxItem( listbox ) | ||
994 | { | ||
995 | mPixmap = pixmap; | ||
996 | if( mPixmap.isNull() == true ) | ||
997 | { | ||
998 | mPixmap = defaultPixmap(); | ||
999 | } | ||
1000 | setText( text ); | ||
1001 | mMinimumWidth = 0; | ||
1002 | } | ||
1003 | |||
1004 | |||
1005 | int OJanusWidget::IconListItem::expandMinimumWidth( int width ) | ||
1006 | { | ||
1007 | mMinimumWidth = QMAX( mMinimumWidth, width ); | ||
1008 | return( mMinimumWidth ); | ||
1009 | } | ||
1010 | |||
1011 | |||
1012 | const QPixmap &OJanusWidget::IconListItem::defaultPixmap() | ||
1013 | { | ||
1014 | static QPixmap *pix=0; | ||
1015 | if( pix == 0 ) | ||
1016 | { | ||
1017 | pix = new QPixmap( 32, 32 ); | ||
1018 | QPainter p( pix ); | ||
1019 | p.eraseRect( 0, 0, pix->width(), pix->height() ); | ||
1020 | p.setPen( Qt::red ); | ||
1021 | p.drawRect ( 0, 0, pix->width(), pix->height() ); | ||
1022 | p.end(); | ||
1023 | |||
1024 | QBitmap mask( pix->width(), pix->height(), true ); | ||
1025 | mask.fill( Qt::black ); | ||
1026 | p.begin( &mask ); | ||
1027 | p.setPen( Qt::white ); | ||
1028 | p.drawRect ( 0, 0, pix->width(), pix->height() ); | ||
1029 | p.end(); | ||
1030 | |||
1031 | pix->setMask( mask ); | ||
1032 | } | ||
1033 | return( *pix ); | ||
1034 | } | ||
1035 | |||
1036 | |||
1037 | void OJanusWidget::IconListItem::paint( QPainter *painter ) | ||
1038 | { | ||
1039 | QFontMetrics fm = painter->fontMetrics(); | ||
1040 | //int wt = fm.boundingRect(text()).width(); | ||
1041 | int wp = mPixmap.width(); | ||
1042 | int ht = fm.lineSpacing(); | ||
1043 | int hp = mPixmap.height(); | ||
1044 | |||
1045 | painter->drawPixmap( (mMinimumWidth-wp)/2, 5, mPixmap ); | ||
1046 | if( text().isEmpty() == false ) | ||
1047 | { | ||
1048 | painter->drawText( 0, hp+7, mMinimumWidth, ht, Qt::AlignCenter, text() ); | ||
1049 | } | ||
1050 | } | ||
1051 | |||
1052 | int OJanusWidget::IconListItem::height( const QListBox *lb ) const | ||
1053 | { | ||
1054 | if( text().isEmpty() == true ) | ||
1055 | { | ||
1056 | return( mPixmap.height() ); | ||
1057 | } | ||
1058 | else | ||
1059 | { | ||
1060 | return( mPixmap.height() + lb->fontMetrics().lineSpacing()+10 ); | ||
1061 | } | ||
1062 | } | ||
1063 | |||
1064 | |||
1065 | int OJanusWidget::IconListItem::width( const QListBox *lb ) const | ||
1066 | { | ||
1067 | int wt = lb->fontMetrics().boundingRect(text()).width()+10; | ||
1068 | int wp = mPixmap.width() + 10; | ||
1069 | int w = QMAX( wt, wp ); | ||
1070 | return( QMAX( w, mMinimumWidth ) ); | ||
1071 | } | ||
1072 | |||
1073 | // Just remove the page from our stack of widgets. Do not modify the given widget in | ||
1074 | // any way. No memory leak occurs as parent is not changed. | ||
1075 | // Make this virtual in KDE 4.0. | ||
1076 | // Ravikiran Rajagopal <ravi@ee.eng.ohio-state.edu> | ||
1077 | void OJanusWidget::removePage( QWidget *page ) | ||
1078 | { | ||
1079 | if (!mPageList || !mPageList->containsRef(page)) | ||
1080 | return; | ||
1081 | |||
1082 | int index = mPageList->findRef( page ); | ||
1083 | if ( mTitleList ) | ||
1084 | mTitleList->remove(mTitleList->at(index)); | ||
1085 | |||
1086 | mPageList->removeRef(page); | ||
1087 | |||
1088 | if ( mFace == TreeList ) | ||
1089 | { | ||
1090 | QMap<QListViewItem*, QWidget *>::Iterator i; | ||
1091 | for( i = mTreeListToPageStack.begin(); i != mTreeListToPageStack.end(); ++i ) | ||
1092 | if (i.data()==page) | ||
1093 | { | ||
1094 | delete i.key(); | ||
1095 | mPageStack->removeWidget(page); | ||
1096 | mTreeListToPageStack.remove(i); | ||
1097 | break; | ||
1098 | } | ||
1099 | } | ||
1100 | else if ( mFace == IconList ) | ||
1101 | { | ||
1102 | QMap<QListBoxItem*, QWidget *>::Iterator i; | ||
1103 | for( i = mIconListToPageStack.begin(); i != mIconListToPageStack.end(); ++i ) | ||
1104 | if (i.data()==page) | ||
1105 | { | ||
1106 | delete i.key(); | ||
1107 | mPageStack->removeWidget(page); | ||
1108 | mIconListToPageStack.remove(i); | ||
1109 | break; | ||
1110 | } | ||
1111 | } | ||
1112 | else // Tabbed | ||
1113 | { | ||
1114 | mTabControl->removePage(page); | ||
1115 | } | ||
1116 | } | ||
diff --git a/libopie2/qt3/opieui/ojanuswidget.h b/libopie2/qt3/opieui/ojanuswidget.h new file mode 100644 index 0000000..b601b8c --- a/dev/null +++ b/libopie2/qt3/opieui/ojanuswidget.h | |||
@@ -0,0 +1,551 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | |||
4 | Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> | ||
5 | Copyright (C) 1999-2000 Espen Sand (espen@kde.org) | ||
6 | =. | ||
7 | .=l. | ||
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 | #ifndef OJANUSWIDGET_H | ||
34 | #define OJANUSWIDGET_H | ||
35 | |||
36 | #include <qptrlist.h> | ||
37 | #include <qpixmap.h> | ||
38 | #include <qlistbox.h> | ||
39 | #include <qmap.h> | ||
40 | #include <qsplitter.h> | ||
41 | #include <qstringlist.h> | ||
42 | |||
43 | class QGrid; | ||
44 | class QHBox; | ||
45 | class QLabel; | ||
46 | class QTabWidget; | ||
47 | class QVBox; | ||
48 | class QWidgetStack; | ||
49 | class OSeparator; | ||
50 | class QListView; | ||
51 | class QListViewItem; | ||
52 | |||
53 | /** | ||
54 | * Provides a number of ready to use layouts (faces). It is used | ||
55 | * as an internal widget in @ref KDialogBase, but can also used as a | ||
56 | * widget of its own. | ||
57 | * | ||
58 | * It provides TreeList, IconList, Tabbed, Plain and Swallow layouts. | ||
59 | * | ||
60 | * The TreeList face provides a list in the left area and pages in the | ||
61 | * right. The area are separated by a movable splitter. The style is somewhat | ||
62 | * similar to the layout in the Control Center. A page is raised by | ||
63 | * selecting the corresponding tree list item. | ||
64 | * | ||
65 | * The IconList face provides an icon list in the left area and pages in the | ||
66 | * right. For each entry the Icon is on top with the text below. The style | ||
67 | * is somewhat similar to the layout of the Eudora configuation dialog box. | ||
68 | * A page is raised by selecting the corresponding icon list item. The | ||
69 | * preferred icon size is 32x32 pixels. | ||
70 | * | ||
71 | * The Tabbed face is a common tabbed widget. The procedure for creating a | ||
72 | * page is similar for creating a TreeList. This has the advantage that if | ||
73 | * your widget contain too many pages it is trivial to convert it into a | ||
74 | * TreeList. Just change the face in the KJanusWidget constructor to | ||
75 | * KJanusWidget::TreeList and you have a tree list layout instead. | ||
76 | * | ||
77 | * The Plain face provides an empty widget (QFrame) where you can place your | ||
78 | * widgets. The KJanusWidget makes no assumptions regarding the contents so | ||
79 | * you are free to add whatever you want. | ||
80 | * | ||
81 | * The Swallow face is provided in order to simplify the usage of existing | ||
82 | * widgets and to allow changing the visible widget. You specify the widget | ||
83 | * to be displayed by @ref #setSwallowedWidget(). Your widget will be | ||
84 | * reparented inside the widget. You can specify a Null (0) widget. A empty | ||
85 | * space is then displayed. | ||
86 | * | ||
87 | * For all modes it is important that you specify the @ref QWidget::minimumSize() | ||
88 | * on the page, plain widget or the swallowed widget. If you use a QLayout | ||
89 | * on the page, plain widget or the swallowed widget this will be taken care | ||
90 | * of automatically. The size is used when the KJanusWidget determines its | ||
91 | * own minimum size. You get the minimum size by using the | ||
92 | * @ref #minimumSizeHint() or @ref #sizeHint() methods. | ||
93 | * | ||
94 | * Pages that have been added in TreeList, IconList or Tabbed mode can be | ||
95 | * removed by simply deleting the page. | ||
96 | * | ||
97 | * @short Easy to use widget with many layouts | ||
98 | * @author Espen Sand (espen@kde.org) | ||
99 | */ | ||
100 | class OJanusWidget : public QWidget | ||
101 | { | ||
102 | Q_OBJECT | ||
103 | |||
104 | private: | ||
105 | |||
106 | class IconListBox : public QListBox | ||
107 | { | ||
108 | public: | ||
109 | IconListBox( QWidget *parent=0, const char *name=0, WFlags f=0 ); | ||
110 | void updateMinimumHeight(); | ||
111 | void updateWidth(); | ||
112 | void invalidateHeight(); | ||
113 | void invalidateWidth(); | ||
114 | void setShowAll( bool showAll ); | ||
115 | |||
116 | private: | ||
117 | bool mShowAll; | ||
118 | bool mHeightValid; | ||
119 | bool mWidthValid; | ||
120 | }; | ||
121 | |||
122 | public: | ||
123 | |||
124 | enum Face | ||
125 | { | ||
126 | TreeList = 0, | ||
127 | Tabbed, | ||
128 | Plain, | ||
129 | Swallow, | ||
130 | IconList | ||
131 | }; | ||
132 | |||
133 | public: | ||
134 | |||
135 | /** | ||
136 | * Constructor where you specify the face. | ||
137 | * | ||
138 | * @param parent Parent of the widget. | ||
139 | * @param name Widget name. | ||
140 | * @param int face The kind of dialog, Use TreeList, Tabbed, Plain or | ||
141 | * Swallow. | ||
142 | */ | ||
143 | OJanusWidget( QWidget *parent=0, const char *name=0, int face=Plain ); | ||
144 | |||
145 | /** | ||
146 | * Destructor. | ||
147 | */ | ||
148 | ~OJanusWidget(); | ||
149 | |||
150 | /** | ||
151 | * Raises the page which was added by @ref addPage(). | ||
152 | * | ||
153 | * @param index The index of the page you want to raise. | ||
154 | */ | ||
155 | virtual bool showPage( int index ); | ||
156 | |||
157 | /** | ||
158 | * Returns the index of the page that are currently displayed. | ||
159 | * | ||
160 | * @return The index or -1 if the face is not Tabbed, TreeList or | ||
161 | * IconList. | ||
162 | */ | ||
163 | virtual int activePageIndex() const; | ||
164 | |||
165 | /** | ||
166 | * Use this to verify | ||
167 | * that no memory allocation failed. | ||
168 | * | ||
169 | * @return true if the widget was properly created. | ||
170 | */ | ||
171 | virtual bool isValid() const; | ||
172 | |||
173 | /** | ||
174 | * Returns the face type. | ||
175 | * | ||
176 | * @return The face type. | ||
177 | */ | ||
178 | virtual int face() const; | ||
179 | |||
180 | /** | ||
181 | * Returns the minimum size that must be made available for the widget | ||
182 | * so that UIs can be displayed properly | ||
183 | * | ||
184 | * @return The minimum size. | ||
185 | */ | ||
186 | virtual QSize minimumSizeHint() const; | ||
187 | |||
188 | /** | ||
189 | * Returns the recommended size for the widget in order to be displayed | ||
190 | * properly. | ||
191 | * | ||
192 | * @return The recommended size. | ||
193 | */ | ||
194 | virtual QSize sizeHint() const; | ||
195 | |||
196 | /** | ||
197 | * Returns the empty widget that is available in Plain mode. | ||
198 | * | ||
199 | * @return The widget or 0 if the face in not Plain. | ||
200 | */ | ||
201 | virtual QFrame *plainPage(); | ||
202 | |||
203 | /** | ||
204 | * Add a new page when the class is used in TreeList, IconList or Tabbed | ||
205 | * mode. The returned widget is empty and you must add your widgets | ||
206 | * as children to this widget. In most cases you must create a layout | ||
207 | * manager and associate it with this widget as well. | ||
208 | * | ||
209 | * Deleting the returned frame will cause the listitem or tab to be | ||
210 | * removed (you can re-add a page with the same name later. | ||
211 | * | ||
212 | * @param item String used in the list or Tab item. | ||
213 | * @param header A longer string used in TreeList and IconList mode to | ||
214 | * describe the contents of a page. If empty, the item string | ||
215 | * will be used instead. | ||
216 | * @param pixmap Used in IconList mode or in TreeList mode. You should | ||
217 | * prefer a pixmap with size 32x32 pixels. | ||
218 | * | ||
219 | * @return The empty page or 0 if the face is not TreeList, IconList or | ||
220 | * Tabbed. | ||
221 | */ | ||
222 | virtual QFrame *addPage(const QString &item,const QString &header=QString::null, | ||
223 | const QPixmap &pixmap=QPixmap() ); | ||
224 | |||
225 | /** | ||
226 | * This is like addPage just above, with the difference that the first | ||
227 | * element is a list of strings. These strings are used to form a path | ||
228 | * of folders down to the given page. The initial elements are names | ||
229 | * for the folders, while the last element is the name of the page. | ||
230 | * Note: This does yet only work for the TreeList face. Later this may | ||
231 | * be added for the IconList face too. In other faces than the | ||
232 | * TreeList, all the strings except the last one is ignored. | ||
233 | * Deleting the returned frame will cause the listitem or tab to be | ||
234 | * removed (you can re-add a page with the same name later. | ||
235 | * | ||
236 | * Deleting the returned frame will cause the listitem or tab to be | ||
237 | * removed (you can re-add a page with the same name later. | ||
238 | **/ | ||
239 | virtual QFrame *addPage(const QStringList &items, const QString &header=QString::null, | ||
240 | const QPixmap &pixmap=QPixmap() ); | ||
241 | |||
242 | /** | ||
243 | * Add a new page when the class is used in TreeList, IconList or Tabbed | ||
244 | * mode. The returned widget is empty and you must add your widgets | ||
245 | * as children to this widget. The returned widget is a @ref QVBox | ||
246 | * so it contains a QVBoxLayout layout that lines up the child widgets | ||
247 | * are vertically. | ||
248 | * | ||
249 | * Deleting the returned frame will cause the listitem or tab to be | ||
250 | * removed (you can re-add a page with the same name later. | ||
251 | * | ||
252 | * @param item String used in the list or Tab item. | ||
253 | * @param header A longer string used in TreeList and IconList mode to | ||
254 | * describe the contents of a page. If empty, the item string | ||
255 | * will be used instead. | ||
256 | * @param pixmap Used in IconList mode or in TreeList mode. You should | ||
257 | * prefer a pixmap with size 32x32 pixels. | ||
258 | * | ||
259 | * @return The empty page or 0 if the face is not TreeList, IconList or | ||
260 | * Tabbed. */ | ||
261 | virtual QVBox *addVBoxPage( const QString &item, | ||
262 | const QString &header=QString::null, | ||
263 | const QPixmap &pixmap=QPixmap() ); | ||
264 | |||
265 | /** | ||
266 | * This is like addVBoxPage just above, with the difference that the first | ||
267 | * element is a list of strings. These strings are used to form a path | ||
268 | * of folders down to the given page. The initial elements are names | ||
269 | * for the folders, while the last element is the name of the page. | ||
270 | * Note: This does yet only work for the TreeList face. Later this may | ||
271 | * be added for the IconList face too. In other faces than the | ||
272 | * TreeList, all the strings except the last one is ignored. | ||
273 | * | ||
274 | * Deleting the returned frame will cause the listitem or tab to be | ||
275 | * removed (you can re-add a page with the same name later. | ||
276 | **/ | ||
277 | virtual QVBox *addVBoxPage( const QStringList &items, | ||
278 | const QString &header=QString::null, | ||
279 | const QPixmap &pixmap=QPixmap() ); | ||
280 | |||
281 | /** | ||
282 | * Add a new page when the class is used in TreeList, IconList or Tabbed | ||
283 | * mode. The returned widget is empty and you must add your widgets | ||
284 | * as children to this widget. The returned widget is a @ref QHBox | ||
285 | * so it contains a QHBoxLayout layout that lines up the child widgets | ||
286 | * are horizontally. | ||
287 | * | ||
288 | * Deleting the returned frame will cause the listitem or tab to be | ||
289 | * removed (you can re-add a page with the same name later. | ||
290 | * | ||
291 | * @param item String used in the list or Tab item. | ||
292 | * @param header A longer string used in TreeList and IconList mode to | ||
293 | * describe the contents of a page. If empty, the item string | ||
294 | * will be used instead. | ||
295 | * @param pixmap Used in IconList mode or in TreeList mode. You should | ||
296 | * prefer a pixmap with size 32x32 pixels. | ||
297 | * | ||
298 | * @return The empty page or 0 if the face is not TreeList, IconList or | ||
299 | * Tabbed. | ||
300 | */ | ||
301 | virtual QHBox *addHBoxPage( const QString &itemName, | ||
302 | const QString &header=QString::null, | ||
303 | const QPixmap &pixmap=QPixmap() ); | ||
304 | |||
305 | /** | ||
306 | * This is like addHBoxPage just above, with the difference that the first | ||
307 | * element is a list of strings. These strings are used to form a path | ||
308 | * of folders down to the given page. The initial elements are names | ||
309 | * for the folders, while the last element is the name of the page. | ||
310 | * Note: This does yet only work for the TreeList face. Later this may | ||
311 | * be added for the IconList face too. In other faces than the | ||
312 | * TreeList, all the strings except the last one is ignored. | ||
313 | * | ||
314 | * Deleting the returned frame will cause the listitem or tab to be | ||
315 | * removed (you can re-add a page with the same name later. | ||
316 | **/ | ||
317 | virtual QHBox *addHBoxPage( const QStringList &items, | ||
318 | const QString &header=QString::null, | ||
319 | const QPixmap &pixmap=QPixmap() ); | ||
320 | |||
321 | /** | ||
322 | * Add a new page when the class is used in either TreeList or Tabbed | ||
323 | * mode. The returned widget is empty and you must add your widgets | ||
324 | * as children to this widget. The returned widget is a @ref QGrid | ||
325 | * so it contains a QGridLayout layout that places up the child widgets | ||
326 | * in a grid. | ||
327 | * | ||
328 | * Deleting the returned frame will cause the listitem or tab to be | ||
329 | * removed (you can re-add a page with the same name later. | ||
330 | * | ||
331 | * @param n Specifies the number of columns if 'dir' is QGrid::Horizontal | ||
332 | * or the number of rows if 'dir' is QGrid::Vertical. | ||
333 | * @param dir Can be QGrid::Horizontal or QGrid::Vertical. | ||
334 | * @param item String used in the list or Tab item. | ||
335 | * @param header A longer string used in TreeList and IconList mode to | ||
336 | * describe the contents of a page. If empty, the item string | ||
337 | * will be used instead. | ||
338 | * @param pixmap Used in IconList mode or in TreeList mode. You should | ||
339 | * prefer a pixmap with size 32x32 pixels. | ||
340 | * | ||
341 | * @return The empty page or 0 if the face is not TreeList, IconList or | ||
342 | * Tabbed. | ||
343 | */ | ||
344 | virtual QGrid *addGridPage( int n, Orientation dir, | ||
345 | const QString &itemName, | ||
346 | const QString &header=QString::null, | ||
347 | const QPixmap &pixmap=QPixmap() ); | ||
348 | |||
349 | /** | ||
350 | * This is like addGridPage just above, with the difference that the first | ||
351 | * element is a list of strings. These strings are used to form a path | ||
352 | * of folders down to the given page. The initial elements are names | ||
353 | * for the folders, while the last element is the name of the page. | ||
354 | * Note: This does yet only work for the TreeList face. Later this may | ||
355 | * be added for the IconList face too. In other faces than the | ||
356 | * TreeList, all the strings except the last one is ignored. | ||
357 | * | ||
358 | * Deleting the returned frame will cause the listitem or tab to be | ||
359 | * removed (you can re-add a page with the same name later. | ||
360 | **/ | ||
361 | virtual QGrid *addGridPage( int n, Orientation dir, | ||
362 | const QStringList &items, | ||
363 | const QString &header=QString::null, | ||
364 | const QPixmap &pixmap=QPixmap() ); | ||
365 | |||
366 | /** | ||
367 | * @short Removes a page created with @ref addPage, @ref addVBoxPage, | ||
368 | * @ref addHBoxPage or @ref addGridPage. If the page has already | ||
369 | * been deleted or has already been removed, nothing happens. The widget | ||
370 | * itself is not deleted. | ||
371 | * | ||
372 | * @param page The widget returned by @ref addPage , @ref addVBoxPage , | ||
373 | * @ref addHBoxPage or @ref addGridPage . | ||
374 | */ | ||
375 | void removePage( QWidget *page ); | ||
376 | |||
377 | |||
378 | /** | ||
379 | * Returns the index of a page created with @ref addPage , | ||
380 | * @ref addVBoxPage , @ref addHBoxPage or @ref addGridPage . | ||
381 | * You can can compare this index with the value returned from | ||
382 | * @ref activePageIndex if you need to do some page specific actions | ||
383 | * in your code. | ||
384 | * | ||
385 | * The returned index will never change so you can safely use this | ||
386 | * function once and save the value. | ||
387 | * | ||
388 | * @param widget The widget returned by @ref addPage , @ref addVBoxPage , | ||
389 | * @ref addHBoxPage or @ref addGridPage . | ||
390 | * | ||
391 | * @return The index or -1 if the face is not Tabbed, TreeList or | ||
392 | * IconList | ||
393 | */ | ||
394 | virtual int pageIndex( QWidget *widget ) const; | ||
395 | |||
396 | /** | ||
397 | * Defines the widget to be swallowed. | ||
398 | * | ||
399 | * This method can be used several | ||
400 | * times. Only the latest defined widget will be shown. | ||
401 | * | ||
402 | * @param widget The widget to be swallowed. If 0, then an empty rectangle | ||
403 | * is displayed. | ||
404 | */ | ||
405 | virtual bool setSwallowedWidget( QWidget *widget ); | ||
406 | |||
407 | /** | ||
408 | * This function has only effect in TreeList mode. | ||
409 | * | ||
410 | * Defines how the tree list is resized when the widget is resized | ||
411 | * horizontally. By default the tree list keeps its width when the | ||
412 | * widget becomes wider. | ||
413 | * | ||
414 | * @param state The resize mode. If false (default) the TreeList keeps | ||
415 | * its current width when the widget becomes wider. | ||
416 | */ | ||
417 | virtual void setTreeListAutoResize( bool state ); | ||
418 | |||
419 | /** | ||
420 | * This function has only effect in TreeList mode. | ||
421 | * | ||
422 | * This tells the widgets whether the icons given in the @ref addPage, | ||
423 | * @ref addVBoxPage, @ref addHBoxPage, or @ref addGridPage methods should | ||
424 | * be shown in the TreeList. | ||
425 | * | ||
426 | * Note: This method must be called before calling any of the methods | ||
427 | * which add icons to the page. | ||
428 | * | ||
429 | * @param state If true the icons are shown. | ||
430 | **/ | ||
431 | virtual void setShowIconsInTreeList(bool state); | ||
432 | |||
433 | /** | ||
434 | * This function has only effect in TreeList mode. | ||
435 | * | ||
436 | * This tells the widgets whether the root should be decorated. | ||
437 | * For details see @ref QListView::setRootIsDecorated | ||
438 | * | ||
439 | * @param state Root will be decorated if true. | ||
440 | **/ | ||
441 | virtual void setRootIsDecorated( bool state ); | ||
442 | |||
443 | /** | ||
444 | * This function has only effect in TreeList mode. | ||
445 | * | ||
446 | * This tells the TreeList to unfold the whole tree so that all entries | ||
447 | * are visible. | ||
448 | * | ||
449 | * If the list is empty when you call this method newly created entries | ||
450 | * will not automatically be opened. If the @p persist flag is set opened | ||
451 | * entries cannot be closed again, though. | ||
452 | * | ||
453 | * @param persist If true the tree always stays unfolded. | ||
454 | * @since 3.2 | ||
455 | */ | ||
456 | /*virtual*/ void unfoldTreeList( bool persist = false ); //### KDE4 BIC add virtual | ||
457 | |||
458 | /** | ||
459 | * This function has only effect in IconList mode. | ||
460 | * | ||
461 | * Defines how the icon list widget is displayed. By default it is | ||
462 | * the widgets in the pages that decide the minimum height | ||
463 | * of the toplevel widget. A vertical scrollbar can be used in | ||
464 | * the icon list area. | ||
465 | * | ||
466 | * @param state The visibility mode. If true, the minimum height is | ||
467 | * adjusted so that every icon in the list is visible at the | ||
468 | * same time. The vertical scrollbar will never be visible. | ||
469 | */ | ||
470 | virtual void setIconListAllVisible( bool state ); | ||
471 | |||
472 | /** | ||
473 | * Sets the icon used in TreeList Mode for the given path. | ||
474 | * @param path The path for which this icon should be shown. | ||
475 | * @param pixmap The icon used. | ||
476 | **/ | ||
477 | virtual void setFolderIcon(const QStringList &path, const QPixmap &pixmap); | ||
478 | |||
479 | signals: | ||
480 | void aboutToShowPage(QWidget *page); | ||
481 | |||
482 | public slots: | ||
483 | /** | ||
484 | * Give the keyboard input focus to the widget. | ||
485 | */ | ||
486 | virtual void setFocus(); | ||
487 | |||
488 | protected: | ||
489 | /** | ||
490 | * Reimplemented to handle the splitter width when the the face | ||
491 | * is TreeList | ||
492 | */ | ||
493 | virtual void showEvent( QShowEvent * ); | ||
494 | |||
495 | /** | ||
496 | * This function is used internally when in IconList mode. If you | ||
497 | * reimplement this class a make your own event filter, make sure to | ||
498 | * call this function from your filter. | ||
499 | * | ||
500 | * @param o Object that has received an event. | ||
501 | * @param e The event. | ||
502 | */ | ||
503 | virtual bool eventFilter( QObject *o, QEvent *e ); | ||
504 | |||
505 | private slots: | ||
506 | bool slotShowPage(); | ||
507 | void slotFontChanged(); | ||
508 | void slotItemClicked(QListViewItem *it); | ||
509 | void pageGone(QObject *obj); // signal from the added page's "destroyed" signal | ||
510 | void slotReopen(QListViewItem *item); | ||
511 | |||
512 | protected: | ||
513 | bool showPage( QWidget *w ); | ||
514 | void addPageWidget( QFrame *page, const QStringList &items, | ||
515 | const QString &header, const QPixmap &pixmap ); | ||
516 | void InsertTreeListItem(const QStringList &items, const QPixmap &pixmap, QFrame *page); | ||
517 | QWidget *FindParent(); | ||
518 | |||
519 | private: | ||
520 | bool mValid; | ||
521 | |||
522 | QPtrList<QWidget> *mPageList; | ||
523 | QStringList *mTitleList; | ||
524 | |||
525 | int mFace; | ||
526 | QListView *mTreeList; | ||
527 | IconListBox *mIconList; | ||
528 | QWidgetStack *mPageStack; | ||
529 | QLabel *mTitleLabel; | ||
530 | QTabWidget *mTabControl; | ||
531 | QFrame *mPlainPage; | ||
532 | QWidget *mSwallowPage; | ||
533 | QWidget *mActivePageWidget; | ||
534 | OSeparator *mTitleSep; | ||
535 | QSplitter::ResizeMode mTreeListResizeMode; | ||
536 | bool mShowIconsInTreeList; | ||
537 | QMap<QListViewItem *, QWidget *> mTreeListToPageStack; | ||
538 | QMap<QListBoxItem *, QWidget *> mIconListToPageStack; | ||
539 | QMap<QString, QPixmap> mFolderIconMap; | ||
540 | QMap<QString, QStringList> mChildrenNames; | ||
541 | QMap<QString, QWidget *> mChildPages; | ||
542 | |||
543 | public: | ||
544 | class IconListItem; | ||
545 | |||
546 | private: | ||
547 | class OJanusWidgetPrivate; | ||
548 | OJanusWidgetPrivate *d; | ||
549 | }; | ||
550 | |||
551 | #endif | ||
diff --git a/libopie2/qt3/opieui/olineedit.cpp b/libopie2/qt3/opieui/olineedit.cpp new file mode 100644 index 0000000..9cb0cff --- a/dev/null +++ b/libopie2/qt3/opieui/olineedit.cpp | |||
@@ -0,0 +1,729 @@ | |||
1 | /* | ||
2 | This file Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> | ||
3 | is part of the Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@kde.org>, Dawit Alemayehu <adawit@kde.org> | ||
4 | Opie Project Copyright (C) 1999 Preston Brown <pbrown@kde.org>, Patrick Ward <PAT_WARD@HP-USA-om5.om.hp.com> | ||
5 | Copyright (C) 1997 Sven Radej (sven.radej@iname.com) | ||
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 | /* QT */ | ||
34 | |||
35 | #include <qapplication.h> | ||
36 | #include <qclipboard.h> | ||
37 | #include <qtimer.h> | ||
38 | #include <qpopupmenu.h> | ||
39 | |||
40 | /* OPIE */ | ||
41 | |||
42 | #include <opie2/ocompletionbox.h> | ||
43 | #include <opie2/olineedit.h> | ||
44 | #include <opie2/oglobalsettings.h> | ||
45 | |||
46 | typedef QString KURL; //FIXME: Revise for Opie | ||
47 | |||
48 | /*====================================================================================== | ||
49 | * OLineEditPrivate | ||
50 | *======================================================================================*/ | ||
51 | |||
52 | class OLineEdit::OLineEditPrivate | ||
53 | { | ||
54 | public: | ||
55 | OLineEditPrivate() | ||
56 | { | ||
57 | grabReturnKeyEvents = false; | ||
58 | handleURLDrops = true; | ||
59 | completionBox = 0L; | ||
60 | } | ||
61 | ~OLineEditPrivate() | ||
62 | { | ||
63 | delete completionBox; | ||
64 | } | ||
65 | |||
66 | bool grabReturnKeyEvents; | ||
67 | bool handleURLDrops; | ||
68 | OCompletionBox *completionBox; | ||
69 | }; | ||
70 | |||
71 | |||
72 | /*====================================================================================== | ||
73 | * OLineEdit | ||
74 | *======================================================================================*/ | ||
75 | |||
76 | OLineEdit::OLineEdit( const QString &string, QWidget *parent, const char *name ) | ||
77 | : QLineEdit( string, parent, name ) | ||
78 | { | ||
79 | init(); | ||
80 | } | ||
81 | |||
82 | OLineEdit::OLineEdit( QWidget *parent, const char *name ) | ||
83 | : QLineEdit( parent, name ) | ||
84 | { | ||
85 | init(); | ||
86 | } | ||
87 | |||
88 | OLineEdit::~OLineEdit () | ||
89 | { | ||
90 | delete d; | ||
91 | } | ||
92 | |||
93 | void OLineEdit::init() | ||
94 | { | ||
95 | d = new OLineEditPrivate; | ||
96 | possibleTripleClick = false; | ||
97 | // Enable the context menu by default. | ||
98 | setContextMenuEnabled( true ); | ||
99 | //OCursor::setAutoHideCursor( this, true, true ); | ||
100 | installEventFilter( this ); | ||
101 | } | ||
102 | |||
103 | void OLineEdit::setCompletionMode( OGlobalSettings::Completion mode ) | ||
104 | { | ||
105 | OGlobalSettings::Completion oldMode = completionMode(); | ||
106 | if ( oldMode != mode && oldMode == OGlobalSettings::CompletionPopup && | ||
107 | d->completionBox && d->completionBox->isVisible() ) | ||
108 | d->completionBox->hide(); | ||
109 | |||
110 | // If the widgets echo mode is not Normal, no completion | ||
111 | // feature will be enabled even if one is requested. | ||
112 | if ( echoMode() != QLineEdit::Normal ) | ||
113 | mode = OGlobalSettings::CompletionNone; // Override the request. | ||
114 | |||
115 | OCompletionBase::setCompletionMode( mode ); | ||
116 | } | ||
117 | |||
118 | void OLineEdit::setCompletedText( const QString& t, bool marked ) | ||
119 | { | ||
120 | QString txt = text(); | ||
121 | if ( t != txt ) | ||
122 | { | ||
123 | int curpos = marked ? txt.length() : t.length(); | ||
124 | validateAndSet( t, curpos, curpos, t.length() ); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | void OLineEdit::setCompletedText( const QString& text ) | ||
129 | { | ||
130 | OGlobalSettings::Completion mode = completionMode(); | ||
131 | bool marked = ( mode == OGlobalSettings::CompletionAuto || | ||
132 | mode == OGlobalSettings::CompletionMan || | ||
133 | mode == OGlobalSettings::CompletionPopup ); | ||
134 | setCompletedText( text, marked ); | ||
135 | } | ||
136 | |||
137 | void OLineEdit::rotateText( OCompletionBase::KeyBindingType type ) | ||
138 | { | ||
139 | OCompletion* comp = compObj(); | ||
140 | if ( comp && | ||
141 | (type == OCompletionBase::PrevCompletionMatch || | ||
142 | type == OCompletionBase::NextCompletionMatch ) ) | ||
143 | { | ||
144 | QString input = (type == OCompletionBase::PrevCompletionMatch) ? comp->previousMatch() : comp->nextMatch(); | ||
145 | // Skip rotation if previous/next match is null or the same text | ||
146 | if ( input.isNull() || input == displayText() ) | ||
147 | return; | ||
148 | #if QT_VERSION > 290 | ||
149 | setCompletedText( input, hasSelectedText() ); | ||
150 | #else | ||
151 | setCompletedText( input, hasMarkedText() ); | ||
152 | #endif | ||
153 | } | ||
154 | } | ||
155 | |||
156 | void OLineEdit::makeCompletion( const QString& text ) | ||
157 | { | ||
158 | OCompletion *comp = compObj(); | ||
159 | if ( !comp ) | ||
160 | return; // No completion object... | ||
161 | |||
162 | QString match = comp->makeCompletion( text ); | ||
163 | OGlobalSettings::Completion mode = completionMode(); | ||
164 | if ( mode == OGlobalSettings::CompletionPopup ) | ||
165 | { | ||
166 | if ( match.isNull() ) | ||
167 | { | ||
168 | if ( d->completionBox ) { | ||
169 | d->completionBox->hide(); | ||
170 | d->completionBox->clear(); | ||
171 | } | ||
172 | } | ||
173 | else | ||
174 | setCompletedItems( comp->allMatches() ); | ||
175 | } | ||
176 | else | ||
177 | { | ||
178 | // all other completion modes | ||
179 | // If no match or the same match, simply return without completing. | ||
180 | if ( match.isNull() || match == text ) | ||
181 | return; | ||
182 | |||
183 | setCompletedText( match ); | ||
184 | } | ||
185 | } | ||
186 | |||
187 | void OLineEdit::setReadOnly(bool readOnly) | ||
188 | { | ||
189 | QPalette p = palette(); | ||
190 | if (readOnly) | ||
191 | { | ||
192 | QColor color = p.color(QPalette::Disabled, QColorGroup::Background); | ||
193 | p.setColor(QColorGroup::Base, color); | ||
194 | p.setColor(QColorGroup::Background, color); | ||
195 | } | ||
196 | else | ||
197 | { | ||
198 | QColor color = p.color(QPalette::Normal, QColorGroup::Base); | ||
199 | p.setColor(QColorGroup::Base, color); | ||
200 | p.setColor(QColorGroup::Background, color); | ||
201 | } | ||
202 | setPalette(p); | ||
203 | |||
204 | QLineEdit::setReadOnly (readOnly); | ||
205 | } | ||
206 | |||
207 | void OLineEdit::keyPressEvent( QKeyEvent *e ) | ||
208 | { | ||
209 | qDebug( "OLineEdit::keyPressEvent()" ); | ||
210 | |||
211 | /* | ||
212 | |||
213 | KKey key( e ); | ||
214 | |||
215 | if ( KStdAccel::copy().contains( key ) ) { | ||
216 | copy(); | ||
217 | return; | ||
218 | } | ||
219 | else if ( KStdAccel::paste().contains( key ) ) { | ||
220 | paste(); | ||
221 | return; | ||
222 | } | ||
223 | else if ( KStdAccel::cut().contains( key ) ) { | ||
224 | cut(); | ||
225 | return; | ||
226 | } | ||
227 | else if ( KStdAccel::undo().contains( key ) ) { | ||
228 | undo(); | ||
229 | return; | ||
230 | } | ||
231 | else if ( KStdAccel::redo().contains( key ) ) { | ||
232 | redo(); | ||
233 | return; | ||
234 | } | ||
235 | else if ( KStdAccel::deleteWordBack().contains( key ) ) | ||
236 | { | ||
237 | cursorWordBackward(TRUE); | ||
238 | if ( hasSelectedText() ) | ||
239 | del(); | ||
240 | |||
241 | e->accept(); | ||
242 | return; | ||
243 | } | ||
244 | else if ( KStdAccel::deleteWordForward().contains( key ) ) | ||
245 | { | ||
246 | // Workaround for QT bug where | ||
247 | cursorWordForward(TRUE); | ||
248 | if ( hasSelectedText() ) | ||
249 | del(); | ||
250 | |||
251 | e->accept(); | ||
252 | return; | ||
253 | } | ||
254 | */ | ||
255 | |||
256 | // Filter key-events if EchoMode is normal & | ||
257 | // completion mode is not set to CompletionNone | ||
258 | if ( echoMode() == QLineEdit::Normal && | ||
259 | completionMode() != OGlobalSettings::CompletionNone ) | ||
260 | { | ||
261 | KeyBindingMap keys = getKeyBindings(); | ||
262 | OGlobalSettings::Completion mode = completionMode(); | ||
263 | bool noModifier = (e->state() == NoButton || e->state()== ShiftButton); | ||
264 | |||
265 | if ( (mode == OGlobalSettings::CompletionAuto || | ||
266 | mode == OGlobalSettings::CompletionMan) && noModifier ) | ||
267 | { | ||
268 | QString keycode = e->text(); | ||
269 | if ( !keycode.isNull() && keycode.unicode()->isPrint() ) | ||
270 | { | ||
271 | QLineEdit::keyPressEvent ( e ); | ||
272 | QString txt = text(); | ||
273 | int len = txt.length(); | ||
274 | #if QT_VERSION > 290 | ||
275 | if ( !hasSelectedText() && len && cursorPosition() == len ) | ||
276 | #else | ||
277 | if ( !hasMarkedText() && len && cursorPosition() == len ) | ||
278 | #endif | ||
279 | { | ||
280 | if ( emitSignals() ) | ||
281 | emit completion( txt ); | ||
282 | if ( handleSignals() ) | ||
283 | makeCompletion( txt ); | ||
284 | e->accept(); | ||
285 | } | ||
286 | return; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | else if ( mode == OGlobalSettings::CompletionPopup && noModifier ) | ||
291 | { | ||
292 | qDebug( "OLineEdit::keyPressEvent() - global settings = CompletionPopup & noModifier" ); | ||
293 | |||
294 | QString old_txt = text(); | ||
295 | QLineEdit::keyPressEvent ( e ); | ||
296 | QString txt = text(); | ||
297 | int len = txt.length(); | ||
298 | QString keycode = e->text(); | ||
299 | |||
300 | |||
301 | if ( txt != old_txt && len && cursorPosition() == len && | ||
302 | ( (!keycode.isNull() && keycode.unicode()->isPrint()) || | ||
303 | e->key() == Key_Backspace ) ) | ||
304 | { | ||
305 | if ( emitSignals() ) | ||
306 | emit completion( txt ); // emit when requested... | ||
307 | if ( handleSignals() ) | ||
308 | makeCompletion( txt ); // handle when requested... | ||
309 | e->accept(); | ||
310 | } | ||
311 | else if (!len && d->completionBox && d->completionBox->isVisible()) | ||
312 | d->completionBox->hide(); | ||
313 | |||
314 | return; | ||
315 | } | ||
316 | |||
317 | /*else if ( mode == OGlobalSettings::CompletionShell ) | ||
318 | { | ||
319 | // Handles completion. | ||
320 | KShortcut cut; | ||
321 | if ( keys[TextCompletion].isNull() ) | ||
322 | cut = KStdAccel::shortcut(KStdAccel::TextCompletion); | ||
323 | else | ||
324 | cut = keys[TextCompletion]; | ||
325 | |||
326 | if ( cut.contains( key ) ) | ||
327 | { | ||
328 | // Emit completion if the completion mode is CompletionShell | ||
329 | // and the cursor is at the end of the string. | ||
330 | QString txt = text(); | ||
331 | int len = txt.length(); | ||
332 | if ( cursorPosition() == len && len != 0 ) | ||
333 | { | ||
334 | if ( emitSignals() ) | ||
335 | emit completion( txt ); | ||
336 | if ( handleSignals() ) | ||
337 | makeCompletion( txt ); | ||
338 | return; | ||
339 | } | ||
340 | } | ||
341 | else if ( d->completionBox ) | ||
342 | d->completionBox->hide(); | ||
343 | } | ||
344 | |||
345 | // handle rotation | ||
346 | if ( mode != OGlobalSettings::CompletionNone ) | ||
347 | { | ||
348 | // Handles previous match | ||
349 | KShortcut cut; | ||
350 | if ( keys[PrevCompletionMatch].isNull() ) | ||
351 | cut = KStdAccel::shortcut(KStdAccel::PrevCompletion); | ||
352 | else | ||
353 | cut = keys[PrevCompletionMatch]; | ||
354 | |||
355 | if ( cut.contains( key ) ) | ||
356 | { | ||
357 | if ( emitSignals() ) | ||
358 | emit textRotation( OCompletionBase::PrevCompletionMatch ); | ||
359 | if ( handleSignals() ) | ||
360 | rotateText( OCompletionBase::PrevCompletionMatch ); | ||
361 | return; | ||
362 | } | ||
363 | |||
364 | // Handles next match | ||
365 | if ( keys[NextCompletionMatch].isNull() ) | ||
366 | cut = KStdAccel::key(KStdAccel::NextCompletion); | ||
367 | else | ||
368 | cut = keys[NextCompletionMatch]; | ||
369 | |||
370 | if ( cut.contains( key ) ) | ||
371 | { | ||
372 | if ( emitSignals() ) | ||
373 | emit textRotation( OCompletionBase::NextCompletionMatch ); | ||
374 | if ( handleSignals() ) | ||
375 | rotateText( OCompletionBase::NextCompletionMatch ); | ||
376 | return; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | // substring completion | ||
381 | if ( compObj() ) | ||
382 | { | ||
383 | KShortcut cut; | ||
384 | if ( keys[SubstringCompletion].isNull() ) | ||
385 | cut = KStdAccel::shortcut(KStdAccel::SubstringCompletion); | ||
386 | else | ||
387 | cut = keys[SubstringCompletion]; | ||
388 | |||
389 | if ( cut.contains( key ) ) | ||
390 | { | ||
391 | if ( emitSignals() ) | ||
392 | emit substringCompletion( text() ); | ||
393 | if ( handleSignals() ) | ||
394 | { | ||
395 | setCompletedItems( compObj()->substringCompletion(text())); | ||
396 | e->accept(); | ||
397 | } | ||
398 | return; | ||
399 | } | ||
400 | } */ | ||
401 | } | ||
402 | |||
403 | // Let QLineEdit handle any other keys events. | ||
404 | QLineEdit::keyPressEvent ( e ); | ||
405 | } | ||
406 | |||
407 | void OLineEdit::mouseDoubleClickEvent( QMouseEvent* e ) | ||
408 | { | ||
409 | if ( e->button() == Qt::LeftButton ) | ||
410 | { | ||
411 | possibleTripleClick=true; | ||
412 | QTimer::singleShot( QApplication::doubleClickInterval(),this, | ||
413 | SLOT(tripleClickTimeout()) ); | ||
414 | } | ||
415 | QLineEdit::mouseDoubleClickEvent( e ); | ||
416 | } | ||
417 | |||
418 | void OLineEdit::mousePressEvent( QMouseEvent* e ) | ||
419 | { | ||
420 | if ( possibleTripleClick && e->button() == Qt::LeftButton ) | ||
421 | { | ||
422 | selectAll(); | ||
423 | return; | ||
424 | } | ||
425 | QLineEdit::mousePressEvent( e ); | ||
426 | } | ||
427 | |||
428 | void OLineEdit::tripleClickTimeout() | ||
429 | { | ||
430 | possibleTripleClick=false; | ||
431 | } | ||
432 | |||
433 | QPopupMenu *OLineEdit::createPopupMenu() | ||
434 | { | ||
435 | // Return if popup menu is not enabled !! | ||
436 | if ( !m_bEnableMenu ) | ||
437 | return 0; | ||
438 | |||
439 | #if QT_VERSION > 290 | ||
440 | QPopupMenu *popup = QLineEdit::createPopupMenu(); | ||
441 | #else | ||
442 | QPopupMenu *popup = new QPopupMenu(); | ||
443 | #warning OLineEdit is not fully functional on Qt2 | ||
444 | #endif | ||
445 | |||
446 | // completion object is present. | ||
447 | if ( compObj() ) | ||
448 | { | ||
449 | QPopupMenu *subMenu = new QPopupMenu( popup ); | ||
450 | connect( subMenu, SIGNAL( activated( int ) ), | ||
451 | this, SLOT( completionMenuActivated( int ) ) ); | ||
452 | |||
453 | popup->insertSeparator(); | ||
454 | //popup->insertItem( SmallIconSet("completion"), i18n("Text Completion"), | ||
455 | // subMenu ); | ||
456 | |||
457 | popup->insertItem( tr("Text Completion"), subMenu ); | ||
458 | |||
459 | subMenu->insertItem( tr("None"), NoCompletion ); | ||
460 | subMenu->insertItem( tr("Manual"), ShellCompletion ); | ||
461 | subMenu->insertItem( tr("Automatic"), AutoCompletion ); | ||
462 | subMenu->insertItem( tr("Dropdown List"), PopupCompletion ); | ||
463 | subMenu->insertItem( tr("Short Automatic"), SemiAutoCompletion ); | ||
464 | |||
465 | //subMenu->setAccel( KStdAccel::completion(), ShellCompletion ); | ||
466 | subMenu->setAccel( Key_Tab, ShellCompletion ); | ||
467 | |||
468 | OGlobalSettings::Completion mode = completionMode(); | ||
469 | subMenu->setItemChecked( NoCompletion, | ||
470 | mode == OGlobalSettings::CompletionNone ); | ||
471 | subMenu->setItemChecked( ShellCompletion, | ||
472 | mode == OGlobalSettings::CompletionShell ); | ||
473 | subMenu->setItemChecked( PopupCompletion, | ||
474 | mode == OGlobalSettings::CompletionPopup ); | ||
475 | subMenu->setItemChecked( AutoCompletion, | ||
476 | mode == OGlobalSettings::CompletionAuto ); | ||
477 | subMenu->setItemChecked( SemiAutoCompletion, | ||
478 | mode == OGlobalSettings::CompletionMan ); | ||
479 | if ( mode != OGlobalSettings::completionMode() ) | ||
480 | { | ||
481 | subMenu->insertSeparator(); | ||
482 | subMenu->insertItem( tr("Default"), Default ); | ||
483 | } | ||
484 | } | ||
485 | // ### do we really need this? Yes, Please do not remove! This | ||
486 | // allows applications to extend the popup menu without having to | ||
487 | // inherit from this class! (DA) | ||
488 | emit aboutToShowContextMenu( popup ); | ||
489 | |||
490 | return popup; | ||
491 | } | ||
492 | |||
493 | void OLineEdit::completionMenuActivated( int id ) | ||
494 | { | ||
495 | OGlobalSettings::Completion oldMode = completionMode(); | ||
496 | |||
497 | switch ( id ) | ||
498 | { | ||
499 | case Default: | ||
500 | setCompletionMode( OGlobalSettings::completionMode() ); break; | ||
501 | case NoCompletion: | ||
502 | setCompletionMode( OGlobalSettings::CompletionNone ); break; | ||
503 | case AutoCompletion: | ||
504 | setCompletionMode( OGlobalSettings::CompletionAuto ); break; | ||
505 | case SemiAutoCompletion: | ||
506 | setCompletionMode( OGlobalSettings::CompletionMan ); break; | ||
507 | case ShellCompletion: | ||
508 | setCompletionMode( OGlobalSettings::CompletionShell ); break; | ||
509 | case PopupCompletion: | ||
510 | setCompletionMode( OGlobalSettings::CompletionPopup ); break; | ||
511 | default: return; | ||
512 | } | ||
513 | |||
514 | if ( oldMode != completionMode() ) | ||
515 | { | ||
516 | if ( oldMode == OGlobalSettings::CompletionPopup && | ||
517 | d->completionBox && d->completionBox->isVisible() ) | ||
518 | d->completionBox->hide(); | ||
519 | emit completionModeChanged( completionMode() ); | ||
520 | } | ||
521 | } | ||
522 | |||
523 | /*void OLineEdit::dropEvent(QDropEvent *e) | ||
524 | { | ||
525 | KURL::List urlList; | ||
526 | if( d->handleURLDrops && KURLDrag::decode( e, urlList ) ) | ||
527 | { | ||
528 | QString dropText = text(); | ||
529 | KURL::List::ConstIterator it; | ||
530 | for( it = urlList.begin() ; it != urlList.end() ; ++it ) | ||
531 | { | ||
532 | if(!dropText.isEmpty()) | ||
533 | dropText+=' '; | ||
534 | |||
535 | dropText += (*it).prettyURL(); | ||
536 | } | ||
537 | |||
538 | validateAndSet( dropText, dropText.length(), 0, 0); | ||
539 | |||
540 | e->accept(); | ||
541 | } | ||
542 | else | ||
543 | QLineEdit::dropEvent(e); | ||
544 | }*/ | ||
545 | |||
546 | bool OLineEdit::eventFilter( QObject* o, QEvent* ev ) | ||
547 | { | ||
548 | if( o == this ) | ||
549 | { | ||
550 | //OCursor::autoHideEventFilter( this, ev ); | ||
551 | if ( ev->type() == QEvent::AccelOverride ) | ||
552 | { | ||
553 | QKeyEvent *e = static_cast<QKeyEvent *>( ev ); | ||
554 | // if (overrideAccel (e)) | ||
555 | // { | ||
556 | // e->accept(); | ||
557 | // return true; | ||
558 | // } | ||
559 | } | ||
560 | else if( ev->type() == QEvent::KeyPress ) | ||
561 | { | ||
562 | QKeyEvent *e = static_cast<QKeyEvent *>( ev ); | ||
563 | |||
564 | if( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter ) | ||
565 | { | ||
566 | bool trap = d->completionBox && d->completionBox->isVisible(); | ||
567 | |||
568 | // Qt will emit returnPressed() itself if we return false | ||
569 | if ( d->grabReturnKeyEvents || trap ) | ||
570 | emit QLineEdit::returnPressed(); | ||
571 | |||
572 | emit returnPressed( displayText() ); | ||
573 | |||
574 | if ( trap ) | ||
575 | d->completionBox->hide(); | ||
576 | |||
577 | // Eat the event if the user asked for it, or if a completionbox was visible | ||
578 | return d->grabReturnKeyEvents || trap; | ||
579 | } | ||
580 | } | ||
581 | } | ||
582 | return QLineEdit::eventFilter( o, ev ); | ||
583 | } | ||
584 | |||
585 | |||
586 | void OLineEdit::setURLDropsEnabled(bool enable) | ||
587 | { | ||
588 | d->handleURLDrops=enable; | ||
589 | } | ||
590 | |||
591 | bool OLineEdit::isURLDropsEnabled() const | ||
592 | { | ||
593 | return d->handleURLDrops; | ||
594 | } | ||
595 | |||
596 | void OLineEdit::setTrapReturnKey( bool grab ) | ||
597 | { | ||
598 | d->grabReturnKeyEvents = grab; | ||
599 | } | ||
600 | |||
601 | bool OLineEdit::trapReturnKey() const | ||
602 | { | ||
603 | return d->grabReturnKeyEvents; | ||
604 | } | ||
605 | |||
606 | /*void OLineEdit::setURL( const KURL& url ) | ||
607 | { | ||
608 | QLineEdit::setText( url.prettyURL() ); | ||
609 | }*/ | ||
610 | |||
611 | void OLineEdit::makeCompletionBox() | ||
612 | { | ||
613 | if ( d->completionBox ) | ||
614 | return; | ||
615 | |||
616 | d->completionBox = new OCompletionBox( this, "completion box" ); | ||
617 | if ( handleSignals() ) | ||
618 | { | ||
619 | connect( d->completionBox, SIGNAL(highlighted( const QString& )), | ||
620 | SLOT(setText( const QString& )) ); | ||
621 | connect( d->completionBox, SIGNAL(userCancelled( const QString& )), | ||
622 | SLOT(setText( const QString& )) ); | ||
623 | |||
624 | // Nice lil' hacklet ;) KComboBox doesn't know when the completionbox | ||
625 | // is created (childEvent() is even more hacky, IMHO), so we simply | ||
626 | // forward the completionbox' activated signal from here. | ||
627 | if ( parentWidget() && parentWidget()->inherits("KComboBox") ) | ||
628 | connect( d->completionBox, SIGNAL( activated( const QString& )), | ||
629 | parentWidget(), SIGNAL( activated( const QString & ))); | ||
630 | } | ||
631 | } | ||
632 | |||
633 | /*bool OLineEdit::overrideAccel (const QKeyEvent* e) | ||
634 | { | ||
635 | KShortcut scKey; | ||
636 | |||
637 | KKey key( e ); | ||
638 | KeyBindingMap keys = getKeyBindings(); | ||
639 | |||
640 | if (keys[TextCompletion].isNull()) | ||
641 | scKey = KStdAccel::shortcut(KStdAccel::TextCompletion); | ||
642 | else | ||
643 | scKey = keys[TextCompletion]; | ||
644 | |||
645 | if (scKey.contains( key )) | ||
646 | return true; | ||
647 | |||
648 | if (keys[NextCompletionMatch].isNull()) | ||
649 | scKey = KStdAccel::shortcut(KStdAccel::NextCompletion); | ||
650 | else | ||
651 | scKey = keys[NextCompletionMatch]; | ||
652 | |||
653 | if (scKey.contains( key )) | ||
654 | return true; | ||
655 | |||
656 | if (keys[PrevCompletionMatch].isNull()) | ||
657 | scKey = KStdAccel::shortcut(KStdAccel::PrevCompletion); | ||
658 | else | ||
659 | scKey = keys[PrevCompletionMatch]; | ||
660 | |||
661 | if (scKey.contains( key )) | ||
662 | return true; | ||
663 | |||
664 | if (KStdAccel::deleteWordBack().contains( key )) | ||
665 | return true; | ||
666 | if (KStdAccel::deleteWordForward().contains( key )) | ||
667 | return true; | ||
668 | |||
669 | if (d->completionBox && d->completionBox->isVisible ()) | ||
670 | if (e->key () == Key_Backtab) | ||
671 | return true; | ||
672 | |||
673 | return false; | ||
674 | }*/ | ||
675 | |||
676 | void OLineEdit::setCompletedItems( const QStringList& items ) | ||
677 | { | ||
678 | QString txt = text(); | ||
679 | if ( !items.isEmpty() && | ||
680 | !(items.count() == 1 && txt == items.first()) ) | ||
681 | { | ||
682 | if ( !d->completionBox ) | ||
683 | makeCompletionBox(); | ||
684 | |||
685 | if ( !txt.isEmpty() ) | ||
686 | d->completionBox->setCancelledText( txt ); | ||
687 | d->completionBox->setItems( items ); | ||
688 | d->completionBox->popup(); | ||
689 | } | ||
690 | else | ||
691 | { | ||
692 | if ( d->completionBox && d->completionBox->isVisible() ) | ||
693 | d->completionBox->hide(); | ||
694 | } | ||
695 | } | ||
696 | |||
697 | OCompletionBox * OLineEdit::completionBox( bool create ) | ||
698 | { | ||
699 | if ( create ) | ||
700 | makeCompletionBox(); | ||
701 | |||
702 | return d->completionBox; | ||
703 | } | ||
704 | |||
705 | void OLineEdit::setCompletionObject( OCompletion* comp, bool hsig ) | ||
706 | { | ||
707 | OCompletion *oldComp = compObj(); | ||
708 | if ( oldComp && handleSignals() ) | ||
709 | disconnect( oldComp, SIGNAL( matches( const QStringList& )), | ||
710 | this, SLOT( setCompletedItems( const QStringList& ))); | ||
711 | |||
712 | if ( comp && hsig ) | ||
713 | connect( comp, SIGNAL( matches( const QStringList& )), | ||
714 | this, SLOT( setCompletedItems( const QStringList& ))); | ||
715 | |||
716 | OCompletionBase::setCompletionObject( comp, hsig ); | ||
717 | } | ||
718 | |||
719 | // QWidget::create() turns off mouse-Tracking which would break auto-hiding | ||
720 | void OLineEdit::create( WId id, bool initializeWindow, bool destroyOldWindow ) | ||
721 | { | ||
722 | QLineEdit::create( id, initializeWindow, destroyOldWindow ); | ||
723 | //OCursor::setAutoHideCursor( this, true, true ); | ||
724 | } | ||
725 | |||
726 | void OLineEdit::clear() | ||
727 | { | ||
728 | setText( QString::null ); | ||
729 | } | ||
diff --git a/libopie2/qt3/opieui/olineedit.h b/libopie2/qt3/opieui/olineedit.h new file mode 100644 index 0000000..ecfca27 --- a/dev/null +++ b/libopie2/qt3/opieui/olineedit.h | |||
@@ -0,0 +1,498 @@ | |||
1 | /* | ||
2 | This file Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> | ||
3 | is part of the Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@kde.org>, Dawit Alemayehu <adawit@kde.org> | ||
4 | Opie Project Copyright (C) 1999 Preston Brown <pbrown@kde.org>, Patrick Ward <PAT_WARD@HP-USA-om5.om.hp.com> | ||
5 | Copyright (C) 1997 Sven Radej (sven.radej@iname.com) | ||
6 | =. | ||
7 | .=l. | ||
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 | #ifndef OLINEEDIT_H | ||
34 | #define OLINEEDIT_H | ||
35 | |||
36 | /* QT */ | ||
37 | |||
38 | #include <qlineedit.h> | ||
39 | |||
40 | /* OPIE */ | ||
41 | |||
42 | #include <opie2/ocompletion.h> | ||
43 | #include <opie2/ocompletionbase.h> | ||
44 | |||
45 | class QPopupMenu; | ||
46 | |||
47 | class OCompletionBox; | ||
48 | typedef QString KURL; //class KURL; | ||
49 | |||
50 | /** | ||
51 | * An enhanced QLineEdit widget for inputting text. | ||
52 | * | ||
53 | * @sect Detail | ||
54 | * | ||
55 | * This widget inherits from @ref QLineEdit and implements the following | ||
56 | * additional functionalities: q completion object that provides both | ||
57 | * automatic and manual text completion as well as multiple match iteration | ||
58 | * features, configurable key-bindings to activate these features and a | ||
59 | * popup-menu item that can be used to allow the user to set text completion | ||
60 | * modes on the fly based on their preference. | ||
61 | * | ||
62 | * To support these new features OLineEdit also emits a few more | ||
63 | * additional signals. These are: @ref completion( const QString& ), | ||
64 | * textRotation( KeyBindingType ), and @ref returnPressed( const QString& ). | ||
65 | * The completion signal can be connected to a slot that will assist the | ||
66 | * user in filling out the remaining text. The text rotation signal is | ||
67 | * intended to be used to iterate through the list of all possible matches | ||
68 | * whenever there is more than one match for the entered text. The | ||
69 | * @p returnPressed( const QString& ) signals are the same as QLineEdit's | ||
70 | * except it provides the current text in the widget as its argument whenever | ||
71 | * appropriate. | ||
72 | * | ||
73 | * This widget by default creates a completion object when you invoke | ||
74 | * the @ref completionObject( bool ) member function for the first time or | ||
75 | * use @ref setCompletionObject( OCompletion*, bool ) to assign your own | ||
76 | * completion object. Additionally, to make this widget more functional, | ||
77 | * OLineEdit will by default handle the text rotation and completion | ||
78 | * events internally when a completion object is created through either one | ||
79 | * of the methods mentioned above. If you do not need this functionality, | ||
80 | * simply use @ref OCompletionBase::setHandleSignals( bool ) or set the | ||
81 | * boolean parameter in the above functions to FALSE. | ||
82 | * | ||
83 | * The default key-bindings for completion and rotation is determined | ||
84 | * from the global settings in @ref OStdAccel. These values, however, | ||
85 | * can be overriden locally by invoking @ref OCompletionBase::setKeyBinding(). | ||
86 | * The values can easily be reverted back to the default setting, by simply | ||
87 | * calling @ref useGlobalSettings(). An alternate method would be to default | ||
88 | * individual key-bindings by usning @ref setKeyBinding() with the default | ||
89 | * second argument. | ||
90 | * | ||
91 | * NOTE that if the @p EchoMode for this widget is set to something other | ||
92 | * than @p QLineEdit::Normal, the completion mode will always be defaulted | ||
93 | * to @ref PGlobalSettings::CompletionNone. This is done purposefully to guard | ||
94 | * against protected entries such as passwords being cached in @ref OCompletion's | ||
95 | * list. Hence, if the @p EchoMode is not @ref QLineEdit::Normal, the completion | ||
96 | * mode is automatically disabled. | ||
97 | * | ||
98 | * @sect Useage | ||
99 | * | ||
100 | * To enable the basic completion feature : | ||
101 | * | ||
102 | * <pre> | ||
103 | * OLineEdit *edit = new OLineEdit( this, "mywidget" ); | ||
104 | * OCompletion *comp = edit->completionObject(); | ||
105 | * // Fill the completion object with a list of possible matches | ||
106 | * QStringList list; | ||
107 | * list << "mickeyl@handhelds.org" << "mickey@tm.informatik.uni-frankfurt.de>" << "mickey@Vanille.de"; | ||
108 | * comp->setItems( list ); | ||
109 | * // Connect to the return pressed signal (optional) | ||
110 | * connect(edit,SIGNAL(returnPressed(const QString&)),comp,SLOT(addItem(const QString&)); | ||
111 | * </pre> | ||
112 | * | ||
113 | * To use a customized completion objects or your | ||
114 | * own completion object : | ||
115 | * | ||
116 | * <pre> | ||
117 | * OLineEdit *edit = new OLineEdit( this,"mywidget" ); | ||
118 | * KURLCompletion *comp = new KURLCompletion(); | ||
119 | * edit->setCompletionObject( comp ); | ||
120 | * // Connect to the return pressed signal - optional | ||
121 | * connect(edit,SIGNAL(returnPressed(const QString&)),comp,SLOT(addItem(const QString&)); | ||
122 | * </pre> | ||
123 | * | ||
124 | * Note that you have to either delete the allocated completion object | ||
125 | * when you don't need it anymore, or call | ||
126 | * setAutoDeleteCompletionObject( true ); | ||
127 | * | ||
128 | * @sect Miscellaneous function calls : | ||
129 | * | ||
130 | * <pre> | ||
131 | * // Tell the widget not to handle completion and | ||
132 | * // iteration internally. | ||
133 | * edit->setHandleSignals( false ); | ||
134 | * // Set your own completion key for manual completions. | ||
135 | * edit->setKeyBinding( OCompletionBase::TextCompletion, Qt::End ); | ||
136 | * // Hide the context (popup) menu | ||
137 | * edit->setContextMenuEnabled( false ); | ||
138 | * // Temporarly disable signal emitions | ||
139 | * // (both completion & iteration signals) | ||
140 | * edit->disableSignals(); | ||
141 | * // Default the key-bindings to system settings. | ||
142 | * edit->useGlobalKeyBindings(); | ||
143 | * </pre> | ||
144 | * | ||
145 | * @short An enhanced single line input widget. | ||
146 | * @author Dawit Alemayehu <adawit@kde.org> | ||
147 | * @author Opie adaption by Michael Lauer <mickey@tm.informatik.uni-frankfurt.de> | ||
148 | */ | ||
149 | |||
150 | class OLineEdit : public QLineEdit, public OCompletionBase | ||
151 | { | ||
152 | friend class OComboBox; | ||
153 | |||
154 | Q_OBJECT | ||
155 | Q_PROPERTY( bool contextMenuEnabled READ isContextMenuEnabled WRITE setContextMenuEnabled ) | ||
156 | Q_PROPERTY( bool urlDropsEnabled READ isURLDropsEnabled WRITE setURLDropsEnabled ) | ||
157 | |||
158 | public: | ||
159 | |||
160 | /** | ||
161 | * Constructs a OLineEdit object with a default text, a parent, | ||
162 | * and a name. | ||
163 | * | ||
164 | * @param string Text to be shown in the edit widget. | ||
165 | * @param parent The parent object of this widget. | ||
166 | * @param name the name of this widget | ||
167 | */ | ||
168 | OLineEdit( const QString &string, QWidget *parent, const char *name = 0 ); | ||
169 | |||
170 | /** | ||
171 | * Constructs a OLineEdit object with a parent and a name. | ||
172 | * | ||
173 | * @param string Text to be shown in the edit widget. | ||
174 | * @param parent The parent object of this widget. | ||
175 | * @param name The name of this widget. | ||
176 | */ | ||
177 | OLineEdit ( QWidget *parent=0, const char *name=0 ); | ||
178 | |||
179 | /** | ||
180 | * Destructor. | ||
181 | */ | ||
182 | virtual ~OLineEdit (); | ||
183 | |||
184 | /** | ||
185 | * Sets @p url into the lineedit. It uses @ref KURL::prettyURL() so | ||
186 | * that the url is properly decoded for displaying. | ||
187 | */ | ||
188 | void setURL( const KURL& url ); | ||
189 | |||
190 | /** | ||
191 | * Puts the text cursor at the end of the string. | ||
192 | * | ||
193 | * This method is deprecated. Use @ref QLineEdit::end() | ||
194 | * instead. | ||
195 | * | ||
196 | * @deprecated | ||
197 | * @ref QLineEdit::end() | ||
198 | */ | ||
199 | void cursorAtEnd() { end( false ); } | ||
200 | |||
201 | /** | ||
202 | * Re-implemented from @ref OCompletionBase for internal reasons. | ||
203 | * | ||
204 | * This function is re-implemented in order to make sure that | ||
205 | * the EchoMode is acceptable before we set the completion mode. | ||
206 | * | ||
207 | * See @ref OCompletionBase::setCompletionMode | ||
208 | */ | ||
209 | virtual void setCompletionMode( OGlobalSettings::Completion mode ); | ||
210 | |||
211 | /** | ||
212 | * Enables/disables the popup (context) menu. | ||
213 | * | ||
214 | * Note that when this function is invoked with its argument | ||
215 | * set to @p true, then both the context menu and the completion | ||
216 | * menu item are enabled. If you do not want to the completion | ||
217 | * item to be visible simply invoke @ref hideModechanger() right | ||
218 | * after calling this method. Also by default, the context | ||
219 | * menu is automatically created if this widget is editable. Thus | ||
220 | * you need to call this function with the argument set to false | ||
221 | * if you do not want this behaviour. | ||
222 | * | ||
223 | * @param showMenu If @p true, show the context menu. | ||
224 | */ | ||
225 | virtual void setContextMenuEnabled( bool showMenu ) { m_bEnableMenu = showMenu; } | ||
226 | |||
227 | /** | ||
228 | * Returns @p true when the context menu is enabled. | ||
229 | */ | ||
230 | bool isContextMenuEnabled() const { return m_bEnableMenu; } | ||
231 | |||
232 | /** | ||
233 | * Enables/Disables handling of URL drops. If enabled and the user | ||
234 | * drops an URL, the decoded URL will be inserted. Otherwise the default | ||
235 | * behaviour of QLineEdit is used, which inserts the encoded URL. | ||
236 | * | ||
237 | * @param enable If @p true, insert decoded URLs | ||
238 | */ | ||
239 | void setURLDropsEnabled( bool enable ); | ||
240 | |||
241 | /** | ||
242 | * Returns @p true when decoded URL drops are enabled | ||
243 | */ | ||
244 | bool isURLDropsEnabled() const; | ||
245 | |||
246 | /** | ||
247 | * By default, OLineEdit recognizes @p Key_Return and @p Key_Enter and emits | ||
248 | * the @ref returnPressed() signals, but it also lets the event pass, | ||
249 | * for example causing a dialog's default-button to be called. | ||
250 | * | ||
251 | * Call this method with @p trap = @p true to make @p OLineEdit stop these | ||
252 | * events. The signals will still be emitted of course. | ||
253 | * | ||
254 | * @see trapReturnKey() | ||
255 | */ | ||
256 | void setTrapReturnKey( bool trap ); | ||
257 | |||
258 | /** | ||
259 | * @returns @p true if keyevents of @p Key_Return or | ||
260 | * @p Key_Enter will be stopped or if they will be propagated. | ||
261 | * | ||
262 | * @see setTrapReturnKey () | ||
263 | */ | ||
264 | bool trapReturnKey() const; | ||
265 | |||
266 | /** | ||
267 | * Re-implemented for internal reasons. API not affected. | ||
268 | * | ||
269 | * @reimplemented | ||
270 | */ | ||
271 | virtual bool eventFilter( QObject *, QEvent * ); | ||
272 | |||
273 | /** | ||
274 | * @returns the completion-box, that is used in completion mode | ||
275 | * @ref KGlobalSettings::CompletionPopup. | ||
276 | * This method will create a completion-box if none is there, yet. | ||
277 | * | ||
278 | * @param create Set this to false if you don't want the box to be created | ||
279 | * i.e. to test if it is available. | ||
280 | */ | ||
281 | OCompletionBox * completionBox( bool create = true ); | ||
282 | |||
283 | /** | ||
284 | * Reimplemented for internal reasons, the API is not affected. | ||
285 | */ | ||
286 | virtual void setCompletionObject( OCompletion *, bool hsig = true ); | ||
287 | |||
288 | |||
289 | signals: | ||
290 | |||
291 | /** | ||
292 | * Emitted when the user presses the return key. | ||
293 | * | ||
294 | * The argument is the current text. Note that this | ||
295 | * signal is @em not emitted if the widget's @p EchoMode is set to | ||
296 | * @ref QLineEdit::EchoMode. | ||
297 | */ | ||
298 | void returnPressed( const QString& ); | ||
299 | |||
300 | /** | ||
301 | * Emitted when the completion key is pressed. | ||
302 | * | ||
303 | * Please note that this signal is @em not emitted if the | ||
304 | * completion mode is set to @p CompletionNone or @p EchoMode is | ||
305 | * @em normal. | ||
306 | */ | ||
307 | void completion( const QString& ); | ||
308 | |||
309 | /** | ||
310 | * Emitted when the shortcut for substring completion is pressed. | ||
311 | */ | ||
312 | void substringCompletion( const QString& ); | ||
313 | |||
314 | /** | ||
315 | * Emitted when the text rotation key-bindings are pressed. | ||
316 | * | ||
317 | * The argument indicates which key-binding was pressed. | ||
318 | * In OLineEdit's case this can be either one of two values: | ||
319 | * @ref PrevCompletionMatch or @ref NextCompletionMatch. See | ||
320 | * @ref OCompletionBase::setKeyBinding for details. | ||
321 | * | ||
322 | * Note that this signal is @em not emitted if the completion | ||
323 | * mode is set to @p KGlobalSettings::CompletionNone or @p echoMode() is @em not normal. | ||
324 | */ | ||
325 | void textRotation( OCompletionBase::KeyBindingType ); | ||
326 | |||
327 | /** | ||
328 | * Emitted when the user changed the completion mode by using the | ||
329 | * popupmenu. | ||
330 | */ | ||
331 | void completionModeChanged( OGlobalSettings::Completion ); | ||
332 | |||
333 | /** | ||
334 | * Emitted before the context menu is displayed. | ||
335 | * | ||
336 | * The signal allows you to add your own entries into the | ||
337 | * the context menu that is created on demand. | ||
338 | * | ||
339 | * NOTE: Do not store the pointer to the QPopupMenu | ||
340 | * provided through since it is created and deleted | ||
341 | * on demand. | ||
342 | * | ||
343 | * @param the context menu about to be displayed | ||
344 | */ | ||
345 | void aboutToShowContextMenu( QPopupMenu* ); | ||
346 | |||
347 | public slots: | ||
348 | |||
349 | /** | ||
350 | * Re-implemented for internal reasons. API not changed. | ||
351 | */ | ||
352 | virtual void setReadOnly(bool); | ||
353 | |||
354 | /** | ||
355 | * Iterates through all possible matches of the completed text or | ||
356 | * the history list. | ||
357 | * | ||
358 | * This function simply iterates over all possible matches in case | ||
359 | * multimple matches are found as a result of a text completion request. | ||
360 | * It will have no effect if only a single match is found. | ||
361 | * | ||
362 | * @param type The key-binding invoked. | ||
363 | */ | ||
364 | void rotateText( OCompletionBase::KeyBindingType /* type */ ); | ||
365 | |||
366 | /** | ||
367 | * See @ref OCompletionBase::setCompletedText. | ||
368 | */ | ||
369 | virtual void setCompletedText( const QString& ); | ||
370 | |||
371 | /** | ||
372 | * Sets @p items into the completion-box if @ref completionMode() is | ||
373 | * CompletionPopup. The popup will be shown immediately. | ||
374 | */ | ||
375 | void setCompletedItems( const QStringList& items ); | ||
376 | |||
377 | /** | ||
378 | * Reimplemented to workaround a buggy QLineEdit::clear() | ||
379 | * (changing the clipboard to the text we just had in the lineedit) | ||
380 | */ | ||
381 | virtual void clear(); | ||
382 | |||
383 | protected slots: | ||
384 | |||
385 | /** | ||
386 | * Completes the remaining text with a matching one from | ||
387 | * a given list. | ||
388 | */ | ||
389 | virtual void makeCompletion( const QString& ); | ||
390 | |||
391 | /** | ||
392 | * @deprecated. Will be removed in the next major release! | ||
393 | */ | ||
394 | void slotAboutToShow() {} | ||
395 | |||
396 | /** | ||
397 | * @deprecated. Will be removed in the next major release! | ||
398 | */ | ||
399 | void slotCancelled() {} | ||
400 | |||
401 | protected: | ||
402 | |||
403 | /** | ||
404 | * Re-implemented for internal reasons. API not affected. | ||
405 | * | ||
406 | * See @ref QLineEdit::keyPressEvent(). | ||
407 | */ | ||
408 | virtual void keyPressEvent( QKeyEvent * ); | ||
409 | |||
410 | /** | ||
411 | * Re-implemented for internal reasons. API not affected. | ||
412 | * | ||
413 | * See @ref QLineEdit::mousePressEvent(). | ||
414 | */ | ||
415 | virtual void mousePressEvent( QMouseEvent * ); | ||
416 | |||
417 | /** | ||
418 | * Re-implemented for internal reasons. API not affected. | ||
419 | * | ||
420 | * See @ref QWidget::mouseDoubleClickEvent(). | ||
421 | */ | ||
422 | virtual void mouseDoubleClickEvent( QMouseEvent * ); | ||
423 | |||
424 | /** | ||
425 | * Re-implemented for internal reasons. API not affected. | ||
426 | * | ||
427 | * See @ref QLineEdit::createPopupMenu(). | ||
428 | */ | ||
429 | virtual QPopupMenu *createPopupMenu(); | ||
430 | |||
431 | /** | ||
432 | * Re-implemented to handle URI drops. | ||
433 | * | ||
434 | * See @ref QLineEdit::dropEvent(). | ||
435 | */ | ||
436 | //virtual void dropEvent( QDropEvent * ); | ||
437 | |||
438 | /* | ||
439 | * This function simply sets the lineedit text and | ||
440 | * highlights the text appropriately if the boolean | ||
441 | * value is set to true. | ||
442 | * | ||
443 | * @param text | ||
444 | * @param marked | ||
445 | */ | ||
446 | virtual void setCompletedText( const QString& /*text*/, bool /*marked*/ ); | ||
447 | |||
448 | /** | ||
449 | * Reimplemented for internal reasons, the API is not affected. | ||
450 | */ | ||
451 | virtual void create( WId = 0, bool initializeWindow = true, | ||
452 | bool destroyOldWindow = true ); | ||
453 | |||
454 | private slots: | ||
455 | void completionMenuActivated( int id ); | ||
456 | void tripleClickTimeout(); // resets possibleTripleClick | ||
457 | |||
458 | private: | ||
459 | // Constants that represent the ID's of the popup menu. | ||
460 | // TODO: See if we can replace this mess with KActionMenu | ||
461 | // in the future though it's working lovely. | ||
462 | enum MenuID { | ||
463 | Default = 42, | ||
464 | NoCompletion, | ||
465 | AutoCompletion, | ||
466 | ShellCompletion, | ||
467 | PopupCompletion, | ||
468 | SemiAutoCompletion | ||
469 | }; | ||
470 | |||
471 | /** | ||
472 | * Initializes variables. Called from the constructors. | ||
473 | */ | ||
474 | void init(); | ||
475 | |||
476 | /** | ||
477 | * Creates the completion box | ||
478 | */ | ||
479 | void makeCompletionBox(); | ||
480 | |||
481 | /** | ||
482 | * Checks whether we should/should not consume a key used as | ||
483 | * an accelerator. | ||
484 | */ | ||
485 | //bool overrideAccel (const QKeyEvent* e); | ||
486 | |||
487 | bool m_bEnableMenu; | ||
488 | |||
489 | bool possibleTripleClick; // set in mousePressEvent, deleted in tripleClickTimeout | ||
490 | |||
491 | protected: | ||
492 | //virtual void virtual_hook( int id, void* data ); | ||
493 | private: | ||
494 | class OLineEditPrivate; | ||
495 | OLineEditPrivate *d; | ||
496 | }; | ||
497 | |||
498 | #endif | ||