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 | |
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/opiecore/ocompletion.cpp | 1061 | ||||
-rw-r--r-- | libopie2/qt3/opiecore/ocompletion.h | 603 | ||||
-rw-r--r-- | libopie2/qt3/opiecore/ocompletionbase.cpp | 171 | ||||
-rw-r--r-- | libopie2/qt3/opiecore/ocompletionbase.h | 403 | ||||
-rw-r--r-- | libopie2/qt3/opiecore/opair.h | 99 | ||||
-rw-r--r-- | libopie2/qt3/opiecore/osortablevaluelist.h | 117 | ||||
-rw-r--r-- | libopie2/qt3/opiecore/otl.h | 325 | ||||
-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 |
17 files changed, 8435 insertions, 0 deletions
diff --git a/libopie2/qt3/opiecore/ocompletion.cpp b/libopie2/qt3/opiecore/ocompletion.cpp new file mode 100644 index 0000000..7b263ab --- a/dev/null +++ b/libopie2/qt3/opiecore/ocompletion.cpp | |||
@@ -0,0 +1,1061 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | Originally part of the KDE Project | ||
4 | Copyright (C) 1999,2000,2001 Carsten Pfeiffer <pfeiffer@kde.org> | ||
5 | =. | ||
6 | .=l. | ||
7 | .>+-= | ||
8 | _;:, .> :=|. This program is free software; you can | ||
9 | .> <`_, > . <= redistribute it and/or modify it under | ||
10 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
11 | .="- .-=="i, .._ License as published by the Free Software | ||
12 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
13 | ._= =} : or (at your option) any later version. | ||
14 | .%`+i> _;_. | ||
15 | .i_,=:_. -<s. This program is distributed in the hope that | ||
16 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
17 | : .. .:, . . . without even the implied warranty of | ||
18 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
19 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
20 | ..}^=.= = ; Library General Public License for more | ||
21 | ++= -. .` .: details. | ||
22 | : = ...= . :.=- | ||
23 | -. .:....=;==+<; You should have received a copy of the GNU | ||
24 | -_. . . )=. = Library General Public License along with | ||
25 | -- :-=` this library; see the file COPYING.LIB. | ||
26 | If not, write to the Free Software Foundation, | ||
27 | Inc., 59 Temple Place - Suite 330, | ||
28 | Boston, MA 02111-1307, USA. | ||
29 | */ | ||
30 | |||
31 | #include <opie2/ocompletion.h> | ||
32 | |||
33 | class OCompTreeNode; | ||
34 | |||
35 | /**************************************************************************************************/ | ||
36 | /* OCompTreeNodeList | ||
37 | /**************************************************************************************************/ | ||
38 | |||
39 | class OCompTreeNodeList | ||
40 | { | ||
41 | public: | ||
42 | OCompTreeNodeList() : first(0), last(0), m_count(0) {} | ||
43 | OCompTreeNode *begin() const { return first; } | ||
44 | OCompTreeNode *end() const { return last; } | ||
45 | |||
46 | OCompTreeNode *at(uint index) const; | ||
47 | void append(OCompTreeNode *item); | ||
48 | void prepend(OCompTreeNode *item); | ||
49 | void insert(OCompTreeNode *after, OCompTreeNode *item); | ||
50 | OCompTreeNode *remove(OCompTreeNode *item); | ||
51 | uint count() const { return m_count; } | ||
52 | |||
53 | private: | ||
54 | OCompTreeNode *first, *last; | ||
55 | uint m_count; | ||
56 | }; | ||
57 | |||
58 | typedef OCompTreeNodeList OCompTreeChildren; | ||
59 | typedef OSortableValueList<QString> OCompletionMatchesList; | ||
60 | |||
61 | /** | ||
62 | * A helper class for OCompletion. Implements a tree of QChar. | ||
63 | * | ||
64 | * The tree looks like this (containing the items "kde", "kde-ui", | ||
65 | * "kde-core" and "pfeiffer". Every item is delimited with QChar( 0x0 ) | ||
66 | * | ||
67 | * some_root_node | ||
68 | * / \ | ||
69 | * k p | ||
70 | * | | | ||
71 | * d f | ||
72 | * | | | ||
73 | * e e | ||
74 | * /| | | ||
75 | * 0x0 - i | ||
76 | * / \ | | ||
77 | * u c f | ||
78 | * | | | | ||
79 | * i o f | ||
80 | * | | | | ||
81 | * 0x0 r e | ||
82 | * | | | ||
83 | * e r | ||
84 | * | | | ||
85 | * 0x0 0x0 | ||
86 | * | ||
87 | * @author Carsten Pfeiffer <pfeiffer@kde.org> | ||
88 | * @internal | ||
89 | */ | ||
90 | |||
91 | /**************************************************************************************************/ | ||
92 | /* OCompTreeNode | ||
93 | /**************************************************************************************************/ | ||
94 | |||
95 | class OCompTreeNode : public QChar | ||
96 | { | ||
97 | public: | ||
98 | OCompTreeNode():QChar(), myWeight(0) {} | ||
99 | OCompTreeNode( const QChar& ch, uint weight = 0 ):QChar( ch ), myWeight( weight ) {} | ||
100 | ~OCompTreeNode(); | ||
101 | |||
102 | // FIXME: Do we need this for Opie? [see also the static ZoneAllocater below] | ||
103 | //void * operator new( size_t s ) { | ||
104 | // return alloc.allocate( s ); | ||
105 | //} | ||
106 | //void operator delete( void * s ) { | ||
107 | // alloc.deallocate( s ); | ||
108 | //} | ||
109 | |||
110 | // Returns a child of this node matching ch, if available. | ||
111 | // Otherwise, returns 0L | ||
112 | inline OCompTreeNode * find( const QChar& ch ) const { | ||
113 | OCompTreeNode * cur = myChildren.begin(); | ||
114 | while (cur && (*cur != ch)) cur = cur->next; | ||
115 | return cur; | ||
116 | } | ||
117 | |||
118 | OCompTreeNode * insert( const QChar&, bool sorted ); | ||
119 | void remove( const QString& ); | ||
120 | |||
121 | inline int childrenCount() const { return myChildren.count(); }; | ||
122 | |||
123 | // weighting | ||
124 | inline void confirm() { myWeight++; }; | ||
125 | inline void confirm(uint w) { myWeight += w; }; | ||
126 | inline void decline() { myWeight--; }; | ||
127 | inline uint weight() const { return myWeight; }; | ||
128 | |||
129 | inline const OCompTreeChildren * children() const { return &myChildren; }; | ||
130 | inline const OCompTreeNode * childAt(int index) const { return myChildren.at(index); }; | ||
131 | inline const OCompTreeNode * firstChild() const { return myChildren.begin(); }; | ||
132 | inline const OCompTreeNode * lastChild() const { return myChildren.end(); }; | ||
133 | |||
134 | /* We want to handle a list of OCompTreeNodes on our own, to not | ||
135 | need to use QValueList<>. And to make it even more fast we don't | ||
136 | use an accessor, but just a public member. */ | ||
137 | OCompTreeNode *next; | ||
138 | |||
139 | private: | ||
140 | uint myWeight; | ||
141 | OCompTreeNodeListmyChildren; | ||
142 | //static OZoneAllocator alloc; // FIXME: Do we need this for Opie? | ||
143 | }; | ||
144 | |||
145 | /**************************************************************************************************/ | ||
146 | /* OCompletionMatchesWrapper | ||
147 | /**************************************************************************************************/ | ||
148 | |||
149 | class OCompletionMatchesWrapper | ||
150 | { | ||
151 | public: | ||
152 | OCompletionMatchesWrapper( bool sort = false ) | ||
153 | : sortedList( sort ? new OCompletionMatchesList : 0L ), | ||
154 | dirty( false ) | ||
155 | {} | ||
156 | ~OCompletionMatchesWrapper() { | ||
157 | delete sortedList; | ||
158 | } | ||
159 | |||
160 | void setSorting( bool sort ) { | ||
161 | if ( sort && !sortedList ) | ||
162 | sortedList = new OCompletionMatchesList; | ||
163 | else if ( !sort ) { | ||
164 | delete sortedList; | ||
165 | sortedList = 0L; | ||
166 | } | ||
167 | stringList.clear(); | ||
168 | dirty = false; | ||
169 | } | ||
170 | |||
171 | bool sorting() const { | ||
172 | return sortedList != 0L; | ||
173 | } | ||
174 | |||
175 | void append( int i, const QString& string ) { | ||
176 | if ( sortedList ) | ||
177 | sortedList->insert( i, string ); | ||
178 | else | ||
179 | stringList.append( string ); | ||
180 | dirty = true; | ||
181 | } | ||
182 | |||
183 | void clear() { | ||
184 | if ( sortedList ) | ||
185 | sortedList->clear(); | ||
186 | stringList.clear(); | ||
187 | dirty = false; | ||
188 | } | ||
189 | |||
190 | uint count() const { | ||
191 | if ( sortedList ) | ||
192 | return sortedList->count(); | ||
193 | return stringList.count(); | ||
194 | } | ||
195 | |||
196 | bool isEmpty() const { | ||
197 | return count() == 0; | ||
198 | } | ||
199 | |||
200 | QString first() const { | ||
201 | return list().first(); | ||
202 | } | ||
203 | |||
204 | QString last() const { | ||
205 | return list().last(); | ||
206 | } | ||
207 | |||
208 | QStringList list() const; | ||
209 | |||
210 | mutable QStringList stringList; | ||
211 | OCompletionMatchesList *sortedList; | ||
212 | mutable bool dirty; | ||
213 | }; | ||
214 | |||
215 | /**************************************************************************************************/ | ||
216 | /* OCompletionPrivate | ||
217 | /**************************************************************************************************/ | ||
218 | |||
219 | class OCompletionPrivate | ||
220 | { | ||
221 | public: | ||
222 | // not a member to avoid #including kcompletion_private.h from kcompletion.h | ||
223 | // list used for nextMatch() and previousMatch() | ||
224 | OCompletionMatchesWrapper matches; | ||
225 | }; | ||
226 | |||
227 | /**************************************************************************************************/ | ||
228 | /* OCompletion | ||
229 | /**************************************************************************************************/ | ||
230 | |||
231 | OCompletion::OCompletion() | ||
232 | { | ||
233 | d = new OCompletionPrivate; | ||
234 | |||
235 | myCompletionMode = OGlobalSettings::completionMode(); | ||
236 | myTreeRoot = new OCompTreeNode; | ||
237 | myBeep = true; | ||
238 | myIgnoreCase = false; | ||
239 | myHasMultipleMatches = false; | ||
240 | myRotationIndex = 0; | ||
241 | setOrder( Insertion ); | ||
242 | } | ||
243 | |||
244 | |||
245 | OCompletion::~OCompletion() | ||
246 | { | ||
247 | delete d; | ||
248 | delete myTreeRoot; | ||
249 | } | ||
250 | |||
251 | |||
252 | void OCompletion::setOrder( CompOrder order ) | ||
253 | { | ||
254 | myOrder = order; | ||
255 | d->matches.setSorting( order == Weighted ); | ||
256 | } | ||
257 | |||
258 | |||
259 | void OCompletion::setIgnoreCase( bool ignoreCase ) | ||
260 | { | ||
261 | myIgnoreCase = ignoreCase; | ||
262 | } | ||
263 | |||
264 | |||
265 | void OCompletion::setItems( const QStringList& items ) | ||
266 | { | ||
267 | clear(); | ||
268 | insertItems( items ); | ||
269 | } | ||
270 | |||
271 | |||
272 | void OCompletion::insertItems( const QStringList& items ) | ||
273 | { | ||
274 | bool weighted = (myOrder == Weighted); | ||
275 | QStringList::ConstIterator it; | ||
276 | if ( weighted ) { // determine weight | ||
277 | for ( it = items.begin(); it != items.end(); ++it ) addWeightedItem( *it ); | ||
278 | } | ||
279 | else { | ||
280 | for ( it = items.begin(); it != items.end(); ++it ) addItem( *it, 0 ); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | |||
285 | QStringList OCompletion::items() const | ||
286 | { | ||
287 | OCompletionMatchesWrapper list; // unsorted | ||
288 | bool addWeight = (myOrder == Weighted); | ||
289 | extractStringsFromNode( myTreeRoot, QString::null, &list, addWeight ); | ||
290 | |||
291 | return list.list(); | ||
292 | } | ||
293 | |||
294 | |||
295 | void OCompletion::addItem( const QString& item ) | ||
296 | { | ||
297 | d->matches.clear(); | ||
298 | myRotationIndex = 0; | ||
299 | myLastString = QString::null; | ||
300 | |||
301 | addItem( item, 0 ); | ||
302 | } | ||
303 | |||
304 | |||
305 | void OCompletion::addItem( const QString& item, uint weight ) | ||
306 | { | ||
307 | if ( item.isEmpty() ) return; | ||
308 | |||
309 | OCompTreeNode *node = myTreeRoot; | ||
310 | uint len = item.length(); | ||
311 | |||
312 | bool sorted = (myOrder == Sorted); | ||
313 | bool weighted = ((myOrder == Weighted) && weight > 1); | ||
314 | |||
315 | // knowing the weight of an item, we simply add this weight to all of its | ||
316 | // nodes. | ||
317 | |||
318 | for ( uint i = 0; i < len; i++ ) { | ||
319 | node = node->insert( item.at(i), sorted ); | ||
320 | if ( weighted ) node->confirm( weight -1 ); // node->insert() sets weighting to 1 | ||
321 | } | ||
322 | |||
323 | // add 0x0-item as delimiter with evtl. weight | ||
324 | node = node->insert( 0x0, true ); | ||
325 | if ( weighted ) | ||
326 | node->confirm( weight -1 ); | ||
327 | //qDebug( "OCompletion: added: %s (%i)", item.latin1(), node->weight()); | ||
328 | } | ||
329 | |||
330 | |||
331 | void OCompletion::addWeightedItem( const QString& item ) | ||
332 | { | ||
333 | if ( myOrder != Weighted ) { | ||
334 | addItem( item, 0 ); | ||
335 | return; | ||
336 | } | ||
337 | |||
338 | uint len = item.length(); | ||
339 | uint weight = 0; | ||
340 | |||
341 | // find out the weighting of this item (appended to the string as ":num") | ||
342 | int index = item.findRev(':'); | ||
343 | if ( index > 0 ) { | ||
344 | bool ok; | ||
345 | weight = item.mid( index + 1 ).toUInt( &ok ); | ||
346 | if ( !ok ) | ||
347 | weight = 0; | ||
348 | |||
349 | len = index; // only insert until the ':' | ||
350 | } | ||
351 | |||
352 | addItem( item.left( len ), weight ); | ||
353 | return; | ||
354 | } | ||
355 | |||
356 | |||
357 | void OCompletion::removeItem( const QString& item ) | ||
358 | { | ||
359 | d->matches.clear(); | ||
360 | myRotationIndex = 0; | ||
361 | myLastString = QString::null; | ||
362 | |||
363 | myTreeRoot->remove( item ); | ||
364 | } | ||
365 | |||
366 | |||
367 | void OCompletion::clear() | ||
368 | { | ||
369 | d->matches.clear(); | ||
370 | myRotationIndex = 0; | ||
371 | myLastString = QString::null; | ||
372 | |||
373 | delete myTreeRoot; | ||
374 | myTreeRoot = new OCompTreeNode; | ||
375 | } | ||
376 | |||
377 | |||
378 | QString OCompletion::makeCompletion( const QString& string ) | ||
379 | { | ||
380 | if ( myCompletionMode == OGlobalSettings::CompletionNone ) | ||
381 | return QString::null; | ||
382 | |||
383 | //qDebug( "OCompletion: completing: %s", string ); | ||
384 | |||
385 | d->matches.clear(); | ||
386 | myRotationIndex = 0; | ||
387 | myHasMultipleMatches = false; | ||
388 | myLastMatch = myCurrentMatch; | ||
389 | |||
390 | // in Shell-completion-mode, emit all matches when we get the same | ||
391 | // complete-string twice | ||
392 | if ( myCompletionMode == OGlobalSettings::CompletionShell && | ||
393 | string == myLastString ) { | ||
394 | // Don't use d->matches since calling postProcessMatches() | ||
395 | // on d->matches here would interfere with call to | ||
396 | // postProcessMatch() during rotation | ||
397 | |||
398 | findAllCompletions( string, &d->matches, myHasMultipleMatches ); | ||
399 | QStringList l = d->matches.list(); | ||
400 | postProcessMatches( &l ); | ||
401 | emit matches( l ); | ||
402 | |||
403 | if ( l.isEmpty() ) | ||
404 | doBeep( NoMatch ); | ||
405 | |||
406 | return QString::null; | ||
407 | } | ||
408 | |||
409 | QString completion; | ||
410 | // in case-insensitive popup mode, we search all completions at once | ||
411 | if ( myCompletionMode == OGlobalSettings::CompletionPopup || | ||
412 | myCompletionMode == OGlobalSettings::CompletionPopupAuto ) { | ||
413 | findAllCompletions( string, &d->matches, myHasMultipleMatches ); | ||
414 | if ( !d->matches.isEmpty() ) | ||
415 | completion = d->matches.first(); | ||
416 | } | ||
417 | else | ||
418 | completion = findCompletion( string ); | ||
419 | |||
420 | if ( myHasMultipleMatches ) | ||
421 | emit multipleMatches(); | ||
422 | |||
423 | myLastString = string; | ||
424 | myCurrentMatch = completion; | ||
425 | |||
426 | postProcessMatch( &completion ); | ||
427 | |||
428 | if ( !string.isEmpty() ) { // only emit match when string != "" | ||
429 | //qDebug( "OCompletion: Match: %s", completion ); | ||
430 | emit match( completion ); | ||
431 | } | ||
432 | |||
433 | if ( completion.isNull() ) | ||
434 | doBeep( NoMatch ); | ||
435 | |||
436 | return completion; | ||
437 | } | ||
438 | |||
439 | QStringList OCompletion::substringCompletion( const QString& string ) const | ||
440 | { | ||
441 | // get all items in the tree, eventually in sorted order | ||
442 | bool sorted = (myOrder == Weighted); | ||
443 | OCompletionMatchesWrapper allItems( sorted ); | ||
444 | extractStringsFromNode( myTreeRoot, QString::null, &allItems, false ); | ||
445 | |||
446 | QStringList list = allItems.list(); | ||
447 | |||
448 | // subStringMatches is invoked manually, via a shortcut, so we should | ||
449 | // beep here, if necessary. | ||
450 | if ( list.isEmpty() ) { | ||
451 | doBeep( NoMatch ); | ||
452 | return list; | ||
453 | } | ||
454 | |||
455 | if ( string.isEmpty() ) { // shortcut | ||
456 | postProcessMatches( &list ); | ||
457 | return list; | ||
458 | } | ||
459 | |||
460 | QStringList matches; | ||
461 | QStringList::ConstIterator it = list.begin(); | ||
462 | |||
463 | for( ; it != list.end(); ++it ) { | ||
464 | QString item = *it; | ||
465 | if ( item.find( string, 0, false ) != -1 ) { // always case insensitive | ||
466 | postProcessMatch( &item ); | ||
467 | matches.append( item ); | ||
468 | } | ||
469 | } | ||
470 | |||
471 | if ( matches.isEmpty() ) | ||
472 | doBeep( NoMatch ); | ||
473 | |||
474 | return matches; | ||
475 | } | ||
476 | |||
477 | |||
478 | void OCompletion::setCompletionMode( OGlobalSettings::Completion mode ) | ||
479 | { | ||
480 | myCompletionMode = mode; | ||
481 | } | ||
482 | |||
483 | |||
484 | QStringList OCompletion::allMatches() | ||
485 | { | ||
486 | // Don't use d->matches since calling postProcessMatches() | ||
487 | // on d->matches here would interfere with call to | ||
488 | // postProcessMatch() during rotation | ||
489 | OCompletionMatchesWrapper matches( myOrder == Weighted ); | ||
490 | bool dummy; | ||
491 | findAllCompletions( myLastString, &matches, dummy ); | ||
492 | QStringList l = matches.list(); | ||
493 | postProcessMatches( &l ); | ||
494 | return l; | ||
495 | } | ||
496 | |||
497 | |||
498 | OCompletionMatches OCompletion::allWeightedMatches() | ||
499 | { | ||
500 | // Don't use d->matches since calling postProcessMatches() | ||
501 | // on d->matches here would interfere with call to | ||
502 | // postProcessMatch() during rotation | ||
503 | OCompletionMatchesWrapper matches( myOrder == Weighted ); | ||
504 | bool dummy; | ||
505 | findAllCompletions( myLastString, &matches, dummy ); | ||
506 | OCompletionMatches ret( matches ); | ||
507 | postProcessMatches( &ret ); | ||
508 | return ret; | ||
509 | } | ||
510 | |||
511 | QStringList OCompletion::allMatches( const QString &string ) | ||
512 | { | ||
513 | OCompletionMatchesWrapper matches( myOrder == Weighted ); | ||
514 | bool dummy; | ||
515 | findAllCompletions( string, &matches, dummy ); | ||
516 | QStringList l = matches.list(); | ||
517 | postProcessMatches( &l ); | ||
518 | return l; | ||
519 | } | ||
520 | |||
521 | OCompletionMatches OCompletion::allWeightedMatches( const QString &string ) | ||
522 | { | ||
523 | OCompletionMatchesWrapper matches( myOrder == Weighted ); | ||
524 | bool dummy; | ||
525 | findAllCompletions( string, &matches, dummy ); | ||
526 | OCompletionMatches ret( matches ); | ||
527 | postProcessMatches( &ret ); | ||
528 | return ret; | ||
529 | } | ||
530 | |||
531 | ///////////////////////////////////////////////////// | ||
532 | ///////////////// tree operations /////////////////// | ||
533 | |||
534 | |||
535 | QString OCompletion::nextMatch() | ||
536 | { | ||
537 | QString completion; | ||
538 | myLastMatch = myCurrentMatch; | ||
539 | |||
540 | if ( d->matches.isEmpty() ) { | ||
541 | findAllCompletions( myLastString, &d->matches, myHasMultipleMatches ); | ||
542 | completion = d->matches.first(); | ||
543 | myCurrentMatch = completion; | ||
544 | myRotationIndex = 0; | ||
545 | postProcessMatch( &completion ); | ||
546 | emit match( completion ); | ||
547 | return completion; | ||
548 | } | ||
549 | |||
550 | QStringList matches = d->matches.list(); | ||
551 | myLastMatch = matches[ myRotationIndex++ ]; | ||
552 | |||
553 | if ( myRotationIndex == matches.count() -1 ) | ||
554 | doBeep( Rotation ); // indicate last matching item -> rotating | ||
555 | |||
556 | else if ( myRotationIndex == matches.count() ) | ||
557 | myRotationIndex = 0; | ||
558 | |||
559 | completion = matches[ myRotationIndex ]; | ||
560 | myCurrentMatch = completion; | ||
561 | postProcessMatch( &completion ); | ||
562 | emit match( completion ); | ||
563 | return completion; | ||
564 | } | ||
565 | |||
566 | |||
567 | |||
568 | QString OCompletion::previousMatch() | ||
569 | { | ||
570 | QString completion; | ||
571 | myLastMatch = myCurrentMatch; | ||
572 | |||
573 | if ( d->matches.isEmpty() ) { | ||
574 | findAllCompletions( myLastString, &d->matches, myHasMultipleMatches ); | ||
575 | completion = d->matches.last(); | ||
576 | myCurrentMatch = completion; | ||
577 | myRotationIndex = 0; | ||
578 | postProcessMatch( &completion ); | ||
579 | emit match( completion ); | ||
580 | return completion; | ||
581 | } | ||
582 | |||
583 | QStringList matches = d->matches.list(); | ||
584 | myLastMatch = matches[ myRotationIndex ]; | ||
585 | if ( myRotationIndex == 1 ) | ||
586 | doBeep( Rotation ); // indicate first item -> rotating | ||
587 | |||
588 | else if ( myRotationIndex == 0 ) | ||
589 | myRotationIndex = matches.count(); | ||
590 | |||
591 | myRotationIndex--; | ||
592 | |||
593 | completion = matches[ myRotationIndex ]; | ||
594 | myCurrentMatch = completion; | ||
595 | postProcessMatch( &completion ); | ||
596 | emit match( completion ); | ||
597 | return completion; | ||
598 | } | ||
599 | |||
600 | |||
601 | |||
602 | // tries to complete "string" from the tree-root | ||
603 | QString OCompletion::findCompletion( const QString& string ) | ||
604 | { | ||
605 | QChar ch; | ||
606 | QString completion; | ||
607 | const OCompTreeNode *node = myTreeRoot; | ||
608 | |||
609 | // start at the tree-root and try to find the search-string | ||
610 | for( uint i = 0; i < string.length(); i++ ) { | ||
611 | ch = string.at( i ); | ||
612 | node = node->find( ch ); | ||
613 | |||
614 | if ( node ) | ||
615 | completion += ch; | ||
616 | else | ||
617 | return QString::null; // no completion | ||
618 | } | ||
619 | |||
620 | // Now we have the last node of the to be completed string. | ||
621 | // Follow it as long as it has exactly one child (= longest possible | ||
622 | // completion) | ||
623 | |||
624 | while ( node->childrenCount() == 1 ) { | ||
625 | node = node->firstChild(); | ||
626 | if ( !node->isNull() ) | ||
627 | completion += *node; | ||
628 | } | ||
629 | // if multiple matches and auto-completion mode | ||
630 | // -> find the first complete match | ||
631 | if ( node && node->childrenCount() > 1 ) { | ||
632 | myHasMultipleMatches = true; | ||
633 | |||
634 | if ( myCompletionMode == OGlobalSettings::CompletionAuto ) { | ||
635 | myRotationIndex = 1; | ||
636 | if (myOrder != Weighted) { | ||
637 | while ( (node = node->firstChild()) ) { | ||
638 | if ( !node->isNull() ) | ||
639 | completion += *node; | ||
640 | else | ||
641 | break; | ||
642 | } | ||
643 | } | ||
644 | else { | ||
645 | // don't just find the "first" match, but the one with the | ||
646 | // highest priority | ||
647 | |||
648 | const OCompTreeNode* temp_node = 0L; | ||
649 | while(1) { | ||
650 | int count = node->childrenCount(); | ||
651 | temp_node = node->firstChild(); | ||
652 | uint weight = temp_node->weight(); | ||
653 | const OCompTreeNode* hit = temp_node; | ||
654 | for( int i = 1; i < count; i++ ) { | ||
655 | temp_node = node->childAt(i); | ||
656 | if( temp_node->weight() > weight ) { | ||
657 | hit = temp_node; | ||
658 | weight = hit->weight(); | ||
659 | } | ||
660 | } | ||
661 | // 0x0 has the highest priority -> we have the best match | ||
662 | if ( hit->isNull() ) | ||
663 | break; | ||
664 | |||
665 | node = hit; | ||
666 | completion += *node; | ||
667 | } | ||
668 | } | ||
669 | } | ||
670 | |||
671 | else | ||
672 | doBeep( PartialMatch ); // partial match -> beep | ||
673 | } | ||
674 | |||
675 | return completion; | ||
676 | } | ||
677 | |||
678 | |||
679 | void OCompletion::findAllCompletions(const QString& string, | ||
680 | OCompletionMatchesWrapper *matches, | ||
681 | bool& hasMultipleMatches) const | ||
682 | { | ||
683 | //qDebug( "OCompletion: finding all completions for %s", (const char*) string ); | ||
684 | |||
685 | if ( string.isEmpty() ) | ||
686 | return; | ||
687 | |||
688 | if ( myIgnoreCase ) { // case insensitive completion | ||
689 | extractStringsFromNodeCI( myTreeRoot, QString::null, string, matches ); | ||
690 | hasMultipleMatches = (matches->count() > 1); | ||
691 | return; | ||
692 | } | ||
693 | |||
694 | QChar ch; | ||
695 | QString completion; | ||
696 | const OCompTreeNode *node = myTreeRoot; | ||
697 | |||
698 | // start at the tree-root and try to find the search-string | ||
699 | for( uint i = 0; i < string.length(); i++ ) { | ||
700 | ch = string.at( i ); | ||
701 | node = node->find( ch ); | ||
702 | |||
703 | if ( node ) | ||
704 | completion += ch; | ||
705 | else | ||
706 | return; // no completion -> return empty list | ||
707 | } | ||
708 | |||
709 | // Now we have the last node of the to be completed string. | ||
710 | // Follow it as long as it has exactly one child (= longest possible | ||
711 | // completion) | ||
712 | |||
713 | while ( node->childrenCount() == 1 ) { | ||
714 | node = node->firstChild(); | ||
715 | if ( !node->isNull() ) | ||
716 | completion += *node; | ||
717 | // kdDebug() << completion << node->latin1(); | ||
718 | } | ||
719 | |||
720 | |||
721 | // there is just one single match) | ||
722 | if ( node->childrenCount() == 0 ) | ||
723 | matches->append( node->weight(), completion ); | ||
724 | |||
725 | else { | ||
726 | // node has more than one child | ||
727 | // -> recursively find all remaining completions | ||
728 | hasMultipleMatches = true; | ||
729 | extractStringsFromNode( node, completion, matches ); | ||
730 | } | ||
731 | } | ||
732 | |||
733 | |||
734 | void OCompletion::extractStringsFromNode( const OCompTreeNode *node, | ||
735 | const QString& beginning, | ||
736 | OCompletionMatchesWrapper *matches, | ||
737 | bool addWeight ) const | ||
738 | { | ||
739 | if ( !node || !matches ) return; | ||
740 | |||
741 | // kDebug() << "Beginning: " << beginning << endl; | ||
742 | const OCompTreeChildren *list = node->children(); | ||
743 | QString string; | ||
744 | QString w; | ||
745 | |||
746 | // loop thru all children | ||
747 | for ( OCompTreeNode *cur = list->begin(); cur ; cur = cur->next) { | ||
748 | string = beginning; | ||
749 | node = cur; | ||
750 | if ( !node->isNull() ) | ||
751 | string += *node; | ||
752 | |||
753 | while ( node && node->childrenCount() == 1 ) { | ||
754 | node = node->firstChild(); | ||
755 | if ( node->isNull() ) break; | ||
756 | string += *node; | ||
757 | } | ||
758 | |||
759 | if ( node && node->isNull() ) { // we found a leaf | ||
760 | if ( addWeight ) { | ||
761 | // add ":num" to the string to store the weighting | ||
762 | string += ':'; | ||
763 | w.setNum( node->weight() ); | ||
764 | string.append( w ); | ||
765 | } | ||
766 | matches->append( node->weight(), string ); | ||
767 | } | ||
768 | |||
769 | // recursively find all other strings. | ||
770 | if ( node && node->childrenCount() > 1 ) | ||
771 | extractStringsFromNode( node, string, matches, addWeight ); | ||
772 | } | ||
773 | } | ||
774 | |||
775 | void OCompletion::extractStringsFromNodeCI( const OCompTreeNode *node, | ||
776 | const QString& beginning, | ||
777 | const QString& restString, | ||
778 | OCompletionMatchesWrapper *matches ) const | ||
779 | { | ||
780 | if ( restString.isEmpty() ) { | ||
781 | extractStringsFromNode( node, beginning, matches, false /*noweight*/ ); | ||
782 | return; | ||
783 | } | ||
784 | |||
785 | QChar ch1 = restString.at(0); | ||
786 | QString newRest = restString.mid(1); | ||
787 | OCompTreeNode *child1, *child2; | ||
788 | |||
789 | child1 = node->find( ch1 ); // the correct match | ||
790 | if ( child1 ) | ||
791 | extractStringsFromNodeCI( child1, beginning + *child1, newRest, | ||
792 | matches ); | ||
793 | |||
794 | // append the case insensitive matches, if available | ||
795 | if ( ch1.isLetter() ) { | ||
796 | // find out if we have to lower or upper it. Is there a better way? | ||
797 | QChar ch2 = ch1.lower(); | ||
798 | if ( ch1 == ch2 ) | ||
799 | ch2 = ch1.upper(); | ||
800 | if ( ch1 != ch2 ) { | ||
801 | child2 = node->find( ch2 ); | ||
802 | if ( child2 ) | ||
803 | extractStringsFromNodeCI( child2, beginning + *child2, newRest, | ||
804 | matches ); | ||
805 | } | ||
806 | } | ||
807 | } | ||
808 | |||
809 | // FIXME: Revise this for Opie? | ||
810 | |||
811 | void OCompletion::doBeep( BeepMode mode ) const | ||
812 | { | ||
813 | if ( !myBeep ) return; | ||
814 | |||
815 | QString text, event; | ||
816 | |||
817 | switch ( mode ) { | ||
818 | case Rotation: | ||
819 | event = QString::fromLatin1("Textcompletion: rotation"); | ||
820 | text = tr("You reached the end of the list\nof matching items.\n"); | ||
821 | break; | ||
822 | case PartialMatch: | ||
823 | if ( myCompletionMode == OGlobalSettings::CompletionShell || | ||
824 | myCompletionMode == OGlobalSettings::CompletionMan ) { | ||
825 | event = QString::fromLatin1("Textcompletion: partial match"); | ||
826 | text = tr("The completion is ambiguous, more than one\nmatch is available.\n"); | ||
827 | } | ||
828 | break; | ||
829 | case NoMatch: | ||
830 | if ( myCompletionMode == OGlobalSettings::CompletionShell ) { | ||
831 | event = QString::fromLatin1("Textcompletion: no match"); | ||
832 | text = tr("There is no matching item available.\n"); | ||
833 | } | ||
834 | break; | ||
835 | } | ||
836 | |||
837 | //if ( !text.isEmpty() ) | ||
838 | //ONotifyClient::event( event, text ); // FIXME: Revise for Opie? | ||
839 | } | ||
840 | |||
841 | // Implements the tree. Every node is a QChar and has a list of children, which | ||
842 | // are Nodes as well. | ||
843 | // QChar( 0x0 ) is used as the delimiter of a string; the last child of each | ||
844 | // inserted string is 0x0. | ||
845 | |||
846 | OCompTreeNode::~OCompTreeNode() | ||
847 | { | ||
848 | // delete all children | ||
849 | OCompTreeNode *cur = myChildren.begin(); | ||
850 | while (cur) { | ||
851 | OCompTreeNode * next = cur->next; | ||
852 | delete myChildren.remove(cur); | ||
853 | cur = next; | ||
854 | } | ||
855 | } | ||
856 | |||
857 | |||
858 | // Adds a child-node "ch" to this node. If such a node is already existant, | ||
859 | // it will not be created. Returns the new/existing node. | ||
860 | OCompTreeNode * OCompTreeNode::insert( const QChar& ch, bool sorted ) | ||
861 | { | ||
862 | OCompTreeNode *child = find( ch ); | ||
863 | if ( !child ) { | ||
864 | child = new OCompTreeNode( ch ); | ||
865 | |||
866 | // FIXME, first (slow) sorted insertion implementation | ||
867 | if ( sorted ) { | ||
868 | OCompTreeNode * prev = 0; | ||
869 | OCompTreeNode * cur = myChildren.begin(); | ||
870 | while ( cur ) { | ||
871 | if ( ch > *cur ) { | ||
872 | prev = cur; | ||
873 | cur = cur->next; | ||
874 | } else | ||
875 | break; | ||
876 | } | ||
877 | if (prev) | ||
878 | myChildren.insert( prev, child ); | ||
879 | else | ||
880 | myChildren.prepend(child); | ||
881 | } | ||
882 | |||
883 | else | ||
884 | myChildren.append( child ); | ||
885 | } | ||
886 | |||
887 | // implicit weighting: the more often an item is inserted, the higher | ||
888 | // priority it gets. | ||
889 | child->confirm(); | ||
890 | |||
891 | return child; | ||
892 | } | ||
893 | |||
894 | |||
895 | // Recursively removes a string from the tree (untested :-) | ||
896 | void OCompTreeNode::remove( const QString& string ) | ||
897 | { | ||
898 | OCompTreeNode *child = 0L; | ||
899 | |||
900 | if ( string.isEmpty() ) { | ||
901 | child = find( 0x0 ); | ||
902 | delete myChildren.remove( child ); | ||
903 | return; | ||
904 | } | ||
905 | |||
906 | QChar ch = string.at(0); | ||
907 | child = find( ch ); | ||
908 | if ( child ) { | ||
909 | child->remove( string.right( string.length() -1 ) ); | ||
910 | if ( child->myChildren.count() == 0 ) { | ||
911 | delete myChildren.remove( child ); | ||
912 | } | ||
913 | } | ||
914 | } | ||
915 | |||
916 | QStringList OCompletionMatchesWrapper::list() const { | ||
917 | if ( sortedList && dirty ) { | ||
918 | sortedList->sort(); | ||
919 | dirty = false; | ||
920 | |||
921 | stringList.clear(); | ||
922 | |||
923 | // high weight == sorted last -> reverse the sorting here | ||
924 | QValueListConstIterator<OSortableItem<QString> > it; | ||
925 | for ( it = sortedList->begin(); it != sortedList->end(); ++it ) | ||
926 | stringList.prepend( (*it).value() ); | ||
927 | } | ||
928 | |||
929 | return stringList; | ||
930 | } | ||
931 | |||
932 | OCompletionMatches::OCompletionMatches( bool sort_P ) | ||
933 | : _sorting( sort_P ) | ||
934 | { | ||
935 | } | ||
936 | |||
937 | OCompletionMatches::OCompletionMatches( const OCompletionMatchesWrapper& matches ) | ||
938 | : _sorting( matches.sorting()) | ||
939 | { | ||
940 | if( matches.sortedList != 0L ) | ||
941 | OCompletionMatchesList::operator=( *matches.sortedList ); | ||
942 | else { | ||
943 | QStringList l = matches.list(); | ||
944 | for( QStringList::ConstIterator it = l.begin(); | ||
945 | it != l.end(); | ||
946 | ++it ) | ||
947 | prepend( OSortableItem<QString, int>( 1, *it ) ); | ||
948 | } | ||
949 | } | ||
950 | |||
951 | OCompletionMatches::~OCompletionMatches() | ||
952 | { | ||
953 | } | ||
954 | |||
955 | QStringList OCompletionMatches::list( bool sort_P ) const | ||
956 | { | ||
957 | if( _sorting && sort_P ) | ||
958 | const_cast< OCompletionMatches* >( this )->sort(); | ||
959 | QStringList stringList; | ||
960 | // high weight == sorted last -> reverse the sorting here | ||
961 | for ( ConstIterator it = begin(); it != end(); ++it ) | ||
962 | stringList.prepend( (*it).value() ); | ||
963 | return stringList; | ||
964 | } | ||
965 | |||
966 | void OCompletionMatches::removeDuplicates() | ||
967 | { | ||
968 | Iterator it1, it2; | ||
969 | for ( it1 = begin(); it1 != end(); ++it1 ) { | ||
970 | for ( (it2 = it1), ++it2; it2 != end();) { | ||
971 | if( (*it1).value() == (*it2).value()) { | ||
972 | // use the max height | ||
973 | //(*it1).first = kMax( (*it1).index(), (*it2).index()); | ||
974 | (*it1).first = (*it2).index() < (*it1).index() ? (*it1).index() : (*it2).index(); | ||
975 | it2 = remove( it2 ); | ||
976 | continue; | ||
977 | } | ||
978 | ++it2; | ||
979 | } | ||
980 | } | ||
981 | } | ||
982 | |||
983 | void OCompTreeNodeList::append(OCompTreeNode *item) | ||
984 | { | ||
985 | m_count++; | ||
986 | if (!last) { | ||
987 | last = item; | ||
988 | last->next = 0; | ||
989 | first = item; | ||
990 | return; | ||
991 | } | ||
992 | last->next = item; | ||
993 | item->next = 0; | ||
994 | last = item; | ||
995 | } | ||
996 | |||
997 | void OCompTreeNodeList::prepend(OCompTreeNode *item) | ||
998 | { | ||
999 | m_count++; | ||
1000 | if (!last) { | ||
1001 | last = item; | ||
1002 | last->next = 0; | ||
1003 | first = item; | ||
1004 | return; | ||
1005 | } | ||
1006 | item->next = first; | ||
1007 | first = item; | ||
1008 | } | ||
1009 | |||
1010 | void OCompTreeNodeList::insert(OCompTreeNode *after, OCompTreeNode *item) | ||
1011 | { | ||
1012 | if (!after) { | ||
1013 | append(item); | ||
1014 | return; | ||
1015 | } | ||
1016 | |||
1017 | m_count++; | ||
1018 | |||
1019 | item->next = after->next; | ||
1020 | after->next = item; | ||
1021 | |||
1022 | if (after == last) | ||
1023 | last = item; | ||
1024 | } | ||
1025 | |||
1026 | OCompTreeNode *OCompTreeNodeList::remove(OCompTreeNode *item) | ||
1027 | { | ||
1028 | if (!first || !item) | ||
1029 | return 0; | ||
1030 | OCompTreeNode *cur = 0; | ||
1031 | |||
1032 | if (item == first) | ||
1033 | first = first->next; | ||
1034 | else { | ||
1035 | cur = first; | ||
1036 | while (cur && cur->next != item) cur = cur->next; | ||
1037 | if (!cur) | ||
1038 | return 0; | ||
1039 | cur->next = item->next; | ||
1040 | } | ||
1041 | if (item == last) | ||
1042 | last = cur; | ||
1043 | m_count--; | ||
1044 | return item; | ||
1045 | } | ||
1046 | |||
1047 | OCompTreeNode *OCompTreeNodeList::at(uint index) const | ||
1048 | { | ||
1049 | OCompTreeNode *cur = first; | ||
1050 | while (index-- && cur) cur = cur->next; | ||
1051 | return cur; | ||
1052 | } | ||
1053 | |||
1054 | // FIXME: Revise for Opie? | ||
1055 | //OZoneAllocator OCompTreeNode::alloc(8192); | ||
1056 | |||
1057 | //void OCompletion::virtual_hook( int, void* ) | ||
1058 | //{ /*BASE::virtual_hook( id, data );*/ } | ||
1059 | |||
1060 | //void OCompletionBase::virtual_hook( int, void* ) | ||
1061 | //{ /*BASE::virtual_hook( id, data );*/ } | ||
diff --git a/libopie2/qt3/opiecore/ocompletion.h b/libopie2/qt3/opiecore/ocompletion.h new file mode 100644 index 0000000..0317c1b --- a/dev/null +++ b/libopie2/qt3/opiecore/ocompletion.h | |||
@@ -0,0 +1,603 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | Originally part of the KDE Project | ||
4 | Copyright (C) 1999,2000 Carsten Pfeiffer <pfeiffer@kde.org> | ||
5 | =. | ||
6 | .=l. | ||
7 | .>+-= | ||
8 | _;:, .> :=|. This program is free software; you can | ||
9 | .> <`_, > . <= redistribute it and/or modify it under | ||
10 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
11 | .="- .-=="i, .._ License as published by the Free Software | ||
12 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
13 | ._= =} : or (at your option) any later version. | ||
14 | .%`+i> _;_. | ||
15 | .i_,=:_. -<s. This program is distributed in the hope that | ||
16 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
17 | : .. .:, . . . without even the implied warranty of | ||
18 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
19 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
20 | ..}^=.= = ; Library General Public License for more | ||
21 | ++= -. .` .: details. | ||
22 | : = ...= . :.=- | ||
23 | -. .:....=;==+<; You should have received a copy of the GNU | ||
24 | -_. . . )=. = Library General Public License along with | ||
25 | -- :-=` this library; see the file COPYING.LIB. | ||
26 | If not, write to the Free Software Foundation, | ||
27 | Inc., 59 Temple Place - Suite 330, | ||
28 | Boston, MA 02111-1307, USA. | ||
29 | */ | ||
30 | |||
31 | #ifndef OCOMPLETION_H | ||
32 | #define OCOMPLETION_H | ||
33 | |||
34 | /* QT */ | ||
35 | |||
36 | #include <qmap.h> | ||
37 | #include <qlist.h> | ||
38 | #include <qobject.h> | ||
39 | #include <qstring.h> | ||
40 | #include <qstringlist.h> | ||
41 | #include <qguardedptr.h> | ||
42 | |||
43 | /* OPIE */ | ||
44 | |||
45 | #include <opie2/oglobalsettings.h> | ||
46 | #include <opie2/osortablevaluelist.h> | ||
47 | |||
48 | /* FORWARDS */ | ||
49 | |||
50 | class OCompTreeNode; | ||
51 | class OCompletionPrivate; | ||
52 | class OCompletionBasePrivate; | ||
53 | class OCompletionMatchesWrapper; | ||
54 | class OCompletionMatches; | ||
55 | class QPopupMenu; | ||
56 | |||
57 | // FIXME: Do we need special ShortCut handling in Opie? If so, revise this. | ||
58 | class OShortcut | ||
59 | { | ||
60 | public: | ||
61 | bool isNull() const { return true; }; | ||
62 | bool operator == ( const OShortcut& bla ) const { return false; }; | ||
63 | }; | ||
64 | |||
65 | |||
66 | /** | ||
67 | * This class offers easy use of "auto-completion", "manual-completion" or | ||
68 | * "shell completion" on QString objects. A common use is completing filenames | ||
69 | * or URLs (see @ref OURLCompletion()). | ||
70 | * But it is not limited to URL-completion -- everything should be completable! | ||
71 | * The user should be able to complete email-addresses, telephone-numbers, | ||
72 | * commands, SQL queries, ... | ||
73 | * Every time your program knows what the user can type into an edit-field, you | ||
74 | * should offer completion. With OCompletion, this is very easy, and if you are | ||
75 | * using a line edit widget (@ref OLineEdit), it is even more easy. | ||
76 | * Basically, you tell a OCompletion object what strings should be completable | ||
77 | * and whenever completion should be invoked, you call @ref makeCompletion(). | ||
78 | * OLineEdit and (an editable) OComboBox even do this automatically for you. | ||
79 | * | ||
80 | * OCompletion offers the completed string via the signal @ref match() and | ||
81 | * all matching strings (when the result is ambiguous) via the method | ||
82 | * @ref allMatches(). | ||
83 | * | ||
84 | * Notice: auto-completion, shell completion and manual completion work | ||
85 | * slightly differently: | ||
86 | * | ||
87 | * @li auto-completion always returns a complete item as match. | ||
88 | * When more than one matching items are available, it will deliver just | ||
89 | * the first (depending on sorting order) item. Iterating over all matches | ||
90 | * is possible via @ref nextMatch() and @ref previousMatch(). | ||
91 | * | ||
92 | * @li popup-completion works in the same way, the only difference being that | ||
93 | * the completed items are not put into the edit-widget, but into a | ||
94 | * separate popup-box. | ||
95 | * | ||
96 | * @li manual completion works the same way as auto-completion, the | ||
97 | * subtle difference is, that it isn't invoked automatically while the user | ||
98 | * is typing, but only when the user presses a special key. The difference | ||
99 | * of manual and auto-completion is therefore only visible in UI classes, | ||
100 | * OCompletion needs to know whether to deliver partial matches | ||
101 | * (shell completion) or whole matches (auto/manual completion), therefore | ||
102 | * @ref OGlobalSettings::CompletionMan and | ||
103 | * @ref OGlobalSettings::CompletionAuto have the exact same effect in | ||
104 | * OCompletion. | ||
105 | * | ||
106 | * @li shell completion works like how shells complete filenames: | ||
107 | * when multiple matches are available, the longest possible string of all | ||
108 | * matches is returned (i.e. only a partial item). | ||
109 | * Iterating over all matching items (complete, not partial) is possible | ||
110 | * via @ref nextMatch() and @ref previousMatch(). | ||
111 | * | ||
112 | * You don't have to worry much about that though, OCompletion handles | ||
113 | * that for you, according to the setting @ref setCompletionMode(). | ||
114 | * The default setting is globally configured by the user and read | ||
115 | * from @ref OGlobalSettings::completionMode(). | ||
116 | * | ||
117 | * A short example: | ||
118 | * <pre> | ||
119 | * OCompletion completion; | ||
120 | * completion.setOrder( OCompletion::Sorted ); | ||
121 | * completion.addItem( "pfeiffer@kde.org" ); | ||
122 | * completion.addItem( "coolo@kde.org" ); | ||
123 | * completion.addItem( "carpdjih@sp.zrz.tu-berlin.de" ); | ||
124 | * completion.addItem( "carp@cs.tu-berlin.de" ); | ||
125 | * | ||
126 | * cout << completion.makeCompletion( "ca" ).latin1() << endl; | ||
127 | * </pre> | ||
128 | * In shell-completion-mode, this will be "carp"; in auto-completion- | ||
129 | * mode it will be "carp@cs.tu-berlin.de", as that is alphabetically | ||
130 | * smaller. | ||
131 | * If setOrder was set to Insertion, "carpdjih@sp.zrz.tu-berlin.de" | ||
132 | * would be completed in auto-completion-mode, as that was inserted before | ||
133 | * "carp@cs.tu-berlin.de". | ||
134 | * | ||
135 | * You can dynamically update the completable items by removing and adding them | ||
136 | * whenever you want. | ||
137 | * For advanced usage, you could even use multiple OCompletion objects. E.g. | ||
138 | * imagine an editor like kwrite with multiple open files. You could store | ||
139 | * items of each file in a different OCompletion object, so that you know (and | ||
140 | * tell the user) where a completion comes from. | ||
141 | * | ||
142 | * Note: OCompletion does not work with strings that contain 0x0 characters | ||
143 | * (unicode nul), as this is used internally as a delimiter. | ||
144 | * | ||
145 | * You may inherit from OCompletion and override @ref makeCompletion() in | ||
146 | * special cases (like reading directories/urls and then supplying the | ||
147 | * contents to OCompletion, as OURLCompletion does), but generally, this is | ||
148 | * not necessary. | ||
149 | * | ||
150 | * | ||
151 | * @short A generic class for completing QStrings | ||
152 | * @author Carsten Pfeiffer <pfeiffer@kde.org> | ||
153 | * @version $Id$ | ||
154 | */ | ||
155 | |||
156 | class OCompletion : public QObject | ||
157 | { | ||
158 | Q_ENUMS( CompOrder ) | ||
159 | Q_PROPERTY( CompOrder order READ order WRITE setOrder ) | ||
160 | Q_PROPERTY( bool ignoreCase READ ignoreCase WRITE setIgnoreCase ) | ||
161 | Q_PROPERTY( QStringList items READ items WRITE setItems ) | ||
162 | Q_OBJECT | ||
163 | |||
164 | public: | ||
165 | /** | ||
166 | * Constants that represent the order in which OCompletion performs | ||
167 | * completion-lookups. | ||
168 | */ | ||
169 | enum CompOrder { Sorted, Insertion, Weighted }; | ||
170 | |||
171 | /** | ||
172 | * Constructor, nothing special here :) | ||
173 | */ | ||
174 | OCompletion(); | ||
175 | |||
176 | // FIXME: copy constructor, assignment constructor... | ||
177 | |||
178 | /** | ||
179 | * Destructor, nothing special here, either. | ||
180 | */ | ||
181 | virtual ~OCompletion(); | ||
182 | |||
183 | /** | ||
184 | * Attempts to find an item in the list of available completions, | ||
185 | * that begins with @p string. Will either return the first matching item | ||
186 | * (if there is more than one match) or QString::null, if no match was | ||
187 | * found. | ||
188 | * | ||
189 | * In the latter case, a sound will be issued, depending on | ||
190 | * @ref isSoundsEnabled(). | ||
191 | * If a match was found, it will also be emitted via the signal | ||
192 | * @ref match(). | ||
193 | * | ||
194 | * If this is called twice or more often with the same string while no | ||
195 | * items were added or removed in the meantime, all available completions | ||
196 | * will be emitted via the signal @ref matches(). | ||
197 | * This happens only in shell-completion-mode. | ||
198 | * | ||
199 | * @returns the matching item, or QString::null if there is no matching | ||
200 | * item. | ||
201 | * @see #slotMakeCompletion | ||
202 | * @see #substringCompletion | ||
203 | */ | ||
204 | virtual QString makeCompletion( const QString& string ); | ||
205 | |||
206 | /** | ||
207 | * @returns a list of items which all contain @p text as a substring, | ||
208 | * i.e. not necessarily at the beginning. | ||
209 | * | ||
210 | * @see #makeCompletion | ||
211 | */ | ||
212 | QStringList substringCompletion( const QString& string ) const; | ||
213 | |||
214 | /** | ||
215 | * @returns the next item from the matching-items-list. | ||
216 | * When reaching the beginning, the list is rotated so it will return the | ||
217 | * last match and a sound is issued (depending on @ref isSoundsEnabled()). | ||
218 | * When there is no match, QString::null is returned and | ||
219 | * a sound is be issued. | ||
220 | * @see #slotPreviousMatch | ||
221 | */ | ||
222 | QString previousMatch(); | ||
223 | |||
224 | /** | ||
225 | * @returns the previous item from the matching-items-list | ||
226 | * When reaching the last item, the list is rotated, so it will return | ||
227 | * the first match and a sound is issued (depending on | ||
228 | * @ref isSoundsEnabled()). When there is no match, QString::null is | ||
229 | * returned and a sound is issued. | ||
230 | * @see #slotNextMatch | ||
231 | */ | ||
232 | QString nextMatch(); | ||
233 | |||
234 | /** | ||
235 | * @returns the last match. Might be useful if you need to check whether | ||
236 | * a completion is different from the last one. | ||
237 | * QString::null is returned when there is no last match. | ||
238 | */ | ||
239 | virtual const QString& lastMatch() const { return myLastMatch; } | ||
240 | |||
241 | /** | ||
242 | * Returns a list of all items inserted into OCompletion. This is useful | ||
243 | * if you need to save the state of a OCompletion object and restore it | ||
244 | * later. | ||
245 | * | ||
246 | * Important note: when @ref order() == Weighted, then every item in the | ||
247 | * stringlist has its weight appended, delimited by a colon. E.g. an item | ||
248 | * "www.kde.org" might look like "www.kde.org:4", where 4 is the weight. | ||
249 | * | ||
250 | * This is necessary so that you can save the items along with its | ||
251 | * weighting on disk and load them back with @ref setItems(), restoring its | ||
252 | * weight as well. If you really don't want the appended weightings, call | ||
253 | * @ref setOrder( OCompletion::Insertion ) | ||
254 | * before calling items(). | ||
255 | * | ||
256 | * @returns a list of all items | ||
257 | * @see #setItems | ||
258 | */ | ||
259 | QStringList items() const; | ||
260 | |||
261 | /** | ||
262 | * Sets the completion mode to Auto/Manual, Shell or None. | ||
263 | * If you don't set the mode explicitly, the global default value | ||
264 | * OGlobalSettings::completionMode() is used. | ||
265 | * @ref OGlobalSettings::CompletionNone disables completion. | ||
266 | * @see #completionMode | ||
267 | * @see #OGlobalSettings::completionMode | ||
268 | */ | ||
269 | virtual void setCompletionMode( OGlobalSettings::Completion mode ); | ||
270 | |||
271 | /** | ||
272 | * @returns the current completion mode. | ||
273 | * May be different from @ref OGlobalSettings::completionMode(), if you | ||
274 | * explicitly called @ref setCompletionMode(). | ||
275 | * @see #setCompletionMode | ||
276 | */ | ||
277 | OGlobalSettings::Completion completionMode() const { return myCompletionMode; }; | ||
278 | |||
279 | /** | ||
280 | * OCompletion offers three different ways in which it offers its items: | ||
281 | * @li in the order of insertion | ||
282 | * @li sorted alphabetically | ||
283 | * @li weighted | ||
284 | * | ||
285 | * Choosing weighted makes OCompletion perform an implicit weighting based | ||
286 | * on how often an item is inserted. Imagine a web browser with a location | ||
287 | * bar, where the user enters URLs. The more often a URL is entered, the | ||
288 | * higher priority it gets. | ||
289 | * | ||
290 | * Note: Setting the order to sorted only affects new inserted items, | ||
291 | * already existing items will stay in the current order. So you probably | ||
292 | * want to call setOrder( Sorted ) before inserting items, when you want | ||
293 | * everything sorted. | ||
294 | * | ||
295 | * Default is insertion order | ||
296 | * @see #order | ||
297 | */ | ||
298 | virtual void setOrder( CompOrder order ); | ||
299 | |||
300 | /** | ||
301 | * @returns the current completion order. | ||
302 | * @see #setOrder | ||
303 | */ | ||
304 | CompOrder order() const { return myOrder; } | ||
305 | |||
306 | /** | ||
307 | * Setting this to true makes OCompletion behave case insensitively. | ||
308 | * E.g. makeCompletion( "CA" ); might return "carp@cs.tu-berlin.de". | ||
309 | * Default is false (case sensitive). | ||
310 | * @see #ignoreCase | ||
311 | */ | ||
312 | virtual void setIgnoreCase( bool ignoreCase ); | ||
313 | |||
314 | /** | ||
315 | * @returns whether OCompletion acts case insensitively or not. | ||
316 | * Default is false (case sensitive). | ||
317 | * @see #setIgnoreCase | ||
318 | */ | ||
319 | bool ignoreCase() const { return myIgnoreCase; }; | ||
320 | |||
321 | /** | ||
322 | * @returns a list of all items matching the last completed string. | ||
323 | * Might take some time, when you have LOTS of items. | ||
324 | * | ||
325 | * @see #substringCompletion | ||
326 | */ | ||
327 | QStringList allMatches(); | ||
328 | |||
329 | /** | ||
330 | * @returns a list of all items matching @p string. | ||
331 | */ | ||
332 | QStringList allMatches( const QString& string ); | ||
333 | |||
334 | /** | ||
335 | * @returns a list of all items matching the last completed string. | ||
336 | * Might take some time, when you have LOTS of items. | ||
337 | * The matches are returned as OCompletionMatches, which also | ||
338 | * keeps the weight of the matches, allowing | ||
339 | * you to modify some matches or merge them with matches | ||
340 | * from another call to allWeightedMatches(), and sort the matches | ||
341 | * after that in order to have the matches ordered correctly | ||
342 | * | ||
343 | * @see #substringCompletion | ||
344 | */ | ||
345 | OCompletionMatches allWeightedMatches(); | ||
346 | |||
347 | /** | ||
348 | * @returns a list of all items matching @p string. | ||
349 | */ | ||
350 | OCompletionMatches allWeightedMatches( const QString& string ); | ||
351 | |||
352 | /** | ||
353 | * Enables/disables playing a sound when | ||
354 | * @li @ref makeCompletion() can't find a match | ||
355 | * @li there is a partial completion (= multiple matches in | ||
356 | * Shell-completion mode) | ||
357 | * @li @ref nextMatch() or @ref previousMatch() hit the last possible | ||
358 | * match -> rotation | ||
359 | * | ||
360 | * For playing the sounds, @ref ONotifyClient() is used. // FIXME: Revise this for Opie | ||
361 | * | ||
362 | * @see #isSoundsEnabled | ||
363 | */ | ||
364 | virtual void setEnableSounds( bool enable ) { myBeep = enable; } | ||
365 | |||
366 | /** | ||
367 | * Tells you whether OCompletion will play sounds on certain occasions. | ||
368 | * Default is enabled | ||
369 | * @see #enableSounds | ||
370 | * @see #disableSounds | ||
371 | */ | ||
372 | bool isSoundsEnabled() const { return myBeep; }; | ||
373 | |||
374 | /** | ||
375 | * @returns true when more than one match is found | ||
376 | * @see #multipleMatches | ||
377 | */ | ||
378 | bool hasMultipleMatches() const { return myHasMultipleMatches; }; | ||
379 | |||
380 | public slots: | ||
381 | /** | ||
382 | * Attempts to complete "string" and emits the completion via @ref match(). | ||
383 | * Same as @ref makeCompletion() (just as a slot). | ||
384 | * @see #makeCompletion | ||
385 | */ | ||
386 | void slotMakeCompletion( const QString& string ) { (void) makeCompletion( string ); }; | ||
387 | |||
388 | /** | ||
389 | * Searches the previous matching item and emits it via @ref match() | ||
390 | * Same as @ref previousMatch() (just as a slot). | ||
391 | * @see #previousMatch | ||
392 | */ | ||
393 | void slotPreviousMatch() { (void) previousMatch(); }; | ||
394 | |||
395 | /** | ||
396 | * Searches the next matching item and emits it via @ref match() | ||
397 | * Same as @ref nextMatch() (just as a slot). | ||
398 | * @see #nextMatch | ||
399 | */ | ||
400 | void slotNextMatch() { (void) nextMatch(); }; | ||
401 | |||
402 | /** | ||
403 | * Inserts @p items into the list of possible completions. | ||
404 | * Does the same as @ref setItems(), but does not call @ref clear() before. | ||
405 | */ | ||
406 | void insertItems( const QStringList& items ); | ||
407 | |||
408 | /** | ||
409 | * Sets the list of items available for completion. Removes all previous | ||
410 | * items. | ||
411 | * | ||
412 | * Notice: when order() == Weighted, then the weighting is looked up for | ||
413 | * every item in the stringlist. Every item should have ":number" appended, | ||
414 | * where number is an unsigned integer, specifying the weighting. | ||
415 | * | ||
416 | * If you don't like this, call | ||
417 | * setOrder( OCompletion::Insertion ) | ||
418 | * before calling setItems(). | ||
419 | * | ||
420 | * @see #items | ||
421 | */ | ||
422 | virtual void setItems( const QStringList& ); | ||
423 | |||
424 | /** | ||
425 | * Adds an item to the list of available completions. | ||
426 | * Resets the current item-state (@ref previousMatch() and @ref nextMatch() | ||
427 | * won't work anymore). | ||
428 | */ | ||
429 | void addItem( const QString& ); | ||
430 | |||
431 | /** | ||
432 | * Adds an item to the list of available completions. | ||
433 | * Resets the current item-state (@ref previousMatch() and @ref nextMatch() | ||
434 | * won't work anymore). | ||
435 | * | ||
436 | * Sets the weighting of the item to @p weight or adds it to the current | ||
437 | * weighting if the item is already available. The weight has to be greater | ||
438 | * than 1 to take effect (default weight is 1). | ||
439 | */ | ||
440 | void addItem( const QString&, uint weight ); | ||
441 | |||
442 | /** | ||
443 | * Removes an item from the list of available completions. | ||
444 | * Resets the current item-state (@ref previousMatch() and @ref nextMatch() | ||
445 | * won't work anymore). | ||
446 | */ | ||
447 | void removeItem( const QString& ); | ||
448 | |||
449 | /** | ||
450 | * Removes all inserted items. | ||
451 | */ | ||
452 | virtual void clear(); | ||
453 | |||
454 | signals: | ||
455 | /** | ||
456 | * The matching item. Will be emitted by @ref makeCompletion(), | ||
457 | * @ref previousMatch() or @ref nextMatch(). May be QString::null if there | ||
458 | * is no matching item. | ||
459 | */ | ||
460 | void match( const QString& ); | ||
461 | |||
462 | /** | ||
463 | * All matching items. Will be emitted by @ref makeCompletion() in shell- | ||
464 | * completion-mode, when the same string is passed to makeCompletion twice | ||
465 | * or more often. | ||
466 | */ | ||
467 | void matches( const QStringList& ); | ||
468 | |||
469 | /** | ||
470 | * This signal is emitted, when calling @ref makeCompletion() and more than | ||
471 | * one matching item is found. | ||
472 | * @see #hasMultipleMatches | ||
473 | */ | ||
474 | void multipleMatches(); | ||
475 | |||
476 | protected: | ||
477 | /** | ||
478 | * This method is called after a completion is found and before the | ||
479 | * matching string is emitted. You can override this method to modify the | ||
480 | * string that will be emitted. | ||
481 | * This is necessary e.g. in @ref OURLCompletion(), where files with spaces | ||
482 | * in their names are shown escaped ("filename\ with\ spaces"), but stored | ||
483 | * unescaped inside OCompletion. | ||
484 | * Never delete that pointer! | ||
485 | * | ||
486 | * Default implementation does nothing. | ||
487 | * @see #postProcessMatches | ||
488 | */ | ||
489 | virtual void postProcessMatch( QString * /*match*/ ) const {} | ||
490 | |||
491 | /** | ||
492 | * This method is called before a list of all available completions is | ||
493 | * emitted via @ref matches. You can override this method to modify the | ||
494 | * found items before @ref match() or @ref matches() are emitted. | ||
495 | * Never delete that pointer! | ||
496 | * | ||
497 | * Default implementation does nothing. | ||
498 | * @see #postProcessMatch | ||
499 | */ | ||
500 | virtual void postProcessMatches( QStringList * /*matches*/ ) const {} | ||
501 | |||
502 | /** | ||
503 | * This method is called before a list of all available completions is | ||
504 | * emitted via @ref matches. You can override this method to modify the | ||
505 | * found items before @ref match() or @ref matches() are emitted. | ||
506 | * Never delete that pointer! | ||
507 | * | ||
508 | * Default implementation does nothing. | ||
509 | * @see #postProcessMatch | ||
510 | */ | ||
511 | virtual void postProcessMatches( OCompletionMatches * /*matches*/ ) const {} | ||
512 | |||
513 | private: | ||
514 | void addWeightedItem( const QString& ); | ||
515 | QString findCompletion( const QString& string ); | ||
516 | void findAllCompletions( const QString&, OCompletionMatchesWrapper *matches, bool& hasMultipleMatches ) const; | ||
517 | |||
518 | void extractStringsFromNode( const OCompTreeNode *, | ||
519 | const QString& beginning, | ||
520 | OCompletionMatchesWrapper *matches, | ||
521 | bool addWeight = false ) const; | ||
522 | void extractStringsFromNodeCI( const OCompTreeNode *, | ||
523 | const QString& beginning, | ||
524 | const QString& restString, | ||
525 | OCompletionMatchesWrapper *matches) const; | ||
526 | |||
527 | enum BeepMode { NoMatch, PartialMatch, Rotation }; | ||
528 | void doBeep( BeepMode ) const; | ||
529 | |||
530 | OGlobalSettings::Completion myCompletionMode; | ||
531 | |||
532 | CompOrder myOrder; | ||
533 | QString myLastString; | ||
534 | QString myLastMatch; | ||
535 | QString myCurrentMatch; | ||
536 | OCompTreeNode * myTreeRoot; | ||
537 | QStringList myRotations; | ||
538 | bool myBeep; | ||
539 | bool myIgnoreCase; | ||
540 | bool myHasMultipleMatches; | ||
541 | uint myRotationIndex; | ||
542 | |||
543 | private: | ||
544 | OCompletionPrivate *d; | ||
545 | }; | ||
546 | |||
547 | // some more helper stuff | ||
548 | typedef OSortableValueList<QString> OCompletionMatchesList; | ||
549 | class OCompletionMatchesPrivate; | ||
550 | |||
551 | /** | ||
552 | * This structure is returned by @ref OCompletion::allWeightedMatches . | ||
553 | * It also keeps the weight of the matches, allowing | ||
554 | * you to modify some matches or merge them with matches | ||
555 | * from another call to allWeightedMatches(), and sort the matches | ||
556 | * after that in order to have the matches ordered correctly | ||
557 | * | ||
558 | * Example (a simplified example of what Oonqueror's completion does): | ||
559 | * <pre> | ||
560 | * OCompletionMatches matches = completion->allWeightedMatches( location ); | ||
561 | * if( !location.startsWith( "www." )) | ||
562 | matches += completion->allWeightedmatches( "www." + location" ); | ||
563 | * matches.removeDuplicates(); | ||
564 | * QStringList list = matches.list(); | ||
565 | * </pre> | ||
566 | * | ||
567 | * @short List for keeping matches returned from OCompletion | ||
568 | */ | ||
569 | |||
570 | class OCompletionMatches | ||
571 | : public OCompletionMatchesList | ||
572 | { | ||
573 | public: | ||
574 | OCompletionMatches( bool sort ); | ||
575 | /** | ||
576 | * @internal | ||
577 | */ | ||
578 | OCompletionMatches( const OCompletionMatchesWrapper& matches ); | ||
579 | ~OCompletionMatches(); | ||
580 | /** | ||
581 | * Removes duplicate matches. Needed only when you merged several matches | ||
582 | * results and there's a possibility of duplicates. | ||
583 | */ | ||
584 | void removeDuplicates(); | ||
585 | /** | ||
586 | * Returns the matches as a QStringList. | ||
587 | * @param sort if false, the matches won't be sorted before the conversion, | ||
588 | * use only if you're sure the sorting is not needed | ||
589 | */ | ||
590 | QStringList list( bool sort = true ) const; | ||
591 | /** | ||
592 | * If sorting() returns false, the matches aren't sorted by their weight, | ||
593 | * even if true is passed to list(). | ||
594 | */ | ||
595 | bool sorting() const { | ||
596 | return _sorting; | ||
597 | } | ||
598 | private: | ||
599 | bool _sorting; | ||
600 | OCompletionMatchesPrivate* d; | ||
601 | }; | ||
602 | |||
603 | #endif // OCOMPLETION_H | ||
diff --git a/libopie2/qt3/opiecore/ocompletionbase.cpp b/libopie2/qt3/opiecore/ocompletionbase.cpp new file mode 100644 index 0000000..6ff129a --- a/dev/null +++ b/libopie2/qt3/opiecore/ocompletionbase.cpp | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | |||
4 | Copyright (C) 2003 Michael Lauer <mickey@tm.informatik.uni-frankfurt.de> | ||
5 | Inspired by the KDE completion classes which are | ||
6 | Copyright (C) 2000 Dawit Alemayehu <adawit@kde.org> | ||
7 | =. | ||
8 | .=l. | ||
9 | .>+-= | ||
10 | _;:, .> :=|. This program is free software; you can | ||
11 | .> <`_, > . <= redistribute it and/or modify it under | ||
12 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
13 | .="- .-=="i, .._ License as published by the Free Software | ||
14 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
15 | ._= =} : or (at your option) any later version. | ||
16 | .%`+i> _;_. | ||
17 | .i_,=:_. -<s. This program is distributed in the hope that | ||
18 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
19 | : .. .:, . . . without even the implied warranty of | ||
20 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
21 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
22 | ..}^=.= = ; Library General Public License for more | ||
23 | ++= -. .` .: details. | ||
24 | : = ...= . :.=- | ||
25 | -. .:....=;==+<; You should have received a copy of the GNU | ||
26 | -_. . . )=. = Library General Public License along with | ||
27 | -- :-=` this library; see the file COPYING.LIB. | ||
28 | If not, write to the Free Software Foundation, | ||
29 | Inc., 59 Temple Place - Suite 330, | ||
30 | Boston, MA 02111-1307, USA. | ||
31 | */ | ||
32 | |||
33 | #include <opie2/ocompletion.h> | ||
34 | #include <opie2/ocompletionbase.h> | ||
35 | |||
36 | OCompletionBase::OCompletionBase() | ||
37 | { | ||
38 | m_delegate = 0L; | ||
39 | // Assign the default completion type to use. | ||
40 | m_iCompletionMode = OGlobalSettings::completionMode(); | ||
41 | |||
42 | // Initialize all key-bindings to 0 by default so that | ||
43 | // the event filter will use the global settings. | ||
44 | useGlobalKeyBindings(); | ||
45 | |||
46 | // By default we initialize everything to false. | ||
47 | // All the variables would be setup properly when | ||
48 | // the appropriate member functions are called. | ||
49 | setup( false, false, false ); | ||
50 | } | ||
51 | |||
52 | OCompletionBase::~OCompletionBase() | ||
53 | { | ||
54 | if( m_bAutoDelCompObj && m_pCompObj ) | ||
55 | { | ||
56 | delete m_pCompObj; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | void OCompletionBase::setDelegate( OCompletionBase *delegate ) | ||
61 | { | ||
62 | m_delegate = delegate; | ||
63 | |||
64 | if ( m_delegate ) { | ||
65 | m_delegate->m_bAutoDelCompObj = m_bAutoDelCompObj; | ||
66 | m_delegate->m_bHandleSignals = m_bHandleSignals; | ||
67 | m_delegate->m_bEmitSignals = m_bEmitSignals; | ||
68 | m_delegate->m_iCompletionMode = m_iCompletionMode; | ||
69 | m_delegate->m_keyMap = m_keyMap; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | OCompletion* OCompletionBase::completionObject( bool hsig ) | ||
74 | { | ||
75 | if ( m_delegate ) | ||
76 | return m_delegate->completionObject( hsig ); | ||
77 | |||
78 | if ( !m_pCompObj ) | ||
79 | { | ||
80 | setCompletionObject( new OCompletion(), hsig ); | ||
81 | m_bAutoDelCompObj = true; | ||
82 | } | ||
83 | return m_pCompObj; | ||
84 | } | ||
85 | |||
86 | void OCompletionBase::setCompletionObject( OCompletion* compObj, bool hsig ) | ||
87 | { | ||
88 | if ( m_delegate ) { | ||
89 | m_delegate->setCompletionObject( compObj, hsig ); | ||
90 | return; | ||
91 | } | ||
92 | |||
93 | if ( m_bAutoDelCompObj && compObj != m_pCompObj ) | ||
94 | delete m_pCompObj; | ||
95 | |||
96 | m_pCompObj = compObj; | ||
97 | |||
98 | // We emit rotation and completion signals | ||
99 | // if completion object is not NULL. | ||
100 | setup( false, hsig, !m_pCompObj.isNull() ); | ||
101 | } | ||
102 | |||
103 | // BC: Inline this function and possibly rename it to setHandleEvents??? (DA) | ||
104 | void OCompletionBase::setHandleSignals( bool handle ) | ||
105 | { | ||
106 | if ( m_delegate ) | ||
107 | m_delegate->setHandleSignals( handle ); | ||
108 | else | ||
109 | m_bHandleSignals = handle; | ||
110 | } | ||
111 | |||
112 | void OCompletionBase::setCompletionMode( OGlobalSettings::Completion mode ) | ||
113 | { | ||
114 | if ( m_delegate ) { | ||
115 | m_delegate->setCompletionMode( mode ); | ||
116 | return; | ||
117 | } | ||
118 | |||
119 | m_iCompletionMode = mode; | ||
120 | // Always sync up OCompletion mode with ours as long as we | ||
121 | // are performing completions. | ||
122 | if( m_pCompObj && m_iCompletionMode != OGlobalSettings::CompletionNone ) | ||
123 | m_pCompObj->setCompletionMode( m_iCompletionMode ); | ||
124 | } | ||
125 | |||
126 | bool OCompletionBase::setKeyBinding( KeyBindingType item, const OShortcut& cut ) | ||
127 | { | ||
128 | if ( m_delegate ) | ||
129 | return m_delegate->setKeyBinding( item, cut ); | ||
130 | |||
131 | |||
132 | if( !cut.isNull() ) | ||
133 | { | ||
134 | for( KeyBindingMap::Iterator it = m_keyMap.begin(); it != m_keyMap.end(); ++it ) | ||
135 | if( it.data() == cut ) return false; | ||
136 | } | ||
137 | m_keyMap.replace( item, cut ); | ||
138 | return true; | ||
139 | } | ||
140 | |||
141 | void OCompletionBase::useGlobalKeyBindings() | ||
142 | { | ||
143 | |||
144 | /* | ||
145 | |||
146 | if ( m_delegate ) { | ||
147 | m_delegate->useGlobalKeyBindings(); | ||
148 | return; | ||
149 | } | ||
150 | |||
151 | m_keyMap.clear(); | ||
152 | m_keyMap.insert( TextCompletion, 0 ); | ||
153 | m_keyMap.insert( PrevCompletionMatch, 0 ); | ||
154 | m_keyMap.insert( NextCompletionMatch, 0 ); | ||
155 | m_keyMap.insert( SubstringCompletion, 0 ); | ||
156 | |||
157 | */ | ||
158 | |||
159 | } | ||
160 | |||
161 | void OCompletionBase::setup( bool autodel, bool hsig, bool esig ) | ||
162 | { | ||
163 | if ( m_delegate ) { | ||
164 | m_delegate->setup( autodel, hsig, esig ); | ||
165 | return; | ||
166 | } | ||
167 | |||
168 | m_bAutoDelCompObj = autodel; | ||
169 | m_bHandleSignals = hsig; | ||
170 | m_bEmitSignals = esig; | ||
171 | } | ||
diff --git a/libopie2/qt3/opiecore/ocompletionbase.h b/libopie2/qt3/opiecore/ocompletionbase.h new file mode 100644 index 0000000..517667e --- a/dev/null +++ b/libopie2/qt3/opiecore/ocompletionbase.h | |||
@@ -0,0 +1,403 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | |||
4 | Copyright (C) 2003 Michael Lauer <mickey@tm.informatik.uni-frankfurt.de> | ||
5 | Inspired by the KDE completion classes which are | ||
6 | Copyright (C) 2000 Dawit Alemayehu <adawit@kde.org> | ||
7 | =. | ||
8 | .=l. | ||
9 | .>+-= | ||
10 | _;:, .> :=|. This program is free software; you can | ||
11 | .> <`_, > . <= redistribute it and/or modify it under | ||
12 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
13 | .="- .-=="i, .._ License as published by the Free Software | ||
14 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
15 | ._= =} : or (at your option) any later version. | ||
16 | .%`+i> _;_. | ||
17 | .i_,=:_. -<s. This program is distributed in the hope that | ||
18 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
19 | : .. .:, . . . without even the implied warranty of | ||
20 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
21 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
22 | ..}^=.= = ; Library General Public License for more | ||
23 | ++= -. .` .: details. | ||
24 | : = ...= . :.=- | ||
25 | -. .:....=;==+<; You should have received a copy of the GNU | ||
26 | -_. . . )=. = Library General Public License along with | ||
27 | -- :-=` this library; see the file COPYING.LIB. | ||
28 | If not, write to the Free Software Foundation, | ||
29 | Inc., 59 Temple Place - Suite 330, | ||
30 | Boston, MA 02111-1307, USA. | ||
31 | */ | ||
32 | |||
33 | #ifndef OCOMPLETIONBASE_H | ||
34 | #define OCOMPLETIONBASE_H | ||
35 | |||
36 | /** | ||
37 | * An abstract base class for adding a completion feature | ||
38 | * into widgets. | ||
39 | * | ||
40 | * This is a convenience class that provides the basic functions | ||
41 | * needed to add text completion support into widgets. All that | ||
42 | * is required is an implementation for the pure virtual function | ||
43 | * @ref setCompletedText. Refer to @ref OLineEdit or @ref OComboBox | ||
44 | * to see how easily such support can be added using this as a base | ||
45 | * class. | ||
46 | * | ||
47 | * @short An abstract class for adding text completion support to widgets. | ||
48 | * @author Dawit Alemayehu <adawit@kde.org> | ||
49 | */ | ||
50 | |||
51 | class OCompletionBase | ||
52 | { | ||
53 | |||
54 | public: | ||
55 | |||
56 | /** | ||
57 | * Constants that represent the items whose short-cut | ||
58 | * key-binding is programmable. The default key-bindings | ||
59 | * for these items are defined in @ref OStdAccel. | ||
60 | */ | ||
61 | enum KeyBindingType { | ||
62 | /** | ||
63 | * Text completion (by default Ctrl-E). | ||
64 | */ | ||
65 | TextCompletion, | ||
66 | /** | ||
67 | * Switch to previous completion (by default Ctrl-Up). | ||
68 | */ | ||
69 | PrevCompletionMatch, | ||
70 | /** | ||
71 | * Switch to next completion (by default Ctrl-Down). | ||
72 | */ | ||
73 | NextCompletionMatch, | ||
74 | /** | ||
75 | * Substring completion (by default Ctrl-T). | ||
76 | */ | ||
77 | SubstringCompletion | ||
78 | }; | ||
79 | |||
80 | |||
81 | // Map for the key binding types mentioned above. | ||
82 | typedef QMap<KeyBindingType, OShortcut> KeyBindingMap; | ||
83 | |||
84 | /** | ||
85 | * Default constructor. | ||
86 | */ | ||
87 | OCompletionBase(); | ||
88 | |||
89 | /** | ||
90 | * Destructor. | ||
91 | */ | ||
92 | virtual ~OCompletionBase(); | ||
93 | |||
94 | /** | ||
95 | * Returns a pointer to the current completion object. | ||
96 | * | ||
97 | * If the object does not exist, it is automatically | ||
98 | * created. Note that the completion object created | ||
99 | * here is used by default to handle the signals | ||
100 | * internally. It is also deleted when this object's | ||
101 | * destructor is invoked. If you do not want these | ||
102 | * default settings, use @ref setAutoDeleteCompletionObject | ||
103 | * and @ref setHandleSignals to change the behavior. | ||
104 | * Alternatively, you can set the boolean parameter to | ||
105 | * false to disable the automatic handling of the signals | ||
106 | * by this object. Note that the boolean argument will be | ||
107 | * ignored if there already exists a completion object since | ||
108 | * no new object needs to be created. You need to use either | ||
109 | * @ref setHandleSignals or @ref setCompletionObject for | ||
110 | * such cases depending on your requirement. | ||
111 | * | ||
112 | * @param hsig if true, handles signals internally. | ||
113 | * @return a pointer the completion object. | ||
114 | */ | ||
115 | OCompletion* completionObject( bool hsig = true ); | ||
116 | |||
117 | /** | ||
118 | * Sets up the completion object to be used. | ||
119 | * | ||
120 | * This method assigns the completion object and sets it | ||
121 | * up to automatically handle the completion and rotation | ||
122 | * signals internally. You should use this function if | ||
123 | * you want to share one completion object among you widgets | ||
124 | * or need to use a customized completion object. | ||
125 | * | ||
126 | * The object assigned through this method is not deleted | ||
127 | * when this object's destructor is invoked unless you | ||
128 | * explicitly call @ref setAutoDeleteCompletionObject after | ||
129 | * calling this method. Also if you do not want the signals | ||
130 | * to be handled by an internal implementation, be sure to | ||
131 | * set the bool argument to false. | ||
132 | * | ||
133 | * This method is also called when a completion-object is created | ||
134 | * automatically, when completionObject() is called the first time. | ||
135 | * | ||
136 | * @param compObj a @ref OCompletion() or a derived child object. | ||
137 | * @param hsig if true, handles signals internally. | ||
138 | */ | ||
139 | virtual void setCompletionObject( OCompletion* /*compObj*/, bool hsig = true ); | ||
140 | |||
141 | /** | ||
142 | * Enables this object to handle completion and rotation | ||
143 | * events internally. | ||
144 | * | ||
145 | * This function simply assigns a boolean value that | ||
146 | * indicates whether it should handle rotation and | ||
147 | * completion events or not. Note that this does not | ||
148 | * stop the object from emitting signals when these | ||
149 | * events occur. | ||
150 | * | ||
151 | * @param handle if true, handle completion & rotation internally. | ||
152 | */ | ||
153 | virtual void setHandleSignals( bool /*handle*/ ); | ||
154 | |||
155 | /** | ||
156 | * Returns true if the completion object is deleted | ||
157 | * upon this widget's destruction. | ||
158 | * | ||
159 | * See @ref setCompletionObject() and @ref enableCompletion() | ||
160 | * for details. | ||
161 | * | ||
162 | * @return true if the completion object | ||
163 | */ | ||
164 | bool isCompletionObjectAutoDeleted() const { | ||
165 | return m_delegate ? m_delegate->isCompletionObjectAutoDeleted() : m_bAutoDelCompObj; | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * Sets the completion object when this widget's destructor | ||
170 | * is called. | ||
171 | * | ||
172 | * If the argument is set to true, the completion object | ||
173 | * is deleted when this widget's destructor is called. | ||
174 | * | ||
175 | * @param autoDelete if true, delete completion object on destruction. | ||
176 | */ | ||
177 | void setAutoDeleteCompletionObject( bool autoDelete ) { | ||
178 | if ( m_delegate ) | ||
179 | m_delegate->setAutoDeleteCompletionObject( autoDelete ); | ||
180 | else | ||
181 | m_bAutoDelCompObj = autoDelete; | ||
182 | } | ||
183 | |||
184 | /** | ||
185 | * Sets the widget's ability to emit text completion and | ||
186 | * rotation signals. | ||
187 | * | ||
188 | * Invoking this function with @p enable set to @p false will | ||
189 | * cause the completion & rotation signals not to be emitted. | ||
190 | * However, unlike setting the completion object to @p NULL | ||
191 | * using @ref setCompletionObject, disabling the emition of | ||
192 | * the signals through this method does not affect the current | ||
193 | * completion object. | ||
194 | * | ||
195 | * There is no need to invoke this function by default. When a | ||
196 | * completion object is created through @ref completionObject or | ||
197 | * @ref setCompletionObject, these signals are set to emit | ||
198 | * automatically. Also note that disabling this signals will not | ||
199 | * necessarily interfere with the objects ability to handle these | ||
200 | * events internally. See @ref setHandleSignals. | ||
201 | * | ||
202 | * @param enable if false, disables the emition of completion & rotation signals. | ||
203 | */ | ||
204 | void setEnableSignals( bool enable ) { | ||
205 | if ( m_delegate ) | ||
206 | m_delegate->setEnableSignals( enable ); | ||
207 | else | ||
208 | m_bEmitSignals = enable; | ||
209 | } | ||
210 | |||
211 | /** | ||
212 | * Returns true if the object handles the signals | ||
213 | * | ||
214 | * @return true if this signals are handled internally. | ||
215 | */ | ||
216 | bool handleSignals() const { return m_delegate ? m_delegate->handleSignals() : m_bHandleSignals; } | ||
217 | |||
218 | /** | ||
219 | * Returns true if the object emits the signals | ||
220 | * | ||
221 | * @return true if signals are emitted | ||
222 | */ | ||
223 | bool emitSignals() const { return m_delegate ? m_delegate->emitSignals() : m_bEmitSignals; } | ||
224 | |||
225 | /** | ||
226 | * Sets the type of completion to be used. | ||
227 | * | ||
228 | * The completion modes supported are those defined in | ||
229 | * @ref OGlobalSettings(). See below. | ||
230 | * | ||
231 | * @param mode Completion type: | ||
232 | * @li CompletionNone: Disables completion feature. | ||
233 | * @li CompletionAuto: Attempts to find a match & | ||
234 | * fills-in the remaining text. | ||
235 | * @li CompletionMan: Acts the same as the above | ||
236 | * except the action has to be | ||
237 | * manually triggered through | ||
238 | * pre-defined completion key. | ||
239 | * @li CompletionShell: Mimics the completion feature | ||
240 | * found in typical *nix shell | ||
241 | * environments. | ||
242 | * @li CompletionPopup: Shows all available completions at once, | ||
243 | * in a listbox popping up. | ||
244 | */ | ||
245 | virtual void setCompletionMode( OGlobalSettings::Completion mode ); | ||
246 | |||
247 | /** | ||
248 | * Returns the current completion mode. | ||
249 | * | ||
250 | * The return values are of type @ref OGlobalSettings::Completion. | ||
251 | * See @ref setCompletionMode() for details. | ||
252 | * | ||
253 | * @return the completion mode. | ||
254 | */ | ||
255 | OGlobalSettings::Completion completionMode() const { | ||
256 | return m_delegate ? m_delegate->completionMode() : m_iCompletionMode; | ||
257 | } | ||
258 | |||
259 | /** | ||
260 | * Sets the key-binding to be used for manual text | ||
261 | * completion, text rotation in a history list as | ||
262 | * well as a completion list. | ||
263 | * | ||
264 | * | ||
265 | * When the keys set by this function are pressed, a | ||
266 | * signal defined by the inheriting widget will be activated. | ||
267 | * If the default value or 0 is specified by the second | ||
268 | * parameter, then the key-binding as defined in the global | ||
269 | * setting should be used. This method returns false value | ||
270 | * for @p key is negative or the supplied key-binding conflicts | ||
271 | * with the ones set for one of the other features. | ||
272 | * | ||
273 | * NOTE: To use a modifier key (Shift, Ctrl, Alt) as part of | ||
274 | * the key-binding simply simply @p sum up the values of the | ||
275 | * modifier and the actual key. For example, to use CTRL+E as | ||
276 | * a key binding for one of the items, you would simply supply | ||
277 | * @p "Qt::CtrlButton + Qt::Key_E" as the second argument to this | ||
278 | * function. | ||
279 | * | ||
280 | * @param item the feature whose key-binding needs to be set: | ||
281 | * | ||
282 | * @li TextCompletionthe manual completion key-binding. | ||
283 | * @li PrevCompletionMatchthe previous match key for multiple completion. | ||
284 | * @li NextCompletionMatchthe next match key for for multiple completion. | ||
285 | * @li SubstringCompletion the key for substring completion | ||
286 | * | ||
287 | * @param key key-binding used to rotate down in a list. | ||
288 | * | ||
289 | * @return true if key-binding can successfully be set. | ||
290 | * @see #getKeyBinding | ||
291 | */ | ||
292 | bool setKeyBinding( KeyBindingType /*item*/ , const OShortcut& cut ); | ||
293 | |||
294 | /** | ||
295 | * Returns the key-binding used for the specified item. | ||
296 | * | ||
297 | * This methods returns the key-binding used to activate | ||
298 | * the feature feature given by @p item. If the binding | ||
299 | * contains modifier key(s), the SUM of the modifier key | ||
300 | * and the actual key code are returned. | ||
301 | * | ||
302 | * @return the key-binding used for the feature given by @p item. | ||
303 | * @see #setKeyBinding | ||
304 | */ | ||
305 | const OShortcut& getKeyBinding( KeyBindingType item ) const { | ||
306 | return m_delegate ? m_delegate->getKeyBinding( item ) : m_keyMap[ item ]; | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * Sets this object to use global values for key-bindings. | ||
311 | * | ||
312 | * This method changes the values of the key bindings for | ||
313 | * rotation and completion features to the default values | ||
314 | * provided in OGlobalSettings. | ||
315 | * | ||
316 | * NOTE: By default inheriting widgets should uses the | ||
317 | * global key-bindings so that there will be no need to | ||
318 | * call this method. | ||
319 | */ | ||
320 | void useGlobalKeyBindings(); | ||
321 | |||
322 | /** | ||
323 | * A pure virtual function that must be implemented by | ||
324 | * all inheriting classes. | ||
325 | * | ||
326 | * This function is intended to allow external completion | ||
327 | * implementations to set completed text appropriately. It | ||
328 | * is mostly relevant when the completion mode is set to | ||
329 | * CompletionAuto and CompletionManual modes. See | ||
330 | * @ref OCompletionBase::setCompletedText. | ||
331 | * Does nothing in CompletionPopup mode, as all available | ||
332 | * matches will be shown in the popup. | ||
333 | * | ||
334 | * @param text the completed text to be set in the widget. | ||
335 | */ | ||
336 | virtual void setCompletedText( const QString& text ) = 0; | ||
337 | |||
338 | /** | ||
339 | * A pure virtual function that must be implemented by | ||
340 | * all inheriting classes. | ||
341 | * | ||
342 | */ | ||
343 | virtual void setCompletedItems( const QStringList& items ) = 0; | ||
344 | |||
345 | /** | ||
346 | * Returns a pointer to the completion object. | ||
347 | * | ||
348 | * This method is only different from @ref completionObject() | ||
349 | * in that it does not create a new OCompletion object even if | ||
350 | * the internal pointer is @p NULL. Use this method to get the | ||
351 | * pointer to a completion object when inheriting so that you | ||
352 | * won't inadvertently create it!! | ||
353 | * | ||
354 | * @returns the completion object or NULL if one does not exist. | ||
355 | */ | ||
356 | OCompletion* compObj() const { return m_delegate ? m_delegate->compObj() : (OCompletion*) m_pCompObj; } | ||
357 | |||
358 | protected: | ||
359 | /** | ||
360 | * Returns a key-binding map | ||
361 | * | ||
362 | * This method is the same as @ref getKeyBinding() except it | ||
363 | * returns the whole keymap containing the key-bindings. | ||
364 | * | ||
365 | * @return the key-binding used for the feature given by @p item. | ||
366 | */ | ||
367 | KeyBindingMap getKeyBindings() const { return m_delegate ? m_delegate->getKeyBindings() : m_keyMap; } | ||
368 | |||
369 | void setDelegate( OCompletionBase *delegate ); | ||
370 | OCompletionBase *delegate() const { return m_delegate; } | ||
371 | |||
372 | private: | ||
373 | // This method simply sets the autodelete boolean for | ||
374 | // the completion object, the emit signals and handle | ||
375 | // signals internally flags to the provided values. | ||
376 | void setup( bool, bool, bool ); | ||
377 | |||
378 | // Flag that determined whether the completion object | ||
379 | // should be deleted when this object is destroyed. | ||
380 | bool m_bAutoDelCompObj; | ||
381 | // Determines whether this widget handles completion signals | ||
382 | // internally or not | ||
383 | bool m_bHandleSignals; | ||
384 | // Determines whether this widget fires rotation signals | ||
385 | bool m_bEmitSignals; | ||
386 | // Stores the completion mode locally. | ||
387 | OGlobalSettings::Completion m_iCompletionMode; | ||
388 | // Pointer to Completion object. | ||
389 | QGuardedPtr<OCompletion> m_pCompObj; | ||
390 | // Keybindings | ||
391 | KeyBindingMap m_keyMap; | ||
392 | // we may act as a proxy to another OCompletionBase object | ||
393 | OCompletionBase *m_delegate; | ||
394 | |||
395 | // FIXME: Revise this for Opie? | ||
396 | //protected: | ||
397 | // virtual void virtual_hook( int id, void* data ); | ||
398 | private: | ||
399 | OCompletionBasePrivate *d; | ||
400 | }; | ||
401 | |||
402 | #endif // OCOMPLETIONBASE_H | ||
403 | |||
diff --git a/libopie2/qt3/opiecore/opair.h b/libopie2/qt3/opiecore/opair.h new file mode 100644 index 0000000..26f617d --- a/dev/null +++ b/libopie2/qt3/opiecore/opair.h | |||
@@ -0,0 +1,99 @@ | |||
1 | // QPair minus QT_INLINE_TEMPLATE (instead directly using 'inline' directive) | ||
2 | //FIXME: remove and use qpair.h as soon as we're on Qt3 | ||
3 | |||
4 | /**************************************************************************** | ||
5 | ** | ||
6 | ** Definition of QPair class | ||
7 | ** | ||
8 | ** | ||
9 | ** Copyright (C) 1992-2001 Trolltech AS. All rights reserved. | ||
10 | ** | ||
11 | ** This file is part of the tools module of the Qt GUI Toolkit. | ||
12 | ** | ||
13 | ** This file may be distributed under the terms of the Q Public License | ||
14 | ** as defined by Trolltech AS of Norway and appearing in the file | ||
15 | ** LICENSE.QPL included in the packaging of this file. | ||
16 | ** | ||
17 | ** This file may be distributed and/or modified under the terms of the | ||
18 | ** GNU General Public License version 2 as published by the Free Software | ||
19 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
20 | ** packaging of this file. | ||
21 | ** | ||
22 | ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition | ||
23 | ** licenses may use this file in accordance with the Qt Commercial License | ||
24 | ** Agreement provided with the Software. | ||
25 | ** | ||
26 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
27 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
28 | ** | ||
29 | ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for | ||
30 | ** information about Qt Commercial License Agreements. | ||
31 | ** See http://www.trolltech.com/qpl/ for QPL licensing information. | ||
32 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
33 | ** | ||
34 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
35 | ** not clear to you. | ||
36 | ** | ||
37 | **********************************************************************/ | ||
38 | |||
39 | #ifndef QPAIR_H | ||
40 | #define QPAIR_H | ||
41 | |||
42 | #ifndef QT_H | ||
43 | #include "qglobal.h" | ||
44 | #include "qdatastream.h" | ||
45 | #endif // QT_H | ||
46 | |||
47 | template <class T1, class T2> | ||
48 | struct QPair | ||
49 | { | ||
50 | typedef T1 first_type; | ||
51 | typedef T2 second_type; | ||
52 | |||
53 | QPair() | ||
54 | : first( T1() ), second( T2() ) | ||
55 | {} | ||
56 | QPair( const T1& t1, const T2& t2 ) | ||
57 | : first( t1 ), second( t2 ) | ||
58 | {} | ||
59 | |||
60 | T1 first; | ||
61 | T2 second; | ||
62 | }; | ||
63 | |||
64 | template <class T1, class T2> | ||
65 | inline bool operator==( const QPair<T1, T2>& x, const QPair<T1, T2>& y ) | ||
66 | { | ||
67 | return x.first == y.first && x.second == y.second; | ||
68 | } | ||
69 | |||
70 | template <class T1, class T2> | ||
71 | inline bool operator<( const QPair<T1, T2>& x, const QPair<T1, T2>& y ) | ||
72 | { | ||
73 | return x.first < y.first || | ||
74 | ( !( y.first < x.first ) && x.second < y.second ); | ||
75 | } | ||
76 | |||
77 | template <class T1, class T2> | ||
78 | inline QPair<T1, T2> qMakePair( const T1& x, const T2& y ) | ||
79 | { | ||
80 | return QPair<T1, T2>( x, y ); | ||
81 | } | ||
82 | |||
83 | #ifndef QT_NO_DATASTREAM | ||
84 | template <class T1, class T2> | ||
85 | inline QDataStream& operator>>( QDataStream& s, QPair<T1, T2>& p ) | ||
86 | { | ||
87 | s >> p.first >> p.second; | ||
88 | return s; | ||
89 | } | ||
90 | |||
91 | template <class T1, class T2> | ||
92 | inline QDataStream& operator<<( QDataStream& s, const QPair<T1, T2>& p ) | ||
93 | { | ||
94 | s << p.first << p.second; | ||
95 | return s; | ||
96 | } | ||
97 | #endif | ||
98 | |||
99 | #endif | ||
diff --git a/libopie2/qt3/opiecore/osortablevaluelist.h b/libopie2/qt3/opiecore/osortablevaluelist.h new file mode 100644 index 0000000..f66cf25 --- a/dev/null +++ b/libopie2/qt3/opiecore/osortablevaluelist.h | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | Originally a part of the KDE Project | ||
4 | (C) 2001 Carsten Pfeiffer <pfeiffer@kde.org> | ||
5 | =. | ||
6 | .=l. | ||
7 | .>+-= | ||
8 | _;:, .> :=|. This program is free software; you can | ||
9 | .> <`_, > . <= redistribute it and/or modify it under | ||
10 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
11 | .="- .-=="i, .._ License as published by the Free Software | ||
12 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
13 | ._= =} : or (at your option) any later version. | ||
14 | .%`+i> _;_. | ||
15 | .i_,=:_. -<s. This program is distributed in the hope that | ||
16 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
17 | : .. .:, . . . without even the implied warranty of | ||
18 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
19 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
20 | ..}^=.= = ; Library General Public License for more | ||
21 | ++= -. .` .: details. | ||
22 | : = ...= . :.=- | ||
23 | -. .:....=;==+<; You should have received a copy of the GNU | ||
24 | -_. . . )=. = Library General Public License along with | ||
25 | -- :-=` this library; see the file COPYING.LIB. | ||
26 | If not, write to the Free Software Foundation, | ||
27 | Inc., 59 Temple Place - Suite 330, | ||
28 | Boston, MA 02111-1307, USA. | ||
29 | */ | ||
30 | |||
31 | #ifndef OSORTABLEVALUELIST_H | ||
32 | #define OSORTABLEVALUELIST_H | ||
33 | |||
34 | #if QT_VERSION > 290 | ||
35 | #include <qtl.h> | ||
36 | #include <qpair.h> | ||
37 | #else | ||
38 | #include <opie2/otl.h> | ||
39 | #include <opie2/opair.h> | ||
40 | #endif | ||
41 | #include <qvaluelist.h> | ||
42 | |||
43 | template<class T, class Key = int> class OSortableItem : public QPair<Key,T> | ||
44 | { | ||
45 | public: | ||
46 | OSortableItem( Key i, const T& t ) : QPair<Key, T>( i, t ) {} | ||
47 | OSortableItem( const OSortableItem<T, Key> &rhs ) | ||
48 | : QPair<Key,T>( rhs.first, rhs.second ) {} | ||
49 | |||
50 | OSortableItem() {} | ||
51 | |||
52 | OSortableItem<T, Key> &operator=( const OSortableItem<T, Key>& i ) { | ||
53 | first = i.first; | ||
54 | second = i.second; | ||
55 | return *this; | ||
56 | } | ||
57 | |||
58 | // operators for sorting | ||
59 | bool operator> ( const OSortableItem<T, Key>& i2 ) const { | ||
60 | return (i2.first < first); | ||
61 | } | ||
62 | bool operator< ( const OSortableItem<T, Key>& i2 ) const { | ||
63 | return (first < i2.first); | ||
64 | } | ||
65 | bool operator>= ( const OSortableItem<T, Key>& i2 ) const { | ||
66 | return (first >= i2.first); | ||
67 | } | ||
68 | bool operator<= ( const OSortableItem<T, Key>& i2 ) const { | ||
69 | return !(i2.first < first); | ||
70 | } | ||
71 | bool operator== ( const OSortableItem<T, Key>& i2 ) const { | ||
72 | return (first == i2.first); | ||
73 | } | ||
74 | bool operator!= ( const OSortableItem<T, Key>& i2 ) const { | ||
75 | return (first != i2.first); | ||
76 | } | ||
77 | |||
78 | T& value() { | ||
79 | return second; | ||
80 | } | ||
81 | const T& value() const { | ||
82 | return second; | ||
83 | } | ||
84 | |||
85 | Key index() const { | ||
86 | return first; | ||
87 | } | ||
88 | }; | ||
89 | |||
90 | |||
91 | // convenience | ||
92 | template <class T, class Key = int> | ||
93 | class OSortableValueList : public QValueList<OSortableItem<T, Key> > | ||
94 | { | ||
95 | public: | ||
96 | void insert( Key i, const T& t ) { | ||
97 | QValueList<OSortableItem<T, Key> >::append( OSortableItem<T, Key>( i, t ) ); | ||
98 | } | ||
99 | // add more as you please... | ||
100 | |||
101 | T& operator[]( Key i ) { | ||
102 | return QValueList<OSortableItem<T, Key> >::operator[]( i ).value(); | ||
103 | } | ||
104 | const T& operator[]( Key i ) const { | ||
105 | return QValueList<OSortableItem<T, Key> >::operator[]( i ).value(); | ||
106 | } | ||
107 | |||
108 | void sort() { | ||
109 | qHeapSort( *this ); | ||
110 | } | ||
111 | }; | ||
112 | |||
113 | // template <class T> class OSortableValueListIterator : public QValueListIterator<OSortableItem<T> > | ||
114 | // { | ||
115 | // }; | ||
116 | |||
117 | #endif // OSORTABLEVALUELIST_H | ||
diff --git a/libopie2/qt3/opiecore/otl.h b/libopie2/qt3/opiecore/otl.h new file mode 100644 index 0000000..ee2a28e --- a/dev/null +++ b/libopie2/qt3/opiecore/otl.h | |||
@@ -0,0 +1,325 @@ | |||
1 | // qtl minus QT_INLINE_TEMPLATE and QT_EXPLICIT (instead directly using 'inline' directive) | ||
2 | //FIXME: remove and use qtl.h as soon as we're on Qt3 | ||
3 | |||
4 | /**************************************************************************** | ||
5 | ** $Id$ | ||
6 | ** | ||
7 | ** Definition of Qt template library classes | ||
8 | ** | ||
9 | ** Created : 990128 | ||
10 | ** | ||
11 | ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. | ||
12 | ** | ||
13 | ** This file is part of the tools module of the Qt GUI Toolkit. | ||
14 | ** | ||
15 | ** This file may be distributed under the terms of the Q Public License | ||
16 | ** as defined by Trolltech AS of Norway and appearing in the file | ||
17 | ** LICENSE.QPL included in the packaging of this file. | ||
18 | ** | ||
19 | ** This file may be distributed and/or modified under the terms of the | ||
20 | ** GNU General Public License version 2 as published by the Free Software | ||
21 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
22 | ** packaging of this file. | ||
23 | ** | ||
24 | ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition | ||
25 | ** licenses may use this file in accordance with the Qt Commercial License | ||
26 | ** Agreement provided with the Software. | ||
27 | ** | ||
28 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
29 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
30 | ** | ||
31 | ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for | ||
32 | ** information about Qt Commercial License Agreements. | ||
33 | ** See http://www.trolltech.com/qpl/ for QPL licensing information. | ||
34 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
35 | ** | ||
36 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
37 | ** not clear to you. | ||
38 | ** | ||
39 | **********************************************************************/ | ||
40 | |||
41 | #ifndef QTL_H | ||
42 | #define QTL_H | ||
43 | |||
44 | #ifndef QT_H | ||
45 | #include "qglobal.h" | ||
46 | #include "qtextstream.h" | ||
47 | #include "qstring.h" | ||
48 | #endif // QT_H | ||
49 | |||
50 | #ifndef QT_NO_TEXTSTREAM | ||
51 | template <class T> | ||
52 | class QTextOStreamIterator | ||
53 | { | ||
54 | protected: | ||
55 | QTextOStream& stream; | ||
56 | QString separator; | ||
57 | |||
58 | public: | ||
59 | QTextOStreamIterator( QTextOStream& s) : stream( s ) {} | ||
60 | QTextOStreamIterator( QTextOStream& s, const QString& sep ) | ||
61 | : stream( s ), separator( sep ) {} | ||
62 | QTextOStreamIterator<T>& operator= ( const T& x ) { | ||
63 | stream << x; | ||
64 | if ( !separator.isEmpty() ) | ||
65 | stream << separator; | ||
66 | return *this; | ||
67 | } | ||
68 | QTextOStreamIterator<T>& operator*() { return *this; } | ||
69 | QTextOStreamIterator<T>& operator++() { return *this; } | ||
70 | QTextOStreamIterator<T>& operator++(int) { return *this; } | ||
71 | }; | ||
72 | #endif //QT_NO_TEXTSTREAM | ||
73 | |||
74 | template <class InputIterator, class OutputIterator> | ||
75 | inline OutputIterator qCopy( InputIterator _begin, InputIterator _end, | ||
76 | OutputIterator _dest ) | ||
77 | { | ||
78 | while( _begin != _end ) | ||
79 | *_dest++ = *_begin++; | ||
80 | return _dest; | ||
81 | } | ||
82 | |||
83 | template <class BiIterator, class BiOutputIterator> | ||
84 | inline BiOutputIterator qCopyBackward( BiIterator _begin, BiIterator _end, | ||
85 | BiOutputIterator _dest ) | ||
86 | { | ||
87 | while ( _begin != _end ) | ||
88 | *--_dest = *--_end; | ||
89 | return _dest; | ||
90 | } | ||
91 | |||
92 | template <class InputIterator1, class InputIterator2> | ||
93 | inline bool qEqual( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2 ) | ||
94 | { | ||
95 | // ### compare using !(*first1 == *first2) in Qt 4.0 | ||
96 | for ( ; first1 != last1; ++first1, ++first2 ) | ||
97 | if ( *first1 != *first2 ) | ||
98 | return FALSE; | ||
99 | return TRUE; | ||
100 | } | ||
101 | |||
102 | template <class ForwardIterator, class T> | ||
103 | inline void qFill( ForwardIterator first, ForwardIterator last, const T& val ) | ||
104 | { | ||
105 | for ( ; first != last; ++first ) | ||
106 | *first = val; | ||
107 | } | ||
108 | |||
109 | #if 0 | ||
110 | template <class BiIterator, class OutputIterator> | ||
111 | inline OutputIterator qReverseCopy( BiIterator _begin, BiIterator _end, | ||
112 | OutputIterator _dest ) | ||
113 | { | ||
114 | while ( _begin != _end ) { | ||
115 | --_end; | ||
116 | *_dest = *_end; | ||
117 | ++_dest; | ||
118 | } | ||
119 | return _dest; | ||
120 | } | ||
121 | #endif | ||
122 | |||
123 | |||
124 | template <class InputIterator, class T> | ||
125 | inline InputIterator qFind( InputIterator first, InputIterator last, | ||
126 | const T& val ) | ||
127 | { | ||
128 | while ( first != last && *first != val ) | ||
129 | ++first; | ||
130 | return first; | ||
131 | } | ||
132 | |||
133 | template <class InputIterator, class T, class Size> | ||
134 | inline void qCount( InputIterator first, InputIterator last, const T& value, | ||
135 | Size& n ) | ||
136 | { | ||
137 | for ( ; first != last; ++first ) | ||
138 | if ( *first == value ) | ||
139 | ++n; | ||
140 | } | ||
141 | |||
142 | template <class T> | ||
143 | inline void qSwap( T& _value1, T& _value2 ) | ||
144 | { | ||
145 | T tmp = _value1; | ||
146 | _value1 = _value2; | ||
147 | _value2 = tmp; | ||
148 | } | ||
149 | |||
150 | |||
151 | template <class InputIterator> | ||
152 | inline void qBubbleSort( InputIterator b, InputIterator e ) | ||
153 | { | ||
154 | // Goto last element; | ||
155 | InputIterator last = e; | ||
156 | --last; | ||
157 | // only one element or no elements ? | ||
158 | if ( last == b ) | ||
159 | return; | ||
160 | |||
161 | // So we have at least two elements in here | ||
162 | while( b != last ) { | ||
163 | bool swapped = FALSE; | ||
164 | InputIterator swap_pos = b; | ||
165 | InputIterator x = e; | ||
166 | InputIterator y = x; | ||
167 | y--; | ||
168 | do { | ||
169 | --x; | ||
170 | --y; | ||
171 | if ( *x < *y ) { | ||
172 | swapped = TRUE; | ||
173 | qSwap( *x, *y ); | ||
174 | swap_pos = y; | ||
175 | } | ||
176 | } while( y != b ); | ||
177 | if ( !swapped ) | ||
178 | return; | ||
179 | b = swap_pos; | ||
180 | b++; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | |||
185 | template <class Container> | ||
186 | inline void qBubbleSort( Container &c ) | ||
187 | { | ||
188 | qBubbleSort( c.begin(), c.end() ); | ||
189 | } | ||
190 | |||
191 | |||
192 | template <class Value> | ||
193 | inline void qHeapSortPushDown( Value* heap, int first, int last ) | ||
194 | { | ||
195 | int r = first; | ||
196 | while ( r <= last / 2 ) { | ||
197 | if ( last == 2 * r ) { | ||
198 | // node r has only one child | ||
199 | if ( heap[2 * r] < heap[r] ) | ||
200 | qSwap( heap[r], heap[2 * r] ); | ||
201 | r = last; | ||
202 | } else { | ||
203 | // node r has two children | ||
204 | if ( heap[2 * r] < heap[r] && !(heap[2 * r + 1] < heap[2 * r]) ) { | ||
205 | // swap with left child | ||
206 | qSwap( heap[r], heap[2 * r] ); | ||
207 | r *= 2; | ||
208 | } else if ( heap[2 * r + 1] < heap[r] | ||
209 | && heap[2 * r + 1] < heap[2 * r] ) { | ||
210 | // swap with right child | ||
211 | qSwap( heap[r], heap[2 * r + 1] ); | ||
212 | r = 2 * r + 1; | ||
213 | } else { | ||
214 | r = last; | ||
215 | } | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | |||
220 | |||
221 | template <class InputIterator, class Value> | ||
222 | inline void qHeapSortHelper( InputIterator b, InputIterator e, Value, uint n ) | ||
223 | { | ||
224 | // Create the heap | ||
225 | InputIterator insert = b; | ||
226 | Value* realheap = new Value[n]; | ||
227 | // Wow, what a fake. But I want the heap to be indexed as 1...n | ||
228 | Value* heap = realheap - 1; | ||
229 | int size = 0; | ||
230 | for( ; insert != e; ++insert ) { | ||
231 | heap[++size] = *insert; | ||
232 | int i = size; | ||
233 | while( i > 1 && heap[i] < heap[i / 2] ) { | ||
234 | qSwap( heap[i], heap[i / 2] ); | ||
235 | i /= 2; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | // Now do the sorting | ||
240 | for( uint i = n; i > 0; i-- ) { | ||
241 | *b++ = heap[1]; | ||
242 | if ( i > 1 ) { | ||
243 | heap[1] = heap[i]; | ||
244 | qHeapSortPushDown( heap, 1, (int)i - 1 ); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | delete[] realheap; | ||
249 | } | ||
250 | |||
251 | |||
252 | template <class InputIterator> | ||
253 | inline void qHeapSort( InputIterator b, InputIterator e ) | ||
254 | { | ||
255 | // Empty ? | ||
256 | if ( b == e ) | ||
257 | return; | ||
258 | |||
259 | // How many entries have to be sorted ? | ||
260 | InputIterator it = b; | ||
261 | uint n = 0; | ||
262 | while ( it != e ) { | ||
263 | ++n; | ||
264 | ++it; | ||
265 | } | ||
266 | |||
267 | // The second last parameter is a hack to retrieve the value type | ||
268 | // Do the real sorting here | ||
269 | qHeapSortHelper( b, e, *b, n ); | ||
270 | } | ||
271 | |||
272 | |||
273 | template <class Container> | ||
274 | inline void qHeapSort( Container &c ) | ||
275 | { | ||
276 | if ( c.begin() == c.end() ) | ||
277 | return; | ||
278 | |||
279 | // The second last parameter is a hack to retrieve the value type | ||
280 | // Do the real sorting here | ||
281 | qHeapSortHelper( c.begin(), c.end(), *(c.begin()), (uint)c.count() ); | ||
282 | } | ||
283 | |||
284 | template <class Container> | ||
285 | class QBackInsertIterator | ||
286 | { | ||
287 | public: | ||
288 | QBackInsertIterator( Container &c ) | ||
289 | : container( &c ) | ||
290 | { | ||
291 | } | ||
292 | |||
293 | QBackInsertIterator<Container>& | ||
294 | operator=( const typename Container::value_type &value ) | ||
295 | { | ||
296 | container->push_back( value ); | ||
297 | return *this; | ||
298 | } | ||
299 | |||
300 | QBackInsertIterator<Container>& operator*() | ||
301 | { | ||
302 | return *this; | ||
303 | } | ||
304 | |||
305 | QBackInsertIterator<Container>& operator++() | ||
306 | { | ||
307 | return *this; | ||
308 | } | ||
309 | |||
310 | QBackInsertIterator<Container>& operator++(int) | ||
311 | { | ||
312 | return *this; | ||
313 | } | ||
314 | |||
315 | protected: | ||
316 | Container *container; | ||
317 | }; | ||
318 | |||
319 | template <class Container> | ||
320 | inline QBackInsertIterator<Container> qBackInserter( Container &c ) | ||
321 | { | ||
322 | return QBackInsertIterator<Container>( c ); | ||
323 | } | ||
324 | |||
325 | #endif | ||
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 | ||