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