summaryrefslogtreecommitdiff
path: root/libopie2/qt3
Side-by-side diff
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 @@
+/*
+                 This file is part of the Opie Project
+ Originally part of the KDE Project
+ Copyright (C) 1999,2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
+ =.
+ .=l.
+           .>+-=
+ _;:,     .>    :=|. This program is free software; you can
+.> <`_,   >  .   <= redistribute it and/or modify it under
+:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
+.="- .-=="i,     .._ License as published by the Free Software
+ - .   .-<_>     .<> Foundation; either version 2 of the License,
+     ._= =}       : or (at your option) any later version.
+    .%`+i>       _;_.
+    .i_,=:_.      -<s. This program is distributed in the hope that
+     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
+    : ..    .:,     . . . without even the implied warranty of
+    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
+  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
+..}^=.=       =       ; Library General Public License for more
+++=   -.     .`     .: details.
+ :     =  ...= . :.=-
+ -.   .:....=;==+<; You should have received a copy of the GNU
+  -_. . .   )=.  = Library General Public License along with
+    --        :-=` this library; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <opie2/ocompletion.h>
+
+class OCompTreeNode;
+
+/**************************************************************************************************/
+/* OCompTreeNodeList
+/**************************************************************************************************/
+
+class OCompTreeNodeList
+{
+public:
+ OCompTreeNodeList() : first(0), last(0), m_count(0) {}
+ OCompTreeNode *begin() const { return first; }
+ OCompTreeNode *end() const { return last; }
+
+ OCompTreeNode *at(uint index) const;
+ void append(OCompTreeNode *item);
+ void prepend(OCompTreeNode *item);
+ void insert(OCompTreeNode *after, OCompTreeNode *item);
+ OCompTreeNode *remove(OCompTreeNode *item);
+ uint count() const { return m_count; }
+
+private:
+ OCompTreeNode *first, *last;
+ uint m_count;
+};
+
+typedef OCompTreeNodeList OCompTreeChildren;
+typedef OSortableValueList<QString> OCompletionMatchesList;
+
+/**
+ * A helper class for OCompletion. Implements a tree of QChar.
+ *
+ * The tree looks like this (containing the items "kde", "kde-ui",
+ * "kde-core" and "pfeiffer". Every item is delimited with QChar( 0x0 )
+ *
+ * some_root_node
+ * / \
+ * k p
+ * | |
+ * d f
+ * | |
+ * e e
+ * /| |
+ * 0x0 - i
+ * / \ |
+ * u c f
+ * | | |
+ * i o f
+ * | | |
+ * 0x0 r e
+ * | |
+ * e r
+ * | |
+ * 0x0 0x0
+ *
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ * @internal
+ */
+
+/**************************************************************************************************/
+/* OCompTreeNode
+/**************************************************************************************************/
+
+class OCompTreeNode : public QChar
+{
+public:
+ OCompTreeNode():QChar(), myWeight(0) {}
+ OCompTreeNode( const QChar& ch, uint weight = 0 ):QChar( ch ), myWeight( weight ) {}
+ ~OCompTreeNode();
+
+ // FIXME: Do we need this for Opie? [see also the static ZoneAllocater below]
+ //void * operator new( size_t s ) {
+ // return alloc.allocate( s );
+ //}
+ //void operator delete( void * s ) {
+ // alloc.deallocate( s );
+ //}
+
+ // Returns a child of this node matching ch, if available.
+ // Otherwise, returns 0L
+ inline OCompTreeNode * find( const QChar& ch ) const {
+ OCompTreeNode * cur = myChildren.begin();
+ while (cur && (*cur != ch)) cur = cur->next;
+ return cur;
+ }
+
+ OCompTreeNode * insert( const QChar&, bool sorted );
+ void remove( const QString& );
+
+ inline int childrenCount() const { return myChildren.count(); };
+
+ // weighting
+ inline void confirm() { myWeight++; };
+ inline void confirm(uint w) { myWeight += w; };
+ inline void decline() { myWeight--; };
+ inline uint weight() const { return myWeight; };
+
+ inline const OCompTreeChildren * children() const { return &myChildren; };
+ inline const OCompTreeNode * childAt(int index) const { return myChildren.at(index); };
+ inline const OCompTreeNode * firstChild() const { return myChildren.begin(); };
+ inline const OCompTreeNode * lastChild() const { return myChildren.end(); };
+
+ /* We want to handle a list of OCompTreeNodes on our own, to not
+ need to use QValueList<>. And to make it even more fast we don't
+ use an accessor, but just a public member. */
+ OCompTreeNode *next;
+
+private:
+ uint myWeight;
+ OCompTreeNodeList myChildren;
+ //static OZoneAllocator alloc; // FIXME: Do we need this for Opie?
+};
+
+/**************************************************************************************************/
+/* OCompletionMatchesWrapper
+/**************************************************************************************************/
+
+class OCompletionMatchesWrapper
+{
+public:
+ OCompletionMatchesWrapper( bool sort = false )
+ : sortedList( sort ? new OCompletionMatchesList : 0L ),
+ dirty( false )
+ {}
+ ~OCompletionMatchesWrapper() {
+ delete sortedList;
+ }
+
+ void setSorting( bool sort ) {
+ if ( sort && !sortedList )
+ sortedList = new OCompletionMatchesList;
+ else if ( !sort ) {
+ delete sortedList;
+ sortedList = 0L;
+ }
+ stringList.clear();
+ dirty = false;
+ }
+
+ bool sorting() const {
+ return sortedList != 0L;
+ }
+
+ void append( int i, const QString& string ) {
+ if ( sortedList )
+ sortedList->insert( i, string );
+ else
+ stringList.append( string );
+ dirty = true;
+ }
+
+ void clear() {
+ if ( sortedList )
+ sortedList->clear();
+ stringList.clear();
+ dirty = false;
+ }
+
+ uint count() const {
+ if ( sortedList )
+ return sortedList->count();
+ return stringList.count();
+ }
+
+ bool isEmpty() const {
+ return count() == 0;
+ }
+
+ QString first() const {
+ return list().first();
+ }
+
+ QString last() const {
+ return list().last();
+ }
+
+ QStringList list() const;
+
+ mutable QStringList stringList;
+ OCompletionMatchesList *sortedList;
+ mutable bool dirty;
+};
+
+/**************************************************************************************************/
+/* OCompletionPrivate
+/**************************************************************************************************/
+
+class OCompletionPrivate
+{
+public:
+ // not a member to avoid #including kcompletion_private.h from kcompletion.h
+ // list used for nextMatch() and previousMatch()
+ OCompletionMatchesWrapper matches;
+};
+
+/**************************************************************************************************/
+/* OCompletion
+/**************************************************************************************************/
+
+OCompletion::OCompletion()
+{
+ d = new OCompletionPrivate;
+
+ myCompletionMode = OGlobalSettings::completionMode();
+ myTreeRoot = new OCompTreeNode;
+ myBeep = true;
+ myIgnoreCase = false;
+ myHasMultipleMatches = false;
+ myRotationIndex = 0;
+ setOrder( Insertion );
+}
+
+
+OCompletion::~OCompletion()
+{
+ delete d;
+ delete myTreeRoot;
+}
+
+
+void OCompletion::setOrder( CompOrder order )
+{
+ myOrder = order;
+ d->matches.setSorting( order == Weighted );
+}
+
+
+void OCompletion::setIgnoreCase( bool ignoreCase )
+{
+ myIgnoreCase = ignoreCase;
+}
+
+
+void OCompletion::setItems( const QStringList& items )
+{
+ clear();
+ insertItems( items );
+}
+
+
+void OCompletion::insertItems( const QStringList& items )
+{
+ bool weighted = (myOrder == Weighted);
+ QStringList::ConstIterator it;
+ if ( weighted ) { // determine weight
+ for ( it = items.begin(); it != items.end(); ++it ) addWeightedItem( *it );
+ }
+ else {
+ for ( it = items.begin(); it != items.end(); ++it ) addItem( *it, 0 );
+ }
+}
+
+
+QStringList OCompletion::items() const
+{
+ OCompletionMatchesWrapper list; // unsorted
+ bool addWeight = (myOrder == Weighted);
+ extractStringsFromNode( myTreeRoot, QString::null, &list, addWeight );
+
+ return list.list();
+}
+
+
+void OCompletion::addItem( const QString& item )
+{
+ d->matches.clear();
+ myRotationIndex = 0;
+ myLastString = QString::null;
+
+ addItem( item, 0 );
+}
+
+
+void OCompletion::addItem( const QString& item, uint weight )
+{
+ if ( item.isEmpty() ) return;
+
+ OCompTreeNode *node = myTreeRoot;
+ uint len = item.length();
+
+ bool sorted = (myOrder == Sorted);
+ bool weighted = ((myOrder == Weighted) && weight > 1);
+
+ // knowing the weight of an item, we simply add this weight to all of its
+ // nodes.
+
+ for ( uint i = 0; i < len; i++ ) {
+ node = node->insert( item.at(i), sorted );
+ if ( weighted ) node->confirm( weight -1 ); // node->insert() sets weighting to 1
+ }
+
+ // add 0x0-item as delimiter with evtl. weight
+ node = node->insert( 0x0, true );
+ if ( weighted )
+ node->confirm( weight -1 );
+ //qDebug( "OCompletion: added: %s (%i)", item.latin1(), node->weight());
+}
+
+
+void OCompletion::addWeightedItem( const QString& item )
+{
+ if ( myOrder != Weighted ) {
+ addItem( item, 0 );
+ return;
+ }
+
+ uint len = item.length();
+ uint weight = 0;
+
+ // find out the weighting of this item (appended to the string as ":num")
+ int index = item.findRev(':');
+ if ( index > 0 ) {
+ bool ok;
+ weight = item.mid( index + 1 ).toUInt( &ok );
+ if ( !ok )
+ weight = 0;
+
+ len = index; // only insert until the ':'
+ }
+
+ addItem( item.left( len ), weight );
+ return;
+}
+
+
+void OCompletion::removeItem( const QString& item )
+{
+ d->matches.clear();
+ myRotationIndex = 0;
+ myLastString = QString::null;
+
+ myTreeRoot->remove( item );
+}
+
+
+void OCompletion::clear()
+{
+ d->matches.clear();
+ myRotationIndex = 0;
+ myLastString = QString::null;
+
+ delete myTreeRoot;
+ myTreeRoot = new OCompTreeNode;
+}
+
+
+QString OCompletion::makeCompletion( const QString& string )
+{
+ if ( myCompletionMode == OGlobalSettings::CompletionNone )
+ return QString::null;
+
+ //qDebug( "OCompletion: completing: %s", string );
+
+ d->matches.clear();
+ myRotationIndex = 0;
+ myHasMultipleMatches = false;
+ myLastMatch = myCurrentMatch;
+
+ // in Shell-completion-mode, emit all matches when we get the same
+ // complete-string twice
+ if ( myCompletionMode == OGlobalSettings::CompletionShell &&
+ string == myLastString ) {
+ // Don't use d->matches since calling postProcessMatches()
+ // on d->matches here would interfere with call to
+ // postProcessMatch() during rotation
+
+ findAllCompletions( string, &d->matches, myHasMultipleMatches );
+ QStringList l = d->matches.list();
+ postProcessMatches( &l );
+ emit matches( l );
+
+ if ( l.isEmpty() )
+ doBeep( NoMatch );
+
+ return QString::null;
+ }
+
+ QString completion;
+ // in case-insensitive popup mode, we search all completions at once
+ if ( myCompletionMode == OGlobalSettings::CompletionPopup ||
+ myCompletionMode == OGlobalSettings::CompletionPopupAuto ) {
+ findAllCompletions( string, &d->matches, myHasMultipleMatches );
+ if ( !d->matches.isEmpty() )
+ completion = d->matches.first();
+ }
+ else
+ completion = findCompletion( string );
+
+ if ( myHasMultipleMatches )
+ emit multipleMatches();
+
+ myLastString = string;
+ myCurrentMatch = completion;
+
+ postProcessMatch( &completion );
+
+ if ( !string.isEmpty() ) { // only emit match when string != ""
+ //qDebug( "OCompletion: Match: %s", completion );
+ emit match( completion );
+ }
+
+ if ( completion.isNull() )
+ doBeep( NoMatch );
+
+ return completion;
+}
+
+QStringList OCompletion::substringCompletion( const QString& string ) const
+{
+ // get all items in the tree, eventually in sorted order
+ bool sorted = (myOrder == Weighted);
+ OCompletionMatchesWrapper allItems( sorted );
+ extractStringsFromNode( myTreeRoot, QString::null, &allItems, false );
+
+ QStringList list = allItems.list();
+
+ // subStringMatches is invoked manually, via a shortcut, so we should
+ // beep here, if necessary.
+ if ( list.isEmpty() ) {
+ doBeep( NoMatch );
+ return list;
+ }
+
+ if ( string.isEmpty() ) { // shortcut
+ postProcessMatches( &list );
+ return list;
+ }
+
+ QStringList matches;
+ QStringList::ConstIterator it = list.begin();
+
+ for( ; it != list.end(); ++it ) {
+ QString item = *it;
+ if ( item.find( string, 0, false ) != -1 ) { // always case insensitive
+ postProcessMatch( &item );
+ matches.append( item );
+ }
+ }
+
+ if ( matches.isEmpty() )
+ doBeep( NoMatch );
+
+ return matches;
+}
+
+
+void OCompletion::setCompletionMode( OGlobalSettings::Completion mode )
+{
+ myCompletionMode = mode;
+}
+
+
+QStringList OCompletion::allMatches()
+{
+ // Don't use d->matches since calling postProcessMatches()
+ // on d->matches here would interfere with call to
+ // postProcessMatch() during rotation
+ OCompletionMatchesWrapper matches( myOrder == Weighted );
+ bool dummy;
+ findAllCompletions( myLastString, &matches, dummy );
+ QStringList l = matches.list();
+ postProcessMatches( &l );
+ return l;
+}
+
+
+OCompletionMatches OCompletion::allWeightedMatches()
+{
+ // Don't use d->matches since calling postProcessMatches()
+ // on d->matches here would interfere with call to
+ // postProcessMatch() during rotation
+ OCompletionMatchesWrapper matches( myOrder == Weighted );
+ bool dummy;
+ findAllCompletions( myLastString, &matches, dummy );
+ OCompletionMatches ret( matches );
+ postProcessMatches( &ret );
+ return ret;
+}
+
+QStringList OCompletion::allMatches( const QString &string )
+{
+ OCompletionMatchesWrapper matches( myOrder == Weighted );
+ bool dummy;
+ findAllCompletions( string, &matches, dummy );
+ QStringList l = matches.list();
+ postProcessMatches( &l );
+ return l;
+}
+
+OCompletionMatches OCompletion::allWeightedMatches( const QString &string )
+{
+ OCompletionMatchesWrapper matches( myOrder == Weighted );
+ bool dummy;
+ findAllCompletions( string, &matches, dummy );
+ OCompletionMatches ret( matches );
+ postProcessMatches( &ret );
+ return ret;
+}
+
+/////////////////////////////////////////////////////
+///////////////// tree operations ///////////////////
+
+
+QString OCompletion::nextMatch()
+{
+ QString completion;
+ myLastMatch = myCurrentMatch;
+
+ if ( d->matches.isEmpty() ) {
+ findAllCompletions( myLastString, &d->matches, myHasMultipleMatches );
+ completion = d->matches.first();
+ myCurrentMatch = completion;
+ myRotationIndex = 0;
+ postProcessMatch( &completion );
+ emit match( completion );
+ return completion;
+ }
+
+ QStringList matches = d->matches.list();
+ myLastMatch = matches[ myRotationIndex++ ];
+
+ if ( myRotationIndex == matches.count() -1 )
+ doBeep( Rotation ); // indicate last matching item -> rotating
+
+ else if ( myRotationIndex == matches.count() )
+ myRotationIndex = 0;
+
+ completion = matches[ myRotationIndex ];
+ myCurrentMatch = completion;
+ postProcessMatch( &completion );
+ emit match( completion );
+ return completion;
+}
+
+
+
+QString OCompletion::previousMatch()
+{
+ QString completion;
+ myLastMatch = myCurrentMatch;
+
+ if ( d->matches.isEmpty() ) {
+ findAllCompletions( myLastString, &d->matches, myHasMultipleMatches );
+ completion = d->matches.last();
+ myCurrentMatch = completion;
+ myRotationIndex = 0;
+ postProcessMatch( &completion );
+ emit match( completion );
+ return completion;
+ }
+
+ QStringList matches = d->matches.list();
+ myLastMatch = matches[ myRotationIndex ];
+ if ( myRotationIndex == 1 )
+ doBeep( Rotation ); // indicate first item -> rotating
+
+ else if ( myRotationIndex == 0 )
+ myRotationIndex = matches.count();
+
+ myRotationIndex--;
+
+ completion = matches[ myRotationIndex ];
+ myCurrentMatch = completion;
+ postProcessMatch( &completion );
+ emit match( completion );
+ return completion;
+}
+
+
+
+// tries to complete "string" from the tree-root
+QString OCompletion::findCompletion( const QString& string )
+{
+ QChar ch;
+ QString completion;
+ const OCompTreeNode *node = myTreeRoot;
+
+ // start at the tree-root and try to find the search-string
+ for( uint i = 0; i < string.length(); i++ ) {
+ ch = string.at( i );
+ node = node->find( ch );
+
+ if ( node )
+ completion += ch;
+ else
+ return QString::null; // no completion
+ }
+
+ // Now we have the last node of the to be completed string.
+ // Follow it as long as it has exactly one child (= longest possible
+ // completion)
+
+ while ( node->childrenCount() == 1 ) {
+ node = node->firstChild();
+ if ( !node->isNull() )
+ completion += *node;
+ }
+ // if multiple matches and auto-completion mode
+ // -> find the first complete match
+ if ( node && node->childrenCount() > 1 ) {
+ myHasMultipleMatches = true;
+
+ if ( myCompletionMode == OGlobalSettings::CompletionAuto ) {
+ myRotationIndex = 1;
+ if (myOrder != Weighted) {
+ while ( (node = node->firstChild()) ) {
+ if ( !node->isNull() )
+ completion += *node;
+ else
+ break;
+ }
+ }
+ else {
+ // don't just find the "first" match, but the one with the
+ // highest priority
+
+ const OCompTreeNode* temp_node = 0L;
+ while(1) {
+ int count = node->childrenCount();
+ temp_node = node->firstChild();
+ uint weight = temp_node->weight();
+ const OCompTreeNode* hit = temp_node;
+ for( int i = 1; i < count; i++ ) {
+ temp_node = node->childAt(i);
+ if( temp_node->weight() > weight ) {
+ hit = temp_node;
+ weight = hit->weight();
+ }
+ }
+ // 0x0 has the highest priority -> we have the best match
+ if ( hit->isNull() )
+ break;
+
+ node = hit;
+ completion += *node;
+ }
+ }
+ }
+
+ else
+ doBeep( PartialMatch ); // partial match -> beep
+ }
+
+ return completion;
+}
+
+
+void OCompletion::findAllCompletions(const QString& string,
+ OCompletionMatchesWrapper *matches,
+ bool& hasMultipleMatches) const
+{
+ //qDebug( "OCompletion: finding all completions for %s", (const char*) string );
+
+ if ( string.isEmpty() )
+ return;
+
+ if ( myIgnoreCase ) { // case insensitive completion
+ extractStringsFromNodeCI( myTreeRoot, QString::null, string, matches );
+ hasMultipleMatches = (matches->count() > 1);
+ return;
+ }
+
+ QChar ch;
+ QString completion;
+ const OCompTreeNode *node = myTreeRoot;
+
+ // start at the tree-root and try to find the search-string
+ for( uint i = 0; i < string.length(); i++ ) {
+ ch = string.at( i );
+ node = node->find( ch );
+
+ if ( node )
+ completion += ch;
+ else
+ return; // no completion -> return empty list
+ }
+
+ // Now we have the last node of the to be completed string.
+ // Follow it as long as it has exactly one child (= longest possible
+ // completion)
+
+ while ( node->childrenCount() == 1 ) {
+ node = node->firstChild();
+ if ( !node->isNull() )
+ completion += *node;
+ // kdDebug() << completion << node->latin1();
+ }
+
+
+ // there is just one single match)
+ if ( node->childrenCount() == 0 )
+ matches->append( node->weight(), completion );
+
+ else {
+ // node has more than one child
+ // -> recursively find all remaining completions
+ hasMultipleMatches = true;
+ extractStringsFromNode( node, completion, matches );
+ }
+}
+
+
+void OCompletion::extractStringsFromNode( const OCompTreeNode *node,
+ const QString& beginning,
+ OCompletionMatchesWrapper *matches,
+ bool addWeight ) const
+{
+ if ( !node || !matches ) return;
+
+ // kDebug() << "Beginning: " << beginning << endl;
+ const OCompTreeChildren *list = node->children();
+ QString string;
+ QString w;
+
+ // loop thru all children
+ for ( OCompTreeNode *cur = list->begin(); cur ; cur = cur->next) {
+ string = beginning;
+ node = cur;
+ if ( !node->isNull() )
+ string += *node;
+
+ while ( node && node->childrenCount() == 1 ) {
+ node = node->firstChild();
+ if ( node->isNull() ) break;
+ string += *node;
+ }
+
+ if ( node && node->isNull() ) { // we found a leaf
+ if ( addWeight ) {
+ // add ":num" to the string to store the weighting
+ string += ':';
+ w.setNum( node->weight() );
+ string.append( w );
+ }
+ matches->append( node->weight(), string );
+ }
+
+ // recursively find all other strings.
+ if ( node && node->childrenCount() > 1 )
+ extractStringsFromNode( node, string, matches, addWeight );
+ }
+}
+
+void OCompletion::extractStringsFromNodeCI( const OCompTreeNode *node,
+ const QString& beginning,
+ const QString& restString,
+ OCompletionMatchesWrapper *matches ) const
+{
+ if ( restString.isEmpty() ) {
+ extractStringsFromNode( node, beginning, matches, false /*noweight*/ );
+ return;
+ }
+
+ QChar ch1 = restString.at(0);
+ QString newRest = restString.mid(1);
+ OCompTreeNode *child1, *child2;
+
+ child1 = node->find( ch1 ); // the correct match
+ if ( child1 )
+ extractStringsFromNodeCI( child1, beginning + *child1, newRest,
+ matches );
+
+ // append the case insensitive matches, if available
+ if ( ch1.isLetter() ) {
+ // find out if we have to lower or upper it. Is there a better way?
+ QChar ch2 = ch1.lower();
+ if ( ch1 == ch2 )
+ ch2 = ch1.upper();
+ if ( ch1 != ch2 ) {
+ child2 = node->find( ch2 );
+ if ( child2 )
+ extractStringsFromNodeCI( child2, beginning + *child2, newRest,
+ matches );
+ }
+ }
+}
+
+// FIXME: Revise this for Opie?
+
+void OCompletion::doBeep( BeepMode mode ) const
+{
+ if ( !myBeep ) return;
+
+ QString text, event;
+
+ switch ( mode ) {
+ case Rotation:
+ event = QString::fromLatin1("Textcompletion: rotation");
+ text = tr("You reached the end of the list\nof matching items.\n");
+ break;
+ case PartialMatch:
+ if ( myCompletionMode == OGlobalSettings::CompletionShell ||
+ myCompletionMode == OGlobalSettings::CompletionMan ) {
+ event = QString::fromLatin1("Textcompletion: partial match");
+ text = tr("The completion is ambiguous, more than one\nmatch is available.\n");
+ }
+ break;
+ case NoMatch:
+ if ( myCompletionMode == OGlobalSettings::CompletionShell ) {
+ event = QString::fromLatin1("Textcompletion: no match");
+ text = tr("There is no matching item available.\n");
+ }
+ break;
+ }
+
+ //if ( !text.isEmpty() )
+ //ONotifyClient::event( event, text ); // FIXME: Revise for Opie?
+}
+
+// Implements the tree. Every node is a QChar and has a list of children, which
+// are Nodes as well.
+// QChar( 0x0 ) is used as the delimiter of a string; the last child of each
+// inserted string is 0x0.
+
+OCompTreeNode::~OCompTreeNode()
+{
+ // delete all children
+ OCompTreeNode *cur = myChildren.begin();
+ while (cur) {
+ OCompTreeNode * next = cur->next;
+ delete myChildren.remove(cur);
+ cur = next;
+ }
+}
+
+
+// Adds a child-node "ch" to this node. If such a node is already existant,
+// it will not be created. Returns the new/existing node.
+OCompTreeNode * OCompTreeNode::insert( const QChar& ch, bool sorted )
+{
+ OCompTreeNode *child = find( ch );
+ if ( !child ) {
+ child = new OCompTreeNode( ch );
+
+ // FIXME, first (slow) sorted insertion implementation
+ if ( sorted ) {
+ OCompTreeNode * prev = 0;
+ OCompTreeNode * cur = myChildren.begin();
+ while ( cur ) {
+ if ( ch > *cur ) {
+ prev = cur;
+ cur = cur->next;
+ } else
+ break;
+ }
+ if (prev)
+ myChildren.insert( prev, child );
+ else
+ myChildren.prepend(child);
+ }
+
+ else
+ myChildren.append( child );
+ }
+
+ // implicit weighting: the more often an item is inserted, the higher
+ // priority it gets.
+ child->confirm();
+
+ return child;
+}
+
+
+// Recursively removes a string from the tree (untested :-)
+void OCompTreeNode::remove( const QString& string )
+{
+ OCompTreeNode *child = 0L;
+
+ if ( string.isEmpty() ) {
+ child = find( 0x0 );
+ delete myChildren.remove( child );
+ return;
+ }
+
+ QChar ch = string.at(0);
+ child = find( ch );
+ if ( child ) {
+ child->remove( string.right( string.length() -1 ) );
+ if ( child->myChildren.count() == 0 ) {
+ delete myChildren.remove( child );
+ }
+ }
+}
+
+QStringList OCompletionMatchesWrapper::list() const {
+ if ( sortedList && dirty ) {
+ sortedList->sort();
+ dirty = false;
+
+ stringList.clear();
+
+ // high weight == sorted last -> reverse the sorting here
+ QValueListConstIterator<OSortableItem<QString> > it;
+ for ( it = sortedList->begin(); it != sortedList->end(); ++it )
+ stringList.prepend( (*it).value() );
+ }
+
+ return stringList;
+}
+
+OCompletionMatches::OCompletionMatches( bool sort_P )
+ : _sorting( sort_P )
+{
+}
+
+OCompletionMatches::OCompletionMatches( const OCompletionMatchesWrapper& matches )
+ : _sorting( matches.sorting())
+{
+ if( matches.sortedList != 0L )
+ OCompletionMatchesList::operator=( *matches.sortedList );
+ else {
+ QStringList l = matches.list();
+ for( QStringList::ConstIterator it = l.begin();
+ it != l.end();
+ ++it )
+ prepend( OSortableItem<QString, int>( 1, *it ) );
+ }
+}
+
+OCompletionMatches::~OCompletionMatches()
+{
+}
+
+QStringList OCompletionMatches::list( bool sort_P ) const
+{
+ if( _sorting && sort_P )
+ const_cast< OCompletionMatches* >( this )->sort();
+ QStringList stringList;
+ // high weight == sorted last -> reverse the sorting here
+ for ( ConstIterator it = begin(); it != end(); ++it )
+ stringList.prepend( (*it).value() );
+ return stringList;
+}
+
+void OCompletionMatches::removeDuplicates()
+{
+ Iterator it1, it2;
+ for ( it1 = begin(); it1 != end(); ++it1 ) {
+ for ( (it2 = it1), ++it2; it2 != end();) {
+ if( (*it1).value() == (*it2).value()) {
+ // use the max height
+ //(*it1).first = kMax( (*it1).index(), (*it2).index());
+ (*it1).first = (*it2).index() < (*it1).index() ? (*it1).index() : (*it2).index();
+ it2 = remove( it2 );
+ continue;
+ }
+ ++it2;
+ }
+ }
+}
+
+void OCompTreeNodeList::append(OCompTreeNode *item)
+{
+ m_count++;
+ if (!last) {
+ last = item;
+ last->next = 0;
+ first = item;
+ return;
+ }
+ last->next = item;
+ item->next = 0;
+ last = item;
+}
+
+void OCompTreeNodeList::prepend(OCompTreeNode *item)
+{
+ m_count++;
+ if (!last) {
+ last = item;
+ last->next = 0;
+ first = item;
+ return;
+ }
+ item->next = first;
+ first = item;
+}
+
+void OCompTreeNodeList::insert(OCompTreeNode *after, OCompTreeNode *item)
+{
+ if (!after) {
+ append(item);
+ return;
+ }
+
+ m_count++;
+
+ item->next = after->next;
+ after->next = item;
+
+ if (after == last)
+ last = item;
+}
+
+OCompTreeNode *OCompTreeNodeList::remove(OCompTreeNode *item)
+{
+ if (!first || !item)
+ return 0;
+ OCompTreeNode *cur = 0;
+
+ if (item == first)
+ first = first->next;
+ else {
+ cur = first;
+ while (cur && cur->next != item) cur = cur->next;
+ if (!cur)
+ return 0;
+ cur->next = item->next;
+ }
+ if (item == last)
+ last = cur;
+ m_count--;
+ return item;
+}
+
+OCompTreeNode *OCompTreeNodeList::at(uint index) const
+{
+ OCompTreeNode *cur = first;
+ while (index-- && cur) cur = cur->next;
+ return cur;
+}
+
+// FIXME: Revise for Opie?
+//OZoneAllocator OCompTreeNode::alloc(8192);
+
+//void OCompletion::virtual_hook( int, void* )
+//{ /*BASE::virtual_hook( id, data );*/ }
+
+//void OCompletionBase::virtual_hook( int, void* )
+//{ /*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 @@
+/*
+                 This file is part of the Opie Project
+ Originally part of the KDE Project
+ Copyright (C) 1999,2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ =.
+ .=l.
+           .>+-=
+ _;:,     .>    :=|. This program is free software; you can
+.> <`_,   >  .   <= redistribute it and/or modify it under
+:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
+.="- .-=="i,     .._ License as published by the Free Software
+ - .   .-<_>     .<> Foundation; either version 2 of the License,
+     ._= =}       : or (at your option) any later version.
+    .%`+i>       _;_.
+    .i_,=:_.      -<s. This program is distributed in the hope that
+     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
+    : ..    .:,     . . . without even the implied warranty of
+    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
+  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
+..}^=.=       =       ; Library General Public License for more
+++=   -.     .`     .: details.
+ :     =  ...= . :.=-
+ -.   .:....=;==+<; You should have received a copy of the GNU
+  -_. . .   )=.  = Library General Public License along with
+    --        :-=` this library; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef OCOMPLETION_H
+#define OCOMPLETION_H
+
+/* QT */
+
+#include <qmap.h>
+#include <qlist.h>
+#include <qobject.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qguardedptr.h>
+
+/* OPIE */
+
+#include <opie2/oglobalsettings.h>
+#include <opie2/osortablevaluelist.h>
+
+/* FORWARDS */
+
+class OCompTreeNode;
+class OCompletionPrivate;
+class OCompletionBasePrivate;
+class OCompletionMatchesWrapper;
+class OCompletionMatches;
+class QPopupMenu;
+
+// FIXME: Do we need special ShortCut handling in Opie? If so, revise this.
+class OShortcut
+{
+public:
+ bool isNull() const { return true; };
+ bool operator == ( const OShortcut& bla ) const { return false; };
+};
+
+
+/**
+ * This class offers easy use of "auto-completion", "manual-completion" or
+ * "shell completion" on QString objects. A common use is completing filenames
+ * or URLs (see @ref OURLCompletion()).
+ * But it is not limited to URL-completion -- everything should be completable!
+ * The user should be able to complete email-addresses, telephone-numbers,
+ * commands, SQL queries, ...
+ * Every time your program knows what the user can type into an edit-field, you
+ * should offer completion. With OCompletion, this is very easy, and if you are
+ * using a line edit widget (@ref OLineEdit), it is even more easy.
+ * Basically, you tell a OCompletion object what strings should be completable
+ * and whenever completion should be invoked, you call @ref makeCompletion().
+ * OLineEdit and (an editable) OComboBox even do this automatically for you.
+ *
+ * OCompletion offers the completed string via the signal @ref match() and
+ * all matching strings (when the result is ambiguous) via the method
+ * @ref allMatches().
+ *
+ * Notice: auto-completion, shell completion and manual completion work
+ * slightly differently:
+ *
+ * @li auto-completion always returns a complete item as match.
+ * When more than one matching items are available, it will deliver just
+ * the first (depending on sorting order) item. Iterating over all matches
+ * is possible via @ref nextMatch() and @ref previousMatch().
+ *
+ * @li popup-completion works in the same way, the only difference being that
+ * the completed items are not put into the edit-widget, but into a
+ * separate popup-box.
+ *
+ * @li manual completion works the same way as auto-completion, the
+ * subtle difference is, that it isn't invoked automatically while the user
+ * is typing, but only when the user presses a special key. The difference
+ * of manual and auto-completion is therefore only visible in UI classes,
+ * OCompletion needs to know whether to deliver partial matches
+ * (shell completion) or whole matches (auto/manual completion), therefore
+ * @ref OGlobalSettings::CompletionMan and
+ * @ref OGlobalSettings::CompletionAuto have the exact same effect in
+ * OCompletion.
+ *
+ * @li shell completion works like how shells complete filenames:
+ * when multiple matches are available, the longest possible string of all
+ * matches is returned (i.e. only a partial item).
+ * Iterating over all matching items (complete, not partial) is possible
+ * via @ref nextMatch() and @ref previousMatch().
+ *
+ * You don't have to worry much about that though, OCompletion handles
+ * that for you, according to the setting @ref setCompletionMode().
+ * The default setting is globally configured by the user and read
+ * from @ref OGlobalSettings::completionMode().
+ *
+ * A short example:
+ * <pre>
+ * OCompletion completion;
+ * completion.setOrder( OCompletion::Sorted );
+ * completion.addItem( "pfeiffer@kde.org" );
+ * completion.addItem( "coolo@kde.org" );
+ * completion.addItem( "carpdjih@sp.zrz.tu-berlin.de" );
+ * completion.addItem( "carp@cs.tu-berlin.de" );
+ *
+ * cout << completion.makeCompletion( "ca" ).latin1() << endl;
+ * </pre>
+ * In shell-completion-mode, this will be "carp"; in auto-completion-
+ * mode it will be "carp@cs.tu-berlin.de", as that is alphabetically
+ * smaller.
+ * If setOrder was set to Insertion, "carpdjih@sp.zrz.tu-berlin.de"
+ * would be completed in auto-completion-mode, as that was inserted before
+ * "carp@cs.tu-berlin.de".
+ *
+ * You can dynamically update the completable items by removing and adding them
+ * whenever you want.
+ * For advanced usage, you could even use multiple OCompletion objects. E.g.
+ * imagine an editor like kwrite with multiple open files. You could store
+ * items of each file in a different OCompletion object, so that you know (and
+ * tell the user) where a completion comes from.
+ *
+ * Note: OCompletion does not work with strings that contain 0x0 characters
+ * (unicode nul), as this is used internally as a delimiter.
+ *
+ * You may inherit from OCompletion and override @ref makeCompletion() in
+ * special cases (like reading directories/urls and then supplying the
+ * contents to OCompletion, as OURLCompletion does), but generally, this is
+ * not necessary.
+ *
+ *
+ * @short A generic class for completing QStrings
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ * @version $Id$
+ */
+
+class OCompletion : public QObject
+{
+ Q_ENUMS( CompOrder )
+ Q_PROPERTY( CompOrder order READ order WRITE setOrder )
+ Q_PROPERTY( bool ignoreCase READ ignoreCase WRITE setIgnoreCase )
+ Q_PROPERTY( QStringList items READ items WRITE setItems )
+ Q_OBJECT
+
+ public:
+ /**
+ * Constants that represent the order in which OCompletion performs
+ * completion-lookups.
+ */
+ enum CompOrder { Sorted, Insertion, Weighted };
+
+ /**
+ * Constructor, nothing special here :)
+ */
+ OCompletion();
+
+ // FIXME: copy constructor, assignment constructor...
+
+ /**
+ * Destructor, nothing special here, either.
+ */
+ virtual ~OCompletion();
+
+ /**
+ * Attempts to find an item in the list of available completions,
+ * that begins with @p string. Will either return the first matching item
+ * (if there is more than one match) or QString::null, if no match was
+ * found.
+ *
+ * In the latter case, a sound will be issued, depending on
+ * @ref isSoundsEnabled().
+ * If a match was found, it will also be emitted via the signal
+ * @ref match().
+ *
+ * If this is called twice or more often with the same string while no
+ * items were added or removed in the meantime, all available completions
+ * will be emitted via the signal @ref matches().
+ * This happens only in shell-completion-mode.
+ *
+ * @returns the matching item, or QString::null if there is no matching
+ * item.
+ * @see #slotMakeCompletion
+ * @see #substringCompletion
+ */
+ virtual QString makeCompletion( const QString& string );
+
+ /**
+ * @returns a list of items which all contain @p text as a substring,
+ * i.e. not necessarily at the beginning.
+ *
+ * @see #makeCompletion
+ */
+ QStringList substringCompletion( const QString& string ) const;
+
+ /**
+ * @returns the next item from the matching-items-list.
+ * When reaching the beginning, the list is rotated so it will return the
+ * last match and a sound is issued (depending on @ref isSoundsEnabled()).
+ * When there is no match, QString::null is returned and
+ * a sound is be issued.
+ * @see #slotPreviousMatch
+ */
+ QString previousMatch();
+
+ /**
+ * @returns the previous item from the matching-items-list
+ * When reaching the last item, the list is rotated, so it will return
+ * the first match and a sound is issued (depending on
+ * @ref isSoundsEnabled()). When there is no match, QString::null is
+ * returned and a sound is issued.
+ * @see #slotNextMatch
+ */
+ QString nextMatch();
+
+ /**
+ * @returns the last match. Might be useful if you need to check whether
+ * a completion is different from the last one.
+ * QString::null is returned when there is no last match.
+ */
+ virtual const QString& lastMatch() const { return myLastMatch; }
+
+ /**
+ * Returns a list of all items inserted into OCompletion. This is useful
+ * if you need to save the state of a OCompletion object and restore it
+ * later.
+ *
+ * Important note: when @ref order() == Weighted, then every item in the
+ * stringlist has its weight appended, delimited by a colon. E.g. an item
+ * "www.kde.org" might look like "www.kde.org:4", where 4 is the weight.
+ *
+ * This is necessary so that you can save the items along with its
+ * weighting on disk and load them back with @ref setItems(), restoring its
+ * weight as well. If you really don't want the appended weightings, call
+ * @ref setOrder( OCompletion::Insertion )
+ * before calling items().
+ *
+ * @returns a list of all items
+ * @see #setItems
+ */
+ QStringList items() const;
+
+ /**
+ * Sets the completion mode to Auto/Manual, Shell or None.
+ * If you don't set the mode explicitly, the global default value
+ * OGlobalSettings::completionMode() is used.
+ * @ref OGlobalSettings::CompletionNone disables completion.
+ * @see #completionMode
+ * @see #OGlobalSettings::completionMode
+ */
+ virtual void setCompletionMode( OGlobalSettings::Completion mode );
+
+ /**
+ * @returns the current completion mode.
+ * May be different from @ref OGlobalSettings::completionMode(), if you
+ * explicitly called @ref setCompletionMode().
+ * @see #setCompletionMode
+ */
+ OGlobalSettings::Completion completionMode() const { return myCompletionMode; };
+
+ /**
+ * OCompletion offers three different ways in which it offers its items:
+ * @li in the order of insertion
+ * @li sorted alphabetically
+ * @li weighted
+ *
+ * Choosing weighted makes OCompletion perform an implicit weighting based
+ * on how often an item is inserted. Imagine a web browser with a location
+ * bar, where the user enters URLs. The more often a URL is entered, the
+ * higher priority it gets.
+ *
+ * Note: Setting the order to sorted only affects new inserted items,
+ * already existing items will stay in the current order. So you probably
+ * want to call setOrder( Sorted ) before inserting items, when you want
+ * everything sorted.
+ *
+ * Default is insertion order
+ * @see #order
+ */
+ virtual void setOrder( CompOrder order );
+
+ /**
+ * @returns the current completion order.
+ * @see #setOrder
+ */
+ CompOrder order() const { return myOrder; }
+
+ /**
+ * Setting this to true makes OCompletion behave case insensitively.
+ * E.g. makeCompletion( "CA" ); might return "carp@cs.tu-berlin.de".
+ * Default is false (case sensitive).
+ * @see #ignoreCase
+ */
+ virtual void setIgnoreCase( bool ignoreCase );
+
+ /**
+ * @returns whether OCompletion acts case insensitively or not.
+ * Default is false (case sensitive).
+ * @see #setIgnoreCase
+ */
+ bool ignoreCase() const { return myIgnoreCase; };
+
+ /**
+ * @returns a list of all items matching the last completed string.
+ * Might take some time, when you have LOTS of items.
+ *
+ * @see #substringCompletion
+ */
+ QStringList allMatches();
+
+ /**
+ * @returns a list of all items matching @p string.
+ */
+ QStringList allMatches( const QString& string );
+
+ /**
+ * @returns a list of all items matching the last completed string.
+ * Might take some time, when you have LOTS of items.
+ * The matches are returned as OCompletionMatches, which also
+ * keeps the weight of the matches, allowing
+ * you to modify some matches or merge them with matches
+ * from another call to allWeightedMatches(), and sort the matches
+ * after that in order to have the matches ordered correctly
+ *
+ * @see #substringCompletion
+ */
+ OCompletionMatches allWeightedMatches();
+
+ /**
+ * @returns a list of all items matching @p string.
+ */
+ OCompletionMatches allWeightedMatches( const QString& string );
+
+ /**
+ * Enables/disables playing a sound when
+ * @li @ref makeCompletion() can't find a match
+ * @li there is a partial completion (= multiple matches in
+ * Shell-completion mode)
+ * @li @ref nextMatch() or @ref previousMatch() hit the last possible
+ * match -> rotation
+ *
+ * For playing the sounds, @ref ONotifyClient() is used. // FIXME: Revise this for Opie
+ *
+ * @see #isSoundsEnabled
+ */
+ virtual void setEnableSounds( bool enable ) { myBeep = enable; }
+
+ /**
+ * Tells you whether OCompletion will play sounds on certain occasions.
+ * Default is enabled
+ * @see #enableSounds
+ * @see #disableSounds
+ */
+ bool isSoundsEnabled() const { return myBeep; };
+
+ /**
+ * @returns true when more than one match is found
+ * @see #multipleMatches
+ */
+ bool hasMultipleMatches() const { return myHasMultipleMatches; };
+
+ public slots:
+ /**
+ * Attempts to complete "string" and emits the completion via @ref match().
+ * Same as @ref makeCompletion() (just as a slot).
+ * @see #makeCompletion
+ */
+ void slotMakeCompletion( const QString& string ) { (void) makeCompletion( string ); };
+
+ /**
+ * Searches the previous matching item and emits it via @ref match()
+ * Same as @ref previousMatch() (just as a slot).
+ * @see #previousMatch
+ */
+ void slotPreviousMatch() { (void) previousMatch(); };
+
+ /**
+ * Searches the next matching item and emits it via @ref match()
+ * Same as @ref nextMatch() (just as a slot).
+ * @see #nextMatch
+ */
+ void slotNextMatch() { (void) nextMatch(); };
+
+ /**
+ * Inserts @p items into the list of possible completions.
+ * Does the same as @ref setItems(), but does not call @ref clear() before.
+ */
+ void insertItems( const QStringList& items );
+
+ /**
+ * Sets the list of items available for completion. Removes all previous
+ * items.
+ *
+ * Notice: when order() == Weighted, then the weighting is looked up for
+ * every item in the stringlist. Every item should have ":number" appended,
+ * where number is an unsigned integer, specifying the weighting.
+ *
+ * If you don't like this, call
+ * setOrder( OCompletion::Insertion )
+ * before calling setItems().
+ *
+ * @see #items
+ */
+ virtual void setItems( const QStringList& );
+
+ /**
+ * Adds an item to the list of available completions.
+ * Resets the current item-state (@ref previousMatch() and @ref nextMatch()
+ * won't work anymore).
+ */
+ void addItem( const QString& );
+
+ /**
+ * Adds an item to the list of available completions.
+ * Resets the current item-state (@ref previousMatch() and @ref nextMatch()
+ * won't work anymore).
+ *
+ * Sets the weighting of the item to @p weight or adds it to the current
+ * weighting if the item is already available. The weight has to be greater
+ * than 1 to take effect (default weight is 1).
+ */
+ void addItem( const QString&, uint weight );
+
+ /**
+ * Removes an item from the list of available completions.
+ * Resets the current item-state (@ref previousMatch() and @ref nextMatch()
+ * won't work anymore).
+ */
+ void removeItem( const QString& );
+
+ /**
+ * Removes all inserted items.
+ */
+ virtual void clear();
+
+ signals:
+ /**
+ * The matching item. Will be emitted by @ref makeCompletion(),
+ * @ref previousMatch() or @ref nextMatch(). May be QString::null if there
+ * is no matching item.
+ */
+ void match( const QString& );
+
+ /**
+ * All matching items. Will be emitted by @ref makeCompletion() in shell-
+ * completion-mode, when the same string is passed to makeCompletion twice
+ * or more often.
+ */
+ void matches( const QStringList& );
+
+ /**
+ * This signal is emitted, when calling @ref makeCompletion() and more than
+ * one matching item is found.
+ * @see #hasMultipleMatches
+ */
+ void multipleMatches();
+
+ protected:
+ /**
+ * This method is called after a completion is found and before the
+ * matching string is emitted. You can override this method to modify the
+ * string that will be emitted.
+ * This is necessary e.g. in @ref OURLCompletion(), where files with spaces
+ * in their names are shown escaped ("filename\ with\ spaces"), but stored
+ * unescaped inside OCompletion.
+ * Never delete that pointer!
+ *
+ * Default implementation does nothing.
+ * @see #postProcessMatches
+ */
+ virtual void postProcessMatch( QString * /*match*/ ) const {}
+
+ /**
+ * This method is called before a list of all available completions is
+ * emitted via @ref matches. You can override this method to modify the
+ * found items before @ref match() or @ref matches() are emitted.
+ * Never delete that pointer!
+ *
+ * Default implementation does nothing.
+ * @see #postProcessMatch
+ */
+ virtual void postProcessMatches( QStringList * /*matches*/ ) const {}
+
+ /**
+ * This method is called before a list of all available completions is
+ * emitted via @ref matches. You can override this method to modify the
+ * found items before @ref match() or @ref matches() are emitted.
+ * Never delete that pointer!
+ *
+ * Default implementation does nothing.
+ * @see #postProcessMatch
+ */
+ virtual void postProcessMatches( OCompletionMatches * /*matches*/ ) const {}
+
+private:
+ void addWeightedItem( const QString& );
+ QString findCompletion( const QString& string );
+ void findAllCompletions( const QString&, OCompletionMatchesWrapper *matches, bool& hasMultipleMatches ) const;
+
+ void extractStringsFromNode( const OCompTreeNode *,
+ const QString& beginning,
+ OCompletionMatchesWrapper *matches,
+ bool addWeight = false ) const;
+ void extractStringsFromNodeCI( const OCompTreeNode *,
+ const QString& beginning,
+ const QString& restString,
+ OCompletionMatchesWrapper *matches) const;
+
+ enum BeepMode { NoMatch, PartialMatch, Rotation };
+ void doBeep( BeepMode ) const;
+
+ OGlobalSettings::Completion myCompletionMode;
+
+ CompOrder myOrder;
+ QString myLastString;
+ QString myLastMatch;
+ QString myCurrentMatch;
+ OCompTreeNode * myTreeRoot;
+ QStringList myRotations;
+ bool myBeep;
+ bool myIgnoreCase;
+ bool myHasMultipleMatches;
+ uint myRotationIndex;
+
+ private:
+ OCompletionPrivate *d;
+};
+
+// some more helper stuff
+typedef OSortableValueList<QString> OCompletionMatchesList;
+class OCompletionMatchesPrivate;
+
+/**
+ * This structure is returned by @ref OCompletion::allWeightedMatches .
+ * It also keeps the weight of the matches, allowing
+ * you to modify some matches or merge them with matches
+ * from another call to allWeightedMatches(), and sort the matches
+ * after that in order to have the matches ordered correctly
+ *
+ * Example (a simplified example of what Oonqueror's completion does):
+ * <pre>
+ * OCompletionMatches matches = completion->allWeightedMatches( location );
+ * if( !location.startsWith( "www." ))
+ matches += completion->allWeightedmatches( "www." + location" );
+ * matches.removeDuplicates();
+ * QStringList list = matches.list();
+ * </pre>
+ *
+ * @short List for keeping matches returned from OCompletion
+ */
+
+class OCompletionMatches
+ : public OCompletionMatchesList
+{
+ public:
+ OCompletionMatches( bool sort );
+ /**
+ * @internal
+ */
+ OCompletionMatches( const OCompletionMatchesWrapper& matches );
+ ~OCompletionMatches();
+ /**
+ * Removes duplicate matches. Needed only when you merged several matches
+ * results and there's a possibility of duplicates.
+ */
+ void removeDuplicates();
+ /**
+ * Returns the matches as a QStringList.
+ * @param sort if false, the matches won't be sorted before the conversion,
+ * use only if you're sure the sorting is not needed
+ */
+ QStringList list( bool sort = true ) const;
+ /**
+ * If sorting() returns false, the matches aren't sorted by their weight,
+ * even if true is passed to list().
+ */
+ bool sorting() const {
+ return _sorting;
+ }
+private:
+ bool _sorting;
+ OCompletionMatchesPrivate* d;
+};
+
+#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 @@
+/*
+                 This file is part of the Opie Project
+
+              Copyright (C) 2003 Michael Lauer <mickey@tm.informatik.uni-frankfurt.de>
+ Inspired by the KDE completion classes which are
+ Copyright (C) 2000 Dawit Alemayehu <adawit@kde.org>
+ =.
+ .=l.
+           .>+-=
+ _;:,     .>    :=|. This program is free software; you can
+.> <`_,   >  .   <= redistribute it and/or modify it under
+:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
+.="- .-=="i,     .._ License as published by the Free Software
+ - .   .-<_>     .<> Foundation; either version 2 of the License,
+     ._= =}       : or (at your option) any later version.
+    .%`+i>       _;_.
+    .i_,=:_.      -<s. This program is distributed in the hope that
+     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
+    : ..    .:,     . . . without even the implied warranty of
+    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
+  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
+..}^=.=       =       ; Library General Public License for more
+++=   -.     .`     .: details.
+ :     =  ...= . :.=-
+ -.   .:....=;==+<; You should have received a copy of the GNU
+  -_. . .   )=.  = Library General Public License along with
+    --        :-=` this library; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <opie2/ocompletion.h>
+#include <opie2/ocompletionbase.h>
+
+OCompletionBase::OCompletionBase()
+{
+ m_delegate = 0L;
+ // Assign the default completion type to use.
+ m_iCompletionMode = OGlobalSettings::completionMode();
+
+ // Initialize all key-bindings to 0 by default so that
+ // the event filter will use the global settings.
+ useGlobalKeyBindings();
+
+ // By default we initialize everything to false.
+ // All the variables would be setup properly when
+ // the appropriate member functions are called.
+ setup( false, false, false );
+}
+
+OCompletionBase::~OCompletionBase()
+{
+ if( m_bAutoDelCompObj && m_pCompObj )
+ {
+ delete m_pCompObj;
+ }
+}
+
+void OCompletionBase::setDelegate( OCompletionBase *delegate )
+{
+ m_delegate = delegate;
+
+ if ( m_delegate ) {
+ m_delegate->m_bAutoDelCompObj = m_bAutoDelCompObj;
+ m_delegate->m_bHandleSignals = m_bHandleSignals;
+ m_delegate->m_bEmitSignals = m_bEmitSignals;
+ m_delegate->m_iCompletionMode = m_iCompletionMode;
+ m_delegate->m_keyMap = m_keyMap;
+ }
+}
+
+OCompletion* OCompletionBase::completionObject( bool hsig )
+{
+ if ( m_delegate )
+ return m_delegate->completionObject( hsig );
+
+ if ( !m_pCompObj )
+ {
+ setCompletionObject( new OCompletion(), hsig );
+ m_bAutoDelCompObj = true;
+ }
+ return m_pCompObj;
+}
+
+void OCompletionBase::setCompletionObject( OCompletion* compObj, bool hsig )
+{
+ if ( m_delegate ) {
+ m_delegate->setCompletionObject( compObj, hsig );
+ return;
+ }
+
+ if ( m_bAutoDelCompObj && compObj != m_pCompObj )
+ delete m_pCompObj;
+
+ m_pCompObj = compObj;
+
+ // We emit rotation and completion signals
+ // if completion object is not NULL.
+ setup( false, hsig, !m_pCompObj.isNull() );
+}
+
+// BC: Inline this function and possibly rename it to setHandleEvents??? (DA)
+void OCompletionBase::setHandleSignals( bool handle )
+{
+ if ( m_delegate )
+ m_delegate->setHandleSignals( handle );
+ else
+ m_bHandleSignals = handle;
+}
+
+void OCompletionBase::setCompletionMode( OGlobalSettings::Completion mode )
+{
+ if ( m_delegate ) {
+ m_delegate->setCompletionMode( mode );
+ return;
+ }
+
+ m_iCompletionMode = mode;
+ // Always sync up OCompletion mode with ours as long as we
+ // are performing completions.
+ if( m_pCompObj && m_iCompletionMode != OGlobalSettings::CompletionNone )
+ m_pCompObj->setCompletionMode( m_iCompletionMode );
+}
+
+bool OCompletionBase::setKeyBinding( KeyBindingType item, const OShortcut& cut )
+{
+ if ( m_delegate )
+ return m_delegate->setKeyBinding( item, cut );
+
+
+ if( !cut.isNull() )
+ {
+ for( KeyBindingMap::Iterator it = m_keyMap.begin(); it != m_keyMap.end(); ++it )
+ if( it.data() == cut ) return false;
+ }
+ m_keyMap.replace( item, cut );
+ return true;
+}
+
+void OCompletionBase::useGlobalKeyBindings()
+{
+
+/*
+
+ if ( m_delegate ) {
+ m_delegate->useGlobalKeyBindings();
+ return;
+ }
+
+ m_keyMap.clear();
+ m_keyMap.insert( TextCompletion, 0 );
+ m_keyMap.insert( PrevCompletionMatch, 0 );
+ m_keyMap.insert( NextCompletionMatch, 0 );
+ m_keyMap.insert( SubstringCompletion, 0 );
+
+*/
+
+}
+
+void OCompletionBase::setup( bool autodel, bool hsig, bool esig )
+{
+ if ( m_delegate ) {
+ m_delegate->setup( autodel, hsig, esig );
+ return;
+ }
+
+ m_bAutoDelCompObj = autodel;
+ m_bHandleSignals = hsig;
+ m_bEmitSignals = esig;
+}
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 @@
+/*
+                 This file is part of the Opie Project
+
+              Copyright (C) 2003 Michael Lauer <mickey@tm.informatik.uni-frankfurt.de>
+ Inspired by the KDE completion classes which are
+ Copyright (C) 2000 Dawit Alemayehu <adawit@kde.org>
+ =.
+ .=l.
+           .>+-=
+ _;:,     .>    :=|. This program is free software; you can
+.> <`_,   >  .   <= redistribute it and/or modify it under
+:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
+.="- .-=="i,     .._ License as published by the Free Software
+ - .   .-<_>     .<> Foundation; either version 2 of the License,
+     ._= =}       : or (at your option) any later version.
+    .%`+i>       _;_.
+    .i_,=:_.      -<s. This program is distributed in the hope that
+     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
+    : ..    .:,     . . . without even the implied warranty of
+    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
+  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
+..}^=.=       =       ; Library General Public License for more
+++=   -.     .`     .: details.
+ :     =  ...= . :.=-
+ -.   .:....=;==+<; You should have received a copy of the GNU
+  -_. . .   )=.  = Library General Public License along with
+    --        :-=` this library; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef OCOMPLETIONBASE_H
+#define OCOMPLETIONBASE_H
+
+/**
+ * An abstract base class for adding a completion feature
+ * into widgets.
+ *
+ * This is a convenience class that provides the basic functions
+ * needed to add text completion support into widgets. All that
+ * is required is an implementation for the pure virtual function
+ * @ref setCompletedText. Refer to @ref OLineEdit or @ref OComboBox
+ * to see how easily such support can be added using this as a base
+ * class.
+ *
+ * @short An abstract class for adding text completion support to widgets.
+ * @author Dawit Alemayehu <adawit@kde.org>
+ */
+
+class OCompletionBase
+{
+
+ public:
+
+ /**
+ * Constants that represent the items whose short-cut
+ * key-binding is programmable. The default key-bindings
+ * for these items are defined in @ref OStdAccel.
+ */
+ enum KeyBindingType {
+ /**
+ * Text completion (by default Ctrl-E).
+ */
+ TextCompletion,
+ /**
+ * Switch to previous completion (by default Ctrl-Up).
+ */
+ PrevCompletionMatch,
+ /**
+ * Switch to next completion (by default Ctrl-Down).
+ */
+ NextCompletionMatch,
+ /**
+ * Substring completion (by default Ctrl-T).
+ */
+ SubstringCompletion
+ };
+
+
+ // Map for the key binding types mentioned above.
+ typedef QMap<KeyBindingType, OShortcut> KeyBindingMap;
+
+ /**
+ * Default constructor.
+ */
+ OCompletionBase();
+
+ /**
+ * Destructor.
+ */
+ virtual ~OCompletionBase();
+
+ /**
+ * Returns a pointer to the current completion object.
+ *
+ * If the object does not exist, it is automatically
+ * created. Note that the completion object created
+ * here is used by default to handle the signals
+ * internally. It is also deleted when this object's
+ * destructor is invoked. If you do not want these
+ * default settings, use @ref setAutoDeleteCompletionObject
+ * and @ref setHandleSignals to change the behavior.
+ * Alternatively, you can set the boolean parameter to
+ * false to disable the automatic handling of the signals
+ * by this object. Note that the boolean argument will be
+ * ignored if there already exists a completion object since
+ * no new object needs to be created. You need to use either
+ * @ref setHandleSignals or @ref setCompletionObject for
+ * such cases depending on your requirement.
+ *
+ * @param hsig if true, handles signals internally.
+ * @return a pointer the completion object.
+ */
+ OCompletion* completionObject( bool hsig = true );
+
+ /**
+ * Sets up the completion object to be used.
+ *
+ * This method assigns the completion object and sets it
+ * up to automatically handle the completion and rotation
+ * signals internally. You should use this function if
+ * you want to share one completion object among you widgets
+ * or need to use a customized completion object.
+ *
+ * The object assigned through this method is not deleted
+ * when this object's destructor is invoked unless you
+ * explicitly call @ref setAutoDeleteCompletionObject after
+ * calling this method. Also if you do not want the signals
+ * to be handled by an internal implementation, be sure to
+ * set the bool argument to false.
+ *
+ * This method is also called when a completion-object is created
+ * automatically, when completionObject() is called the first time.
+ *
+ * @param compObj a @ref OCompletion() or a derived child object.
+ * @param hsig if true, handles signals internally.
+ */
+ virtual void setCompletionObject( OCompletion* /*compObj*/, bool hsig = true );
+
+ /**
+ * Enables this object to handle completion and rotation
+ * events internally.
+ *
+ * This function simply assigns a boolean value that
+ * indicates whether it should handle rotation and
+ * completion events or not. Note that this does not
+ * stop the object from emitting signals when these
+ * events occur.
+ *
+ * @param handle if true, handle completion & rotation internally.
+ */
+ virtual void setHandleSignals( bool /*handle*/ );
+
+ /**
+ * Returns true if the completion object is deleted
+ * upon this widget's destruction.
+ *
+ * See @ref setCompletionObject() and @ref enableCompletion()
+ * for details.
+ *
+ * @return true if the completion object
+ */
+ bool isCompletionObjectAutoDeleted() const {
+ return m_delegate ? m_delegate->isCompletionObjectAutoDeleted() : m_bAutoDelCompObj;
+ }
+
+ /**
+ * Sets the completion object when this widget's destructor
+ * is called.
+ *
+ * If the argument is set to true, the completion object
+ * is deleted when this widget's destructor is called.
+ *
+ * @param autoDelete if true, delete completion object on destruction.
+ */
+ void setAutoDeleteCompletionObject( bool autoDelete ) {
+ if ( m_delegate )
+ m_delegate->setAutoDeleteCompletionObject( autoDelete );
+ else
+ m_bAutoDelCompObj = autoDelete;
+ }
+
+ /**
+ * Sets the widget's ability to emit text completion and
+ * rotation signals.
+ *
+ * Invoking this function with @p enable set to @p false will
+ * cause the completion & rotation signals not to be emitted.
+ * However, unlike setting the completion object to @p NULL
+ * using @ref setCompletionObject, disabling the emition of
+ * the signals through this method does not affect the current
+ * completion object.
+ *
+ * There is no need to invoke this function by default. When a
+ * completion object is created through @ref completionObject or
+ * @ref setCompletionObject, these signals are set to emit
+ * automatically. Also note that disabling this signals will not
+ * necessarily interfere with the objects ability to handle these
+ * events internally. See @ref setHandleSignals.
+ *
+ * @param enable if false, disables the emition of completion & rotation signals.
+ */
+ void setEnableSignals( bool enable ) {
+ if ( m_delegate )
+ m_delegate->setEnableSignals( enable );
+ else
+ m_bEmitSignals = enable;
+ }
+
+ /**
+ * Returns true if the object handles the signals
+ *
+ * @return true if this signals are handled internally.
+ */
+ bool handleSignals() const { return m_delegate ? m_delegate->handleSignals() : m_bHandleSignals; }
+
+ /**
+ * Returns true if the object emits the signals
+ *
+ * @return true if signals are emitted
+ */
+ bool emitSignals() const { return m_delegate ? m_delegate->emitSignals() : m_bEmitSignals; }
+
+ /**
+ * Sets the type of completion to be used.
+ *
+ * The completion modes supported are those defined in
+ * @ref OGlobalSettings(). See below.
+ *
+ * @param mode Completion type:
+ * @li CompletionNone: Disables completion feature.
+ * @li CompletionAuto: Attempts to find a match &
+ * fills-in the remaining text.
+ * @li CompletionMan: Acts the same as the above
+ * except the action has to be
+ * manually triggered through
+ * pre-defined completion key.
+ * @li CompletionShell: Mimics the completion feature
+ * found in typical *nix shell
+ * environments.
+ * @li CompletionPopup: Shows all available completions at once,
+ * in a listbox popping up.
+ */
+ virtual void setCompletionMode( OGlobalSettings::Completion mode );
+
+ /**
+ * Returns the current completion mode.
+ *
+ * The return values are of type @ref OGlobalSettings::Completion.
+ * See @ref setCompletionMode() for details.
+ *
+ * @return the completion mode.
+ */
+ OGlobalSettings::Completion completionMode() const {
+ return m_delegate ? m_delegate->completionMode() : m_iCompletionMode;
+ }
+
+ /**
+ * Sets the key-binding to be used for manual text
+ * completion, text rotation in a history list as
+ * well as a completion list.
+ *
+ *
+ * When the keys set by this function are pressed, a
+ * signal defined by the inheriting widget will be activated.
+ * If the default value or 0 is specified by the second
+ * parameter, then the key-binding as defined in the global
+ * setting should be used. This method returns false value
+ * for @p key is negative or the supplied key-binding conflicts
+ * with the ones set for one of the other features.
+ *
+ * NOTE: To use a modifier key (Shift, Ctrl, Alt) as part of
+ * the key-binding simply simply @p sum up the values of the
+ * modifier and the actual key. For example, to use CTRL+E as
+ * a key binding for one of the items, you would simply supply
+ * @p "Qt::CtrlButton + Qt::Key_E" as the second argument to this
+ * function.
+ *
+ * @param item the feature whose key-binding needs to be set:
+ *
+ * @li TextCompletion the manual completion key-binding.
+ * @li PrevCompletionMatch the previous match key for multiple completion.
+ * @li NextCompletionMatch the next match key for for multiple completion.
+ * @li SubstringCompletion the key for substring completion
+ *
+ * @param key key-binding used to rotate down in a list.
+ *
+ * @return true if key-binding can successfully be set.
+ * @see #getKeyBinding
+ */
+ bool setKeyBinding( KeyBindingType /*item*/ , const OShortcut& cut );
+
+ /**
+ * Returns the key-binding used for the specified item.
+ *
+ * This methods returns the key-binding used to activate
+ * the feature feature given by @p item. If the binding
+ * contains modifier key(s), the SUM of the modifier key
+ * and the actual key code are returned.
+ *
+ * @return the key-binding used for the feature given by @p item.
+ * @see #setKeyBinding
+ */
+ const OShortcut& getKeyBinding( KeyBindingType item ) const {
+ return m_delegate ? m_delegate->getKeyBinding( item ) : m_keyMap[ item ];
+ }
+
+ /**
+ * Sets this object to use global values for key-bindings.
+ *
+ * This method changes the values of the key bindings for
+ * rotation and completion features to the default values
+ * provided in OGlobalSettings.
+ *
+ * NOTE: By default inheriting widgets should uses the
+ * global key-bindings so that there will be no need to
+ * call this method.
+ */
+ void useGlobalKeyBindings();
+
+ /**
+ * A pure virtual function that must be implemented by
+ * all inheriting classes.
+ *
+ * This function is intended to allow external completion
+ * implementations to set completed text appropriately. It
+ * is mostly relevant when the completion mode is set to
+ * CompletionAuto and CompletionManual modes. See
+ * @ref OCompletionBase::setCompletedText.
+ * Does nothing in CompletionPopup mode, as all available
+ * matches will be shown in the popup.
+ *
+ * @param text the completed text to be set in the widget.
+ */
+ virtual void setCompletedText( const QString& text ) = 0;
+
+ /**
+ * A pure virtual function that must be implemented by
+ * all inheriting classes.
+ *
+ */
+ virtual void setCompletedItems( const QStringList& items ) = 0;
+
+ /**
+ * Returns a pointer to the completion object.
+ *
+ * This method is only different from @ref completionObject()
+ * in that it does not create a new OCompletion object even if
+ * the internal pointer is @p NULL. Use this method to get the
+ * pointer to a completion object when inheriting so that you
+ * won't inadvertently create it!!
+ *
+ * @returns the completion object or NULL if one does not exist.
+ */
+ OCompletion* compObj() const { return m_delegate ? m_delegate->compObj() : (OCompletion*) m_pCompObj; }
+
+protected:
+ /**
+ * Returns a key-binding map
+ *
+ * This method is the same as @ref getKeyBinding() except it
+ * returns the whole keymap containing the key-bindings.
+ *
+ * @return the key-binding used for the feature given by @p item.
+ */
+ KeyBindingMap getKeyBindings() const { return m_delegate ? m_delegate->getKeyBindings() : m_keyMap; }
+
+ void setDelegate( OCompletionBase *delegate );
+ OCompletionBase *delegate() const { return m_delegate; }
+
+private:
+ // This method simply sets the autodelete boolean for
+ // the completion object, the emit signals and handle
+ // signals internally flags to the provided values.
+ void setup( bool, bool, bool );
+
+ // Flag that determined whether the completion object
+ // should be deleted when this object is destroyed.
+ bool m_bAutoDelCompObj;
+ // Determines whether this widget handles completion signals
+ // internally or not
+ bool m_bHandleSignals;
+ // Determines whether this widget fires rotation signals
+ bool m_bEmitSignals;
+ // Stores the completion mode locally.
+ OGlobalSettings::Completion m_iCompletionMode;
+ // Pointer to Completion object.
+ QGuardedPtr<OCompletion> m_pCompObj;
+ // Keybindings
+ KeyBindingMap m_keyMap;
+ // we may act as a proxy to another OCompletionBase object
+ OCompletionBase *m_delegate;
+
+ // FIXME: Revise this for Opie?
+ //protected:
+ // virtual void virtual_hook( int id, void* data );
+ private:
+ OCompletionBasePrivate *d;
+};
+
+#endif // OCOMPLETIONBASE_H
+
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 @@
+// QPair minus QT_INLINE_TEMPLATE (instead directly using 'inline' directive)
+//FIXME: remove and use qpair.h as soon as we're on Qt3
+
+/****************************************************************************
+**
+** Definition of QPair class
+**
+**
+** Copyright (C) 1992-2001 Trolltech AS. All rights reserved.
+**
+** This file is part of the tools module of the Qt GUI Toolkit.
+**
+** This file may be distributed under the terms of the Q Public License
+** as defined by Trolltech AS of Norway and appearing in the file
+** LICENSE.QPL included in the packaging of this file.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
+** See http://www.trolltech.com/qpl/ for QPL licensing information.
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef QPAIR_H
+#define QPAIR_H
+
+#ifndef QT_H
+#include "qglobal.h"
+#include "qdatastream.h"
+#endif // QT_H
+
+template <class T1, class T2>
+struct QPair
+{
+ typedef T1 first_type;
+ typedef T2 second_type;
+
+ QPair()
+ : first( T1() ), second( T2() )
+ {}
+ QPair( const T1& t1, const T2& t2 )
+ : first( t1 ), second( t2 )
+ {}
+
+ T1 first;
+ T2 second;
+};
+
+template <class T1, class T2>
+inline bool operator==( const QPair<T1, T2>& x, const QPair<T1, T2>& y )
+{
+ return x.first == y.first && x.second == y.second;
+}
+
+template <class T1, class T2>
+inline bool operator<( const QPair<T1, T2>& x, const QPair<T1, T2>& y )
+{
+ return x.first < y.first ||
+ ( !( y.first < x.first ) && x.second < y.second );
+}
+
+template <class T1, class T2>
+inline QPair<T1, T2> qMakePair( const T1& x, const T2& y )
+{
+ return QPair<T1, T2>( x, y );
+}
+
+#ifndef QT_NO_DATASTREAM
+template <class T1, class T2>
+inline QDataStream& operator>>( QDataStream& s, QPair<T1, T2>& p )
+{
+ s >> p.first >> p.second;
+ return s;
+}
+
+template <class T1, class T2>
+inline QDataStream& operator<<( QDataStream& s, const QPair<T1, T2>& p )
+{
+ s << p.first << p.second;
+ return s;
+}
+#endif
+
+#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 @@
+/*
+                 This file is part of the Opie Project
+ Originally a part of the KDE Project
+ (C) 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+ =.
+ .=l.
+           .>+-=
+ _;:,     .>    :=|. This program is free software; you can
+.> <`_,   >  .   <= redistribute it and/or modify it under
+:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
+.="- .-=="i,     .._ License as published by the Free Software
+ - .   .-<_>     .<> Foundation; either version 2 of the License,
+     ._= =}       : or (at your option) any later version.
+    .%`+i>       _;_.
+    .i_,=:_.      -<s. This program is distributed in the hope that
+     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
+    : ..    .:,     . . . without even the implied warranty of
+    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
+  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
+..}^=.=       =       ; Library General Public License for more
+++=   -.     .`     .: details.
+ :     =  ...= . :.=-
+ -.   .:....=;==+<; You should have received a copy of the GNU
+  -_. . .   )=.  = Library General Public License along with
+    --        :-=` this library; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef OSORTABLEVALUELIST_H
+#define OSORTABLEVALUELIST_H
+
+#if QT_VERSION > 290
+#include <qtl.h>
+#include <qpair.h>
+#else
+#include <opie2/otl.h>
+#include <opie2/opair.h>
+#endif
+#include <qvaluelist.h>
+
+template<class T, class Key = int> class OSortableItem : public QPair<Key,T>
+{
+public:
+ OSortableItem( Key i, const T& t ) : QPair<Key, T>( i, t ) {}
+ OSortableItem( const OSortableItem<T, Key> &rhs )
+ : QPair<Key,T>( rhs.first, rhs.second ) {}
+
+ OSortableItem() {}
+
+ OSortableItem<T, Key> &operator=( const OSortableItem<T, Key>& i ) {
+ first = i.first;
+ second = i.second;
+ return *this;
+ }
+
+ // operators for sorting
+ bool operator> ( const OSortableItem<T, Key>& i2 ) const {
+ return (i2.first < first);
+ }
+ bool operator< ( const OSortableItem<T, Key>& i2 ) const {
+ return (first < i2.first);
+ }
+ bool operator>= ( const OSortableItem<T, Key>& i2 ) const {
+ return (first >= i2.first);
+ }
+ bool operator<= ( const OSortableItem<T, Key>& i2 ) const {
+ return !(i2.first < first);
+ }
+ bool operator== ( const OSortableItem<T, Key>& i2 ) const {
+ return (first == i2.first);
+ }
+ bool operator!= ( const OSortableItem<T, Key>& i2 ) const {
+ return (first != i2.first);
+ }
+
+ T& value() {
+ return second;
+ }
+ const T& value() const {
+ return second;
+ }
+
+ Key index() const {
+ return first;
+ }
+};
+
+
+// convenience
+template <class T, class Key = int>
+class OSortableValueList : public QValueList<OSortableItem<T, Key> >
+{
+public:
+ void insert( Key i, const T& t ) {
+ QValueList<OSortableItem<T, Key> >::append( OSortableItem<T, Key>( i, t ) );
+ }
+ // add more as you please...
+
+ T& operator[]( Key i ) {
+ return QValueList<OSortableItem<T, Key> >::operator[]( i ).value();
+ }
+ const T& operator[]( Key i ) const {
+ return QValueList<OSortableItem<T, Key> >::operator[]( i ).value();
+ }
+
+ void sort() {
+ qHeapSort( *this );
+ }
+};
+
+// template <class T> class OSortableValueListIterator : public QValueListIterator<OSortableItem<T> >
+// {
+// };
+
+#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 @@
+// qtl minus QT_INLINE_TEMPLATE and QT_EXPLICIT (instead directly using 'inline' directive)
+//FIXME: remove and use qtl.h as soon as we're on Qt3
+
+/****************************************************************************
+** $Id$
+**
+** Definition of Qt template library classes
+**
+** Created : 990128
+**
+** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
+**
+** This file is part of the tools module of the Qt GUI Toolkit.
+**
+** This file may be distributed under the terms of the Q Public License
+** as defined by Trolltech AS of Norway and appearing in the file
+** LICENSE.QPL included in the packaging of this file.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
+** See http://www.trolltech.com/qpl/ for QPL licensing information.
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef QTL_H
+#define QTL_H
+
+#ifndef QT_H
+#include "qglobal.h"
+#include "qtextstream.h"
+#include "qstring.h"
+#endif // QT_H
+
+#ifndef QT_NO_TEXTSTREAM
+template <class T>
+class QTextOStreamIterator
+{
+protected:
+ QTextOStream& stream;
+ QString separator;
+
+public:
+ QTextOStreamIterator( QTextOStream& s) : stream( s ) {}
+ QTextOStreamIterator( QTextOStream& s, const QString& sep )
+ : stream( s ), separator( sep ) {}
+ QTextOStreamIterator<T>& operator= ( const T& x ) {
+ stream << x;
+ if ( !separator.isEmpty() )
+ stream << separator;
+ return *this;
+ }
+ QTextOStreamIterator<T>& operator*() { return *this; }
+ QTextOStreamIterator<T>& operator++() { return *this; }
+ QTextOStreamIterator<T>& operator++(int) { return *this; }
+};
+#endif //QT_NO_TEXTSTREAM
+
+template <class InputIterator, class OutputIterator>
+inline OutputIterator qCopy( InputIterator _begin, InputIterator _end,
+ OutputIterator _dest )
+{
+ while( _begin != _end )
+ *_dest++ = *_begin++;
+ return _dest;
+}
+
+template <class BiIterator, class BiOutputIterator>
+inline BiOutputIterator qCopyBackward( BiIterator _begin, BiIterator _end,
+ BiOutputIterator _dest )
+{
+ while ( _begin != _end )
+ *--_dest = *--_end;
+ return _dest;
+}
+
+template <class InputIterator1, class InputIterator2>
+inline bool qEqual( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2 )
+{
+ // ### compare using !(*first1 == *first2) in Qt 4.0
+ for ( ; first1 != last1; ++first1, ++first2 )
+ if ( *first1 != *first2 )
+ return FALSE;
+ return TRUE;
+}
+
+template <class ForwardIterator, class T>
+inline void qFill( ForwardIterator first, ForwardIterator last, const T& val )
+{
+ for ( ; first != last; ++first )
+ *first = val;
+}
+
+#if 0
+template <class BiIterator, class OutputIterator>
+inline OutputIterator qReverseCopy( BiIterator _begin, BiIterator _end,
+ OutputIterator _dest )
+{
+ while ( _begin != _end ) {
+ --_end;
+ *_dest = *_end;
+ ++_dest;
+ }
+ return _dest;
+}
+#endif
+
+
+template <class InputIterator, class T>
+inline InputIterator qFind( InputIterator first, InputIterator last,
+ const T& val )
+{
+ while ( first != last && *first != val )
+ ++first;
+ return first;
+}
+
+template <class InputIterator, class T, class Size>
+inline void qCount( InputIterator first, InputIterator last, const T& value,
+ Size& n )
+{
+ for ( ; first != last; ++first )
+ if ( *first == value )
+ ++n;
+}
+
+template <class T>
+inline void qSwap( T& _value1, T& _value2 )
+{
+ T tmp = _value1;
+ _value1 = _value2;
+ _value2 = tmp;
+}
+
+
+template <class InputIterator>
+inline void qBubbleSort( InputIterator b, InputIterator e )
+{
+ // Goto last element;
+ InputIterator last = e;
+ --last;
+ // only one element or no elements ?
+ if ( last == b )
+ return;
+
+ // So we have at least two elements in here
+ while( b != last ) {
+ bool swapped = FALSE;
+ InputIterator swap_pos = b;
+ InputIterator x = e;
+ InputIterator y = x;
+ y--;
+ do {
+ --x;
+ --y;
+ if ( *x < *y ) {
+ swapped = TRUE;
+ qSwap( *x, *y );
+ swap_pos = y;
+ }
+ } while( y != b );
+ if ( !swapped )
+ return;
+ b = swap_pos;
+ b++;
+ }
+}
+
+
+template <class Container>
+inline void qBubbleSort( Container &c )
+{
+ qBubbleSort( c.begin(), c.end() );
+}
+
+
+template <class Value>
+inline void qHeapSortPushDown( Value* heap, int first, int last )
+{
+ int r = first;
+ while ( r <= last / 2 ) {
+ if ( last == 2 * r ) {
+ // node r has only one child
+ if ( heap[2 * r] < heap[r] )
+ qSwap( heap[r], heap[2 * r] );
+ r = last;
+ } else {
+ // node r has two children
+ if ( heap[2 * r] < heap[r] && !(heap[2 * r + 1] < heap[2 * r]) ) {
+ // swap with left child
+ qSwap( heap[r], heap[2 * r] );
+ r *= 2;
+ } else if ( heap[2 * r + 1] < heap[r]
+ && heap[2 * r + 1] < heap[2 * r] ) {
+ // swap with right child
+ qSwap( heap[r], heap[2 * r + 1] );
+ r = 2 * r + 1;
+ } else {
+ r = last;
+ }
+ }
+ }
+}
+
+
+template <class InputIterator, class Value>
+inline void qHeapSortHelper( InputIterator b, InputIterator e, Value, uint n )
+{
+ // Create the heap
+ InputIterator insert = b;
+ Value* realheap = new Value[n];
+ // Wow, what a fake. But I want the heap to be indexed as 1...n
+ Value* heap = realheap - 1;
+ int size = 0;
+ for( ; insert != e; ++insert ) {
+ heap[++size] = *insert;
+ int i = size;
+ while( i > 1 && heap[i] < heap[i / 2] ) {
+ qSwap( heap[i], heap[i / 2] );
+ i /= 2;
+ }
+ }
+
+ // Now do the sorting
+ for( uint i = n; i > 0; i-- ) {
+ *b++ = heap[1];
+ if ( i > 1 ) {
+ heap[1] = heap[i];
+ qHeapSortPushDown( heap, 1, (int)i - 1 );
+ }
+ }
+
+ delete[] realheap;
+}
+
+
+template <class InputIterator>
+inline void qHeapSort( InputIterator b, InputIterator e )
+{
+ // Empty ?
+ if ( b == e )
+ return;
+
+ // How many entries have to be sorted ?
+ InputIterator it = b;
+ uint n = 0;
+ while ( it != e ) {
+ ++n;
+ ++it;
+ }
+
+ // The second last parameter is a hack to retrieve the value type
+ // Do the real sorting here
+ qHeapSortHelper( b, e, *b, n );
+}
+
+
+template <class Container>
+inline void qHeapSort( Container &c )
+{
+ if ( c.begin() == c.end() )
+ return;
+
+ // The second last parameter is a hack to retrieve the value type
+ // Do the real sorting here
+ qHeapSortHelper( c.begin(), c.end(), *(c.begin()), (uint)c.count() );
+}
+
+template <class Container>
+class QBackInsertIterator
+{
+public:
+ QBackInsertIterator( Container &c )
+ : container( &c )
+ {
+ }
+
+ QBackInsertIterator<Container>&
+ operator=( const typename Container::value_type &value )
+ {
+ container->push_back( value );
+ return *this;
+ }
+
+ QBackInsertIterator<Container>& operator*()
+ {
+ return *this;
+ }
+
+ QBackInsertIterator<Container>& operator++()
+ {
+ return *this;
+ }
+
+ QBackInsertIterator<Container>& operator++(int)
+ {
+ return *this;
+ }
+
+protected:
+ Container *container;
+};
+
+template <class Container>
+inline QBackInsertIterator<Container> qBackInserter( Container &c )
+{
+ return QBackInsertIterator<Container>( c );
+}
+
+#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 @@
+/*
+ This file Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
+ is part of the Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ Opie Project Copyright (C) 2000 Dawit Alemayehu <adawit@kde.org>
+
+ =. Originally part of the KDE Project
+ .=l.
+           .>+-=
+ _;:,     .>    :=|. This program is free software; you can
+.> <`_,   >  .   <= redistribute it and/or modify it under
+:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
+.="- .-=="i,     .._ License as published by the Free Software
+ - .   .-<_>     .<> Foundation; either version 2 of the License,
+     ._= =}       : or (at your option) any later version.
+    .%`+i>       _;_.
+    .i_,=:_.      -<s. This program is distributed in the hope that
+     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
+    : ..    .:,     . . . without even the implied warranty of
+    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
+  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
+..}^=.=       =       ; Library General Public License for more
+++=   -.     .`     .: details.
+ :     =  ...= . :.=-
+ -.   .:....=;==+<; You should have received a copy of the GNU
+  -_. . .   )=.  = Library General Public License along with
+    --        :-=` this library; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+*/
+
+/* QT */
+
+#include <qclipboard.h>
+#include <qlistbox.h>
+#include <qpopupmenu.h>
+
+/* OPIE */
+
+#include <opie2/ocompletionbox.h>
+#include <opie2/olineedit.h>
+#include <opie2/opixmapprovider.h>
+#include <opie2/ocombobox.h>
+
+/*======================================================================================
+ * OComboBoxPrivate
+ *======================================================================================*/
+
+class OComboBox::OComboBoxPrivate
+{
+public:
+ OComboBoxPrivate()
+ {
+ olineEdit = 0L;
+ }
+ ~OComboBoxPrivate()
+ {
+ }
+
+ OLineEdit *olineEdit;
+};
+
+/*======================================================================================
+ * OComboBox
+ *======================================================================================*/
+
+OComboBox::OComboBox( QWidget *parent, const char *name )
+ : QComboBox( parent, name )
+{
+ init();
+}
+
+OComboBox::OComboBox( bool rw, QWidget *parent, const char *name )
+ : QComboBox( rw, parent, name )
+{
+ init();
+
+ if ( rw )
+ {
+ OLineEdit *edit = new OLineEdit( this, "combo lineedit" );
+ setLineEdit( edit );
+ }
+}
+
+OComboBox::~OComboBox()
+{
+ delete d;
+}
+
+void OComboBox::init()
+{
+ d = new OComboBoxPrivate;
+
+ // Permanently set some parameters in the parent object.
+ QComboBox::setAutoCompletion( false );
+
+ // Initialize enable popup menu to false.
+ // Below it will be enabled if the widget
+ // is editable.
+ m_bEnableMenu = false;
+
+ m_trapReturnKey = false;
+
+ // Enable context menu by default if widget
+ // is editable.
+ setContextMenuEnabled( true );
+
+ // for wheelscrolling
+ installEventFilter( this );
+ if ( lineEdit() )
+ lineEdit()->installEventFilter( this );
+}
+
+
+bool OComboBox::contains( const QString& _text ) const
+{
+ if ( _text.isEmpty() )
+ return false;
+
+ for (int i = 0; i < count(); i++ ) {
+ if ( text(i) == _text )
+ return true;
+ }
+ return false;
+}
+
+void OComboBox::setAutoCompletion( bool autocomplete )
+{
+ if ( d->olineEdit )
+ {
+ if ( autocomplete )
+ {
+ d->olineEdit->setCompletionMode( OGlobalSettings::CompletionAuto );
+ setCompletionMode( OGlobalSettings::CompletionAuto );
+ }
+ else
+ {
+ d->olineEdit->setCompletionMode( OGlobalSettings::completionMode() );
+ setCompletionMode( OGlobalSettings::completionMode() );
+ }
+ }
+}
+
+void OComboBox::setContextMenuEnabled( bool showMenu )
+{
+ if( d->olineEdit )
+ {
+ d->olineEdit->setContextMenuEnabled( showMenu );
+ m_bEnableMenu = showMenu;
+ }
+}
+
+/*
+void OComboBox::setURLDropsEnabled( bool enable )
+{
+ if ( d->olineEdit )
+ d->olineEdit->setURLDropsEnabled( enable );
+}
+
+bool OComboBox::isURLDropsEnabled() const
+{
+ return d->olineEdit && d->olineEdit->isURLDropsEnabled();
+}
+*/
+
+void OComboBox::setCompletedText( const QString& text, bool marked )
+{
+ if ( d->olineEdit )
+ d->olineEdit->setCompletedText( text, marked );
+}
+
+void OComboBox::setCompletedText( const QString& text )
+{
+ if ( d->olineEdit )
+ d->olineEdit->setCompletedText( text );
+}
+
+void OComboBox::makeCompletion( const QString& text )
+{
+ if( d->olineEdit )
+ d->olineEdit->makeCompletion( text );
+
+ else // read-only combo completion
+ {
+ if( text.isNull() || !listBox() )
+ return;
+
+ int index = listBox()->index( listBox()->findItem( text ) );
+ if( index >= 0 ) {
+ setCurrentItem( index );
+ }
+ }
+}
+
+void OComboBox::rotateText( OCompletionBase::KeyBindingType type )
+{
+ if ( d->olineEdit )
+ d->olineEdit->rotateText( type );
+}
+
+bool OComboBox::eventFilter( QObject* o, QEvent* ev )
+{
+ QLineEdit *edit = lineEdit();
+
+ int type = ev->type();
+
+ if ( o == edit )
+ {
+ //OCursor::autoHideEventFilter( edit, ev );
+
+ if ( type == QEvent::KeyPress )
+ {
+ QKeyEvent *e = static_cast<QKeyEvent *>( ev );
+
+ if ( e->key() == Key_Return || e->key() == Key_Enter)
+ {
+ // On Return pressed event, emit both
+ // returnPressed(const QString&) and returnPressed() signals
+ emit returnPressed();
+ emit returnPressed( currentText() );
+ if ( d->olineEdit && d->olineEdit->completionBox(false) &&
+ d->olineEdit->completionBox()->isVisible() )
+ d->olineEdit->completionBox()->hide();
+
+ return m_trapReturnKey;
+ }
+ }
+ }
+
+
+ // wheel-scrolling changes the current item
+ if ( type == QEvent::Wheel ) {
+ if ( !listBox() || listBox()->isHidden() ) {
+ QWheelEvent *e = static_cast<QWheelEvent*>( ev );
+ static const int WHEEL_DELTA = 120;
+ int skipItems = e->delta() / WHEEL_DELTA;
+ if ( e->state() & ControlButton ) // fast skipping
+ skipItems *= 10;
+
+ int newItem = currentItem() - skipItems;
+
+ if ( newItem < 0 )
+ newItem = 0;
+ else if ( newItem >= count() )
+ newItem = count() -1;
+
+ setCurrentItem( newItem );
+ if ( !text( newItem ).isNull() )
+ emit activated( text( newItem ) );
+ emit activated( newItem );
+ e->accept();
+ return true;
+ }
+ }
+
+ return QComboBox::eventFilter( o, ev );
+}
+
+void OComboBox::setTrapReturnKey( bool grab )
+{
+ m_trapReturnKey = grab;
+}
+
+bool OComboBox::trapReturnKey() const
+{
+ return m_trapReturnKey;
+}
+
+/*
+void OComboBox::setEditURL( const OURL& url )
+{
+ QComboBox::setEditText( url.prettyURL() );
+}
+
+void OComboBox::insertURL( const OURL& url, int index )
+{
+ QComboBox::insertItem( url.prettyURL(), index );
+}
+
+void OComboBox::insertURL( const QPixmap& pixmap, const OURL& url, int index )
+{
+ QComboBox::insertItem( pixmap, url.prettyURL(), index );
+}
+
+void OComboBox::changeURL( const OURL& url, int index )
+{
+ QComboBox::changeItem( url.prettyURL(), index );
+}
+
+void OComboBox::changeURL( const QPixmap& pixmap, const OURL& url, int index )
+{
+ QComboBox::changeItem( pixmap, url.prettyURL(), index );
+}
+*/
+
+
+void OComboBox::setCompletedItems( const QStringList& items )
+{
+ if ( d->olineEdit )
+ d->olineEdit->setCompletedItems( items );
+}
+
+
+OCompletionBox * OComboBox::completionBox( bool create )
+{
+ if ( d->olineEdit )
+ return d->olineEdit->completionBox( create );
+ return 0;
+}
+
+// QWidget::create() turns off mouse-Tracking which would break auto-hiding
+void OComboBox::create( WId id, bool initializeWindow, bool destroyOldWindow )
+{
+ QComboBox::create( id, initializeWindow, destroyOldWindow );
+ //OCursor::setAutoHideCursor( lineEdit(), true, true );
+}
+
+void OComboBox::setLineEdit( OLineEdit *edit )
+{
+ #if QT_VERSION > 290
+ QComboBox::setLineEdit( edit );
+ d->olineEdit = dynamic_cast<OLineEdit*>( edit );
+ setDelegate( d->olineEdit );
+
+ // forward some signals. We only emit returnPressed() ourselves.
+ if ( d->olineEdit ) {
+ connect( d->olineEdit, SIGNAL( completion( const QString& )),
+ SIGNAL( completion( const QString& )) );
+ connect( d->olineEdit, SIGNAL( substringCompletion( const QString& )),
+ SIGNAL( substringCompletion( const QString& )) );
+ connect( d->olineEdit,
+ SIGNAL( textRotation( OCompletionBase::KeyBindingType )),
+ SIGNAL( textRotation( OCompletionBase::KeyBindingType )) );
+ connect( d->olineEdit,
+ SIGNAL( completionModeChanged( OGlobalSettings::Completion )),
+ SIGNAL( completionModeChanged( OGlobalSettings::Completion)));
+
+ connect( d->olineEdit,
+ SIGNAL( aboutToShowContextMenu( QPopupMenu * )),
+ SIGNAL( aboutToShowContextMenu( QPopupMenu * )) );
+ }
+ #else
+ #warning OComboBox is not fully functional with Qt2
+ #endif
+}
+
+// Temporary functions until QT3 appears. - Seth Chaiklin 20 may 2001
+void OComboBox::deleteWordForward()
+{
+ lineEdit()->cursorWordForward(TRUE);
+ #if QT_VERSION > 290
+ if ( lineEdit()->hasSelectedText() )
+ #else
+ if ( lineEdit()->hasMarkedText() )
+ #endif
+ {
+ lineEdit()->del();
+ }
+}
+
+void OComboBox::deleteWordBack()
+{
+ lineEdit()->cursorWordBackward(TRUE);
+ #if QT_VERSION > 290
+ if ( lineEdit()->hasSelectedText() )
+ #else
+ if ( lineEdit()->hasMarkedText() )
+ #endif
+ {
+ lineEdit()->del();
+ }
+}
+
+void OComboBox::setCurrentItem( const QString& item, bool insert, int index )
+{
+ int sel = -1;
+ for (int i = 0; i < count(); ++i)
+ if (text(i) == item)
+ {
+ sel = i;
+ break;
+ }
+ if (sel == -1 && insert)
+ {
+ insertItem(item, index);
+ if (index >= 0)
+ sel = index;
+ else
+ sel = count() - 1;
+ }
+ setCurrentItem(sel);
+}
+
+void OComboBox::setCurrentItem(int index)
+{
+ QComboBox::setCurrentItem(index);
+}
+
+
+/*======================================================================================
+ * OHistoryCombo
+ *======================================================================================*/
+
+// we are always read-write
+OHistoryCombo::OHistoryCombo( QWidget *parent, const char *name )
+ : OComboBox( true, parent, name )
+{
+ init( true ); // using completion
+}
+
+// we are always read-write
+OHistoryCombo::OHistoryCombo( bool useCompletion,
+ QWidget *parent, const char *name )
+ : OComboBox( true, parent, name )
+{
+ init( useCompletion );
+}
+
+void OHistoryCombo::init( bool useCompletion )
+{
+ if ( useCompletion )
+ completionObject()->setOrder( OCompletion::Weighted );
+
+ setInsertionPolicy( NoInsertion );
+ myIterateIndex = -1;
+ myRotated = false;
+ myPixProvider = 0L;
+
+ connect( this, SIGNAL(aboutToShowContextMenu(QPopupMenu*)),
+ SLOT(addContextMenuItems(QPopupMenu*)) );
+ connect( this, SIGNAL( activated(int) ), SLOT( slotReset() ));
+ connect( this, SIGNAL( returnPressed(const QString&) ), SLOT(slotReset()));
+}
+
+OHistoryCombo::~OHistoryCombo()
+{
+ delete myPixProvider;
+}
+
+void OHistoryCombo::setHistoryItems( QStringList items,
+ bool setCompletionList )
+{
+ OComboBox::clear();
+
+ // limit to maxCount()
+ while ( (int) items.count() > maxCount() && !items.isEmpty() )
+ items.remove( items.begin() );
+
+ insertItems( items );
+
+ if ( setCompletionList && useCompletion() ) {
+ // we don't have any weighting information here ;(
+ OCompletion *comp = completionObject();
+ comp->setOrder( OCompletion::Insertion );
+ comp->setItems( items );
+ comp->setOrder( OCompletion::Weighted );
+ }
+
+ clearEdit();
+}
+
+QStringList OHistoryCombo::historyItems() const
+{
+ QStringList list;
+ for ( int i = 0; i < count(); i++ )
+ list.append( text( i ) );
+
+ return list;
+}
+
+void OHistoryCombo::clearHistory()
+{
+ OComboBox::clear();
+ if ( useCompletion() )
+ completionObject()->clear();
+}
+
+void OHistoryCombo::addContextMenuItems( QPopupMenu* menu )
+{
+ if ( menu &&!lineEdit()->text().isEmpty())
+ {
+ menu->insertSeparator();
+ menu->insertItem( tr("Empty Contents"), this, SLOT( slotClear()));
+ }
+}
+
+void OHistoryCombo::addToHistory( const QString& item )
+{
+ if ( item.isEmpty() || (count() > 0 && item == text(0) ))
+ return;
+
+ // remove all existing items before adding
+ if ( !duplicatesEnabled() ) {
+ for ( int i = 0; i < count(); i++ ) {
+ if ( text( i ) == item )
+ removeItem( i );
+ }
+ }
+
+ // now add the item
+ if ( myPixProvider )
+ //insertItem( myPixProvider->pixmapFor(item, KIcon::SizeSmall), item, 0);
+ insertItem( myPixProvider->pixmapFor(item, 16), item, 0);
+ else
+ insertItem( item, 0 );
+
+ int last;
+ QString rmItem;
+
+ bool useComp = useCompletion();
+ while ( count() > maxCount() && count() > 0 ) {
+ // remove the last item, as long as we are longer than maxCount()
+ // remove the removed item from the completionObject if it isn't
+ // anymore available at all in the combobox.
+ last = count() - 1;
+ rmItem = text( last );
+ removeItem( last );
+ if ( useComp && !contains( rmItem ) )
+ completionObject()->removeItem( rmItem );
+ }
+
+ if ( useComp )
+ completionObject()->addItem( item );
+}
+
+bool OHistoryCombo::removeFromHistory( const QString& item )
+{
+ if ( item.isEmpty() )
+ return false;
+
+ bool removed = false;
+ QString temp = currentText();
+ for ( int i = 0; i < count(); i++ ) {
+ while ( item == text( i ) ) {
+ removed = true;
+ removeItem( i );
+ }
+ }
+
+ if ( removed && useCompletion() )
+ completionObject()->removeItem( item );
+
+ setEditText( temp );
+ return removed;
+}
+
+void OHistoryCombo::keyPressEvent( QKeyEvent *e )
+{
+ // save the current text in the lineedit
+ if ( myIterateIndex == -1 )
+ myText = currentText();
+
+ // going up in the history, rotating when reaching QListBox::count()
+ //if ( OStdAccel::isEqual( e, OStdAccel::rotateUp() ) ) {
+ if ( e->key() == Qt::Key_Up ) {
+ myIterateIndex++;
+
+ // skip duplicates/empty items
+ while ( myIterateIndex < count()-1 &&
+ (currentText() == text( myIterateIndex ) ||
+ text( myIterateIndex ).isEmpty()) )
+ myIterateIndex++;
+
+ if ( myIterateIndex >= count() ) {
+ myRotated = true;
+ myIterateIndex = -1;
+
+ // if the typed text is the same as the first item, skip the first
+ if ( myText == text(0) )
+ myIterateIndex = 0;
+
+ setEditText( myText );
+ }
+ else
+ setEditText( text( myIterateIndex ));
+ }
+
+
+ // going down in the history, no rotation possible. Last item will be
+ // the text that was in the lineedit before Up was called.
+ //else if ( OStdAccel::isEqual( e, OStdAccel::rotateDown() ) ) {
+ else if ( e->key() == Qt::Key_Down ) {
+ myIterateIndex--;
+
+ // skip duplicates/empty items
+ while ( myIterateIndex >= 0 &&
+ (currentText() == text( myIterateIndex ) ||
+ text( myIterateIndex ).isEmpty()) )
+ myIterateIndex--;
+
+
+ if ( myIterateIndex < 0 ) {
+ if ( myRotated && myIterateIndex == -2 ) {
+ myRotated = false;
+ myIterateIndex = count() - 1;
+ setEditText( text(myIterateIndex) );
+ }
+ else { // bottom of history
+ if ( myIterateIndex == -2 ) {
+ qDebug( "ONotifyClient is not implemented yet." );
+ //ONotifyClient::event( ONotifyClient::notification,
+ // i18n("No further item in the history."));
+ }
+
+ myIterateIndex = -1;
+ if ( currentText() != myText )
+ setEditText( myText );
+ }
+ }
+ else
+ setEditText( text( myIterateIndex ));
+ }
+
+ else
+ OComboBox::keyPressEvent( e );
+}
+
+void OHistoryCombo::slotReset()
+{
+ myIterateIndex = -1;
+ myRotated = false;
+}
+
+
+void OHistoryCombo::setPixmapProvider( OPixmapProvider *prov )
+{
+ if ( myPixProvider == prov )
+ return;
+
+ delete myPixProvider;
+ myPixProvider = prov;
+
+ // re-insert all the items with/without pixmap
+ // I would prefer to use changeItem(), but that doesn't honour the pixmap
+ // when using an editable combobox (what we do)
+ if ( count() > 0 ) {
+ QStringList items( historyItems() );
+ clear();
+ insertItems( items );
+ }
+}
+
+void OHistoryCombo::insertItems( const QStringList& items )
+{
+ QStringList::ConstIterator it = items.begin();
+ QString item;
+ while ( it != items.end() ) {
+ item = *it;
+ if ( !item.isEmpty() ) { // only insert non-empty items
+ if ( myPixProvider )
+ // insertItem( myPixProvider->pixmapFor(item, OIcon::SizeSmall), item );
+ insertItem( myPixProvider->pixmapFor(item, 16), item );
+ else
+ insertItem( item );
+ }
+ ++it;
+ }
+}
+
+void OHistoryCombo::slotClear()
+{
+ clearHistory();
+ emit cleared();
+}
+
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 @@
+/*
+ This file Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
+ is part of the Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ Opie Project Copyright (C) 2000 Dawit Alemayehu <adawit@kde.org>
+
+ =. Originally part of the KDE projects
+ .=l.
+           .>+-=
+ _;:,     .>    :=|. This program is free software; you can
+.> <`_,   >  .   <= redistribute it and/or modify it under
+:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
+.="- .-=="i,     .._ License as published by the Free Software
+ - .   .-<_>     .<> Foundation; either version 2 of the License,
+     ._= =}       : or (at your option) any later version.
+    .%`+i>       _;_.
+    .i_,=:_.      -<s. This program is distributed in the hope that
+     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
+    : ..    .:,     . . . without even the implied warranty of
+    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
+  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
+..}^=.=       =       ; Library General Public License for more
+++=   -.     .`     .: details.
+ :     =  ...= . :.=-
+ -.   .:....=;==+<; You should have received a copy of the GNU
+  -_. . .   )=.  = Library General Public License along with
+    --        :-=` this library; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef OCOMBOBOX_H
+#define OCOMBOBOX_H
+
+/* QT */
+
+#include <qcombobox.h>
+
+/* OPIE */
+
+#include <opie2/olineedit.h>
+#include <opie2/ocompletion.h>
+#include <opie2/ocompletionbase.h>
+
+/* FORWARDS */
+
+class QListBoxItem;
+class QPopupMenu;
+class OCompletionBox;
+typedef QString OURL;
+
+/**
+ * A combined button, line-edit and a popup list widget.
+ *
+ * @sect Detail
+ *
+ * This widget inherits from @ref QComboBox and implements
+ * the following additional functionalities: a completion
+ * object that provides both automatic and manual text
+ * completion as well as text rotation features, configurable
+ * key-bindings to activate these features, and a popup-menu
+ * item that can be used to allow the user to set text completion
+ * modes on the fly based on their preference.
+ *
+ * To support these new features OComboBox also emits a few
+ * more additional signals as well. The main ones are the
+ * @ref completion( const QString& ) and @ref textRotation( KeyBindingType )
+ * signals. The completion signal is intended to be connected to a slot
+ * that will assist the user in filling out the remaining text while
+ * the rotation signals is intended to be used to traverse through all
+ * possible matches whenever text completion results in multiple matches.
+ * The @ref returnPressed() and @ref returnPressed( const QString& )
+ * signal is emitted when the user presses the Enter/Return key.
+ *
+ * This widget by default creates a completion object when you invoke
+ * the @ref completionObject( bool ) member function for the first time
+ * or use @ref setCompletionObject( OCompletion*, bool ) to assign your
+ * own completion object. Additionally, to make this widget more functional,
+ * OComboBox will by default handle the text rotation and completion
+ * events internally whenever a completion object is created through either
+ * one of the methods mentioned above. If you do not need this functionality,
+ * simply use @ref OCompletionBase::setHandleSignals( bool ) or alternatively
+ * set the boolean parameter in the above methods to FALSE.
+ *
+ * The default key-bindings for completion and rotation is determined
+ * from the global settings in @ref OStdAccel. These values, however,
+ * can be overriden locally by invoking @ref OCompletionBase::setKeyBinding().
+ * The values can easily be reverted back to the default setting, by simply
+ * calling @ref useGlobalSettings(). An alternate method would be to default
+ * individual key-bindings by usning @ref setKeyBinding() with the default
+ * second argument.
+ *
+ * Note that if this widget is not editable ( i.e. select-only ), then only
+ * one completion mode, @p CompletionAuto, will work. All the other modes are
+ * simply ignored. The @p CompletionAuto mode in this case allows you to
+ * automatically select an item from the list by trying to match the pressed
+ * keycode with the first letter of the enteries in the combo box.
+ *
+ * @sect Useage
+ *
+ * To enable the basic completion feature:
+ *
+ * <pre>
+ * OComboBox *combo = new OComboBox( true, this, "mywidget" );
+ * OCompletion *comp = combo->completionObject();
+ * // Connect to the return pressed signal - optional
+ * connect(combo,SIGNAL(returnPressed(const QString&)),comp,SLOT(addItem(const QString&));
+ * </pre>
+ *
+ * To use your own completion object:
+ *
+ * <pre>
+ * OComboBox *combo = new OComboBox( this,"mywidget" );
+ * OURLCompletion *comp = new OURLCompletion();
+ * combo->setCompletionObject( comp );
+ * // Connect to the return pressed signal - optional
+ * connect(combo,SIGNAL(returnPressed(const QString&)),comp,SLOT(addItem(const QString&));
+ * </pre>
+ *
+ * Note that you have to either delete the allocated completion object
+ * when you don't need it anymore, or call
+ * setAutoDeleteCompletionObject( true );
+ *
+ * Miscellaneous function calls:
+ *
+ * <pre>
+ * // Tell the widget not to handle completion and rotation
+ * combo->setHandleSignals( false );
+ * // Set your own completion key for manual completions.
+ * combo->setKeyBinding( OCompletionBase::TextCompletion, Qt::End );
+ * // Hide the context (popup) menu
+ * combo->setContextMenuEnabled( false );
+ * // Temporarly disable signal emition
+ * combo->disableSignals();
+ * // Default the all key-bindings to their system-wide settings.
+ * combo->useGlobalKeyBindings();
+ * </pre>
+ *
+ * @short An enhanced combo box.
+ * @author Dawit Alemayehu <adawit@kde.org>
+ */
+class OComboBox : public QComboBox, public OCompletionBase
+{
+ Q_OBJECT
+
+ //Q_PROPERTY( bool autoCompletion READ autoCompletion WRITE setAutoCompletion )
+ //Q_PROPERTY( bool contextMenuEnabled READ isContextMenuEnabled WRITE setContextMenuEnabled )
+ //Q_PROPERTY( bool urlDropsEnabled READ isURLDropsEnabled WRITE setURLDropsEnabled )
+
+public:
+
+ /**
+ * Constructs a read-only or rather select-only combo box with a
+ * parent object and a name.
+ *
+ * @param parent The parent object of this widget
+ * @param name The name of this widget
+ */
+ OComboBox( QWidget *parent=0, const char *name=0 );
+
+ /**
+ * Constructs a "read-write" or "read-only" combo box depending on
+ * the value of the first argument( @p rw ) with a parent, a
+ * name.
+ *
+ * @param rw When @p true, widget will be editable.
+ * @param parent The parent object of this widget.
+ * @param name The name of this widget.
+ */
+ OComboBox( bool rw, QWidget *parent=0, const char *name=0 );
+
+ /**
+ * Destructor.
+ */
+ virtual ~OComboBox();
+
+ /**
+ * Sets @p url into the edit field of the combobox. It uses
+ * @ref OURL::prettyURL() so that the url is properly decoded for
+ * displaying.
+ */
+ //void setEditURL( const OURL& url );
+
+ /**
+ * Inserts @p url at position @p index into the combobox. The item will
+ * be appended if @p index is negative. @ref OURL::prettyURL() is used
+ * so that the url is properly decoded for displaying.
+ */
+ //void insertURL( const OURL& url, int index = -1 );
+
+ /**
+ * Inserts @p url with the pixmap &p pixmap at position @p index into
+ * the combobox. The item will be appended if @p index is negative.
+ * @ref OURL::prettyURL() is used so that the url is properly decoded
+ * for displaying.
+ */
+ //void insertURL( const QPixmap& pixmap, const OURL& url, int index = -1 );
+
+ /**
+ * Replaces the item at position @p index with @p url.
+ * @ref OURL::prettyURL() is used so that the url is properly decoded
+ * for displaying.
+ */
+ //void changeURL( const OURL& url, int index );
+
+ /**
+ * Replaces the item at position @p index with @p url and pixmap @p pixmap.
+ * @ref OURL::prettyURL() is used so that the url is properly decoded
+ * for displaying.
+ */
+ //void changeURL( const QPixmap& pixmap, const OURL& url, int index );
+
+ /**
+ * Returns the current cursor position.
+ *
+ * This method always returns a -1 if the combo-box is @em not
+ * editable (read-write).
+ *
+ * @return Current cursor position.
+ */
+ int cursorPosition() const { return ( lineEdit() ) ? lineEdit()->cursorPosition() : -1; }
+
+ /**
+ * Re-implemented from @ref QComboBox.
+ *
+ * If @p true, the completion mode will be set to automatic.
+ * Otherwise, it is defaulted to the global setting. This
+ * method has been replaced by the more comprehensive
+ * @ref setCompletionMode().
+ *
+ * @param autocomplete Flag to enable/disable automatic completion mode.
+ */
+ virtual void setAutoCompletion( bool autocomplete );
+
+ /**
+ * Re-implemented from QComboBox.
+ *
+ * Returns @p true if the current completion mode is set
+ * to automatic. See its more comprehensive replacement
+ * @ref completionMode().
+ *
+ * @return @p true when completion mode is automatic.
+ */
+ bool autoCompletion() const {
+ return completionMode() == OGlobalSettings::CompletionAuto;
+ }
+
+ /**
+ * Enables or disable the popup (context) menu.
+ *
+ * This method only works if this widget is editable, i.e.
+ * read-write and allows you to enable/disable the context
+ * menu. It does nothing if invoked for a none-editable
+ * combo-box. Note that by default the mode changer item
+ * is made visiable whenever the context menu is enabled.
+ * Use @ref hideModechanger() if you want to hide this
+ * item. Also by default, the context menu is created if
+ * this widget is editable. Call this function with the
+ * argument set to false to disable the popup menu.
+ *
+ * @param showMenu If @p true, show the context menu.
+ * @param showMode If @p true, show the mode changer.
+ */
+ virtual void setContextMenuEnabled( bool showMenu );
+
+ /**
+ * Returns @p true when the context menu is enabled.
+ */
+ bool isContextMenuEnabled() const { return m_bEnableMenu; }
+
+ /**
+ * Enables/Disables handling of URL drops. If enabled and the user
+ * drops an URL, the decoded URL will be inserted. Otherwise the default
+ * behaviour of QComboBox is used, which inserts the encoded URL.
+ *
+ * @param enable If @p true, insert decoded URLs
+ */
+ //void setURLDropsEnabled( bool enable );
+
+ /**
+ * Returns @p true when decoded URL drops are enabled
+ */
+ //bool isURLDropsEnabled() const;
+
+ /**
+ * Convenience method which iterates over all items and checks if
+ * any of them is equal to @p text.
+ *
+ * If @p text is an empty string, @p false
+ * is returned.
+ *
+ * @return @p true if an item with the string @p text is in the combobox.
+ */
+ bool contains( const QString& text ) const;
+
+ /**
+ * By default, OComboBox recognizes Key_Return and Key_Enter
+ * and emits
+ * the @ref returnPressed() signals, but it also lets the event pass,
+ * for example causing a dialog's default-button to be called.
+ *
+ * Call this method with @p trap equal to true to make OComboBox
+ * stop these
+ * events. The signals will still be emitted of course.
+ *
+ * Only affects read-writable comboboxes.
+ *
+ * @see setTrapReturnKey()
+ */
+ void setTrapReturnKey( bool trap );
+
+ /**
+ * @return @p true if keyevents of Key_Return or Key_Enter will
+ * be stopped or if they will be propagated.
+ *
+ * @see setTrapReturnKey ()
+ */
+ bool trapReturnKey() const;
+
+ /**
+ * Re-implemented for internal reasons. API not affected.
+ *
+ * @reimplemented
+ */
+ virtual bool eventFilter( QObject *, QEvent * );
+
+ /**
+ * @returns the completion-box, that is used in completion mode
+ * @ref OGlobalSettings::CompletionPopup and @ref OGlobalSettings::CompletionPopupAuto.
+ * This method will create a completion-box by calling
+ * @ref OLineEdit::completionBox, if none is there, yet.
+ *
+ * @param create Set this to false if you don't want the box to be created
+ * i.e. to test if it is available.
+ */
+ OCompletionBox * completionBox( bool create = true );
+
+ virtual void setLineEdit( OLineEdit * );
+
+signals:
+ /**
+ * Emitted when the user presses the Enter key.
+ *
+ * Note that this signal is only
+ * emitted if this widget is editable.
+ */
+ void returnPressed();
+
+ /**
+ * Emitted when the user presses
+ * the Enter key.
+ *
+ * The argument is the current
+ * text being edited. This signal is just like
+ * @ref returnPressed() except it contains the
+ * current text as its argument.
+ *
+ * Note that this signal is only emitted if this
+ * widget is editable.
+ */
+ void returnPressed( const QString& );
+
+ /**
+ * This signal is emitted when the completion key
+ * is pressed.
+ *
+ * The argument is the current text
+ * being edited.
+ *
+ * Note that this signal is @em not available if this
+ * widget is non-editable or the completion mode is
+ * set to @p OGlobalSettings::CompletionNone.
+ */
+ void completion( const QString& );
+
+ /**
+ * Emitted when the shortcut for substring completion is pressed.
+ */
+ void substringCompletion( const QString& );
+
+ /**
+ * Emitted when the text rotation key-bindings are pressed.
+ *
+ * The argument indicates which key-binding was pressed.
+ * In this case this can be either one of four values:
+ * @p PrevCompletionMatch, @p NextCompletionMatch, @p RotateUp or
+ * @p RotateDown. See @ref OCompletionBase::setKeyBinding() for
+ * details.
+ *
+ * Note that this signal is @em NOT emitted if the completion
+ * mode is set to CompletionNone.
+ */
+ void textRotation( OCompletionBase::KeyBindingType );
+
+ /**
+ * Emitted when the user changed the completion mode by using the
+ * popupmenu.
+ */
+ void completionModeChanged( OGlobalSettings::Completion );
+
+ /**
+ * Emitted before the context menu is displayed.
+ *
+ * The signal allows you to add your own entries into the
+ * the context menu that is created on demand.
+ *
+ * NOTE: Do not store the pointer to the QPopupMenu
+ * provided through since it is created and deleted
+ * on demand.
+ *
+ * @param the context menu about to be displayed
+ */
+ void aboutToShowContextMenu( QPopupMenu * );
+
+public slots:
+
+ /**
+ * Iterates through all possible matches of the completed text
+ * or the history list.
+ *
+ * Depending on the value of the argument, this function either
+ * iterates through the history list of this widget or the all
+ * possible matches in whenever multiple matches result from a
+ * text completion request. Note that the all-possible-match
+ * iteration will not work if there are no previous matches, i.e.
+ * no text has been completed and the *nix shell history list
+ * rotation is only available if the insertion policy for this
+ * widget is set either @p QComobBox::AtTop or @p QComboBox::AtBottom.
+ * For other insertion modes whatever has been typed by the user
+ * when the rotation event was initiated will be lost.
+ *
+ * @param type The key-binding invoked.
+ */
+ void rotateText( OCompletionBase::KeyBindingType /* type */ );
+
+ /**
+ * Sets the completed text in the line-edit appropriately.
+ *
+ * This function is an implementation for
+ * @ref OCompletionBase::setCompletedText.
+ */
+ virtual void setCompletedText( const QString& );
+
+ /**
+ * Sets @p items into the completion-box if @ref completionMode() is
+ * CompletionPopup. The popup will be shown immediately.
+ */
+ void setCompletedItems( const QStringList& items );
+
+ public:
+ /**
+ * Selects the first item that matches @p item. If there is no such item,
+ * it is inserted at position @p index if @p insert is true. Otherwise,
+ * no item is selected.
+ */
+ void setCurrentItem( const QString& item, bool insert = false, int index = -1 );
+ void setCurrentItem(int index);
+
+protected slots:
+
+ /**
+ * @deprecated.
+ */
+ virtual void itemSelected( QListBoxItem* ) {};
+
+ /**
+ * Completes text according to the completion mode.
+ *
+ * Note: this method is @p not invoked if the completion mode is
+ * set to CompletionNone. Also if the mode is set to @p CompletionShell
+ * and multiple matches are found, this method will complete the
+ * text to the first match with a beep to inidicate that there are
+ * more matches. Then any successive completion key event iterates
+ * through the remaining matches. This way the rotation functionality
+ * is left to iterate through the list as usual.
+ */
+ virtual void makeCompletion( const QString& );
+
+protected:
+ /*
+ * This function simply sets the lineedit text and
+ * highlights the text appropriately if the boolean
+ * value is set to true.
+ *
+ * @param
+ * @param
+ */
+ virtual void setCompletedText( const QString& /* */, bool /*marked*/ );
+
+ /**
+ * Reimplemented for internal reasons, the API is not affected.
+ */
+ virtual void create( WId = 0, bool initializeWindow = true,
+ bool destroyOldWindow = true );
+
+private:
+ // Constants that represent the ID's of the popup menu.
+ // TODO: See if we can replace this mess with OActionMenu
+ // in the future though this is working lovely.
+ enum MenuID {
+ Default=0,
+ Cut,
+ Copy,
+ Paste,
+ Clear,
+ Unselect,
+ SelectAll,
+ NoCompletion,
+ AutoCompletion,
+ ShellCompletion,
+ PopupCompletion,
+ SemiAutoCompletion
+ };
+
+ /**
+ * Initializes the variables upon construction.
+ */
+ void init();
+ /**
+ * Temporary functions to delete words back and foward until
+ * alternatives are available in QT3 (Seth Chaiklin, 21 may 2001)
+ */
+ void deleteWordBack();
+ void deleteWordForward();
+
+ bool m_bEnableMenu;
+
+ // indicating if we should stop return-key events from propagating
+ bool m_trapReturnKey;
+
+//protected:
+// virtual void virtual_hook( int id, void* data );
+private:
+ class OComboBoxPrivate;
+ OComboBoxPrivate *d;
+};
+
+
+class OPixmapProvider;
+
+/**
+ * A combobox which implements a history like a unix shell. You can navigate
+ * through all the items by using the Up or Down arrows (configurable of
+ * course). Additionally, weighted completion is available. So you should
+ * load and save the completion list to preserve the weighting between
+ * sessions.
+ *
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ * @short A combobox for offering a history and completion
+ */
+class OHistoryCombo : public OComboBox
+{
+ Q_OBJECT
+ Q_PROPERTY( QStringList historyItems READ historyItems WRITE setHistoryItems )
+
+public:
+ /**
+ * Constructs a "read-write" combobox. A read-only history combobox
+ * doesn't make much sense, so it is only available as read-write.
+ * Completion will be used automatically for the items in the combo.
+ *
+ * The insertion-policy is set to NoInsertion, you have to add the items
+ * yourself via the slot @ref addToHistory. If you want every item added,
+ * use
+ *
+ * <pre>
+ * connect( combo, SIGNAL( activated( const QString& )),
+ * combo, SLOT( addToHistory( const QString& )));
+ * </pre>
+ *
+ * Use @ref QComboBox::setMaxCount() to limit the history.
+ *
+ * @p parent the parent object of this widget.
+ * @p name the name of this widget.
+ */
+ OHistoryCombo( QWidget *parent = 0L, const char *name = 0L );
+
+ // ### merge these two constructors
+ /**
+ * Same as the previous constructor, but additionally has the option
+ * to specify whether you want to let OHistoryCombo handle completion
+ * or not. If set to @p true, OHistoryCombo will sync the completion to the
+ * contents of the combobox.
+ */
+ OHistoryCombo( bool useCompletion,
+ QWidget *parent = 0L, const char *name = 0L );
+
+ /**
+ * Destructs the combo, the completion-object and the pixmap-provider
+ */
+ ~OHistoryCombo();
+
+ /**
+ * Inserts @p items into the combobox. @p items might get
+ * truncated if it is longer than @ref maxCount()
+ *
+ * @see #historyItems
+ */
+ inline void setHistoryItems( QStringList items ) {
+ setHistoryItems(items, false);
+ }
+
+ /**
+ * Inserts @p items into the combobox. @p items might get
+ * truncated if it is longer than @ref maxCount()
+ *
+ * Set @p setCompletionList to true, if you don't have a list of
+ * completions. This tells OHistoryCombo to use all the items for the
+ * completion object as well.
+ * You won't have the benefit of weighted completion though, so normally
+ * you should do something like
+ * <pre>
+ * OConfig *config = kapp->config();
+ * QStringList list;
+ *
+ * // load the history and completion list after creating the history combo
+ * list = config->readListEntry( "Completion list" );
+ * combo->completionObject()->setItems( list );
+ * list = config->readListEntry( "History list" );
+ * combo->setHistoryItems( list );
+ *
+ * [...]
+ *
+ * // save the history and completion list when the history combo is
+ * // destroyed
+ * list = combo->completionObject()->items()
+ * config->writeEntry( "Completion list", list );
+ * list = combo->historyItems();
+ * config->writeEntry( "History list", list );
+ * </pre>
+ *
+ * Be sure to use different names for saving with OConfig if you have more
+ * than one OHistoryCombo.
+ *
+ * Note: When @p setCompletionList is true, the items are inserted into the
+ * OCompletion object with mode OCompletion::Insertion and the mode is set
+ * to OCompletion::Weighted afterwards.
+ *
+ * @see #historyItems
+ * @see OComboBox::completionObject
+ * @see OCompletion::setItems
+ * @see OCompletion::items
+ */
+ void setHistoryItems( QStringList items, bool setCompletionList );
+
+ /**
+ * Returns the list of history items. Empty, when this is not a read-write
+ * combobox.
+ *
+ * @see #setHistoryItems
+ */
+ QStringList historyItems() const;
+
+ /**
+ * Removes all items named @p item.
+ *
+ * @return @p true if at least one item was removed.
+ *
+ * @see #addToHistory
+ */
+ bool removeFromHistory( const QString& item );
+
+ /**
+ * Sets a pixmap provider, so that items in the combobox can have a pixmap.
+ * @ref OPixmapProvider is just an abstract class with the one pure virtual
+ * method @ref OPixmapProvider::pixmapFor(). This method is called whenever
+ * an item is added to the OHistoryComboBox. Implement it to return your
+ * own custom pixmaps, or use the @ref OURLPixmapProvider from libkio,
+ * which uses @ref OMimeType::pixmapForURL to resolve icons.
+ *
+ * Set @p prov to 0L if you want to disable pixmaps. Default no pixmaps.
+ *
+ * @see #pixmapProvider
+ */
+ void setPixmapProvider( OPixmapProvider *prov );
+
+ /**
+ * @returns the current pixmap provider.
+ * @see #setPixmapProvider
+ * @see OPixmapProvider
+ */
+ OPixmapProvider * pixmapProvider() const { return myPixProvider; }
+
+ /**
+ * Resets the current position of the up/down history. Call this
+ * when you manually call @ref setCurrentItem() or @ref clearEdit().
+ */
+ void reset() { slotReset(); }
+
+public slots:
+ /**
+ * Adds an item to the end of the history list and to the completion list.
+ * If @ref maxCount() is reached, the first item of the list will be
+ * removed.
+ *
+ * If the last inserted item is the same as @p item, it will not be
+ * inserted again.
+ *
+ * If @ref duplicatesEnabled() is false, any equal existing item will be
+ * removed before @p item is added.
+ *
+ * Note: By using this method and not the Q and OComboBox insertItem()
+ * methods, you make sure that the combobox stays in sync with the
+ * completion. It would be annoying if completion would give an item
+ * not in the combobox, and vice versa.
+ *
+ * @see #removeFromHistory
+ * @see QComboBox::setDuplicatesEnabled
+ */
+ void addToHistory( const QString& item );
+
+ /**
+ * Clears the history and the completion list.
+ */
+ void clearHistory();
+
+signals:
+ /**
+ * Emitted when the history was cleared by the entry in the popup menu.
+ */
+ void cleared();
+
+protected:
+ /**
+ * Handling key-events, the shortcuts to rotate the items.
+ */
+ virtual void keyPressEvent( QKeyEvent * );
+
+
+ /**
+ * Inserts @p items into the combo, honouring @ref pixmapProvider()
+ * Does not update the completionObject.
+ *
+ * Note: @ref duplicatesEnabled() is not honored here.
+ *
+ * Called from @ref setHistoryItems() and @ref setPixmapProvider()
+ */
+ void insertItems( const QStringList& items );
+
+ /**
+ * @returns if we can modify the completion object or not.
+ */
+ bool useCompletion() const { return compObj() != 0L; }
+
+private slots:
+ /**
+ * Resets the iterate index to -1
+ */
+ void slotReset();
+
+ /**
+ * Called from the popupmenu,
+ * calls clearHistory() and emits cleared()
+ */
+ void slotClear();
+
+ /**
+ * Appends our own context menu entry.
+ */
+ void addContextMenuItems( QPopupMenu* );
+
+private:
+ void init( bool useCompletion );
+
+ /**
+ * The current position (index) in the combobox, used for Up and Down
+ */
+ int myIterateIndex;
+
+ /**
+ * The text typed before Up or Down was pressed.
+ */
+ QString myText;
+
+ /**
+ * Indicates that the user at least once rotated Up through the entire list
+ * Needed to allow going back after rotation.
+ */
+ bool myRotated;
+ OPixmapProvider *myPixProvider;
+
+private:
+ class OHistoryComboPrivate;
+ OHistoryComboPrivate *d;
+};
+
+
+#endif
+
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 @@
+/*
+ This file Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
+ is part of the Copyright (C) 2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
+ Opie Project Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ Copyright (C) 2000,2001 Dawit Alemayehu <adawit@kde.org>
+ =.
+ .=l. Originally part of the KDE Project
+           .>+-=
+ _;:,     .>    :=|. This program is free software; you can
+.> <`_,   >  .   <= redistribute it and/or modify it under
+:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
+.="- .-=="i,     .._ License as published by the Free Software
+ - .   .-<_>     .<> Foundation; either version 2 of the License,
+     ._= =}       : or (at your option) any later version.
+    .%`+i>       _;_.
+    .i_,=:_.      -<s. This program is distributed in the hope that
+     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
+    : ..    .:,     . . . without even the implied warranty of
+    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
+  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
+..}^=.=       =       ; Library General Public License for more
+++=   -.     .`     .: details.
+ :     =  ...= . :.=-
+ -.   .:....=;==+<; You should have received a copy of the GNU
+  -_. . .   )=.  = Library General Public License along with
+    --        :-=` this library; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+*/
+
+#include <qapplication.h>
+#include <qevent.h>
+#include <qstyle.h>
+
+#include <opie2/ocompletionbox.h>
+
+#define OListBox QListBox
+
+class OCompletionBox::OCompletionBoxPrivate
+{
+public:
+ QWidget *m_parent; // necessary to set the focus back
+ QString cancelText;
+ bool tabHandling;
+ bool down_workaround;
+};
+
+OCompletionBox::OCompletionBox( QWidget *parent, const char *name )
+ :OListBox( parent, name, WType_Popup )
+{
+ d = new OCompletionBoxPrivate;
+ d->m_parent = parent;
+ d->tabHandling = true;
+ d->down_workaround = false;
+
+ setColumnMode( 1 );
+ setLineWidth( 1 );
+ setFrameStyle( QFrame::Box | QFrame::Plain );
+
+ if ( parent )
+ setFocusProxy( parent );
+ else
+ setFocusPolicy( NoFocus );
+
+ setVScrollBarMode( Auto );
+ setHScrollBarMode( AlwaysOff );
+
+ connect( this, SIGNAL( doubleClicked( QListBoxItem * )),
+ SLOT( slotActivated( QListBoxItem * )) );
+
+ // grmbl, just QListBox workarounds :[ Thanks Volker.
+ connect( this, SIGNAL( currentChanged( QListBoxItem * )),
+ SLOT( slotCurrentChanged() ));
+ connect( this, SIGNAL( clicked( QListBoxItem * )),
+ SLOT( slotItemClicked( QListBoxItem * )) );
+}
+
+OCompletionBox::~OCompletionBox()
+{
+ d->m_parent = 0L;
+ delete d;
+}
+
+QStringList OCompletionBox::items() const
+{
+ QStringList list;
+ for ( uint i = 0; i < count(); i++ ) {
+ list.append( text( i ) );
+ }
+ return list;
+}
+
+void OCompletionBox::slotActivated( QListBoxItem *item )
+{
+ if ( !item )
+ return;
+
+ hide();
+ emit activated( item->text() );
+}
+
+bool OCompletionBox::eventFilter( QObject *o, QEvent *e )
+{
+ int type = e->type();
+
+ if ( o == d->m_parent ) {
+ if ( isVisible() ) {
+ if ( type == QEvent::KeyPress ) {
+ QKeyEvent *ev = static_cast<QKeyEvent *>( e );
+ switch ( ev->key() ) {
+ case Key_BackTab:
+ if ( d->tabHandling ) {
+ up();
+ ev->accept();
+ return true;
+ }
+ break;
+ case Key_Tab:
+ if ( d->tabHandling ) {
+ down(); // Only on TAB!!
+ ev->accept();
+ return true;
+ }
+ break;
+ case Key_Down:
+ down();
+ ev->accept();
+ return true;
+ case Key_Up:
+ up();
+ ev->accept();
+ return true;
+ case Key_Prior:
+ pageUp();
+ ev->accept();
+ return true;
+ case Key_Next:
+ pageDown();
+ ev->accept();
+ return true;
+ case Key_Escape:
+ cancelled();
+ ev->accept();
+ return true;
+ case Key_Enter:
+ case Key_Return:
+ if ( ev->state() & ShiftButton ) {
+ hide();
+ ev->accept(); // Consume the Enter event
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else if ( type == QEvent::AccelOverride ) {
+ // Override any acceleartors that match
+ // the key sequences we use here...
+ QKeyEvent *ev = static_cast<QKeyEvent *>( e );
+ switch ( ev->key() ) {
+ case Key_Tab:
+ case Key_BackTab:
+ case Key_Down:
+ case Key_Up:
+ case Key_Prior:
+ case Key_Next:
+ case Key_Escape:
+ case Key_Enter:
+ case Key_Return:
+ ev->accept();
+ return true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // parent loses focus or gets a click -> we hide
+ else if ( type == QEvent::FocusOut || type == QEvent::Resize ||
+ type == QEvent::Close || type == QEvent::Hide ||
+ type == QEvent::Move ) {
+ hide();
+ }
+ else if ( type == QEvent::Move )
+ move( d->m_parent->mapToGlobal(QPoint(0, d->m_parent->height())));
+ else if ( type == QEvent::Resize )
+ resize( sizeHint() );
+ }
+ }
+
+ // any mouse-click on something else than "this" makes us hide
+ else if ( type == QEvent::MouseButtonPress ) {
+ QMouseEvent *ev = static_cast<QMouseEvent *>( e );
+ if ( !rect().contains( ev->pos() )) // this widget
+ hide();
+ }
+
+ return OListBox::eventFilter( o, e );
+}
+
+
+void OCompletionBox::popup()
+{
+ if ( count() == 0 )
+ hide();
+ else {
+ ensureCurrentVisible();
+ bool block = signalsBlocked();
+ blockSignals( true );
+ setCurrentItem( 0 );
+ blockSignals( block );
+ clearSelection();
+ if ( !isVisible() )
+ show();
+ else if ( size().height() < sizeHint().height() )
+ resize( sizeHint() );
+ }
+}
+
+void OCompletionBox::show()
+{
+ resize( sizeHint() );
+
+ if ( d->m_parent )
+ {
+ //QDesktopWidget *screen = QApplication::desktop();
+ QWidget *screen = QApplication::desktop();
+
+ QPoint orig = d->m_parent->mapToGlobal( QPoint(0, d->m_parent->height()) );
+ int x = orig.x();
+ int y = orig.y();
+
+ if ( x + width() > screen->width() )
+ x = screen->width() - width();
+ if (y + height() > screen->height() )
+ y = y - height() - d->m_parent->height();
+
+ move( x, y);
+ qApp->installEventFilter( this );
+ }
+
+ // ### we shouldn't need to call this, but without this, the scrollbars
+ // are pretty b0rked.
+ //triggerUpdate( true );
+
+ OListBox::show();
+}
+
+void OCompletionBox::hide()
+{
+ if ( d->m_parent )
+ qApp->removeEventFilter( this );
+ d->cancelText = QString::null;
+ OListBox::hide();
+}
+
+QSize OCompletionBox::sizeHint() const
+{
+ int ih = itemHeight();
+ int h = QMIN( 15 * ih, (int) count() * ih ) +1;
+ h = QMAX( h, OListBox::minimumSizeHint().height() );
+
+ int w = (d->m_parent) ? d->m_parent->width() : OListBox::minimumSizeHint().width();
+ w = QMAX( OListBox::minimumSizeHint().width(), w );
+ return QSize( w, h );
+}
+
+void OCompletionBox::down()
+{
+ int i = currentItem();
+
+ if ( i == 0 && d->down_workaround ) {
+ d->down_workaround = false;
+ setCurrentItem( 0 );
+ setSelected( 0, true );
+ emit highlighted( currentText() );
+ }
+
+ else if ( i < (int) count() - 1 )
+ setCurrentItem( i + 1 );
+}
+
+void OCompletionBox::up()
+{
+ if ( currentItem() > 0 )
+ setCurrentItem( currentItem() - 1 );
+}
+
+void OCompletionBox::pageDown()
+{
+ int i = currentItem() + numItemsVisible();
+ i = i > (int)count() - 1 ? (int)count() - 1 : i;
+ setCurrentItem( i );
+}
+
+void OCompletionBox::pageUp()
+{
+ int i = currentItem() - numItemsVisible();
+ i = i < 0 ? 0 : i;
+ setCurrentItem( i );
+}
+
+void OCompletionBox::home()
+{
+ setCurrentItem( 0 );
+}
+
+void OCompletionBox::end()
+{
+ setCurrentItem( count() -1 );
+}
+
+void OCompletionBox::setTabHandling( bool enable )
+{
+ d->tabHandling = enable;
+}
+
+bool OCompletionBox::isTabHandling() const
+{
+ return d->tabHandling;
+}
+
+void OCompletionBox::setCancelledText( const QString& text )
+{
+ d->cancelText = text;
+}
+
+QString OCompletionBox::cancelledText() const
+{
+ return d->cancelText;
+}
+
+void OCompletionBox::cancelled()
+{
+ if ( !d->cancelText.isNull() )
+ emit userCancelled( d->cancelText );
+ if ( isVisible() )
+ hide();
+}
+
+class OCompletionBoxItem : public QListBoxItem
+{
+public:
+ void reuse( const QString &text ) { setText( text ); }
+};
+
+
+void OCompletionBox::insertItems( const QStringList& items, int index )
+{
+ bool block = signalsBlocked();
+ blockSignals( true );
+ insertStringList( items, index );
+ blockSignals( block );
+ d->down_workaround = true;
+}
+
+void OCompletionBox::setItems( const QStringList& items )
+{
+ bool block = signalsBlocked();
+ blockSignals( true );
+
+ QListBoxItem* item = firstItem();
+ if ( !item ) {
+ insertStringList( items );
+ }
+ else {
+ for ( QStringList::ConstIterator it = items.begin(); it != items.end(); it++) {
+ if ( item ) {
+ ((OCompletionBoxItem*)item)->reuse( *it );
+ item = item->next();
+ }
+ else {
+ insertItem( new QListBoxText( *it ) );
+ }
+ }
+ QListBoxItem* tmp = item;
+ while ( (item = tmp ) ) {
+ tmp = item->next();
+ delete item;
+ }
+ triggerUpdate( false );
+ }
+
+ blockSignals( block );
+ d->down_workaround = true;
+}
+
+void OCompletionBox::slotCurrentChanged()
+{
+ d->down_workaround = false;
+}
+
+void OCompletionBox::slotItemClicked( QListBoxItem *item )
+{
+ if ( item )
+ {
+ if ( d->down_workaround ) {
+ d->down_workaround = false;
+ emit highlighted( item->text() );
+ }
+
+ hide();
+ emit activated( item->text() );
+ }
+}
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 @@
+/*
+ This file Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
+ is part of the Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ Opie Project Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+
+ =. Originally part of the KDE Project
+ .=l.
+           .>+-=
+ _;:,     .>    :=|. This program is free software; you can
+.> <`_,   >  .   <= redistribute it and/or modify it under
+:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
+.="- .-=="i,     .._ License as published by the Free Software
+ - .   .-<_>     .<> Foundation; either version 2 of the License,
+     ._= =}       : or (at your option) any later version.
+    .%`+i>       _;_.
+    .i_,=:_.      -<s. This program is distributed in the hope that
+     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
+    : ..    .:,     . . . without even the implied warranty of
+    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
+  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
+..}^=.=       =       ; Library General Public License for more
+++=   -.     .`     .: details.
+ :     =  ...= . :.=-
+ -.   .:....=;==+<; You should have received a copy of the GNU
+  -_. . .   )=.  = Library General Public License along with
+    --        :-=` this library; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef OCOMPLETIONBOX_H
+#define OCOMPLETIONBOX_H
+
+class QEvent;
+#include <qstringlist.h>
+#include <qlistbox.h>
+
+// ML: Until we don't have an own OListBox, we use the QListBox
+#define OListBox QListBox
+
+/**
+ * A little utility class for "completion-widgets", like @ref OLineEdit or
+ * @ref OComboBox. OCompletionBox is a listbox, displayed as a rectangle without
+ * any window decoration, usually directly under the lineedit or combobox.
+ * It is filled with all possible matches for a completion, so the user
+ * can select the one he wants.
+ *
+ * It is used when OGlobalSettings::Completion == CompletionPopup or CompletionPopupAuto.
+ *
+ * @short A helper widget for "completion-widgets" (OLineEdit, OComboBox))
+ * @short Adapted for the Opie project by Michael Lauer <mickey@tm.informatik.uni-frankfurt.de>
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ */
+class OCompletionBox : public OListBox
+{
+ Q_OBJECT
+ Q_PROPERTY( bool isTabHandling READ isTabHandling WRITE setTabHandling )
+ Q_PROPERTY(QString cancelledText READ cancelledText WRITE setCancelledText)
+
+public:
+ /**
+ * Constructs a OCompletionBox.
+ *
+ * Notice: the parent needs to be always 0L,
+ * so you can't specify it in the constructor. Because of that, Qt's
+ * auto-deletion does not take place, so you have to explicitly delete
+ * this widget when you don't need it anymore.
+ *
+ * The parent widget is used to give the focus back when pressing the
+ * up-button on the very first item.
+ */
+ OCompletionBox( QWidget *parent, const char *name = 0 );
+
+ /**
+ * Destroys the box
+ */
+ ~OCompletionBox();
+
+ virtual QSize sizeHint() const;
+
+public slots:
+ /**
+ * Returns a list of all items currently in the box.
+ */
+ QStringList items() const;
+
+ /**
+ * Inserts @p items into the box. Does not clear the items before.
+ * @p index determines at which position @p items will be inserted.
+ * (defaults to appending them at the end)
+ */
+ void insertItems( const QStringList& items, int index = -1 );
+
+ /**
+ * Clears the box and inserts @p items.
+ */
+ void setItems( const QStringList& items );
+
+ /**
+ * Adjusts the size of the box to fit the width of the parent given in the
+ * constructor and pops it up at the most appropriate place, relative to
+ * the parent.
+ *
+ * Depending on the screensize and the position of the parent, this may
+ * be a different place, however the default is to pop it up and the
+ * lower left corner of the parent.
+ *
+ * Make sure to hide() the box when appropriate.
+ */
+ virtual void popup();
+
+ /**
+ * Makes this widget (when visible) capture Tab-key events to traverse the
+ * items in the dropdown list.
+ *
+ * Default off, as it conflicts with the usual behavior of Tab to traverse
+ * widgets. It is useful for cases like Konqueror's Location Bar, though.
+ *
+ * @see #isTabHandling
+ */
+ void setTabHandling( bool enable );
+
+ /**
+ * @returns true if this widget is handling Tab-key events to traverse the
+ * items in the dropdown list, otherwise false.
+ *
+ * Default is false.
+ *
+ * @see #setTabHandling
+ */
+ bool isTabHandling() const;
+
+ /**
+ * Sets the text to be emitted if the user chooses not to
+ * pick from the available matches.
+ *
+ * If the cancelled text is not set through this function, the
+ * @ref userCancelled signal will not be emitted.
+ *
+ * @see userCancelled( const QString& )
+ * @param txt the text to be emitted if the user cancels this box
+ */
+ void setCancelledText( const QString& );
+
+ /**
+ * @returns the text set via @ref setCancelledText() or QString::null.
+ */
+ QString cancelledText() const;
+
+ /**
+ * Moves the selection one line down or select the first item if nothing is selected yet.
+ */
+ void down();
+
+ /**
+ * Moves the selection one line up or select the first item if nothing is selected yet.
+ */
+ void up();
+
+ /**
+ * Moves the selection one page down.
+ */
+ void pageDown();
+
+ /**
+ * Moves the selection one page up.
+ */
+ void pageUp();
+
+ /**
+ * Moves the selection up to the first item.
+ */
+ void home();
+
+ /**
+ * Moves the selection down to the last item.
+ */
+ void end();
+
+ /**
+ * Re-implemented for internal reasons. API is unaffected.
+ */
+ virtual void show();
+
+ /**
+ * Re-implemented for internal reasons. API is unaffected.
+ */
+ virtual void hide();
+
+signals:
+ /**
+ * Emitted when an item was selected, contains the text of
+ * the selected item.
+ */
+ void activated( const QString& );
+
+ /**
+ * Emitted whenever the user chooses to ignore the available
+ * selections and close the this box.
+ */
+ void userCancelled( const QString& );
+
+protected:
+ /**
+ * Reimplemented from OListBox to get events from the viewport (to hide
+ * this widget on mouse-click, Escape-presses, etc.
+ */
+ virtual bool eventFilter( QObject *, QEvent * );
+
+protected slots:
+ /**
+ * Called when an item was activated. Emits
+ * @ref activated() with the item.
+ */
+ virtual void slotActivated( QListBoxItem * );
+
+private slots:
+ void slotSetCurrentItem( QListBoxItem *i ) { setCurrentItem( i ); } // grrr
+ void slotCurrentChanged();
+ void cancelled();
+ void slotItemClicked( QListBoxItem * );
+
+private:
+ class OCompletionBoxPrivate;
+ OCompletionBoxPrivate* d;
+};
+
+
+#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 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>, Alexander Neundorf <neundorf@kde.org>
+ 2000, 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/* QT */
+
+#include <qstringlist.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qlistbox.h>
+#include <qwhatsthis.h>
+#include <qlabel.h>
+
+/* OPIE */
+
+#include <opie2/ocombobox.h>
+#include <opie2/odialog.h>
+#include <opie2/olineedit.h>
+#include <opie2/oeditlistbox.h>
+
+/* UNIX */
+
+#include <assert.h>
+
+/*======================================================================================
+ * OEditListBoxPrivate
+ *======================================================================================*/
+
+class OEditListBoxPrivate
+{
+public:
+ bool m_checkAtEntering;
+ int buttons;
+};
+
+/*======================================================================================
+ * OEditListBox
+ *======================================================================================*/
+
+OEditListBox::OEditListBox(QWidget *parent, const char *name,
+ bool checkAtEntering, int buttons )
+ :QGroupBox(parent, name )
+{
+ init( checkAtEntering, buttons );
+}
+
+OEditListBox::OEditListBox(const QString& title, QWidget *parent,
+ const char *name, bool checkAtEntering, int buttons)
+ :QGroupBox(title, parent, name )
+{
+ init( checkAtEntering, buttons );
+}
+
+OEditListBox::OEditListBox(const QString& title, const CustomEditor& custom,
+ QWidget *parent, const char *name,
+ bool checkAtEntering, int buttons)
+ :QGroupBox(title, parent, name )
+{
+ m_lineEdit = custom.lineEdit();
+ init( checkAtEntering, buttons, custom.representationWidget() );
+}
+
+OEditListBox::~OEditListBox()
+{
+ delete d;
+ d=0;
+}
+
+void OEditListBox::init( bool checkAtEntering, int buttons,
+ QWidget *representationWidget )
+{
+ d=new OEditListBoxPrivate;
+ d->m_checkAtEntering=checkAtEntering;
+ d->buttons = buttons;
+
+ int lostButtons = 0;
+ if ( (buttons & Add) == 0 )
+ lostButtons++;
+ if ( (buttons & Remove) == 0 )
+ lostButtons++;
+ if ( (buttons & UpDown) == 0 )
+ lostButtons += 2;
+
+
+ servNewButton = servRemoveButton = servUpButton = servDownButton = 0L;
+ setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding,
+ QSizePolicy::MinimumExpanding));
+
+ QWidget * gb = this;
+ QGridLayout * grid = new QGridLayout(gb, 7 - lostButtons, 2,
+ ODialog::marginHint(),
+ ODialog::spacingHint());
+ grid->addRowSpacing(0, fontMetrics().lineSpacing());
+ for ( int i = 1; i < 7 - lostButtons; i++ )
+ grid->setRowStretch(i, 1);
+
+ grid->setMargin(15);
+
+ if ( representationWidget )
+ representationWidget->reparent( gb, QPoint(0,0) );
+ else
+ m_lineEdit=new OLineEdit(gb);
+
+ m_listBox = new QListBox(gb);
+
+ QWidget *editingWidget = representationWidget ?
+ representationWidget : m_lineEdit;
+ grid->addMultiCellWidget(editingWidget,1,1,0,1);
+ grid->addMultiCellWidget(m_listBox, 2, 6 - lostButtons, 0, 0);
+ int row = 2;
+ if ( buttons & Add ) {
+ servNewButton = new QPushButton(tr("&Add"), gb);
+ servNewButton->setEnabled(false);
+ connect(servNewButton, SIGNAL(clicked()), SLOT(addItem()));
+
+ grid->addWidget(servNewButton, row++, 1);
+ }
+
+ if ( buttons & Remove ) {
+ servRemoveButton = new QPushButton(tr("&Remove"), gb);
+ servRemoveButton->setEnabled(false);
+ connect(servRemoveButton, SIGNAL(clicked()), SLOT(removeItem()));
+
+ grid->addWidget(servRemoveButton, row++, 1);
+ }
+
+ if ( buttons & UpDown ) {
+ servUpButton = new QPushButton(tr("Move &Up"), gb);
+ servUpButton->setEnabled(false);
+ connect(servUpButton, SIGNAL(clicked()), SLOT(moveItemUp()));
+
+ servDownButton = new QPushButton(tr("Move &Down"), gb);
+ servDownButton->setEnabled(false);
+ connect(servDownButton, SIGNAL(clicked()), SLOT(moveItemDown()));
+
+ grid->addWidget(servUpButton, row++, 1);
+ grid->addWidget(servDownButton, row++, 1);
+ }
+
+ connect(m_lineEdit,SIGNAL(textChanged(const QString&)),this,SLOT(typedSomething(const QString&)));
+ m_lineEdit->setTrapReturnKey(true);
+ connect(m_lineEdit,SIGNAL(returnPressed()),this,SLOT(addItem()));
+ connect(m_listBox, SIGNAL(highlighted(int)), SLOT(enableMoveButtons(int)));
+
+ // maybe supplied lineedit has some text already
+ typedSomething( m_lineEdit->text() );
+}
+
+void OEditListBox::typedSomething(const QString& text)
+{
+ if(currentItem() >= 0) {
+ if(currentText() != m_lineEdit->text())
+ {
+ // IMHO changeItem() shouldn't do anything with the value
+ // of currentItem() ... like changing it or emitting signals ...
+ // but TT disagree with me on this one (it's been that way since ages ... grrr)
+ bool block = m_listBox->signalsBlocked();
+ m_listBox->blockSignals( true );
+ m_listBox->changeItem(text, currentItem());
+ m_listBox->blockSignals( block );
+ emit changed();
+ }
+ }
+
+ if ( !servNewButton )
+ return;
+
+ if (!d->m_checkAtEntering)
+ servNewButton->setEnabled(!text.isEmpty());
+ else
+ {
+ if (text.isEmpty())
+ {
+ servNewButton->setEnabled(false);
+ }
+ else
+ {
+ #if QT_VERSION > 290
+ StringComparisonMode mode = (StringComparisonMode) (ExactMatch | CaseSensitive );
+ bool enable = (m_listBox->findItem( text, mode ) == 0L);
+ #else
+ bool enable = (m_listBox->findItem( text ) == 0L);
+ #endif
+ servNewButton->setEnabled( enable );
+ }
+ }
+}
+
+void OEditListBox::moveItemUp()
+{
+ if (!m_listBox->isEnabled())
+ {
+ //ONotifyClient::beep();
+ return;
+ }
+
+ unsigned int selIndex = m_listBox->currentItem();
+ if (selIndex == 0)
+ {
+ //ONotifyClient::beep();
+ return;
+ }
+
+ QListBoxItem *selItem = m_listBox->item(selIndex);
+ m_listBox->takeItem(selItem);
+ m_listBox->insertItem(selItem, selIndex-1);
+ m_listBox->setCurrentItem(selIndex - 1);
+
+ emit changed();
+}
+
+void OEditListBox::moveItemDown()
+{
+ if (!m_listBox->isEnabled())
+ {
+ //ONotifyClient::beep();
+ return;
+ }
+
+ unsigned int selIndex = m_listBox->currentItem();
+ if (selIndex == m_listBox->count() - 1)
+ {
+ //ONotifyClient::beep();
+ return;
+ }
+
+ QListBoxItem *selItem = m_listBox->item(selIndex);
+ m_listBox->takeItem(selItem);
+ m_listBox->insertItem(selItem, selIndex+1);
+ m_listBox->setCurrentItem(selIndex + 1);
+
+ emit changed();
+}
+
+void OEditListBox::addItem()
+{
+ // when m_checkAtEntering is true, the add-button is disabled, but this
+ // slot can still be called through Key_Return/Key_Enter. So we guard
+ // against this.
+ if ( !servNewButton || !servNewButton->isEnabled() )
+ return;
+
+ const QString& currentTextLE=m_lineEdit->text();
+ bool alreadyInList(false);
+ //if we didn't check for dupes at the inserting we have to do it now
+ if (!d->m_checkAtEntering)
+ {
+ // first check current item instead of dumb iterating the entire list
+ if ( m_listBox->currentText() == currentTextLE )
+ alreadyInList = true;
+ else
+ {
+ #if QT_VERSION > 290
+ StringComparisonMode mode = (StringComparisonMode) (ExactMatch | CaseSensitive );
+ alreadyInList =(m_listBox->findItem(currentTextLE, mode) != 0);
+ #else
+ alreadyInList =(m_listBox->findItem(currentTextLE) != 0);
+ #endif
+ }
+ }
+
+ if ( servNewButton )
+ servNewButton->setEnabled(false);
+
+ bool block = m_lineEdit->signalsBlocked();
+ m_lineEdit->blockSignals(true);
+ m_lineEdit->clear();
+ m_lineEdit->blockSignals(block);
+
+ m_listBox->setSelected(currentItem(), false);
+
+ if (!alreadyInList)
+ {
+ block = m_listBox->signalsBlocked();
+ m_listBox->blockSignals( true );
+ m_listBox->insertItem(currentTextLE);
+ m_listBox->blockSignals( block );
+ emit changed();
+ emit added( currentTextLE );
+ }
+}
+
+int OEditListBox::currentItem() const
+{
+ int nr = m_listBox->currentItem();
+ #if QT_VERSION > 290
+ if(nr >= 0 && !m_listBox->item(nr)->isSelected()) return -1;
+ #else
+ if(nr >= 0 && !m_listBox->isSelected(m_listBox->item(nr))) return -1;
+ #endif
+ return nr;
+}
+
+void OEditListBox::removeItem()
+{
+ int selected = m_listBox->currentItem();
+
+ if ( selected >= 0 )
+ {
+ QString removedText = m_listBox->currentText();
+
+ m_listBox->removeItem( selected );
+ if ( count() > 0 )
+ m_listBox->setSelected( QMIN( selected, count() - 1 ), true );
+
+ emit changed();
+ emit removed( removedText );
+ }
+
+ if ( servRemoveButton && m_listBox->currentItem() == -1 )
+ servRemoveButton->setEnabled(false);
+}
+
+void OEditListBox::enableMoveButtons(int index)
+{
+ // Update the lineEdit when we select a different line.
+ if(currentText() != m_lineEdit->text())
+ m_lineEdit->setText(currentText());
+
+ bool moveEnabled = servUpButton && servDownButton;
+
+ if (moveEnabled )
+ {
+ if (m_listBox->count() <= 1)
+ {
+ servUpButton->setEnabled(false);
+ servDownButton->setEnabled(false);
+ }
+ else if ((uint) index == (m_listBox->count() - 1))
+ {
+ servUpButton->setEnabled(true);
+ servDownButton->setEnabled(false);
+ }
+ else if (index == 0)
+ {
+ servUpButton->setEnabled(false);
+ servDownButton->setEnabled(true);
+ }
+ else
+ {
+ servUpButton->setEnabled(true);
+ servDownButton->setEnabled(true);
+ }
+ }
+
+ if ( servRemoveButton )
+ servRemoveButton->setEnabled(true);
+}
+
+void OEditListBox::clear()
+{
+ m_lineEdit->clear();
+ m_listBox->clear();
+ emit changed();
+}
+
+void OEditListBox::insertStringList(const QStringList& list, int index)
+{
+ m_listBox->insertStringList(list,index);
+}
+
+void OEditListBox::insertStrList(const QStrList* list, int index)
+{
+ m_listBox->insertStrList(list,index);
+}
+
+void OEditListBox::insertStrList(const QStrList& list, int index)
+{
+ m_listBox->insertStrList(list,index);
+}
+
+void OEditListBox::insertStrList(const char ** list, int numStrings, int index)
+{
+ m_listBox->insertStrList(list,numStrings,index);
+}
+
+QStringList OEditListBox::items() const
+{
+ QStringList list;
+ for ( uint i = 0; i < m_listBox->count(); i++ )
+ list.append( m_listBox->text( i ));
+
+ return list;
+}
+
+void OEditListBox::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+
+/*======================================================================================
+ * CustomEditor
+ *======================================================================================*/
+
+OEditListBox::CustomEditor::CustomEditor( OComboBox *combo )
+{
+ m_representationWidget = combo;
+ m_lineEdit = dynamic_cast<OLineEdit*>( combo->lineEdit() );
+ assert( m_lineEdit );
+}
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 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>, Alexander Neundorf <neundorf@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef OEDITLISTBOX_H
+#define OEDITLISTBOX_H
+
+#include <qgroupbox.h>
+#include <qlistbox.h>
+
+class OLineEdit;
+class OComboBox;
+class QPushButton;
+
+#if QT_VERSION < 300
+ enum StringComparisonMode {
+ CaseSensitive = 0x00001, // 0 0001
+ BeginsWith = 0x00002, // 0 0010
+ EndsWith = 0x00004, // 0 0100
+ Contains = 0x00008, // 0 1000
+ ExactMatch = 0x00010 // 1 0000
+ };
+#endif
+
+class OEditListBoxPrivate;
+/**
+ * An editable listbox
+ *
+ * This class provides a editable listbox ;-), this means
+ * a listbox which is accompanied by a line edit to enter new
+ * items into the listbox and pushbuttons to add and remove
+ * items from the listbox and two buttons to move items up and down.
+ */
+class OEditListBox : public QGroupBox
+{
+ Q_OBJECT
+
+public:
+ /// @since 3.1
+ class CustomEditor
+ {
+ public:
+ CustomEditor()
+ : m_representationWidget( 0L ),
+ m_lineEdit( 0L ) {}
+ CustomEditor( QWidget *repWidget, OLineEdit *edit )
+ : m_representationWidget( repWidget ),
+ m_lineEdit( edit ) {}
+ CustomEditor( OComboBox *combo );
+
+ void setRepresentationWidget( QWidget *repWidget ) {
+ m_representationWidget = repWidget;
+ }
+ void setLineEdit( OLineEdit *edit ) {
+ m_lineEdit = edit;
+ }
+
+ virtual QWidget *representationWidget() const {
+ return m_representationWidget;
+ }
+ virtual OLineEdit *lineEdit() const {
+ return m_lineEdit;
+ }
+
+ protected:
+ QWidget *m_representationWidget;
+ OLineEdit *m_lineEdit;
+ };
+
+ public:
+
+ /**
+ * Enumeration of the buttons, the listbox offers. Specify them in the
+ * constructor in the buttons parameter.
+ */
+ enum Button { Add = 1, Remove = 2, UpDown = 4, All = Add|Remove|UpDown };
+
+ /**
+ * Create an editable listbox.
+ *
+ * If @p checkAtEntering is true, after every character you type
+ * in the line edit OEditListBox will enable or disable
+ * the Add-button, depending whether the current content of the
+ * line edit is already in the listbox. Maybe this can become a
+ * performance hit with large lists on slow machines.
+ * If @p checkAtEntering is false,
+ * it will be checked if you press the Add-button. It is not
+ * possible to enter items twice into the listbox.
+ */
+ OEditListBox(QWidget *parent = 0, const char *name = 0,
+ bool checkAtEntering=false, int buttons = All );
+ /**
+ * Create an editable listbox.
+ *
+ * The same as the other constructor, additionally it takes
+ * @title, which will be the title of the frame around the listbox.
+ */
+ OEditListBox(const QString& title, QWidget *parent = 0,
+ const char *name = 0, bool checkAtEntering=false,
+ int buttons = All );
+
+ /**
+ * Another constructor, which allows to use a custom editing widget
+ * instead of the standard OLineEdit widget. E.g. you can use a
+ * @ref OURLRequester or a @ref OComboBox as input widget. The custom
+ * editor must consist of a lineedit and optionally another widget that
+ * is used as representation. A OComboBox or a OURLRequester have a
+ * OLineEdit as child-widget for example, so the OComboBox is used as
+ * the representation widget.
+ *
+ * @see OURLRequester::customEditor()
+ * @since 3.1
+ */
+ OEditListBox( const QString& title,
+ const CustomEditor &customEditor,
+ QWidget *parent = 0, const char *name = 0,
+ bool checkAtEntering = false, int buttons = All );
+
+ virtual ~OEditListBox();
+
+ /**
+ * Return a pointer to the embedded QListBox.
+ */
+ QListBox* listBox() const { return m_listBox; }
+ /**
+ * Return a pointer to the embedded QLineEdit.
+ */
+ OLineEdit* lineEdit() const { return m_lineEdit; }
+ /**
+ * Return a pointer to the Add button
+ */
+ QPushButton* addButton() const { return servNewButton; }
+ /**
+ * Return a pointer to the Remove button
+ */
+ QPushButton* removeButton() const { return servRemoveButton; }
+ /**
+ * Return a pointer to the Up button
+ */
+ QPushButton* upButton() const { return servUpButton; }
+ /**
+ * Return a pointer to the Down button
+ */
+ QPushButton* downButton() const { return servDownButton; }
+
+ /**
+ * See @ref QListBox::count()
+ */
+ int count() const { return int(m_listBox->count()); }
+ /**
+ * See @ref QListBox::insertStringList()
+ */
+ void insertStringList(const QStringList& list, int index=-1);
+ /**
+ * See @ref QListBox::insertStringList()
+ */
+ void insertStrList(const QStrList* list, int index=-1);
+ /**
+ * See @ref QListBox::insertStrList()
+ */
+ void insertStrList(const QStrList& list, int index=-1);
+ /**
+ * See @ref QListBox::insertStrList()
+ */
+ void insertStrList(const char ** list, int numStrings=-1, int index=-1);
+ /**
+ * See @ref QListBox::insertItem()
+ */
+ void insertItem(const QString& text, int index=-1) {m_listBox->insertItem(text,index);}
+ /**
+ * Clears both the listbox and the line edit.
+ */
+ void clear();
+ /**
+ * See @ref QListBox::text()
+ */
+ QString text(int index) const { return m_listBox->text(index); }
+ /**
+ * See @ref QListBox::currentItem()
+ */
+ int currentItem() const;
+ /**
+ * See @ref QListBox::currentText()
+ */
+ QString currentText() const { return m_listBox->currentText(); }
+
+ /**
+ * @returns a stringlist of all items in the listbox
+ */
+ QStringList items() const;
+
+ signals:
+ void changed();
+
+ /**
+ * This signal is emitted when the user adds a new string to the list,
+ * the parameter is the added string.
+ * @since 3.2
+ */
+ void added( const QString & text );
+
+ /**
+ * This signal is emitted when the user removes a string from the list,
+ * the parameter is the removed string.
+ * @since 3.2
+ */
+ void removed( const QString & text );
+
+ protected slots:
+ //the names should be self-explaining
+ void moveItemUp();
+ void moveItemDown();
+ void addItem();
+ void removeItem();
+ void enableMoveButtons(int index);
+ void typedSomething(const QString& text);
+
+ private:
+ QListBox *m_listBox;
+ QPushButton *servUpButton, *servDownButton;
+ QPushButton *servNewButton, *servRemoveButton;
+ OLineEdit *m_lineEdit;
+
+ //this is called in both ctors, to avoid code duplication
+ void init( bool checkAtEntering, int buttons,
+ QWidget *representationWidget = 0L );
+
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ //our lovely private d-pointer
+ OEditListBoxPrivate *d;
+};
+
+#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 @@
+/*
+                 This file is part of the Opie Project
+
+ Originally part of the KDE project
+ (C) 1999-2000 Espen Sand (espensa@online.no)
+ =.
+ .=l.
+           .>+-=
+ _;:,     .>    :=|. This program is free software; you can
+.> <`_,   >  .   <= redistribute it and/or modify it under
+:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
+.="- .-=="i,     .._ License as published by the Free Software
+ - .   .-<_>     .<> Foundation; either version 2 of the License,
+     ._= =}       : or (at your option) any later version.
+    .%`+i>       _;_.
+    .i_,=:_.      -<s. This program is distributed in the hope that
+     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
+    : ..    .:,     . . . without even the implied warranty of
+    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
+  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
+..}^=.=       =       ; Library General Public License for more
+++=   -.     .`     .: details.
+ :     =  ...= . :.=-
+ -.   .:....=;==+<; You should have received a copy of the GNU
+  -_. . .   )=.  = Library General Public License along with
+    --        :-=` this library; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+*/
+
+/* QT */
+
+#include <qbitmap.h>
+#include <qgrid.h>
+#include <qhbox.h>
+#include <qheader.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qobjectlist.h>
+#include <qpixmap.h>
+#include <qlistview.h>
+#include <qsplitter.h>
+#include <qtabwidget.h>
+#include <qvbox.h>
+#include <qwidgetstack.h>
+#include <qpainter.h>
+#include <qtimer.h>
+#include <qstyle.h>
+
+/* OPIE */
+
+#include <opie2/odialog.h>
+#include <opie2/oseparator.h>
+#include <opie2/ojanuswidget.h>
+
+/*======================================================================================
+ * IconListItem
+ *======================================================================================*/
+
+class OJanusWidget::IconListItem : public QListBoxItem
+{
+ public:
+ IconListItem( QListBox *listbox, const QPixmap &pixmap,
+ const QString &text );
+ virtual int height( const QListBox *lb ) const;
+ virtual int width( const QListBox *lb ) const;
+ int expandMinimumWidth( int width );
+
+ protected:
+ const QPixmap &defaultPixmap();
+ void paint( QPainter *painter );
+
+ private:
+ QPixmap mPixmap;
+ int mMinimumWidth;
+};
+
+template class QPtrList<QListViewItem>;
+
+/*======================================================================================
+ * OJanusWidget
+ *======================================================================================*/
+
+OJanusWidget::OJanusWidget( QWidget *parent, const char *name, int face )
+ : QWidget( parent, name, 0 ),
+ mValid(false), mPageList(0),
+ mTitleList(0), mFace(face), mTitleLabel(0), mActivePageWidget(0),
+ mShowIconsInTreeList(false), d(0)
+{
+ QVBoxLayout *topLayout = new QVBoxLayout( this );
+
+ if( mFace == TreeList || mFace == IconList )
+ {
+ mPageList = new QPtrList<QWidget>;
+ mTitleList = new QStringList();
+
+ QFrame *page;
+ if( mFace == TreeList )
+ {
+ QSplitter *splitter = new QSplitter( this );
+ topLayout->addWidget( splitter, 10 );
+ mTreeListResizeMode = QSplitter::KeepSize;
+
+ mTreeList = new QListView( splitter );
+ mTreeList->addColumn( QString::fromLatin1("") );
+ mTreeList->header()->hide();
+ mTreeList->setRootIsDecorated(true);
+ mTreeList->setSorting( -1 );
+ connect( mTreeList, SIGNAL(selectionChanged()), SLOT(slotShowPage()) );
+ connect( mTreeList, SIGNAL(clicked(QListViewItem *)), SLOT(slotItemClicked(QListViewItem *)));
+
+ //
+ // Page area. Title at top with a separator below and a pagestack using
+ // all available space at bottom.
+ //
+ QFrame *p = new QFrame( splitter );
+
+ QHBoxLayout *hbox = new QHBoxLayout( p, 0, 0 );
+ hbox->addSpacing( ODialog::spacingHint() );
+
+ page = new QFrame( p );
+ hbox->addWidget( page, 10 );
+ }
+ else
+ {
+ QHBoxLayout *hbox = new QHBoxLayout( topLayout );
+ mIconList = new IconListBox( this );
+
+ QFont listFont( mIconList->font() );
+ listFont.setBold( true );
+ mIconList->setFont( listFont );
+
+ mIconList->verticalScrollBar()->installEventFilter( this );
+ hbox->addWidget( mIconList );
+ connect( mIconList, SIGNAL(selectionChanged()), SLOT(slotShowPage()));
+ hbox->addSpacing( ODialog::spacingHint() );
+ page = new QFrame( this );
+ hbox->addWidget( page, 10 );
+ }
+
+ //
+ // Rest of page area. Title at top with a separator below and a
+ // pagestack using all available space at bottom.
+ //
+
+ QVBoxLayout *vbox = new QVBoxLayout( page, 0, ODialog::spacingHint() );
+
+ mTitleLabel = new QLabel( QString::fromLatin1("Empty page"), page, "OJanusWidgetTitleLabel" );
+ vbox->addWidget( mTitleLabel );
+
+ QFont titleFont( mTitleLabel->font() );
+ titleFont.setBold( true );
+ mTitleLabel->setFont( titleFont );
+
+ mTitleSep = new OSeparator( page );
+ mTitleSep->setFrameStyle( QFrame::HLine|QFrame::Plain );
+ vbox->addWidget( mTitleSep );
+
+ mPageStack = new QWidgetStack( page );
+ connect(mPageStack, SIGNAL(aboutToShow(QWidget *)),
+ this, SIGNAL(aboutToShowPage(QWidget *)));
+ vbox->addWidget( mPageStack, 10 );
+ }
+ else if( mFace == Tabbed )
+ {
+ mPageList = new QPtrList<QWidget>;
+
+ mTabControl = new QTabWidget( this );
+ mTabControl->setMargin (ODialog::marginHint());
+ topLayout->addWidget( mTabControl, 10 );
+ }
+ else if( mFace == Swallow )
+ {
+ mSwallowPage = new QWidget( this );
+ topLayout->addWidget( mSwallowPage, 10 );
+ }
+ else
+ {
+ mFace = Plain;
+ mPlainPage = new QFrame( this );
+ topLayout->addWidget( mPlainPage, 10 );
+ }
+
+ /* FIXME: Revise for Opie
+ if ( kapp )
+ connect(kapp,SIGNAL(kdisplayFontChanged()),SLOT(slotFontChanged()));
+ */
+
+ mValid = true;
+
+ setSwallowedWidget(0); // Set default size if 'mFace' is Swallow.
+}
+
+
+OJanusWidget::~OJanusWidget()
+{
+ delete mPageList;
+ mPageList = 0;
+ delete mTitleList;
+ mTitleList = 0;
+}
+
+
+bool OJanusWidget::isValid() const
+{
+ return( mValid );
+}
+
+
+QFrame *OJanusWidget::plainPage()
+{
+ return( mPlainPage );
+}
+
+
+int OJanusWidget::face() const
+{
+ return( mFace );
+}
+
+QWidget *OJanusWidget::FindParent()
+{
+ if( mFace == Tabbed ) {
+ return mTabControl;
+ }
+ else {
+ return this;
+ }
+}
+
+QFrame *OJanusWidget::addPage( const QStringList &items, const QString &header,
+ const QPixmap &pixmap )
+{
+ if( mValid == false )
+ {
+ qDebug( "addPage: Invalid object" );
+ return( 0 );
+ }
+
+ QFrame *page = new QFrame( FindParent(), "page" );
+ addPageWidget( page, items, header, pixmap );
+
+ return page;
+}
+
+void OJanusWidget::pageGone( QObject *obj )
+{
+ removePage( static_cast<QWidget*>( obj ) );
+}
+
+void OJanusWidget::slotReopen( QListViewItem * item )
+{
+ if( item )
+ item->setOpen( true );
+}
+
+QFrame *OJanusWidget::addPage( const QString &itemName, const QString &header,
+ const QPixmap &pixmap )
+{
+ QStringList items;
+ items << itemName;
+ return addPage(items, header, pixmap);
+}
+
+
+
+QVBox *OJanusWidget::addVBoxPage( const QStringList &items,
+ const QString &header,
+ const QPixmap &pixmap )
+{
+ if( mValid == false )
+ {
+ qDebug( "addPage: Invalid object" );
+ return( 0 );
+ }
+
+ QVBox *page = new QVBox(FindParent() , "page" );
+ page->setSpacing( ODialog::spacingHint() );
+ addPageWidget( page, items, header, pixmap );
+
+ return page;
+}
+
+QVBox *OJanusWidget::addVBoxPage( const QString &itemName,
+ const QString &header,
+ const QPixmap &pixmap )
+{
+ QStringList items;
+ items << itemName;
+ return addVBoxPage(items, header, pixmap);
+}
+
+QHBox *OJanusWidget::addHBoxPage( const QStringList &items,
+ const QString &header,
+ const QPixmap &pixmap )
+{
+ if( mValid == false ) {
+ qDebug( "addPage: Invalid object" );
+ return( 0 );
+ }
+
+ QHBox *page = new QHBox(FindParent(), "page");
+ page->setSpacing( ODialog::spacingHint() );
+ addPageWidget( page, items, header, pixmap );
+
+ return page;
+}
+
+QHBox *OJanusWidget::addHBoxPage( const QString &itemName,
+ const QString &header,
+ const QPixmap &pixmap )
+{
+ QStringList items;
+ items << itemName;
+ return addHBoxPage(items, header, pixmap);
+}
+
+QGrid *OJanusWidget::addGridPage( int n, Orientation dir,
+ const QStringList &items,
+ const QString &header,
+ const QPixmap &pixmap )
+{
+ if( mValid == false )
+ {
+ qDebug( "addPage: Invalid object" );
+ return( 0 );
+ }
+
+ QGrid *page = new QGrid( n, dir, FindParent(), "page" );
+ page->setSpacing( ODialog::spacingHint() );
+ addPageWidget( page, items, header, pixmap );
+
+ return page;
+}
+
+
+QGrid *OJanusWidget::addGridPage( int n, Orientation dir,
+ const QString &itemName,
+ const QString &header,
+ const QPixmap &pixmap )
+{
+ QStringList items;
+ items << itemName;
+ return addGridPage(n, dir, items, header, pixmap);
+}
+
+void OJanusWidget::InsertTreeListItem(const QStringList &items, const QPixmap &pixmap, QFrame *page)
+{
+ bool isTop = true;
+ QListViewItem *curTop = 0, *child, *last, *newChild;
+ unsigned int index = 1;
+ QStringList curPath;
+
+ for ( QStringList::ConstIterator it = items.begin(); it != items.end(); ++it, index++ ) {
+ QString name = (*it);
+ bool isPath = ( index != items.count() );
+
+ // Find the first child.
+ if (isTop) {
+ child = mTreeList->firstChild();
+ }
+ else {
+ child = curTop->firstChild();
+ }
+
+ // Now search for a child with the current Name, and if it we doesn't
+ // find it, then remember the location of the last child.
+ for (last = 0; child && child->text(0) != name ; last = child, child = child->nextSibling());
+
+ if (last == 0 && child == 0) {
+ // This node didn't have any children at all, lets just insert the
+ // new child.
+ if (isTop)
+ newChild = new QListViewItem(mTreeList, name);
+ else
+ newChild = new QListViewItem(curTop, name);
+
+ }
+ else if (child != 0) {
+ // we found the given name in this child.
+ if (!isPath) {
+ qDebug( "The element inserted was already in the TreeList box!" );
+ return;
+ }
+ else {
+ // Ok we found the folder
+ newChild = child;
+ }
+ }
+ else {
+ // the node had some children, but we didn't find the given name
+ if (isTop)
+ newChild = new QListViewItem(mTreeList, last, name);
+ else
+ newChild = new QListViewItem(curTop, last, name);
+ }
+
+ // Now make the element expandable if it is a path component, and make
+ // ready for next loop
+ if (isPath) {
+ newChild->setExpandable(true);
+ curTop = newChild;
+ isTop = false;
+ curPath << name;
+
+ QString key = curPath.join("_/_");
+ if (mFolderIconMap.contains(key)) {
+ QPixmap p = mFolderIconMap[key];
+ newChild->setPixmap(0,p);
+ }
+ }
+ else {
+ if (mShowIconsInTreeList) {
+ newChild->setPixmap(0, pixmap);
+ }
+ mTreeListToPageStack.insert(newChild, page);
+ }
+ }
+}
+
+void OJanusWidget::addPageWidget( QFrame *page, const QStringList &items,
+ const QString &header,const QPixmap &pixmap )
+{
+ connect(page, SIGNAL(destroyed(QObject*)), SLOT(pageGone(QObject*)));
+
+ if( mFace == Tabbed )
+ {
+ mTabControl->addTab (page, items.last());
+ mPageList->append (page);
+ }
+ else if( mFace == TreeList || mFace == IconList )
+ {
+ mPageList->append( page );
+ mPageStack->addWidget( page, 0 );
+
+ if (items.count() == 0) {
+ qDebug( "Invalid QStringList, with zero items" );
+ return;
+ }
+
+ if( mFace == TreeList )
+ {
+ InsertTreeListItem(items, pixmap, page);
+ }
+ else // mFace == IconList
+ {
+ QString itemName = items.last();
+ IconListItem *item = new IconListItem( mIconList, pixmap, itemName );
+ //
+ // 2000-06-01 Espen Sand: If I do this with Qt 2.1.1 all sorts of
+ // strange things happen. With Qt <= 2.1 it worked but now I must
+ // either specify the listbox in the constructor on the item
+ // or as below, not both.
+ // mIconList->insertItem( item );
+ //
+ mIconListToPageStack.insert(item, page);
+ mIconList->invalidateHeight();
+ mIconList->invalidateWidth();
+
+ if (mIconList->isVisible())
+ mIconList->updateWidth();
+ }
+
+ //
+ // Make sure the title label is sufficiently wide
+ //
+ QString lastName = items.last();
+ const QString &title = (header != QString::null ? header : lastName);
+ QRect r = mTitleLabel->fontMetrics().boundingRect( title );
+ if( mTitleLabel->minimumWidth() < r.width() )
+ {
+ mTitleLabel->setMinimumWidth( r.width() );
+ }
+ mTitleList->append( title );
+
+ if( mTitleList->count() == 1 )
+ {
+ showPage(0);
+ }
+ }
+ else
+ {
+ qDebug( "OJanusWidget::addPageWidget: can only add a page in Tabbed, TreeList or IconList modes" );
+ }
+
+}
+
+void OJanusWidget::setFolderIcon(const QStringList &path, const QPixmap &pixmap)
+{
+ QString key = path.join("_/_");
+ mFolderIconMap.insert(key,pixmap);
+}
+
+
+
+bool OJanusWidget::setSwallowedWidget( QWidget *widget )
+{
+ if( mFace != Swallow || mValid == false )
+ {
+ return( false );
+ }
+
+ //
+ // Remove current layout and make a new.
+ //
+ if( mSwallowPage->layout() != 0 )
+ {
+ delete mSwallowPage->layout();
+ }
+ QGridLayout *gbox = new QGridLayout( mSwallowPage, 1, 1, 0 );
+
+ //
+ // Hide old children
+ //
+ QObjectList *l = (QObjectList*)mSwallowPage->children(); // silence please
+ for( uint i=0; i < l->count(); i++ )
+ {
+ QObject *o = l->at(i);
+ if( o->isWidgetType() )
+ {
+ ((QWidget*)o)->hide();
+ }
+ }
+
+ //
+ // Add new child or make default size
+ //
+ if( widget == 0 )
+ {
+ gbox->addRowSpacing(0,100);
+ gbox->addColSpacing(0,100);
+ mSwallowPage->setMinimumSize(100,100);
+ }
+ else
+ {
+ if( widget->parent() != mSwallowPage )
+ {
+ widget->reparent( mSwallowPage, 0, QPoint(0,0) );
+ }
+ gbox->addWidget(widget, 0, 0 );
+ gbox->activate();
+ mSwallowPage->setMinimumSize( widget->minimumSize() );
+ }
+
+ return( true );
+}
+
+bool OJanusWidget::slotShowPage()
+{
+ if( mValid == false )
+ {
+ return( false );
+ }
+
+ if( mFace == TreeList )
+ {
+ QListViewItem *node = mTreeList->selectedItem();
+ if( node == 0 ) { return( false ); }
+
+ QWidget *stackItem = mTreeListToPageStack[node];
+ return showPage(stackItem);
+ }
+ else if( mFace == IconList )
+ {
+ QListBoxItem *node = mIconList->item( mIconList->currentItem() );
+ if( node == 0 ) { return( false ); }
+ QWidget *stackItem = mIconListToPageStack[node];
+ return showPage(stackItem);
+ }
+
+ return( false );
+}
+
+
+bool OJanusWidget::showPage( int index )
+{
+ if( mPageList == 0 || mValid == false )
+ {
+ return( false );
+ }
+ else
+ {
+ return showPage(mPageList->at(index));
+ }
+}
+
+
+bool OJanusWidget::showPage( QWidget *w )
+{
+ if( w == 0 || mValid == false )
+ {
+ return( false );
+ }
+
+ if( mFace == TreeList || mFace == IconList )
+ {
+ mPageStack->raiseWidget( w );
+ mActivePageWidget = w;
+
+ int index = mPageList->findRef( w );
+ mTitleLabel->setText( *mTitleList->at(index) );
+ if( mFace == TreeList )
+ {
+ QMap<QListViewItem *, QWidget *>::Iterator it;
+ for (it = mTreeListToPageStack.begin(); it != mTreeListToPageStack.end(); ++it){
+ QListViewItem *key = it.key();
+ QWidget *val = it.data();
+ if (val == w) {
+ mTreeList->setSelected(key, true );
+ break;
+ }
+ }
+ }
+ else
+ {
+ QMap<QListBoxItem *, QWidget *>::Iterator it;
+ for (it = mIconListToPageStack.begin(); it != mIconListToPageStack.end(); ++it){
+ QListBoxItem *key = it.key();
+ QWidget *val = it.data();
+ if (val == w) {
+ mIconList->setSelected( key, true );
+ break;
+ }
+ }
+
+ //
+ // 2000-02-13 Espen Sand
+ // Don't ask me why (because I don't know). If I select a page
+ // with the mouse the page is not updated until it receives an
+ // event. It seems this event get lost if the mouse is not moved
+ // when released. The timer ensures the update
+ //
+ QTimer::singleShot( 0, mActivePageWidget, SLOT(update()) );
+ }
+ }
+ else if( mFace == Tabbed )
+ {
+ mTabControl->showPage(w);
+ mActivePageWidget = w;
+ }
+ else
+ {
+ return( false );
+ }
+
+ return( true );
+}
+
+
+int OJanusWidget::activePageIndex() const
+{
+ if( mFace == TreeList) {
+ QListViewItem *node = mTreeList->selectedItem();
+ if( node == 0 ) { return -1; }
+ QWidget *stackItem = mTreeListToPageStack[node];
+ return mPageList->findRef(stackItem);
+ }
+ else if (mFace == IconList) {
+ QListBoxItem *node = mIconList->item( mIconList->currentItem() );
+ if( node == 0 ) { return( false ); }
+ QWidget *stackItem = mIconListToPageStack[node];
+ return mPageList->findRef(stackItem);
+ }
+ else if( mFace == Tabbed ) {
+ QWidget *widget = mTabControl->currentPage();
+ return( widget == 0 ? -1 : mPageList->findRef( widget ) );
+ }
+ else {
+ return( -1 );
+ }
+}
+
+
+int OJanusWidget::pageIndex( QWidget *widget ) const
+{
+ if( widget == 0 )
+ {
+ return( -1 );
+ }
+ else if( mFace == TreeList || mFace == IconList )
+ {
+ return( mPageList->findRef( widget ) );
+ }
+ else if( mFace == Tabbed )
+ {
+ //
+ // The user gets the real page widget with addVBoxPage(), addHBoxPage()
+ // and addGridPage() but not with addPage() which returns a child of
+ // the toplevel page. addPage() returns a QFrame so I check for that.
+ //
+ if( widget->isA("QFrame") )
+ {
+ return( mPageList->findRef( widget->parentWidget() ) );
+ }
+ else
+ {
+ return( mPageList->findRef( widget ) );
+ }
+ }
+ else
+ {
+ return( -1 );
+ }
+}
+
+void OJanusWidget::slotFontChanged()
+{
+#ifdef FIXME
+
+ if ( mTitleLabel != 0 )
+ {
+ mTitleLabel->setFont( KGlobalSettings::generalFont() );
+ QFont titleFont( mTitleLabel->font() );
+ titleFont.setBold( true );
+ mTitleLabel->setFont( titleFont );
+ }
+#endif
+
+ if( mFace == IconList )
+ {
+ QFont listFont( mIconList->font() );
+ listFont.setBold( true );
+ mIconList->setFont( listFont );
+ mIconList->invalidateHeight();
+ mIconList->invalidateWidth();
+ }
+}
+
+// makes the treelist behave like the list of kcontrol
+void OJanusWidget::slotItemClicked(QListViewItem *it)
+{
+ if(it && (it->childCount()>0))
+ it->setOpen(!it->isOpen());
+}
+
+void OJanusWidget::setFocus()
+{
+ if( mValid == false ) { return; }
+ if( mFace == TreeList )
+ {
+ mTreeList->setFocus();
+ }
+ if( mFace == IconList )
+ {
+ mIconList->setFocus();
+ }
+ else if( mFace == Tabbed )
+ {
+ mTabControl->setFocus();
+ }
+ else if( mFace == Swallow )
+ {
+ mSwallowPage->setFocus();
+ }
+ else if( mFace == Plain )
+ {
+ mPlainPage->setFocus();
+ }
+}
+
+
+QSize OJanusWidget::minimumSizeHint() const
+{
+ if( mFace == TreeList || mFace == IconList )
+ {
+ QSize s1( ODialog::spacingHint(), ODialog::spacingHint()*2 );
+ QSize s2(0,0);
+ QSize s3(0,0);
+ QSize s4( mPageStack->sizeHint() );
+
+ if( mFace == TreeList )
+ {
+#if QT_VERSION < 300
+ s1.rwidth() += style().splitterWidth();
+#else
+ s1.rwidth() += style().pixelMetric( QStyle::PM_SplitterWidth );
+#endif
+ s2 = mTreeList->minimumSize();
+ }
+ else
+ {
+ mIconList->updateMinimumHeight();
+ mIconList->updateWidth();
+ s2 = mIconList->minimumSize();
+ }
+
+ if( mTitleLabel->isVisible() == true )
+ {
+ s3 += mTitleLabel->sizeHint();
+ s3.rheight() += mTitleSep->minimumSize().height();
+ }
+
+ //
+ // Select the tallest item. It has only effect in IconList mode
+ //
+ int h1 = s1.rheight() + s3.rheight() + s4.height();
+ int h2 = QMAX( h1, s2.rheight() );
+
+ return( QSize( s1.width()+s2.width()+QMAX(s3.width(),s4.width()), h2 ) );
+ }
+ else if( mFace == Tabbed )
+ {
+ return( mTabControl->sizeHint() );
+ }
+ else if( mFace == Swallow )
+ {
+ return( mSwallowPage->minimumSize() );
+ }
+ else if( mFace == Plain )
+ {
+ return( mPlainPage->sizeHint() );
+ }
+ else
+ {
+ return( QSize( 100, 100 ) ); // Should never happen though.
+ }
+
+}
+
+
+QSize OJanusWidget::sizeHint() const
+{
+ return( minimumSizeHint() );
+}
+
+
+void OJanusWidget::setTreeListAutoResize( bool state )
+{
+ if( mFace == TreeList )
+ {
+ mTreeListResizeMode = state == false ?
+ QSplitter::KeepSize : QSplitter::Stretch;
+ QSplitter *splitter = (QSplitter*)(mTreeList->parentWidget());
+ splitter->setResizeMode( mTreeList, mTreeListResizeMode );
+ }
+}
+
+
+void OJanusWidget::setIconListAllVisible( bool state )
+{
+ if( mFace == IconList )
+ {
+ mIconList->setShowAll( state );
+ }
+}
+
+void OJanusWidget::setShowIconsInTreeList( bool state )
+{
+ mShowIconsInTreeList = state;
+}
+
+void OJanusWidget::setRootIsDecorated( bool state )
+{
+ if( mFace == TreeList ) {
+ mTreeList->setRootIsDecorated(state);
+ }
+}
+
+void OJanusWidget::unfoldTreeList( bool persist )
+{
+ if( mFace == TreeList )
+ {
+ if( persist )
+ connect( mTreeList, SIGNAL( collapsed( QListViewItem * ) ), this, SLOT( slotReopen( QListViewItem * ) ) );
+ else
+ disconnect( mTreeList, SIGNAL( collapsed( QListViewItem * ) ), this, SLOT( slotReopen( QListViewItem * ) ) );
+
+ for( QListViewItem * item = mTreeList->firstChild(); item; item = item->itemBelow() )
+ item->setOpen( true );
+ }
+}
+
+void OJanusWidget::showEvent( QShowEvent * )
+{
+ if( mFace == TreeList )
+ {
+ QSplitter *splitter = (QSplitter*)(mTreeList->parentWidget());
+ splitter->setResizeMode( mTreeList, mTreeListResizeMode );
+ }
+}
+
+
+//
+// 2000-13-02 Espen Sand
+// It should be obvious that this eventfilter must only be
+// be installed on the vertical scrollbar of the mIconList.
+//
+bool OJanusWidget::eventFilter( QObject *o, QEvent *e )
+{
+ if( e->type() == QEvent::Show )
+ {
+ IconListItem *item = (IconListItem*)mIconList->item(0);
+ if( item != 0 )
+ {
+ int lw = item->width( mIconList );
+ int sw = mIconList->verticalScrollBar()->sizeHint().width();
+ mIconList->setFixedWidth( lw+sw+mIconList->frameWidth()*2 );
+ }
+ }
+ else if( e->type() == QEvent::Hide )
+ {
+ IconListItem *item = (IconListItem*)mIconList->item(0);
+ if( item != 0 )
+ {
+ int lw = item->width( mIconList );
+ mIconList->setFixedWidth( lw+mIconList->frameWidth()*2 );
+ }
+ }
+ return QWidget::eventFilter( o, e );
+}
+
+
+
+//
+// Code for the icon list box
+//
+
+
+OJanusWidget::IconListBox::IconListBox( QWidget *parent, const char *name,
+ WFlags f )
+ :QListBox( parent, name, f ), mShowAll(false), mHeightValid(false),
+ mWidthValid(false)
+{
+}
+
+
+void OJanusWidget::IconListBox::updateMinimumHeight()
+{
+ if( mShowAll == true && mHeightValid == false )
+ {
+ int h = frameWidth()*2;
+ for( QListBoxItem *i = item(0); i != 0; i = i->next() )
+ {
+ h += i->height( this );
+ }
+ setMinimumHeight( h );
+ mHeightValid = true;
+ }
+}
+
+
+void OJanusWidget::IconListBox::updateWidth()
+{
+ if( mWidthValid == false )
+ {
+ int maxWidth = 10;
+ for( QListBoxItem *i = item(0); i != 0; i = i->next() )
+ {
+ int w = ((IconListItem *)i)->width(this);
+ maxWidth = QMAX( w, maxWidth );
+ }
+
+ for( QListBoxItem *i = item(0); i != 0; i = i->next() )
+ {
+ ((IconListItem *)i)->expandMinimumWidth( maxWidth );
+ }
+
+ if( verticalScrollBar()->isVisible() )
+ {
+ maxWidth += verticalScrollBar()->sizeHint().width();
+ }
+
+ setFixedWidth( maxWidth + frameWidth()*2 );
+ mWidthValid = true;
+ }
+}
+
+
+void OJanusWidget::IconListBox::invalidateHeight()
+{
+ mHeightValid = false;
+}
+
+
+void OJanusWidget::IconListBox::invalidateWidth()
+{
+ mWidthValid = false;
+}
+
+
+void OJanusWidget::IconListBox::setShowAll( bool showAll )
+{
+ mShowAll = showAll;
+ mHeightValid = false;
+}
+
+
+
+OJanusWidget::IconListItem::IconListItem( QListBox *listbox, const QPixmap &pixmap,
+ const QString &text )
+ : QListBoxItem( listbox )
+{
+ mPixmap = pixmap;
+ if( mPixmap.isNull() == true )
+ {
+ mPixmap = defaultPixmap();
+ }
+ setText( text );
+ mMinimumWidth = 0;
+}
+
+
+int OJanusWidget::IconListItem::expandMinimumWidth( int width )
+{
+ mMinimumWidth = QMAX( mMinimumWidth, width );
+ return( mMinimumWidth );
+}
+
+
+const QPixmap &OJanusWidget::IconListItem::defaultPixmap()
+{
+ static QPixmap *pix=0;
+ if( pix == 0 )
+ {
+ pix = new QPixmap( 32, 32 );
+ QPainter p( pix );
+ p.eraseRect( 0, 0, pix->width(), pix->height() );
+ p.setPen( Qt::red );
+ p.drawRect ( 0, 0, pix->width(), pix->height() );
+ p.end();
+
+ QBitmap mask( pix->width(), pix->height(), true );
+ mask.fill( Qt::black );
+ p.begin( &mask );
+ p.setPen( Qt::white );
+ p.drawRect ( 0, 0, pix->width(), pix->height() );
+ p.end();
+
+ pix->setMask( mask );
+ }
+ return( *pix );
+}
+
+
+void OJanusWidget::IconListItem::paint( QPainter *painter )
+{
+ QFontMetrics fm = painter->fontMetrics();
+ //int wt = fm.boundingRect(text()).width();
+ int wp = mPixmap.width();
+ int ht = fm.lineSpacing();
+ int hp = mPixmap.height();
+
+ painter->drawPixmap( (mMinimumWidth-wp)/2, 5, mPixmap );
+ if( text().isEmpty() == false )
+ {
+ painter->drawText( 0, hp+7, mMinimumWidth, ht, Qt::AlignCenter, text() );
+ }
+}
+
+int OJanusWidget::IconListItem::height( const QListBox *lb ) const
+{
+ if( text().isEmpty() == true )
+ {
+ return( mPixmap.height() );
+ }
+ else
+ {
+ return( mPixmap.height() + lb->fontMetrics().lineSpacing()+10 );
+ }
+}
+
+
+int OJanusWidget::IconListItem::width( const QListBox *lb ) const
+{
+ int wt = lb->fontMetrics().boundingRect(text()).width()+10;
+ int wp = mPixmap.width() + 10;
+ int w = QMAX( wt, wp );
+ return( QMAX( w, mMinimumWidth ) );
+}
+
+// Just remove the page from our stack of widgets. Do not modify the given widget in
+// any way. No memory leak occurs as parent is not changed.
+// Make this virtual in KDE 4.0.
+// Ravikiran Rajagopal <ravi@ee.eng.ohio-state.edu>
+void OJanusWidget::removePage( QWidget *page )
+{
+ if (!mPageList || !mPageList->containsRef(page))
+ return;
+
+ int index = mPageList->findRef( page );
+ if ( mTitleList )
+ mTitleList->remove(mTitleList->at(index));
+
+ mPageList->removeRef(page);
+
+ if ( mFace == TreeList )
+ {
+ QMap<QListViewItem*, QWidget *>::Iterator i;
+ for( i = mTreeListToPageStack.begin(); i != mTreeListToPageStack.end(); ++i )
+ if (i.data()==page)
+ {
+ delete i.key();
+ mPageStack->removeWidget(page);
+ mTreeListToPageStack.remove(i);
+ break;
+ }
+ }
+ else if ( mFace == IconList )
+ {
+ QMap<QListBoxItem*, QWidget *>::Iterator i;
+ for( i = mIconListToPageStack.begin(); i != mIconListToPageStack.end(); ++i )
+ if (i.data()==page)
+ {
+ delete i.key();
+ mPageStack->removeWidget(page);
+ mIconListToPageStack.remove(i);
+ break;
+ }
+ }
+ else // Tabbed
+ {
+ mTabControl->removePage(page);
+ }
+}
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 @@
+/*
+                 This file is part of the Opie Project
+
+              Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
+ Copyright (C) 1999-2000 Espen Sand (espen@kde.org)
+ =.
+ .=l.
+           .>+-=
+ _;:,     .>    :=|. This program is free software; you can
+.> <`_,   >  .   <= redistribute it and/or modify it under
+:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
+.="- .-=="i,     .._ License as published by the Free Software
+ - .   .-<_>     .<> Foundation; either version 2 of the License,
+     ._= =}       : or (at your option) any later version.
+    .%`+i>       _;_.
+    .i_,=:_.      -<s. This program is distributed in the hope that
+     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
+    : ..    .:,     . . . without even the implied warranty of
+    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
+  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
+..}^=.=       =       ; Library General Public License for more
+++=   -.     .`     .: details.
+ :     =  ...= . :.=-
+ -.   .:....=;==+<; You should have received a copy of the GNU
+  -_. . .   )=.  = Library General Public License along with
+    --        :-=` this library; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef OJANUSWIDGET_H
+#define OJANUSWIDGET_H
+
+#include <qptrlist.h>
+#include <qpixmap.h>
+#include <qlistbox.h>
+#include <qmap.h>
+#include <qsplitter.h>
+#include <qstringlist.h>
+
+class QGrid;
+class QHBox;
+class QLabel;
+class QTabWidget;
+class QVBox;
+class QWidgetStack;
+class OSeparator;
+class QListView;
+class QListViewItem;
+
+/**
+ * Provides a number of ready to use layouts (faces). It is used
+ * as an internal widget in @ref KDialogBase, but can also used as a
+ * widget of its own.
+ *
+ * It provides TreeList, IconList, Tabbed, Plain and Swallow layouts.
+ *
+ * The TreeList face provides a list in the left area and pages in the
+ * right. The area are separated by a movable splitter. The style is somewhat
+ * similar to the layout in the Control Center. A page is raised by
+ * selecting the corresponding tree list item.
+ *
+ * The IconList face provides an icon list in the left area and pages in the
+ * right. For each entry the Icon is on top with the text below. The style
+ * is somewhat similar to the layout of the Eudora configuation dialog box.
+ * A page is raised by selecting the corresponding icon list item. The
+ * preferred icon size is 32x32 pixels.
+ *
+ * The Tabbed face is a common tabbed widget. The procedure for creating a
+ * page is similar for creating a TreeList. This has the advantage that if
+ * your widget contain too many pages it is trivial to convert it into a
+ * TreeList. Just change the face in the KJanusWidget constructor to
+ * KJanusWidget::TreeList and you have a tree list layout instead.
+ *
+ * The Plain face provides an empty widget (QFrame) where you can place your
+ * widgets. The KJanusWidget makes no assumptions regarding the contents so
+ * you are free to add whatever you want.
+ *
+ * The Swallow face is provided in order to simplify the usage of existing
+ * widgets and to allow changing the visible widget. You specify the widget
+ * to be displayed by @ref #setSwallowedWidget(). Your widget will be
+ * reparented inside the widget. You can specify a Null (0) widget. A empty
+ * space is then displayed.
+ *
+ * For all modes it is important that you specify the @ref QWidget::minimumSize()
+ * on the page, plain widget or the swallowed widget. If you use a QLayout
+ * on the page, plain widget or the swallowed widget this will be taken care
+ * of automatically. The size is used when the KJanusWidget determines its
+ * own minimum size. You get the minimum size by using the
+ * @ref #minimumSizeHint() or @ref #sizeHint() methods.
+ *
+ * Pages that have been added in TreeList, IconList or Tabbed mode can be
+ * removed by simply deleting the page.
+ *
+ * @short Easy to use widget with many layouts
+ * @author Espen Sand (espen@kde.org)
+ */
+class OJanusWidget : public QWidget
+{
+ Q_OBJECT
+
+ private:
+
+ class IconListBox : public QListBox
+ {
+ public:
+ IconListBox( QWidget *parent=0, const char *name=0, WFlags f=0 );
+ void updateMinimumHeight();
+ void updateWidth();
+ void invalidateHeight();
+ void invalidateWidth();
+ void setShowAll( bool showAll );
+
+ private:
+ bool mShowAll;
+ bool mHeightValid;
+ bool mWidthValid;
+ };
+
+ public:
+
+ enum Face
+ {
+ TreeList = 0,
+ Tabbed,
+ Plain,
+ Swallow,
+ IconList
+ };
+
+ public:
+
+ /**
+ * Constructor where you specify the face.
+ *
+ * @param parent Parent of the widget.
+ * @param name Widget name.
+ * @param int face The kind of dialog, Use TreeList, Tabbed, Plain or
+ * Swallow.
+ */
+ OJanusWidget( QWidget *parent=0, const char *name=0, int face=Plain );
+
+ /**
+ * Destructor.
+ */
+ ~OJanusWidget();
+
+ /**
+ * Raises the page which was added by @ref addPage().
+ *
+ * @param index The index of the page you want to raise.
+ */
+ virtual bool showPage( int index );
+
+ /**
+ * Returns the index of the page that are currently displayed.
+ *
+ * @return The index or -1 if the face is not Tabbed, TreeList or
+ * IconList.
+ */
+ virtual int activePageIndex() const;
+
+ /**
+ * Use this to verify
+ * that no memory allocation failed.
+ *
+ * @return true if the widget was properly created.
+ */
+ virtual bool isValid() const;
+
+ /**
+ * Returns the face type.
+ *
+ * @return The face type.
+ */
+ virtual int face() const;
+
+ /**
+ * Returns the minimum size that must be made available for the widget
+ * so that UIs can be displayed properly
+ *
+ * @return The minimum size.
+ */
+ virtual QSize minimumSizeHint() const;
+
+ /**
+ * Returns the recommended size for the widget in order to be displayed
+ * properly.
+ *
+ * @return The recommended size.
+ */
+ virtual QSize sizeHint() const;
+
+ /**
+ * Returns the empty widget that is available in Plain mode.
+ *
+ * @return The widget or 0 if the face in not Plain.
+ */
+ virtual QFrame *plainPage();
+
+ /**
+ * Add a new page when the class is used in TreeList, IconList or Tabbed
+ * mode. The returned widget is empty and you must add your widgets
+ * as children to this widget. In most cases you must create a layout
+ * manager and associate it with this widget as well.
+ *
+ * Deleting the returned frame will cause the listitem or tab to be
+ * removed (you can re-add a page with the same name later.
+ *
+ * @param item String used in the list or Tab item.
+ * @param header A longer string used in TreeList and IconList mode to
+ * describe the contents of a page. If empty, the item string
+ * will be used instead.
+ * @param pixmap Used in IconList mode or in TreeList mode. You should
+ * prefer a pixmap with size 32x32 pixels.
+ *
+ * @return The empty page or 0 if the face is not TreeList, IconList or
+ * Tabbed.
+ */
+ virtual QFrame *addPage(const QString &item,const QString &header=QString::null,
+ const QPixmap &pixmap=QPixmap() );
+
+ /**
+ * This is like addPage just above, with the difference that the first
+ * element is a list of strings. These strings are used to form a path
+ * of folders down to the given page. The initial elements are names
+ * for the folders, while the last element is the name of the page.
+ * Note: This does yet only work for the TreeList face. Later this may
+ * be added for the IconList face too. In other faces than the
+ * TreeList, all the strings except the last one is ignored.
+ * Deleting the returned frame will cause the listitem or tab to be
+ * removed (you can re-add a page with the same name later.
+ *
+ * Deleting the returned frame will cause the listitem or tab to be
+ * removed (you can re-add a page with the same name later.
+ **/
+ virtual QFrame *addPage(const QStringList &items, const QString &header=QString::null,
+ const QPixmap &pixmap=QPixmap() );
+
+ /**
+ * Add a new page when the class is used in TreeList, IconList or Tabbed
+ * mode. The returned widget is empty and you must add your widgets
+ * as children to this widget. The returned widget is a @ref QVBox
+ * so it contains a QVBoxLayout layout that lines up the child widgets
+ * are vertically.
+ *
+ * Deleting the returned frame will cause the listitem or tab to be
+ * removed (you can re-add a page with the same name later.
+ *
+ * @param item String used in the list or Tab item.
+ * @param header A longer string used in TreeList and IconList mode to
+ * describe the contents of a page. If empty, the item string
+ * will be used instead.
+ * @param pixmap Used in IconList mode or in TreeList mode. You should
+ * prefer a pixmap with size 32x32 pixels.
+ *
+ * @return The empty page or 0 if the face is not TreeList, IconList or
+ * Tabbed. */
+ virtual QVBox *addVBoxPage( const QString &item,
+ const QString &header=QString::null,
+ const QPixmap &pixmap=QPixmap() );
+
+ /**
+ * This is like addVBoxPage just above, with the difference that the first
+ * element is a list of strings. These strings are used to form a path
+ * of folders down to the given page. The initial elements are names
+ * for the folders, while the last element is the name of the page.
+ * Note: This does yet only work for the TreeList face. Later this may
+ * be added for the IconList face too. In other faces than the
+ * TreeList, all the strings except the last one is ignored.
+ *
+ * Deleting the returned frame will cause the listitem or tab to be
+ * removed (you can re-add a page with the same name later.
+ **/
+ virtual QVBox *addVBoxPage( const QStringList &items,
+ const QString &header=QString::null,
+ const QPixmap &pixmap=QPixmap() );
+
+ /**
+ * Add a new page when the class is used in TreeList, IconList or Tabbed
+ * mode. The returned widget is empty and you must add your widgets
+ * as children to this widget. The returned widget is a @ref QHBox
+ * so it contains a QHBoxLayout layout that lines up the child widgets
+ * are horizontally.
+ *
+ * Deleting the returned frame will cause the listitem or tab to be
+ * removed (you can re-add a page with the same name later.
+ *
+ * @param item String used in the list or Tab item.
+ * @param header A longer string used in TreeList and IconList mode to
+ * describe the contents of a page. If empty, the item string
+ * will be used instead.
+ * @param pixmap Used in IconList mode or in TreeList mode. You should
+ * prefer a pixmap with size 32x32 pixels.
+ *
+ * @return The empty page or 0 if the face is not TreeList, IconList or
+ * Tabbed.
+ */
+ virtual QHBox *addHBoxPage( const QString &itemName,
+ const QString &header=QString::null,
+ const QPixmap &pixmap=QPixmap() );
+
+ /**
+ * This is like addHBoxPage just above, with the difference that the first
+ * element is a list of strings. These strings are used to form a path
+ * of folders down to the given page. The initial elements are names
+ * for the folders, while the last element is the name of the page.
+ * Note: This does yet only work for the TreeList face. Later this may
+ * be added for the IconList face too. In other faces than the
+ * TreeList, all the strings except the last one is ignored.
+ *
+ * Deleting the returned frame will cause the listitem or tab to be
+ * removed (you can re-add a page with the same name later.
+ **/
+ virtual QHBox *addHBoxPage( const QStringList &items,
+ const QString &header=QString::null,
+ const QPixmap &pixmap=QPixmap() );
+
+ /**
+ * Add a new page when the class is used in either TreeList or Tabbed
+ * mode. The returned widget is empty and you must add your widgets
+ * as children to this widget. The returned widget is a @ref QGrid
+ * so it contains a QGridLayout layout that places up the child widgets
+ * in a grid.
+ *
+ * Deleting the returned frame will cause the listitem or tab to be
+ * removed (you can re-add a page with the same name later.
+ *
+ * @param n Specifies the number of columns if 'dir' is QGrid::Horizontal
+ * or the number of rows if 'dir' is QGrid::Vertical.
+ * @param dir Can be QGrid::Horizontal or QGrid::Vertical.
+ * @param item String used in the list or Tab item.
+ * @param header A longer string used in TreeList and IconList mode to
+ * describe the contents of a page. If empty, the item string
+ * will be used instead.
+ * @param pixmap Used in IconList mode or in TreeList mode. You should
+ * prefer a pixmap with size 32x32 pixels.
+ *
+ * @return The empty page or 0 if the face is not TreeList, IconList or
+ * Tabbed.
+ */
+ virtual QGrid *addGridPage( int n, Orientation dir,
+ const QString &itemName,
+ const QString &header=QString::null,
+ const QPixmap &pixmap=QPixmap() );
+
+ /**
+ * This is like addGridPage just above, with the difference that the first
+ * element is a list of strings. These strings are used to form a path
+ * of folders down to the given page. The initial elements are names
+ * for the folders, while the last element is the name of the page.
+ * Note: This does yet only work for the TreeList face. Later this may
+ * be added for the IconList face too. In other faces than the
+ * TreeList, all the strings except the last one is ignored.
+ *
+ * Deleting the returned frame will cause the listitem or tab to be
+ * removed (you can re-add a page with the same name later.
+ **/
+ virtual QGrid *addGridPage( int n, Orientation dir,
+ const QStringList &items,
+ const QString &header=QString::null,
+ const QPixmap &pixmap=QPixmap() );
+
+ /**
+ * @short Removes a page created with @ref addPage, @ref addVBoxPage,
+ * @ref addHBoxPage or @ref addGridPage. If the page has already
+ * been deleted or has already been removed, nothing happens. The widget
+ * itself is not deleted.
+ *
+ * @param page The widget returned by @ref addPage , @ref addVBoxPage ,
+ * @ref addHBoxPage or @ref addGridPage .
+ */
+ void removePage( QWidget *page );
+
+
+ /**
+ * Returns the index of a page created with @ref addPage ,
+ * @ref addVBoxPage , @ref addHBoxPage or @ref addGridPage .
+ * You can can compare this index with the value returned from
+ * @ref activePageIndex if you need to do some page specific actions
+ * in your code.
+ *
+ * The returned index will never change so you can safely use this
+ * function once and save the value.
+ *
+ * @param widget The widget returned by @ref addPage , @ref addVBoxPage ,
+ * @ref addHBoxPage or @ref addGridPage .
+ *
+ * @return The index or -1 if the face is not Tabbed, TreeList or
+ * IconList
+ */
+ virtual int pageIndex( QWidget *widget ) const;
+
+ /**
+ * Defines the widget to be swallowed.
+ *
+ * This method can be used several
+ * times. Only the latest defined widget will be shown.
+ *
+ * @param widget The widget to be swallowed. If 0, then an empty rectangle
+ * is displayed.
+ */
+ virtual bool setSwallowedWidget( QWidget *widget );
+
+ /**
+ * This function has only effect in TreeList mode.
+ *
+ * Defines how the tree list is resized when the widget is resized
+ * horizontally. By default the tree list keeps its width when the
+ * widget becomes wider.
+ *
+ * @param state The resize mode. If false (default) the TreeList keeps
+ * its current width when the widget becomes wider.
+ */
+ virtual void setTreeListAutoResize( bool state );
+
+ /**
+ * This function has only effect in TreeList mode.
+ *
+ * This tells the widgets whether the icons given in the @ref addPage,
+ * @ref addVBoxPage, @ref addHBoxPage, or @ref addGridPage methods should
+ * be shown in the TreeList.
+ *
+ * Note: This method must be called before calling any of the methods
+ * which add icons to the page.
+ *
+ * @param state If true the icons are shown.
+ **/
+ virtual void setShowIconsInTreeList(bool state);
+
+ /**
+ * This function has only effect in TreeList mode.
+ *
+ * This tells the widgets whether the root should be decorated.
+ * For details see @ref QListView::setRootIsDecorated
+ *
+ * @param state Root will be decorated if true.
+ **/
+ virtual void setRootIsDecorated( bool state );
+
+ /**
+ * This function has only effect in TreeList mode.
+ *
+ * This tells the TreeList to unfold the whole tree so that all entries
+ * are visible.
+ *
+ * If the list is empty when you call this method newly created entries
+ * will not automatically be opened. If the @p persist flag is set opened
+ * entries cannot be closed again, though.
+ *
+ * @param persist If true the tree always stays unfolded.
+ * @since 3.2
+ */
+ /*virtual*/ void unfoldTreeList( bool persist = false ); //### KDE4 BIC add virtual
+
+ /**
+ * This function has only effect in IconList mode.
+ *
+ * Defines how the icon list widget is displayed. By default it is
+ * the widgets in the pages that decide the minimum height
+ * of the toplevel widget. A vertical scrollbar can be used in
+ * the icon list area.
+ *
+ * @param state The visibility mode. If true, the minimum height is
+ * adjusted so that every icon in the list is visible at the
+ * same time. The vertical scrollbar will never be visible.
+ */
+ virtual void setIconListAllVisible( bool state );
+
+ /**
+ * Sets the icon used in TreeList Mode for the given path.
+ * @param path The path for which this icon should be shown.
+ * @param pixmap The icon used.
+ **/
+ virtual void setFolderIcon(const QStringList &path, const QPixmap &pixmap);
+
+ signals:
+ void aboutToShowPage(QWidget *page);
+
+ public slots:
+ /**
+ * Give the keyboard input focus to the widget.
+ */
+ virtual void setFocus();
+
+ protected:
+ /**
+ * Reimplemented to handle the splitter width when the the face
+ * is TreeList
+ */
+ virtual void showEvent( QShowEvent * );
+
+ /**
+ * This function is used internally when in IconList mode. If you
+ * reimplement this class a make your own event filter, make sure to
+ * call this function from your filter.
+ *
+ * @param o Object that has received an event.
+ * @param e The event.
+ */
+ virtual bool eventFilter( QObject *o, QEvent *e );
+
+ private slots:
+ bool slotShowPage();
+ void slotFontChanged();
+ void slotItemClicked(QListViewItem *it);
+ void pageGone(QObject *obj); // signal from the added page's "destroyed" signal
+ void slotReopen(QListViewItem *item);
+
+ protected:
+ bool showPage( QWidget *w );
+ void addPageWidget( QFrame *page, const QStringList &items,
+ const QString &header, const QPixmap &pixmap );
+ void InsertTreeListItem(const QStringList &items, const QPixmap &pixmap, QFrame *page);
+ QWidget *FindParent();
+
+ private:
+ bool mValid;
+
+ QPtrList<QWidget> *mPageList;
+ QStringList *mTitleList;
+
+ int mFace;
+ QListView *mTreeList;
+ IconListBox *mIconList;
+ QWidgetStack *mPageStack;
+ QLabel *mTitleLabel;
+ QTabWidget *mTabControl;
+ QFrame *mPlainPage;
+ QWidget *mSwallowPage;
+ QWidget *mActivePageWidget;
+ OSeparator *mTitleSep;
+ QSplitter::ResizeMode mTreeListResizeMode;
+ bool mShowIconsInTreeList;
+ QMap<QListViewItem *, QWidget *> mTreeListToPageStack;
+ QMap<QListBoxItem *, QWidget *> mIconListToPageStack;
+ QMap<QString, QPixmap> mFolderIconMap;
+ QMap<QString, QStringList> mChildrenNames;
+ QMap<QString, QWidget *> mChildPages;
+
+ public:
+ class IconListItem;
+
+ private:
+ class OJanusWidgetPrivate;
+ OJanusWidgetPrivate *d;
+};
+
+#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 @@
+/*
+ This file Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
+ is part of the Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@kde.org>, Dawit Alemayehu <adawit@kde.org>
+ Opie Project Copyright (C) 1999 Preston Brown <pbrown@kde.org>, Patrick Ward <PAT_WARD@HP-USA-om5.om.hp.com>
+ Copyright (C) 1997 Sven Radej (sven.radej@iname.com)
+ =.
+ .=l. Originally part of the KDE Project
+           .>+-=
+ _;:,     .>    :=|. This program is free software; you can
+.> <`_,   >  .   <= redistribute it and/or modify it under
+:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
+.="- .-=="i,     .._ License as published by the Free Software
+ - .   .-<_>     .<> Foundation; either version 2 of the License,
+     ._= =}       : or (at your option) any later version.
+    .%`+i>       _;_.
+    .i_,=:_.      -<s. This program is distributed in the hope that
+     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
+    : ..    .:,     . . . without even the implied warranty of
+    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
+  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
+..}^=.=       =       ; Library General Public License for more
+++=   -.     .`     .: details.
+ :     =  ...= . :.=-
+ -.   .:....=;==+<; You should have received a copy of the GNU
+  -_. . .   )=.  = Library General Public License along with
+    --        :-=` this library; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+*/
+
+/* QT */
+
+#include <qapplication.h>
+#include <qclipboard.h>
+#include <qtimer.h>
+#include <qpopupmenu.h>
+
+/* OPIE */
+
+#include <opie2/ocompletionbox.h>
+#include <opie2/olineedit.h>
+#include <opie2/oglobalsettings.h>
+
+typedef QString KURL; //FIXME: Revise for Opie
+
+/*======================================================================================
+ * OLineEditPrivate
+ *======================================================================================*/
+
+class OLineEdit::OLineEditPrivate
+{
+public:
+ OLineEditPrivate()
+ {
+ grabReturnKeyEvents = false;
+ handleURLDrops = true;
+ completionBox = 0L;
+ }
+ ~OLineEditPrivate()
+ {
+ delete completionBox;
+ }
+
+ bool grabReturnKeyEvents;
+ bool handleURLDrops;
+ OCompletionBox *completionBox;
+};
+
+
+/*======================================================================================
+ * OLineEdit
+ *======================================================================================*/
+
+OLineEdit::OLineEdit( const QString &string, QWidget *parent, const char *name )
+ : QLineEdit( string, parent, name )
+{
+ init();
+}
+
+OLineEdit::OLineEdit( QWidget *parent, const char *name )
+ : QLineEdit( parent, name )
+{
+ init();
+}
+
+OLineEdit::~OLineEdit ()
+{
+ delete d;
+}
+
+void OLineEdit::init()
+{
+ d = new OLineEditPrivate;
+ possibleTripleClick = false;
+ // Enable the context menu by default.
+ setContextMenuEnabled( true );
+ //OCursor::setAutoHideCursor( this, true, true );
+ installEventFilter( this );
+}
+
+void OLineEdit::setCompletionMode( OGlobalSettings::Completion mode )
+{
+ OGlobalSettings::Completion oldMode = completionMode();
+ if ( oldMode != mode && oldMode == OGlobalSettings::CompletionPopup &&
+ d->completionBox && d->completionBox->isVisible() )
+ d->completionBox->hide();
+
+ // If the widgets echo mode is not Normal, no completion
+ // feature will be enabled even if one is requested.
+ if ( echoMode() != QLineEdit::Normal )
+ mode = OGlobalSettings::CompletionNone; // Override the request.
+
+ OCompletionBase::setCompletionMode( mode );
+}
+
+void OLineEdit::setCompletedText( const QString& t, bool marked )
+{
+ QString txt = text();
+ if ( t != txt )
+ {
+ int curpos = marked ? txt.length() : t.length();
+ validateAndSet( t, curpos, curpos, t.length() );
+ }
+}
+
+void OLineEdit::setCompletedText( const QString& text )
+{
+ OGlobalSettings::Completion mode = completionMode();
+ bool marked = ( mode == OGlobalSettings::CompletionAuto ||
+ mode == OGlobalSettings::CompletionMan ||
+ mode == OGlobalSettings::CompletionPopup );
+ setCompletedText( text, marked );
+}
+
+void OLineEdit::rotateText( OCompletionBase::KeyBindingType type )
+{
+ OCompletion* comp = compObj();
+ if ( comp &&
+ (type == OCompletionBase::PrevCompletionMatch ||
+ type == OCompletionBase::NextCompletionMatch ) )
+ {
+ QString input = (type == OCompletionBase::PrevCompletionMatch) ? comp->previousMatch() : comp->nextMatch();
+ // Skip rotation if previous/next match is null or the same text
+ if ( input.isNull() || input == displayText() )
+ return;
+ #if QT_VERSION > 290
+ setCompletedText( input, hasSelectedText() );
+ #else
+ setCompletedText( input, hasMarkedText() );
+ #endif
+ }
+}
+
+void OLineEdit::makeCompletion( const QString& text )
+{
+ OCompletion *comp = compObj();
+ if ( !comp )
+ return; // No completion object...
+
+ QString match = comp->makeCompletion( text );
+ OGlobalSettings::Completion mode = completionMode();
+ if ( mode == OGlobalSettings::CompletionPopup )
+ {
+ if ( match.isNull() )
+ {
+ if ( d->completionBox ) {
+ d->completionBox->hide();
+ d->completionBox->clear();
+ }
+ }
+ else
+ setCompletedItems( comp->allMatches() );
+ }
+ else
+ {
+ // all other completion modes
+ // If no match or the same match, simply return without completing.
+ if ( match.isNull() || match == text )
+ return;
+
+ setCompletedText( match );
+ }
+}
+
+void OLineEdit::setReadOnly(bool readOnly)
+{
+ QPalette p = palette();
+ if (readOnly)
+ {
+ QColor color = p.color(QPalette::Disabled, QColorGroup::Background);
+ p.setColor(QColorGroup::Base, color);
+ p.setColor(QColorGroup::Background, color);
+ }
+ else
+ {
+ QColor color = p.color(QPalette::Normal, QColorGroup::Base);
+ p.setColor(QColorGroup::Base, color);
+ p.setColor(QColorGroup::Background, color);
+ }
+ setPalette(p);
+
+ QLineEdit::setReadOnly (readOnly);
+}
+
+void OLineEdit::keyPressEvent( QKeyEvent *e )
+{
+ qDebug( "OLineEdit::keyPressEvent()" );
+
+ /*
+
+ KKey key( e );
+
+ if ( KStdAccel::copy().contains( key ) ) {
+ copy();
+ return;
+ }
+ else if ( KStdAccel::paste().contains( key ) ) {
+ paste();
+ return;
+ }
+ else if ( KStdAccel::cut().contains( key ) ) {
+ cut();
+ return;
+ }
+ else if ( KStdAccel::undo().contains( key ) ) {
+ undo();
+ return;
+ }
+ else if ( KStdAccel::redo().contains( key ) ) {
+ redo();
+ return;
+ }
+ else if ( KStdAccel::deleteWordBack().contains( key ) )
+ {
+ cursorWordBackward(TRUE);
+ if ( hasSelectedText() )
+ del();
+
+ e->accept();
+ return;
+ }
+ else if ( KStdAccel::deleteWordForward().contains( key ) )
+ {
+ // Workaround for QT bug where
+ cursorWordForward(TRUE);
+ if ( hasSelectedText() )
+ del();
+
+ e->accept();
+ return;
+ }
+ */
+
+ // Filter key-events if EchoMode is normal &
+ // completion mode is not set to CompletionNone
+ if ( echoMode() == QLineEdit::Normal &&
+ completionMode() != OGlobalSettings::CompletionNone )
+ {
+ KeyBindingMap keys = getKeyBindings();
+ OGlobalSettings::Completion mode = completionMode();
+ bool noModifier = (e->state() == NoButton || e->state()== ShiftButton);
+
+ if ( (mode == OGlobalSettings::CompletionAuto ||
+ mode == OGlobalSettings::CompletionMan) && noModifier )
+ {
+ QString keycode = e->text();
+ if ( !keycode.isNull() && keycode.unicode()->isPrint() )
+ {
+ QLineEdit::keyPressEvent ( e );
+ QString txt = text();
+ int len = txt.length();
+ #if QT_VERSION > 290
+ if ( !hasSelectedText() && len && cursorPosition() == len )
+ #else
+ if ( !hasMarkedText() && len && cursorPosition() == len )
+ #endif
+ {
+ if ( emitSignals() )
+ emit completion( txt );
+ if ( handleSignals() )
+ makeCompletion( txt );
+ e->accept();
+ }
+ return;
+ }
+ }
+
+ else if ( mode == OGlobalSettings::CompletionPopup && noModifier )
+ {
+ qDebug( "OLineEdit::keyPressEvent() - global settings = CompletionPopup & noModifier" );
+
+ QString old_txt = text();
+ QLineEdit::keyPressEvent ( e );
+ QString txt = text();
+ int len = txt.length();
+ QString keycode = e->text();
+
+
+ if ( txt != old_txt && len && cursorPosition() == len &&
+ ( (!keycode.isNull() && keycode.unicode()->isPrint()) ||
+ e->key() == Key_Backspace ) )
+ {
+ if ( emitSignals() )
+ emit completion( txt ); // emit when requested...
+ if ( handleSignals() )
+ makeCompletion( txt ); // handle when requested...
+ e->accept();
+ }
+ else if (!len && d->completionBox && d->completionBox->isVisible())
+ d->completionBox->hide();
+
+ return;
+ }
+
+ /*else if ( mode == OGlobalSettings::CompletionShell )
+ {
+ // Handles completion.
+ KShortcut cut;
+ if ( keys[TextCompletion].isNull() )
+ cut = KStdAccel::shortcut(KStdAccel::TextCompletion);
+ else
+ cut = keys[TextCompletion];
+
+ if ( cut.contains( key ) )
+ {
+ // Emit completion if the completion mode is CompletionShell
+ // and the cursor is at the end of the string.
+ QString txt = text();
+ int len = txt.length();
+ if ( cursorPosition() == len && len != 0 )
+ {
+ if ( emitSignals() )
+ emit completion( txt );
+ if ( handleSignals() )
+ makeCompletion( txt );
+ return;
+ }
+ }
+ else if ( d->completionBox )
+ d->completionBox->hide();
+ }
+
+ // handle rotation
+ if ( mode != OGlobalSettings::CompletionNone )
+ {
+ // Handles previous match
+ KShortcut cut;
+ if ( keys[PrevCompletionMatch].isNull() )
+ cut = KStdAccel::shortcut(KStdAccel::PrevCompletion);
+ else
+ cut = keys[PrevCompletionMatch];
+
+ if ( cut.contains( key ) )
+ {
+ if ( emitSignals() )
+ emit textRotation( OCompletionBase::PrevCompletionMatch );
+ if ( handleSignals() )
+ rotateText( OCompletionBase::PrevCompletionMatch );
+ return;
+ }
+
+ // Handles next match
+ if ( keys[NextCompletionMatch].isNull() )
+ cut = KStdAccel::key(KStdAccel::NextCompletion);
+ else
+ cut = keys[NextCompletionMatch];
+
+ if ( cut.contains( key ) )
+ {
+ if ( emitSignals() )
+ emit textRotation( OCompletionBase::NextCompletionMatch );
+ if ( handleSignals() )
+ rotateText( OCompletionBase::NextCompletionMatch );
+ return;
+ }
+ }
+
+ // substring completion
+ if ( compObj() )
+ {
+ KShortcut cut;
+ if ( keys[SubstringCompletion].isNull() )
+ cut = KStdAccel::shortcut(KStdAccel::SubstringCompletion);
+ else
+ cut = keys[SubstringCompletion];
+
+ if ( cut.contains( key ) )
+ {
+ if ( emitSignals() )
+ emit substringCompletion( text() );
+ if ( handleSignals() )
+ {
+ setCompletedItems( compObj()->substringCompletion(text()));
+ e->accept();
+ }
+ return;
+ }
+ } */
+ }
+
+ // Let QLineEdit handle any other keys events.
+ QLineEdit::keyPressEvent ( e );
+}
+
+void OLineEdit::mouseDoubleClickEvent( QMouseEvent* e )
+{
+ if ( e->button() == Qt::LeftButton )
+ {
+ possibleTripleClick=true;
+ QTimer::singleShot( QApplication::doubleClickInterval(),this,
+ SLOT(tripleClickTimeout()) );
+ }
+ QLineEdit::mouseDoubleClickEvent( e );
+}
+
+void OLineEdit::mousePressEvent( QMouseEvent* e )
+{
+ if ( possibleTripleClick && e->button() == Qt::LeftButton )
+ {
+ selectAll();
+ return;
+ }
+ QLineEdit::mousePressEvent( e );
+}
+
+void OLineEdit::tripleClickTimeout()
+{
+ possibleTripleClick=false;
+}
+
+QPopupMenu *OLineEdit::createPopupMenu()
+{
+ // Return if popup menu is not enabled !!
+ if ( !m_bEnableMenu )
+ return 0;
+
+ #if QT_VERSION > 290
+ QPopupMenu *popup = QLineEdit::createPopupMenu();
+ #else
+ QPopupMenu *popup = new QPopupMenu();
+ #warning OLineEdit is not fully functional on Qt2
+ #endif
+
+ // completion object is present.
+ if ( compObj() )
+ {
+ QPopupMenu *subMenu = new QPopupMenu( popup );
+ connect( subMenu, SIGNAL( activated( int ) ),
+ this, SLOT( completionMenuActivated( int ) ) );
+
+ popup->insertSeparator();
+ //popup->insertItem( SmallIconSet("completion"), i18n("Text Completion"),
+ // subMenu );
+
+ popup->insertItem( tr("Text Completion"), subMenu );
+
+ subMenu->insertItem( tr("None"), NoCompletion );
+ subMenu->insertItem( tr("Manual"), ShellCompletion );
+ subMenu->insertItem( tr("Automatic"), AutoCompletion );
+ subMenu->insertItem( tr("Dropdown List"), PopupCompletion );
+ subMenu->insertItem( tr("Short Automatic"), SemiAutoCompletion );
+
+ //subMenu->setAccel( KStdAccel::completion(), ShellCompletion );
+ subMenu->setAccel( Key_Tab, ShellCompletion );
+
+ OGlobalSettings::Completion mode = completionMode();
+ subMenu->setItemChecked( NoCompletion,
+ mode == OGlobalSettings::CompletionNone );
+ subMenu->setItemChecked( ShellCompletion,
+ mode == OGlobalSettings::CompletionShell );
+ subMenu->setItemChecked( PopupCompletion,
+ mode == OGlobalSettings::CompletionPopup );
+ subMenu->setItemChecked( AutoCompletion,
+ mode == OGlobalSettings::CompletionAuto );
+ subMenu->setItemChecked( SemiAutoCompletion,
+ mode == OGlobalSettings::CompletionMan );
+ if ( mode != OGlobalSettings::completionMode() )
+ {
+ subMenu->insertSeparator();
+ subMenu->insertItem( tr("Default"), Default );
+ }
+ }
+ // ### do we really need this? Yes, Please do not remove! This
+ // allows applications to extend the popup menu without having to
+ // inherit from this class! (DA)
+ emit aboutToShowContextMenu( popup );
+
+ return popup;
+}
+
+void OLineEdit::completionMenuActivated( int id )
+{
+ OGlobalSettings::Completion oldMode = completionMode();
+
+ switch ( id )
+ {
+ case Default:
+ setCompletionMode( OGlobalSettings::completionMode() ); break;
+ case NoCompletion:
+ setCompletionMode( OGlobalSettings::CompletionNone ); break;
+ case AutoCompletion:
+ setCompletionMode( OGlobalSettings::CompletionAuto ); break;
+ case SemiAutoCompletion:
+ setCompletionMode( OGlobalSettings::CompletionMan ); break;
+ case ShellCompletion:
+ setCompletionMode( OGlobalSettings::CompletionShell ); break;
+ case PopupCompletion:
+ setCompletionMode( OGlobalSettings::CompletionPopup ); break;
+ default: return;
+ }
+
+ if ( oldMode != completionMode() )
+ {
+ if ( oldMode == OGlobalSettings::CompletionPopup &&
+ d->completionBox && d->completionBox->isVisible() )
+ d->completionBox->hide();
+ emit completionModeChanged( completionMode() );
+ }
+}
+
+/*void OLineEdit::dropEvent(QDropEvent *e)
+{
+ KURL::List urlList;
+ if( d->handleURLDrops && KURLDrag::decode( e, urlList ) )
+ {
+ QString dropText = text();
+ KURL::List::ConstIterator it;
+ for( it = urlList.begin() ; it != urlList.end() ; ++it )
+ {
+ if(!dropText.isEmpty())
+ dropText+=' ';
+
+ dropText += (*it).prettyURL();
+ }
+
+ validateAndSet( dropText, dropText.length(), 0, 0);
+
+ e->accept();
+ }
+ else
+ QLineEdit::dropEvent(e);
+}*/
+
+bool OLineEdit::eventFilter( QObject* o, QEvent* ev )
+{
+ if( o == this )
+ {
+ //OCursor::autoHideEventFilter( this, ev );
+ if ( ev->type() == QEvent::AccelOverride )
+ {
+ QKeyEvent *e = static_cast<QKeyEvent *>( ev );
+ // if (overrideAccel (e))
+ // {
+ // e->accept();
+ // return true;
+ // }
+ }
+ else if( ev->type() == QEvent::KeyPress )
+ {
+ QKeyEvent *e = static_cast<QKeyEvent *>( ev );
+
+ if( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter )
+ {
+ bool trap = d->completionBox && d->completionBox->isVisible();
+
+ // Qt will emit returnPressed() itself if we return false
+ if ( d->grabReturnKeyEvents || trap )
+ emit QLineEdit::returnPressed();
+
+ emit returnPressed( displayText() );
+
+ if ( trap )
+ d->completionBox->hide();
+
+ // Eat the event if the user asked for it, or if a completionbox was visible
+ return d->grabReturnKeyEvents || trap;
+ }
+ }
+ }
+ return QLineEdit::eventFilter( o, ev );
+}
+
+
+void OLineEdit::setURLDropsEnabled(bool enable)
+{
+ d->handleURLDrops=enable;
+}
+
+bool OLineEdit::isURLDropsEnabled() const
+{
+ return d->handleURLDrops;
+}
+
+void OLineEdit::setTrapReturnKey( bool grab )
+{
+ d->grabReturnKeyEvents = grab;
+}
+
+bool OLineEdit::trapReturnKey() const
+{
+ return d->grabReturnKeyEvents;
+}
+
+/*void OLineEdit::setURL( const KURL& url )
+{
+ QLineEdit::setText( url.prettyURL() );
+}*/
+
+void OLineEdit::makeCompletionBox()
+{
+ if ( d->completionBox )
+ return;
+
+ d->completionBox = new OCompletionBox( this, "completion box" );
+ if ( handleSignals() )
+ {
+ connect( d->completionBox, SIGNAL(highlighted( const QString& )),
+ SLOT(setText( const QString& )) );
+ connect( d->completionBox, SIGNAL(userCancelled( const QString& )),
+ SLOT(setText( const QString& )) );
+
+ // Nice lil' hacklet ;) KComboBox doesn't know when the completionbox
+ // is created (childEvent() is even more hacky, IMHO), so we simply
+ // forward the completionbox' activated signal from here.
+ if ( parentWidget() && parentWidget()->inherits("KComboBox") )
+ connect( d->completionBox, SIGNAL( activated( const QString& )),
+ parentWidget(), SIGNAL( activated( const QString & )));
+ }
+}
+
+/*bool OLineEdit::overrideAccel (const QKeyEvent* e)
+{
+ KShortcut scKey;
+
+ KKey key( e );
+ KeyBindingMap keys = getKeyBindings();
+
+ if (keys[TextCompletion].isNull())
+ scKey = KStdAccel::shortcut(KStdAccel::TextCompletion);
+ else
+ scKey = keys[TextCompletion];
+
+ if (scKey.contains( key ))
+ return true;
+
+ if (keys[NextCompletionMatch].isNull())
+ scKey = KStdAccel::shortcut(KStdAccel::NextCompletion);
+ else
+ scKey = keys[NextCompletionMatch];
+
+ if (scKey.contains( key ))
+ return true;
+
+ if (keys[PrevCompletionMatch].isNull())
+ scKey = KStdAccel::shortcut(KStdAccel::PrevCompletion);
+ else
+ scKey = keys[PrevCompletionMatch];
+
+ if (scKey.contains( key ))
+ return true;
+
+ if (KStdAccel::deleteWordBack().contains( key ))
+ return true;
+ if (KStdAccel::deleteWordForward().contains( key ))
+ return true;
+
+ if (d->completionBox && d->completionBox->isVisible ())
+ if (e->key () == Key_Backtab)
+ return true;
+
+ return false;
+}*/
+
+void OLineEdit::setCompletedItems( const QStringList& items )
+{
+ QString txt = text();
+ if ( !items.isEmpty() &&
+ !(items.count() == 1 && txt == items.first()) )
+ {
+ if ( !d->completionBox )
+ makeCompletionBox();
+
+ if ( !txt.isEmpty() )
+ d->completionBox->setCancelledText( txt );
+ d->completionBox->setItems( items );
+ d->completionBox->popup();
+ }
+ else
+ {
+ if ( d->completionBox && d->completionBox->isVisible() )
+ d->completionBox->hide();
+ }
+}
+
+OCompletionBox * OLineEdit::completionBox( bool create )
+{
+ if ( create )
+ makeCompletionBox();
+
+ return d->completionBox;
+}
+
+void OLineEdit::setCompletionObject( OCompletion* comp, bool hsig )
+{
+ OCompletion *oldComp = compObj();
+ if ( oldComp && handleSignals() )
+ disconnect( oldComp, SIGNAL( matches( const QStringList& )),
+ this, SLOT( setCompletedItems( const QStringList& )));
+
+ if ( comp && hsig )
+ connect( comp, SIGNAL( matches( const QStringList& )),
+ this, SLOT( setCompletedItems( const QStringList& )));
+
+ OCompletionBase::setCompletionObject( comp, hsig );
+}
+
+// QWidget::create() turns off mouse-Tracking which would break auto-hiding
+void OLineEdit::create( WId id, bool initializeWindow, bool destroyOldWindow )
+{
+ QLineEdit::create( id, initializeWindow, destroyOldWindow );
+ //OCursor::setAutoHideCursor( this, true, true );
+}
+
+void OLineEdit::clear()
+{
+ setText( QString::null );
+}
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 @@
+/*
+ This file Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
+ is part of the Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@kde.org>, Dawit Alemayehu <adawit@kde.org>
+ Opie Project Copyright (C) 1999 Preston Brown <pbrown@kde.org>, Patrick Ward <PAT_WARD@HP-USA-om5.om.hp.com>
+ Copyright (C) 1997 Sven Radej (sven.radej@iname.com)
+ =.
+ .=l.
+           .>+-=
+ _;:,     .>    :=|. This program is free software; you can
+.> <`_,   >  .   <= redistribute it and/or modify it under
+:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
+.="- .-=="i,     .._ License as published by the Free Software
+ - .   .-<_>     .<> Foundation; either version 2 of the License,
+     ._= =}       : or (at your option) any later version.
+    .%`+i>       _;_.
+    .i_,=:_.      -<s. This program is distributed in the hope that
+     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
+    : ..    .:,     . . . without even the implied warranty of
+    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
+  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
+..}^=.=       =       ; Library General Public License for more
+++=   -.     .`     .: details.
+ :     =  ...= . :.=-
+ -.   .:....=;==+<; You should have received a copy of the GNU
+  -_. . .   )=.  = Library General Public License along with
+    --        :-=` this library; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef OLINEEDIT_H
+#define OLINEEDIT_H
+
+/* QT */
+
+#include <qlineedit.h>
+
+/* OPIE */
+
+#include <opie2/ocompletion.h>
+#include <opie2/ocompletionbase.h>
+
+class QPopupMenu;
+
+class OCompletionBox;
+typedef QString KURL; //class KURL;
+
+/**
+ * An enhanced QLineEdit widget for inputting text.
+ *
+ * @sect Detail
+ *
+ * This widget inherits from @ref QLineEdit and implements the following
+ * additional functionalities: q completion object that provides both
+ * automatic and manual text completion as well as multiple match iteration
+ * features, configurable key-bindings to activate these features and a
+ * popup-menu item that can be used to allow the user to set text completion
+ * modes on the fly based on their preference.
+ *
+ * To support these new features OLineEdit also emits a few more
+ * additional signals. These are: @ref completion( const QString& ),
+ * textRotation( KeyBindingType ), and @ref returnPressed( const QString& ).
+ * The completion signal can be connected to a slot that will assist the
+ * user in filling out the remaining text. The text rotation signal is
+ * intended to be used to iterate through the list of all possible matches
+ * whenever there is more than one match for the entered text. The
+ * @p returnPressed( const QString& ) signals are the same as QLineEdit's
+ * except it provides the current text in the widget as its argument whenever
+ * appropriate.
+ *
+ * This widget by default creates a completion object when you invoke
+ * the @ref completionObject( bool ) member function for the first time or
+ * use @ref setCompletionObject( OCompletion*, bool ) to assign your own
+ * completion object. Additionally, to make this widget more functional,
+ * OLineEdit will by default handle the text rotation and completion
+ * events internally when a completion object is created through either one
+ * of the methods mentioned above. If you do not need this functionality,
+ * simply use @ref OCompletionBase::setHandleSignals( bool ) or set the
+ * boolean parameter in the above functions to FALSE.
+ *
+ * The default key-bindings for completion and rotation is determined
+ * from the global settings in @ref OStdAccel. These values, however,
+ * can be overriden locally by invoking @ref OCompletionBase::setKeyBinding().
+ * The values can easily be reverted back to the default setting, by simply
+ * calling @ref useGlobalSettings(). An alternate method would be to default
+ * individual key-bindings by usning @ref setKeyBinding() with the default
+ * second argument.
+ *
+ * NOTE that if the @p EchoMode for this widget is set to something other
+ * than @p QLineEdit::Normal, the completion mode will always be defaulted
+ * to @ref PGlobalSettings::CompletionNone. This is done purposefully to guard
+ * against protected entries such as passwords being cached in @ref OCompletion's
+ * list. Hence, if the @p EchoMode is not @ref QLineEdit::Normal, the completion
+ * mode is automatically disabled.
+ *
+ * @sect Useage
+ *
+ * To enable the basic completion feature :
+ *
+ * <pre>
+ * OLineEdit *edit = new OLineEdit( this, "mywidget" );
+ * OCompletion *comp = edit->completionObject();
+ * // Fill the completion object with a list of possible matches
+ * QStringList list;
+ * list << "mickeyl@handhelds.org" << "mickey@tm.informatik.uni-frankfurt.de>" << "mickey@Vanille.de";
+ * comp->setItems( list );
+ * // Connect to the return pressed signal (optional)
+ * connect(edit,SIGNAL(returnPressed(const QString&)),comp,SLOT(addItem(const QString&));
+ * </pre>
+ *
+ * To use a customized completion objects or your
+ * own completion object :
+ *
+ * <pre>
+ * OLineEdit *edit = new OLineEdit( this,"mywidget" );
+ * KURLCompletion *comp = new KURLCompletion();
+ * edit->setCompletionObject( comp );
+ * // Connect to the return pressed signal - optional
+ * connect(edit,SIGNAL(returnPressed(const QString&)),comp,SLOT(addItem(const QString&));
+ * </pre>
+ *
+ * Note that you have to either delete the allocated completion object
+ * when you don't need it anymore, or call
+ * setAutoDeleteCompletionObject( true );
+ *
+ * @sect Miscellaneous function calls :
+ *
+ * <pre>
+ * // Tell the widget not to handle completion and
+ * // iteration internally.
+ * edit->setHandleSignals( false );
+ * // Set your own completion key for manual completions.
+ * edit->setKeyBinding( OCompletionBase::TextCompletion, Qt::End );
+ * // Hide the context (popup) menu
+ * edit->setContextMenuEnabled( false );
+ * // Temporarly disable signal emitions
+ * // (both completion & iteration signals)
+ * edit->disableSignals();
+ * // Default the key-bindings to system settings.
+ * edit->useGlobalKeyBindings();
+ * </pre>
+ *
+ * @short An enhanced single line input widget.
+ * @author Dawit Alemayehu <adawit@kde.org>
+ * @author Opie adaption by Michael Lauer <mickey@tm.informatik.uni-frankfurt.de>
+ */
+
+class OLineEdit : public QLineEdit, public OCompletionBase
+{
+ friend class OComboBox;
+
+ Q_OBJECT
+ Q_PROPERTY( bool contextMenuEnabled READ isContextMenuEnabled WRITE setContextMenuEnabled )
+ Q_PROPERTY( bool urlDropsEnabled READ isURLDropsEnabled WRITE setURLDropsEnabled )
+
+public:
+
+ /**
+ * Constructs a OLineEdit object with a default text, a parent,
+ * and a name.
+ *
+ * @param string Text to be shown in the edit widget.
+ * @param parent The parent object of this widget.
+ * @param name the name of this widget
+ */
+ OLineEdit( const QString &string, QWidget *parent, const char *name = 0 );
+
+ /**
+ * Constructs a OLineEdit object with a parent and a name.
+ *
+ * @param string Text to be shown in the edit widget.
+ * @param parent The parent object of this widget.
+ * @param name The name of this widget.
+ */
+ OLineEdit ( QWidget *parent=0, const char *name=0 );
+
+ /**
+ * Destructor.
+ */
+ virtual ~OLineEdit ();
+
+ /**
+ * Sets @p url into the lineedit. It uses @ref KURL::prettyURL() so
+ * that the url is properly decoded for displaying.
+ */
+ void setURL( const KURL& url );
+
+ /**
+ * Puts the text cursor at the end of the string.
+ *
+ * This method is deprecated. Use @ref QLineEdit::end()
+ * instead.
+ *
+ * @deprecated
+ * @ref QLineEdit::end()
+ */
+ void cursorAtEnd() { end( false ); }
+
+ /**
+ * Re-implemented from @ref OCompletionBase for internal reasons.
+ *
+ * This function is re-implemented in order to make sure that
+ * the EchoMode is acceptable before we set the completion mode.
+ *
+ * See @ref OCompletionBase::setCompletionMode
+ */
+ virtual void setCompletionMode( OGlobalSettings::Completion mode );
+
+ /**
+ * Enables/disables the popup (context) menu.
+ *
+ * Note that when this function is invoked with its argument
+ * set to @p true, then both the context menu and the completion
+ * menu item are enabled. If you do not want to the completion
+ * item to be visible simply invoke @ref hideModechanger() right
+ * after calling this method. Also by default, the context
+ * menu is automatically created if this widget is editable. Thus
+ * you need to call this function with the argument set to false
+ * if you do not want this behaviour.
+ *
+ * @param showMenu If @p true, show the context menu.
+ */
+ virtual void setContextMenuEnabled( bool showMenu ) { m_bEnableMenu = showMenu; }
+
+ /**
+ * Returns @p true when the context menu is enabled.
+ */
+ bool isContextMenuEnabled() const { return m_bEnableMenu; }
+
+ /**
+ * Enables/Disables handling of URL drops. If enabled and the user
+ * drops an URL, the decoded URL will be inserted. Otherwise the default
+ * behaviour of QLineEdit is used, which inserts the encoded URL.
+ *
+ * @param enable If @p true, insert decoded URLs
+ */
+ void setURLDropsEnabled( bool enable );
+
+ /**
+ * Returns @p true when decoded URL drops are enabled
+ */
+ bool isURLDropsEnabled() const;
+
+ /**
+ * By default, OLineEdit recognizes @p Key_Return and @p Key_Enter and emits
+ * the @ref returnPressed() signals, but it also lets the event pass,
+ * for example causing a dialog's default-button to be called.
+ *
+ * Call this method with @p trap = @p true to make @p OLineEdit stop these
+ * events. The signals will still be emitted of course.
+ *
+ * @see trapReturnKey()
+ */
+ void setTrapReturnKey( bool trap );
+
+ /**
+ * @returns @p true if keyevents of @p Key_Return or
+ * @p Key_Enter will be stopped or if they will be propagated.
+ *
+ * @see setTrapReturnKey ()
+ */
+ bool trapReturnKey() const;
+
+ /**
+ * Re-implemented for internal reasons. API not affected.
+ *
+ * @reimplemented
+ */
+ virtual bool eventFilter( QObject *, QEvent * );
+
+ /**
+ * @returns the completion-box, that is used in completion mode
+ * @ref KGlobalSettings::CompletionPopup.
+ * This method will create a completion-box if none is there, yet.
+ *
+ * @param create Set this to false if you don't want the box to be created
+ * i.e. to test if it is available.
+ */
+ OCompletionBox * completionBox( bool create = true );
+
+ /**
+ * Reimplemented for internal reasons, the API is not affected.
+ */
+ virtual void setCompletionObject( OCompletion *, bool hsig = true );
+
+
+signals:
+
+ /**
+ * Emitted when the user presses the return key.
+ *
+ * The argument is the current text. Note that this
+ * signal is @em not emitted if the widget's @p EchoMode is set to
+ * @ref QLineEdit::EchoMode.
+ */
+ void returnPressed( const QString& );
+
+ /**
+ * Emitted when the completion key is pressed.
+ *
+ * Please note that this signal is @em not emitted if the
+ * completion mode is set to @p CompletionNone or @p EchoMode is
+ * @em normal.
+ */
+ void completion( const QString& );
+
+ /**
+ * Emitted when the shortcut for substring completion is pressed.
+ */
+ void substringCompletion( const QString& );
+
+ /**
+ * Emitted when the text rotation key-bindings are pressed.
+ *
+ * The argument indicates which key-binding was pressed.
+ * In OLineEdit's case this can be either one of two values:
+ * @ref PrevCompletionMatch or @ref NextCompletionMatch. See
+ * @ref OCompletionBase::setKeyBinding for details.
+ *
+ * Note that this signal is @em not emitted if the completion
+ * mode is set to @p KGlobalSettings::CompletionNone or @p echoMode() is @em not normal.
+ */
+ void textRotation( OCompletionBase::KeyBindingType );
+
+ /**
+ * Emitted when the user changed the completion mode by using the
+ * popupmenu.
+ */
+ void completionModeChanged( OGlobalSettings::Completion );
+
+ /**
+ * Emitted before the context menu is displayed.
+ *
+ * The signal allows you to add your own entries into the
+ * the context menu that is created on demand.
+ *
+ * NOTE: Do not store the pointer to the QPopupMenu
+ * provided through since it is created and deleted
+ * on demand.
+ *
+ * @param the context menu about to be displayed
+ */
+ void aboutToShowContextMenu( QPopupMenu* );
+
+public slots:
+
+ /**
+ * Re-implemented for internal reasons. API not changed.
+ */
+ virtual void setReadOnly(bool);
+
+ /**
+ * Iterates through all possible matches of the completed text or
+ * the history list.
+ *
+ * This function simply iterates over all possible matches in case
+ * multimple matches are found as a result of a text completion request.
+ * It will have no effect if only a single match is found.
+ *
+ * @param type The key-binding invoked.
+ */
+ void rotateText( OCompletionBase::KeyBindingType /* type */ );
+
+ /**
+ * See @ref OCompletionBase::setCompletedText.
+ */
+ virtual void setCompletedText( const QString& );
+
+ /**
+ * Sets @p items into the completion-box if @ref completionMode() is
+ * CompletionPopup. The popup will be shown immediately.
+ */
+ void setCompletedItems( const QStringList& items );
+
+ /**
+ * Reimplemented to workaround a buggy QLineEdit::clear()
+ * (changing the clipboard to the text we just had in the lineedit)
+ */
+ virtual void clear();
+
+protected slots:
+
+ /**
+ * Completes the remaining text with a matching one from
+ * a given list.
+ */
+ virtual void makeCompletion( const QString& );
+
+ /**
+ * @deprecated. Will be removed in the next major release!
+ */
+ void slotAboutToShow() {}
+
+ /**
+ * @deprecated. Will be removed in the next major release!
+ */
+ void slotCancelled() {}
+
+protected:
+
+ /**
+ * Re-implemented for internal reasons. API not affected.
+ *
+ * See @ref QLineEdit::keyPressEvent().
+ */
+ virtual void keyPressEvent( QKeyEvent * );
+
+ /**
+ * Re-implemented for internal reasons. API not affected.
+ *
+ * See @ref QLineEdit::mousePressEvent().
+ */
+ virtual void mousePressEvent( QMouseEvent * );
+
+ /**
+ * Re-implemented for internal reasons. API not affected.
+ *
+ * See @ref QWidget::mouseDoubleClickEvent().
+ */
+ virtual void mouseDoubleClickEvent( QMouseEvent * );
+
+ /**
+ * Re-implemented for internal reasons. API not affected.
+ *
+ * See @ref QLineEdit::createPopupMenu().
+ */
+ virtual QPopupMenu *createPopupMenu();
+
+ /**
+ * Re-implemented to handle URI drops.
+ *
+ * See @ref QLineEdit::dropEvent().
+ */
+ //virtual void dropEvent( QDropEvent * );
+
+ /*
+ * This function simply sets the lineedit text and
+ * highlights the text appropriately if the boolean
+ * value is set to true.
+ *
+ * @param text
+ * @param marked
+ */
+ virtual void setCompletedText( const QString& /*text*/, bool /*marked*/ );
+
+ /**
+ * Reimplemented for internal reasons, the API is not affected.
+ */
+ virtual void create( WId = 0, bool initializeWindow = true,
+ bool destroyOldWindow = true );
+
+private slots:
+ void completionMenuActivated( int id );
+ void tripleClickTimeout(); // resets possibleTripleClick
+
+private:
+ // Constants that represent the ID's of the popup menu.
+ // TODO: See if we can replace this mess with KActionMenu
+ // in the future though it's working lovely.
+ enum MenuID {
+ Default = 42,
+ NoCompletion,
+ AutoCompletion,
+ ShellCompletion,
+ PopupCompletion,
+ SemiAutoCompletion
+ };
+
+ /**
+ * Initializes variables. Called from the constructors.
+ */
+ void init();
+
+ /**
+ * Creates the completion box
+ */
+ void makeCompletionBox();
+
+ /**
+ * Checks whether we should/should not consume a key used as
+ * an accelerator.
+ */
+ //bool overrideAccel (const QKeyEvent* e);
+
+ bool m_bEnableMenu;
+
+ bool possibleTripleClick; // set in mousePressEvent, deleted in tripleClickTimeout
+
+protected:
+ //virtual void virtual_hook( int id, void* data );
+private:
+ class OLineEditPrivate;
+ OLineEditPrivate *d;
+};
+
+#endif