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/opiecore | |
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 |
7 files changed, 2779 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 | ||