author | mickeyl <mickeyl> | 2003-03-28 15:11:52 (UTC) |
---|---|---|
committer | mickeyl <mickeyl> | 2003-03-28 15:11:52 (UTC) |
commit | 11304d02942e9fa493e4e80943a828f9c65f6772 (patch) (side-by-side diff) | |
tree | a0223c10c067e1afc70d15c2b82be3f3c15e41ae | |
parent | b271d575fa05cf570a1a829136517761bd47e69b (diff) | |
download | opie-11304d02942e9fa493e4e80943a828f9c65f6772.zip opie-11304d02942e9fa493e4e80943a828f9c65f6772.tar.gz opie-11304d02942e9fa493e4e80943a828f9c65f6772.tar.bz2 |
skeleton and the start of libopie2, please read README, ROADMAP and STATUS and comment...
127 files changed, 25255 insertions, 0 deletions
diff --git a/libopie2/.cvsignore b/libopie2/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/README b/libopie2/README new file mode 100644 index 0000000..96210db --- a/dev/null +++ b/libopie2/README @@ -0,0 +1,148 @@ +/******************************************************************** +/* This is an overview of the opielibs2 project +/********************************************************************/ + + Origin: opielibs is about creating classes to + * optimize Qt classes for the embedded environment + * provide sophisticated abstractions for developers + * provide complete documentation and working examples + * provide end users with a common look and feel + * reduce memory footprint through sharing code + * reduce possible bugs through reusing tested code + +-------------------------------------------------------- +1. General Overview +-------------------------------------------------------- + +libopie is functionally seperated into the following libraries: + - libopiecore + - libopieui + - libopiepim + - libopiedb + - libopienet + +1.1 Contents of libopiecore [ opiecore ] +-------------------------------------------------------- + + - odbgstream + - ondbgstream + + - oprocctrl + - oprocess + - odevice + - odevicebutton + + - oconfig + - oconfiggroupsaver + + - ocompletionbase + - ocompletion + - ocomptreenodelist + - ocomptreenode + - ocompletionwrapper + + - oglobal + - oglobalsettings + + - osortableitem + - osortablevaluelist + +1.2 Contents of libopieui [ opieui ] +-------------------------------------------------------- + + - oapplication + + - ofiledialog + - colordialog + - oclickablelabel + - ocolorbutton + - colorpopupmenu + - otabinfo + - otabbar + - otabwidget + - ofontmenu + - ofontselector + - ofileview + - oticker + + - olistview + - olistviewitem + - oversatileview + - oversatileviewitem + - ocompletionbox + - olineedit + - ocombobox + - ohistorycombo + + - omessagebox + - odialogbase + + - todayconfigwidget (rather into opiepim?) + - orecurrancewidget (rather into opiepim?) + - otimepicker (rather into opiepim?) + +1.3 Contents of libopiepim [ opiepim ] +-------------------------------------------------------- + + - ocheckitem + - todoevent + - todoresource + - todayplugininterface + - todovcalresource + +1.4 Contents of libopiedb [ opiedb ] +-------------------------------------------------------- + + - tododb + - xmltree + +1.5 Contents of libopienet [ opienet ] +-------------------------------------------------------- + + - onetwork + - onetworkinterface + - owirelessnetworkinterface + - ochannelhopper + + - omonitoring + - ociscomonitoring + - owlanngmonitoring + - ohostapmonitoring + - oorinocomonitoring + + - opacketcapturer + - opacket + - oethernetpacket + - owavelanpacket + - ollcpacket + - oippacket + - oudppacket + - otcppacket + + <libmail stuff> + <libbend stuff> + <libftp stuff> + + +-------------------------------------------------------- +2.0 Feature Description +-------------------------------------------------------- + +2.1 libopiecore + +... + +2.2 libopieui + +... + +2.3 libopiepim + +... + +2.4 libopiedb + +... + +2.5 libopienet + diff --git a/libopie2/ROADMAP b/libopie2/ROADMAP new file mode 100644 index 0000000..966b67d --- a/dev/null +++ b/libopie2/ROADMAP @@ -0,0 +1,6 @@ + [done] * import current status of opiecore, opienet and opieui + * add contents of libopie1 to libopie2 and functionally split it + * make libopie2 a drop-in-replacement for libopie1 + * add doxygen documentation to all classes + * backport qt3-only stuff (?) + diff --git a/libopie2/STATUS b/libopie2/STATUS new file mode 100644 index 0000000..eb3442c --- a/dev/null +++ b/libopie2/STATUS @@ -0,0 +1,68 @@ + +================================================================== +March 2003 - Initial checkin into the Opie CVS: +================================================================== + +So, this is what I have been working on over the last months. +It's a part of what I think could migrate into our next generation +opielibs. +Of course this won't happen after we released Opie 1.0 and switched +to Qt3-Embedded and gcc 3. + +Right now, there is content only in opiecore, opienet and opieui. +A good part of code has been adapted from the kdelibs, which overall +are pretty good however in details of heterogenous quality. I'm also +not sure if all I ported should be kept, e.g. the pixmapeffect stuff +seems unnecesary to me. However, we should not forget that Opie will +make its debut on more powerful devices with greater display +resolution, e.g. the Sharp C700, so we shouldn't limit ourselves in +what should go into the libraries. + +Generally spoken, a lot of things are still very rough and messy, +but I will keep improving this. Some details about what is usable +and what is not follows: +(everything compiles of course, otherwise I wouldn't have checked in :-) + +[-----------] +[ opiecore ] +[-----------] +oapplication, oconfig, oglobal seem to be usable yet, oglobalsettings +is still very messy and should be revised. A lot more thinking about how +we should keep opie preferences, especially when moving to multi-user, has to be made. +This will affect what goes into oglobalsettings and what configuration data +format we will use. If we switch to Qt3 we will have to decide if we stay +with OConfig deriving from Config or rewrite it using QSettings. + +[-----------] +[ opiedb ] +[-----------] +There is nothing here yet. The sqlite stuff should be here. + +[-----------] +[ opienet ] +[-----------] +onetwork*, omonitoring* and the opacket stuff are pretty usable and not +very far from being complete. documentation for these will come... +Over the next days, opie-wellenreiter, opie-wirelessapplet and the +forthcoming new opie-networkapplet will be using the +new network classes. +I think all the other network libraries spread throught opie, e.g. +libbend, libmail, ftplib should be revised and become part of +opienet eventually. + +[-----------] +[ opiepim ] +[-----------] +Nothing here yet. The stuff currently in libopie/pim should be here. + +[-----------] +[ opieui ] +[-----------] +Pretty messy yet, but some things are usable. Unfortunately, the UI +stuff is very hard to backport to Qt2, so some things only work +if compiled against Qt3, especially all the popupcompletion stuff. +OListView however works nice and is currently used in opie-wellenreiter. + +================================================================== +October 2002 - Started work on cornucopia aka opielib2 +==================================================================
\ No newline at end of file diff --git a/libopie2/config.in b/libopie2/config.in new file mode 100644 index 0000000..7c4d9bb --- a/dev/null +++ b/libopie2/config.in @@ -0,0 +1,10 @@ +menu "libopie2" + source libopie2/opiecore/config.in + source libopie2/opiedb/config.in + source libopie2/opienet/config.in + source libopie2/opiepim/config.in + source libopie2/opieui/config.in + comment "" + source libopie2/examples/config.in +endmenu + diff --git a/libopie2/examples/.cvsignore b/libopie2/examples/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/examples/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/examples/config.in b/libopie2/examples/config.in new file mode 100644 index 0000000..d18e479 --- a/dev/null +++ b/libopie2/examples/config.in @@ -0,0 +1,6 @@ + config LIBOPIE2EXAMPLES + boolean "libopie2 examples" + default "n" + depends ( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE && LIBOPIE2NET && LIBOPIE2UI && LIBOPIE2PIM && LIBOPIE2UI + comment "the examples need a libqpe, libopie2core, libopie2db, libopie2net, libopie2pim and libopie2ui" + depends !(( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE && LIBOPIE2NET && LIBOPIE2UI && LIBOPIE2PIM && LIBOPIE2UI) diff --git a/libopie2/examples/examples.pro b/libopie2/examples/examples.pro new file mode 100644 index 0000000..2ae7eb7 --- a/dev/null +++ b/libopie2/examples/examples.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +unix:SUBDIRS = opieui opienet opiecore + +#include ( ../../../include.pro ) diff --git a/libopie2/examples/opiecore/.cvsignore b/libopie2/examples/opiecore/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/examples/opiecore/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/examples/opiecore/oconfigdemo/.cvsignore b/libopie2/examples/opiecore/oconfigdemo/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/examples/opiecore/oconfigdemo/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/examples/opiecore/oconfigdemo/oconfigdemo.cpp b/libopie2/examples/opiecore/oconfigdemo/oconfigdemo.cpp new file mode 100644 index 0000000..a3f8e10 --- a/dev/null +++ b/libopie2/examples/opiecore/oconfigdemo/oconfigdemo.cpp @@ -0,0 +1,31 @@ +#include <opie2/oapplication.h> +#include <opie2/oconfig.h> +#include <qpe/config.h> + +int main( int argc, char** argv ) +{ + OApplication* app = new OApplication( argc, argv, "MyConfigDemoApplication" ); + + OConfigGroupSaver c1( app->config(), "MyGroup" ); + app->config()->writeEntry( "AnEntry", "InMyGroup" ); + { + OConfigGroupSaver c2( c1.config(), "AnotherGroup" ); + app->config()->writeEntry( "AnEntry", "InAnotherGroup" ); + } // closing the scope returns to the last group + + app->config()->writeEntry( "AnotherEntry", "InMyGroup" ); + + // do more stuff ... + + // in this (special) case it is necessary to manually call OConfig::write() (see below) + app->config()->write(); + + // can't delete the app when using the OConfigGroupSaver on top level scope, + // because the destructor of the OConfigGroupSaver needs an application object + //delete app; // destructor deletes config which writes changes back to disk + + return 0; + +} + +//#include "moc/oconfigdemo.moc" diff --git a/libopie2/examples/opiecore/oconfigdemo/oconfigdemo.pro b/libopie2/examples/opiecore/oconfigdemo/oconfigdemo.pro new file mode 100644 index 0000000..0109c57 --- a/dev/null +++ b/libopie2/examples/opiecore/oconfigdemo/oconfigdemo.pro @@ -0,0 +1,14 @@ +TEMPLATE = app +CONFIG = qt warn_on debug +HEADERS = +SOURCES = oconfigdemo.cpp + +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += $(OPIEDIR)/include +LIBS += -lopiecore2 +TARGET = oconfigdemo +MOC_DIR = moc +OBJECTS_DIR = obj + +include ( $(OPIEDIR)/include.pro ) + diff --git a/libopie2/examples/opiecore/odebugdemo/.cvsignore b/libopie2/examples/opiecore/odebugdemo/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/examples/opiecore/odebugdemo/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/examples/opiecore/odebugdemo/odebugdemo.cpp b/libopie2/examples/opiecore/odebugdemo/odebugdemo.cpp new file mode 100644 index 0000000..74886fa --- a/dev/null +++ b/libopie2/examples/opiecore/odebugdemo/odebugdemo.cpp @@ -0,0 +1,138 @@ +/* QT */ + +#include <qvbox.h> +#include <qhbox.h> +#include <qvbuttongroup.h> +#include <qhbuttongroup.h> +#include <qlineedit.h> +#include <qradiobutton.h> +#include <qpushbutton.h> + +/* OPIE */ + +#include <qpe/config.h> + +#include <opie2/odebug.h> +#include <opie2/oapplication.h> +#include <opie2/oglobal.h> +#include <opie2/oglobalsettings.h> + +class DemoApp : public OApplication +{ +Q_OBJECT +public: + DemoApp( int argc, char** argv ) : OApplication( argc, argv, "libopie2 debug demo" ) + { + // you have access to your OApplication object via oApp + qDebug( "Process-wide OApplication object @ %0x", oApp ); + + // you have access to global settings via OGlobalSettings + int mode = OGlobalSettings::debugMode(); + + QVBox* vbox = new QVBox(); + setMainWidget( vbox ); + + g = new QVButtonGroup( "Output Strategy", vbox ); + QRadioButton* r0 = new QRadioButton( "file", g ); + QRadioButton* r1 = new QRadioButton( "messagebox", g ); + QRadioButton* r2 = new QRadioButton( "stderr", g ); + QRadioButton* r3 = new QRadioButton( "syslog", g ); + QRadioButton* r4 = new QRadioButton( "socket", g ); + g->insert( r0, 0 ); + g->insert( r1, 1 ); + g->insert( r2, 2 ); + g->insert( r3, 3 ); + g->insert( r4, 4 ); + g->setRadioButtonExclusive( true ); + connect( g, SIGNAL( clicked(int) ), this, SLOT( chooseMethod(int) ) ); + + if ( mode != -1 ) g->setButton( mode ); + + QHButtonGroup* hbox = new QHButtonGroup( "Extra Output Information", vbox ); + e = new QLineEdit( hbox ); + QPushButton* pb = new QPushButton( hbox ); + + connect( e, SIGNAL( returnPressed() ), this, SLOT( updateDebugOutput() ) ); + connect( pb, SIGNAL( clicked() ), this, SLOT( updateDebugOutput() ) ); + + // show the additional debug mode dependent output information + e->setText( OGlobalSettings::debugOutput() ); + + // buttos + QPushButton* info = new QPushButton( "Emit Debug(Info) Output!", vbox ); + connect( info, SIGNAL( clicked() ), this, SLOT( emitInfoOutput() ) ); + QPushButton* warn = new QPushButton( "Emit a Warning Output!", vbox ); + connect( warn, SIGNAL( clicked() ), this, SLOT( emitWarningOutput() ) ); + QPushButton* error = new QPushButton( "Emit an Error Output!", vbox ); + connect( error, SIGNAL( clicked() ), this, SLOT( emitErrorOutput() ) ); + QPushButton* fatal = new QPushButton( "Emit a Fatal Output!", vbox ); + connect( fatal, SIGNAL( clicked() ), this, SLOT( emitFatalOutput() ) ); + + QPushButton* tb = new QPushButton( "Emit a Fatal Backtrace!", vbox ); + connect( tb, SIGNAL( clicked() ), this, SLOT( emitTBOutput() ) ); + + info->show(); + warn->show(); + error->show(); + fatal->show(); + tb->show(); + g->show(); + hbox->show(); + e->show(); + vbox->show(); + showMainWidget( vbox ); + } + +public slots: + void chooseMethod(int method) + { + m = method; + qDebug( "choosing method: %d", method ); + OConfig* g = OGlobal::config(); + g->setGroup( "General" ); + g->writeEntry( "debugMode", m ); + e->setText( OGlobalSettings::debugOutput() ); + } + void updateDebugOutput() + { + OConfig* g = OGlobal::config(); + g->setGroup( "General" ); + g->writeEntry( "debugOutput"+QString::number(OGlobalSettings::debugMode()), e->text() ); + } + void emitInfoOutput() + { + odebug << "This is a debug message" << oendl; + } + void emitWarningOutput() + { + owarn << "This is a warning message" << oendl; + } + void emitErrorOutput() + { + oerr << "This is an errror message" << oendl; + } + void emitFatalOutput() + { + ofatal << "This is a fatal message" << oendl; + } + void emitTBOutput() + { + ofatal << "This is a fatal message + backtrace\n" + odBacktrace(); // odBacktrace includes \n + } + +private: + QButtonGroup* g; + int m; + QLineEdit* e; +}; + +int main( int argc, char** argv ) +{ + DemoApp* app = new DemoApp( argc, argv ); + app->exec(); + + return 0; + +} + +#include "moc/odebugdemo.moc" diff --git a/libopie2/examples/opiecore/odebugdemo/odebugdemo.pro b/libopie2/examples/opiecore/odebugdemo/odebugdemo.pro new file mode 100644 index 0000000..a725105 --- a/dev/null +++ b/libopie2/examples/opiecore/odebugdemo/odebugdemo.pro @@ -0,0 +1,14 @@ +TEMPLATE = app +CONFIG = qt warn_on debug +HEADERS = +SOURCES = odebugdemo.cpp +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += $(OPIEDIR)/include +LIBS += -lopiecore2 +TARGET = odebugdemo +MOC_DIR = moc +OBJECTS_DIR = obj + +include ( $(OPIEDIR)/include.pro ) + + diff --git a/libopie2/examples/opiecore/oglobalsettingsdemo/.cvsignore b/libopie2/examples/opiecore/oglobalsettingsdemo/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/examples/opiecore/oglobalsettingsdemo/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/examples/opiecore/oglobalsettingsdemo/oglobalsettingsdemo.cpp b/libopie2/examples/opiecore/oglobalsettingsdemo/oglobalsettingsdemo.cpp new file mode 100644 index 0000000..2f5220b --- a/dev/null +++ b/libopie2/examples/opiecore/oglobalsettingsdemo/oglobalsettingsdemo.cpp @@ -0,0 +1,13 @@ +#include <opie2/oglobalsettings.h> +#include <iostream.h> + +int main( int argc, char** argv ) +{ + printf( "current debugmode seems to be '%d'\n", OGlobalSettings::debugMode() ); + printf( "output information for this mode is '%s'\n", (const char*) OGlobalSettings::debugOutput() ); + + return 0; + +} + +//#include "moc/oconfigdemo.moc" diff --git a/libopie2/examples/opiecore/oglobalsettingsdemo/oglobalsettingsdemo.pro b/libopie2/examples/opiecore/oglobalsettingsdemo/oglobalsettingsdemo.pro new file mode 100644 index 0000000..7fbecce --- a/dev/null +++ b/libopie2/examples/opiecore/oglobalsettingsdemo/oglobalsettingsdemo.pro @@ -0,0 +1,14 @@ +TEMPLATE = app +CONFIG = qt warn_on debug +HEADERS = +SOURCES = oglobalsettingsdemo.cpp +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += $(OPIEDIR)/include +LIBS += -lopiecore2 +TARGET = oglobalsettingsdemo +MOC_DIR = moc +OBJECTS_DIR = obj + +include ( $(OPIEDIR)/include.pro ) + + diff --git a/libopie2/examples/opiecore/opiecore.pro b/libopie2/examples/opiecore/opiecore.pro new file mode 100644 index 0000000..8f3aedc --- a/dev/null +++ b/libopie2/examples/opiecore/opiecore.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +unix:SUBDIRS = odebugdemo oconfigdemo oglobalsettingsdemo + diff --git a/libopie2/examples/opienet/.cvsignore b/libopie2/examples/opienet/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/examples/opienet/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/examples/opienet/miniwellenreiter/.cvsignore b/libopie2/examples/opienet/miniwellenreiter/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/examples/opienet/miniwellenreiter/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/examples/opienet/miniwellenreiter/miniwellenreiter.cpp b/libopie2/examples/opienet/miniwellenreiter/miniwellenreiter.cpp new file mode 100644 index 0000000..aec9cc7 --- a/dev/null +++ b/libopie2/examples/opienet/miniwellenreiter/miniwellenreiter.cpp @@ -0,0 +1,199 @@ +#include <qdict.h> +#include <qsocketnotifier.h> +#include <qstring.h> +#include <opie2/onetwork.h> +#include <qapplication.h> +#include <opie2/opcap.h> +#include <cerrno> +#include <cstdio> +#include <cstdlib> +#include <cstring> + +//======================== Station help class =============================== + +class Station +{ + public: + Station( QString t, int c, bool w ) : type(t), channel(c), wep(w), beacons(1) {}; + ~Station() {}; + + QString type; + int channel; + bool wep; + int beacons; +}; + +QDict<Station> stations; + +//======================== Application class =============================== + +class Wellenreiter : public QApplication +{ +Q_OBJECT +public: + Wellenreiter( int argc, char** argv ) : QApplication( argc, argv ) + { + + ONetwork* net = ONetwork::instance(); + + if ( argc < 3 ) + { + printf( "Usage: ./%s <interface> <driver> <interval>\n", argv[0] ); + printf( "\n" ); + printf( "Valid wireless interfaces (detected) are:\n" ); + + ONetwork::InterfaceIterator it = net->iterator(); + while ( it.current() ) + { + if ( it.current()->isWireless() ) + { + printf( " - '%s' (MAC=%s) (IPv4=%s)\n", (const char*) it.current()->name(), + (const char*) it.current()->macAddress().toString(), + (const char*) it.current()->ipV4Address() ); + } + ++it; + } + exit( -1 ); + } + + printf( "****************************************************\n" ); + printf( "* Wellenreiter mini edition 1.0 (C) 2003 M-M-M *\n" ); + printf( "****************************************************\n" ); + printf( "\n\n" ); + + QString interface( argv[1] ); + QString driver( argv[2] ); + + printf( "Trying to use '%s' as %s-controlled device...\n", (const char*) interface, (const char*) driver ); + + // sanity checks before downcasting + ONetworkInterface* iface = net->interface( interface ); + if ( !iface ) + { + printf( "Interface '%s' doesn't exist. Exiting.\n", (const char*) interface ); + exit( -1 ); + } + if ( !iface->isWireless() ) + { + printf( "Interface '%s' doesn't support wireless extensions. Exiting.\n", (const char*) interface ); + exit( -1 ); + } + + // downcast should be safe now + wiface = (OWirelessNetworkInterface*) iface; + printf( "Using wireless interface '%s' for scanning (current SSID is '%s')...\n", (const char*) interface, (const char*) wiface->SSID() ); + + /* + + // ifconfig down the interface - this enable more crash-proof + // scanning with drivers like spectrum_cs... + if ( wiface->isUp() ) + { + printf( "Interface status is up... switching to down... " ); + wiface->setUp( false ); + if ( wiface->isUp() ) + { + printf( "failed (%s). Exiting.\n", strerror( errno ) ); + exit( -1 ); + } + else + { + printf( "ok.\n" ); + } + } + else + printf( "Interface status is already down - good.\n" ); + + */ + + // ifconfig +promisc the interface to receive all packets + if ( !wiface->promiscuousMode() ) + { + printf( "Interface status is not promisc... switching to promisc... " ); + wiface->setPromiscuousMode( true ); + if ( !wiface->promiscuousMode() ) + { + printf( "failed (%s). Exiting.\n", strerror( errno ) ); + exit( -1 ); + } + else + { + printf( "ok.\n" ); + } + } + else + printf( "Interface status is already promisc - good.\n" ); + + // connect a monitoring strategy to the interface + if ( driver == "orinoco" ) + new OOrinocoMonitoringInterface( wiface ); + else + { + printf( "Unknown driver. Exiting\n" ); + exit( -1 ); + } + + // enable monitoring mode + printf( "Enabling monitor mode...\n" ); + wiface->setMonitorMode( true ); + + // open a packet capturer + cap = new OPacketCapturer(); + cap->open( interface ); + if ( !cap->isOpen() ) + { + printf( "Unable to open libpcap (%s). Exiting.\n", strerror( errno ) ); + exit( -1 ); + } + + // set capturer to non-blocking mode + cap->setBlocking( false ); + + // start channel hopper + wiface->setChannelHopping( 1000 ); + + // connect + connect( cap, SIGNAL( receivedPacket(OPacket*) ), this, SLOT( receivePacket(OPacket*) ) ); + + } + + ~Wellenreiter() {}; + +public slots: + void receivePacket(OPacket* p) + { + if (!p) + { + printf( "(empty packet received)\n" ); + return; + } + + OWaveLanManagementPacket* beacon = (OWaveLanManagementPacket*) p->child( "802.11 Management" ); + + if ( beacon ) + { + if ( stations.find( beacon->SSID() ) ) + stations[beacon->SSID()]->beacons++; + else + { + printf( "found new network @ channel %d, SSID = '%s'\n", wiface->channel(), (const char*) beacon->SSID() ); + stations.insert( beacon->SSID(), new Station( "unknown", wiface->channel(), + ((OWaveLanPacket*) beacon->parent())->usesWep() ) ); + } + } + } +private: + OPacketCapturer* cap; + OWirelessNetworkInterface* wiface; +}; + + +int main( int argc, char** argv ) +{ + Wellenreiter w( argc, argv ); + w.exec(); + return 0; +} + +#include "miniwellenreiter.moc" + diff --git a/libopie2/examples/opienet/miniwellenreiter/miniwellenreiter.pro b/libopie2/examples/opienet/miniwellenreiter/miniwellenreiter.pro new file mode 100644 index 0000000..7ce535c --- a/dev/null +++ b/libopie2/examples/opienet/miniwellenreiter/miniwellenreiter.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +CONFIG = qt warn_on debug +HEADERS = +SOURCES = miniwellenreiter.cpp +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += $(OPIEDIR)/include +LIBS += -lopiecore2 -lopienet2 +TARGET = miniwellenreiter +MOC_DIR = moc +OBJECTS_DIR = obj + +include ( $(OPIEDIR)/include.pro ) + diff --git a/libopie2/examples/opienet/onetworkdemo/.cvsignore b/libopie2/examples/opienet/onetworkdemo/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/examples/opienet/onetworkdemo/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/examples/opienet/onetworkdemo/onetworkdemo.cpp b/libopie2/examples/opienet/onetworkdemo/onetworkdemo.cpp new file mode 100644 index 0000000..7703b4c --- a/dev/null +++ b/libopie2/examples/opienet/onetworkdemo/onetworkdemo.cpp @@ -0,0 +1,35 @@ +#include <opie2/onetwork.h> + +int main( int argc, char** argv ) +{ + qDebug( "OPIE Network Demo" ); + + ONetwork* net = ONetwork::instance(); + + ONetwork::InterfaceIterator it = net->iterator(); + + while ( it.current() ) + { + qDebug( "DEMO: ONetwork contains Interface '%s'", (const char*) it.current()->name() ); + qDebug( "DEMO: MAC Address is '%s'", (const char*) it.current()->macAddress().toString() ); + qDebug( "Demo: IPv4 Address is '%s'", (const char*) it.current()->ipV4Address() ); + if ( it.current()->isWireless() ) + { + OWirelessNetworkInterface* iface = static_cast<OWirelessNetworkInterface*>( it.current() ); + qDebug( "DEMO: '%s' seems to feature the wireless extensions.", (const char*) iface->name() ); + qDebug( "DEMO: Current SSID is '%s'", (const char*) iface->SSID() ); + qDebug( "DEMO: Current NickName is '%s'", (const char*) iface->nickName() ); + qDebug( "DEMO: Antenna is tuned to '%f', that is channel %d", iface->frequency(), iface->channel() ); + + //if ( iface->mode() == OWirelessNetworkInterface::adhoc ) + //{ + qDebug( "DEMO: Associated AP has MAC Address '%s'", (const char*) iface->associatedAP() ); + //} + + } + ++it; + } + + return 0; + +} diff --git a/libopie2/examples/opienet/onetworkdemo/onetworkdemo.pro b/libopie2/examples/opienet/onetworkdemo/onetworkdemo.pro new file mode 100644 index 0000000..2d71aa0 --- a/dev/null +++ b/libopie2/examples/opienet/onetworkdemo/onetworkdemo.pro @@ -0,0 +1,12 @@ +TEMPLATE = app +CONFIG = qt warn_on debug +HEADERS = +SOURCES = onetworkdemo.cpp +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += $(OPIEDIR)/include +LIBS += -lopiecore2 -lopienet2 +TARGET = onetworkdemo +MOC_DIR = moc +OBJECTS_DIR = obj + +include ( $(OPIEDIR)/include.pro ) diff --git a/libopie2/examples/opienet/opienet.pro b/libopie2/examples/opienet/opienet.pro new file mode 100644 index 0000000..c7800a9 --- a/dev/null +++ b/libopie2/examples/opienet/opienet.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = miniwellenreiter onetworkdemo + diff --git a/libopie2/examples/opieui/.cvsignore b/libopie2/examples/opieui/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/examples/opieui/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/examples/opieui/oversatileviewdemo/1.png b/libopie2/examples/opieui/oversatileviewdemo/1.png Binary files differnew file mode 100644 index 0000000..0e2e41b --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/1.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/1small.png b/libopie2/examples/opieui/oversatileviewdemo/1small.png Binary files differnew file mode 100644 index 0000000..ce6b262 --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/1small.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/2.png b/libopie2/examples/opieui/oversatileviewdemo/2.png Binary files differnew file mode 100644 index 0000000..8a0181d --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/2.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/2small.png b/libopie2/examples/opieui/oversatileviewdemo/2small.png Binary files differnew file mode 100644 index 0000000..82a4431 --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/2small.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/3.png b/libopie2/examples/opieui/oversatileviewdemo/3.png Binary files differnew file mode 100644 index 0000000..8a58d6c --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/3.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/3small.png b/libopie2/examples/opieui/oversatileviewdemo/3small.png Binary files differnew file mode 100644 index 0000000..073ba55 --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/3small.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/4.png b/libopie2/examples/opieui/oversatileviewdemo/4.png Binary files differnew file mode 100644 index 0000000..198891b --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/4.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/4small.png b/libopie2/examples/opieui/oversatileviewdemo/4small.png Binary files differnew file mode 100644 index 0000000..7f1cc01 --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/4small.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/5.png b/libopie2/examples/opieui/oversatileviewdemo/5.png Binary files differnew file mode 100644 index 0000000..ee7344a --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/5.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/5small.png b/libopie2/examples/opieui/oversatileviewdemo/5small.png Binary files differnew file mode 100644 index 0000000..105b038 --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/5small.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/6.png b/libopie2/examples/opieui/oversatileviewdemo/6.png Binary files differnew file mode 100644 index 0000000..72c3692 --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/6.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/6small.png b/libopie2/examples/opieui/oversatileviewdemo/6small.png Binary files differnew file mode 100644 index 0000000..1db2a30 --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/6small.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/folder_closed.png b/libopie2/examples/opieui/oversatileviewdemo/folder_closed.png Binary files differnew file mode 100644 index 0000000..4157333 --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/folder_closed.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/folder_closed32.png b/libopie2/examples/opieui/oversatileviewdemo/folder_closed32.png Binary files differnew file mode 100644 index 0000000..acc992c --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/folder_closed32.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/folder_opened.png b/libopie2/examples/opieui/oversatileviewdemo/folder_opened.png Binary files differnew file mode 100644 index 0000000..5e7e37e --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/folder_opened.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/folder_opened32.png b/libopie2/examples/opieui/oversatileviewdemo/folder_opened32.png Binary files differnew file mode 100644 index 0000000..acd3265 --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/folder_opened32.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/leaf.png b/libopie2/examples/opieui/oversatileviewdemo/leaf.png Binary files differnew file mode 100644 index 0000000..c8435ec --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/leaf.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/leaf32.png b/libopie2/examples/opieui/oversatileviewdemo/leaf32.png Binary files differnew file mode 100644 index 0000000..5e90ead --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/leaf32.png diff --git a/libopie2/examples/opieui/oversatileviewdemo/main.cpp b/libopie2/examples/opieui/oversatileviewdemo/main.cpp new file mode 100644 index 0000000..d8c01a4 --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/main.cpp @@ -0,0 +1,29 @@ +/********************************************************************** +** Copyright (C) 2002 Michael 'Mickey' Lauer. All rights reserved. +** +** This file is part of Opie Environment. +** +** 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. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#include "opieuidemo.h" + +#include <opie2/oapplication.h> + +int main( int argc, char **argv ) +{ + OApplication a( argc, argv, "Opie UI Demo" ); + qDebug( "." ); + OpieUIDemo e; + qDebug( "." ); + a.showMainWidget(&e); + qDebug( "." ); + return a.exec(); +} diff --git a/libopie2/examples/opieui/oversatileviewdemo/opieui.pro b/libopie2/examples/opieui/oversatileviewdemo/opieui.pro new file mode 100644 index 0000000..8ad5fc9 --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/opieui.pro @@ -0,0 +1,17 @@ +TEMPLATE = app +CONFIG = qt warn_on debug +HEADERS = opieuidemo.h \ + oversatileviewdemo.h +SOURCES = opieuidemo.cpp \ + oversatileviewdemo.cpp \ + main.cpp +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += $(OPIEDIR)/include +LIBS += -lopieui2 -lopiecore2 +TARGET = opieuidemo +MOC_DIR = moc +OBJECTS_DIR = obj + +include ( $(OPIEDIR)/include.pro ) + + diff --git a/libopie2/examples/opieui/oversatileviewdemo/opieuidemo.cpp b/libopie2/examples/opieui/oversatileviewdemo/opieuidemo.cpp new file mode 100644 index 0000000..197669c --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/opieuidemo.cpp @@ -0,0 +1,205 @@ +/********************************************************************** +** Copyright (C) 2002 Michael 'Mickey' Lauer. All rights reserved. +** +** This file is part of Opie Environment. +** +** 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. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +***********************************************************************/ + +// Qt + +#include <qcolor.h> +#include <qpopupmenu.h> +#include <qmenubar.h> +#include <qmessagebox.h> +#include <qvbox.h> +#include <qstring.h> +#include <qstringlist.h> + +// Qtopia + +#ifdef QWS +#include <qpe/qpeapplication.h> +#include <qpe/global.h> +#endif + +// Opie + +#ifdef QWS +#include <opie/odevice.h> +using namespace Opie; +#endif + +#include <opie2/ocompletionbox.h> +#include <opie2/olineedit.h> +#include <opie2/ocombobox.h> +#include <opie2/oeditlistbox.h> +#include <opie2/oselector.h> +#include <opie2/opopupmenu.h> + +#include <qtabwidget.h> +#include "oversatileviewdemo.h" + +// Local + +#include "opieuidemo.h" + +enum Demos { ocompletionbox, olineedit, ocombobox, oeditlistbox, oselector }; + +OpieUIDemo::OpieUIDemo( QWidget* parent, const char* name, WFlags fl ) + : QMainWindow( parent, name, fl ) +{ + + QMenuBar* mbar = this->menuBar(); + OPopupMenu* demo = new OPopupMenu( this ); + demo->setTitle( "Title" ); + demo->setItemParameter( demo->insertItem( "OCompletionBox", this, SLOT( demo(int) ) ), ocompletionbox ); + demo->setItemParameter( demo->insertItem( "OLineEdit", this, SLOT( demo(int) ) ), olineedit ); + demo->setItemParameter( demo->insertItem( "OComboBox", this, SLOT( demo(int) ) ), ocombobox ); + demo->setItemParameter( demo->insertItem( "OEditListBox", this, SLOT( demo(int) ) ), oeditlistbox ); + demo->setItemParameter( demo->insertItem( "OSelector", this, SLOT( demo(int) ) ), oselector ); + mbar->insertItem( "Demonstrate", demo ); + + build(); + +} + +OpieUIDemo::~OpieUIDemo() +{ +} + +void OpieUIDemo::build() +{ + main = new QTabWidget( this, "tabwidget" ); + setCentralWidget( main ); + main->show(); + + main->addTab( new OVersatileViewDemo( main ), "VersatileView" ); +} + + +void OpieUIDemo::demo( int d ) +{ + switch (d) + { + case ocompletionbox: demoOCompletionBox(); break; + case olineedit: demoOLineEdit(); break; + case ocombobox: demoOComboBox(); break; + case oeditlistbox: demoOEditListBox(); break; + case oselector: demoOSelector(); break; + + } + +} + +void OpieUIDemo::demoOCompletionBox() +{ + qDebug( "ocompletionbox" ); + + OCompletionBox* box = new OCompletionBox( 0 ); + box->insertItem( "This CompletionBox" ); + box->insertItem( "Says 'Hello World'" ); + box->insertItem( "Here are some" ); + box->insertItem( "Additional Items" ); + box->insertItem( "Complete Completion Box" ); + + connect( box, SIGNAL( activated( const QString& ) ), this, SLOT( messageBox( const QString& ) ) ); + box->popup(); + +} + +void OpieUIDemo::demoOLineEdit() +{ + qDebug( "olineedit" ); + + OLineEdit *edit = new OLineEdit( 0, "lineedit" ); + + edit->setCompletionMode( OGlobalSettings::CompletionPopup ); + OCompletion* comp = edit->completionObject(); + + QStringList list; + list << "mickeyl@handhelds.org"; + list << "mickey@tm.informatik.uni-frankfurt.de"; + list << "mickey@vanille.de"; + + comp->setItems( list ); + + edit->show(); + +} + +void OpieUIDemo::demoOComboBox() +{ + qDebug( "ocombobox" ); + + OComboBox *combo = new OComboBox( true, 0, "combobox" ); + + combo->setCompletionMode( OGlobalSettings::CompletionPopup ); + OCompletion* comp = combo->completionObject(); + + QStringList ilist; + ilist << "kergoth@handhelds.org"; + ilist << "harlekin@handhelds.org"; + ilist << "groucho@handhelds.org"; + combo->insertStringList( ilist ); + + QStringList clist; + clist << "mickeyl@handhelds.org"; + clist << "mickey@tm.informatik.uni-frankfurt.de"; + clist << "mickey@vanille.de"; + comp->setItems( clist ); + + combo->show(); + +} + +void OpieUIDemo::demoOEditListBox() +{ + qDebug( "oeditlistbox" ); + + OEditListBox* edit = new OEditListBox( "OEditListBox", 0, "editlistbox" ); + + edit->lineEdit()->setCompletionMode( OGlobalSettings::CompletionPopup ); + OCompletion* comp = edit->lineEdit()->completionObject(); + QStringList clist; + clist << "Completion everywhere"; + clist << "Cool Completion everywhere"; + clist << "History History History"; + comp->setItems( clist ); + + QStringList list; + list << "kergoth@handhelds.org"; + list << "harlekin@handhelds.org"; + list << "groucho@handhelds.org"; + list << "mickeyl@handhelds.org"; + edit->insertStringList( list ); + + edit->show(); + +} + +void OpieUIDemo::demoOSelector() +{ + qDebug( "oselector" ); + + OHSSelector* sel = new OHSSelector( 0, "gradientselector" ); + //#sel->resize( QSize( 200, 30 ) ); + //#sel->setColors( QColor( 90, 190, 60 ), QColor( 200, 55, 255 ) ); + //#sel->setText( "Dark", "Light" ); + + sel->show(); +} + +void OpieUIDemo::messageBox( const QString& text ) +{ + QString info; + info = "You have selected '" + text + "'"; + QMessageBox::information( this, "OpieUIDemo", info ); +} diff --git a/libopie2/examples/opieui/oversatileviewdemo/opieuidemo.h b/libopie2/examples/opieui/oversatileviewdemo/opieuidemo.h new file mode 100644 index 0000000..0519ae6 --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/opieuidemo.h @@ -0,0 +1,56 @@ +/********************************************************************** +** Copyright (C) 2002 Michael 'Mickey' Lauer. All rights reserved. +** +** This file is part of Opie Environment. +** +** 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. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef OPIEUIDEMO_H +#define OPIEUIDEMO_H + +#include <qmainwindow.h> + +class OVersatileView; +class QTabWidget; +class QVBox; + +class OpieUIDemo : public QMainWindow { + Q_OBJECT + +public: + + OpieUIDemo( QWidget* parent = 0, const char* name = 0, WFlags fl = WType_TopLevel ); + ~OpieUIDemo(); + + void demoOCompletionBox(); + void demoOLineEdit(); + void demoOComboBox(); + void demoOEditListBox(); + void demoOSelector(); + +public slots: + void demo( int ); + void messageBox( const QString& text ); + +protected: + void build(); + void buildVV( QVBox* b ); + +private: + QTabWidget* main; + + OVersatileView* vv; + +}; + + + +#endif diff --git a/libopie2/examples/opieui/oversatileviewdemo/oversatileviewdemo.cpp b/libopie2/examples/opieui/oversatileviewdemo/oversatileviewdemo.cpp new file mode 100644 index 0000000..cf1e443 --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/oversatileviewdemo.cpp @@ -0,0 +1,158 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael 'Mickey' Lauer + <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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 "oversatileviewdemo.h" +#include <opie2/oversatileview.h> +#include <opie2/oversatileviewitem.h> + +#include <qstring.h> +#include <qpixmap.h> +#include <qlistview.h> + +OVersatileViewDemo::OVersatileViewDemo( QWidget* parent, const char* name, WFlags f ) + :QVBox( parent, name, f ) +{ + vv = new OVersatileView( this ); + + vv->addColumn( "First" ); + vv->addColumn( "2nd" ); + vv->addColumn( "IIIrd" ); + + QString counter; + + QPixmap leaf( "leaf.png" ); + QPixmap opened( "folder_opened.png" ); + QPixmap closed( "folder_closed.png" ); + + QPixmap leaf32( "leaf32.png" ); + QPixmap opened32( "folder_opened32.png" ); + QPixmap closed32( "folder_closed32.png" ); + + vv->setDefaultPixmaps( OVersatileView::Tree, leaf, opened, closed ); + vv->setDefaultPixmaps( OVersatileView::Icons, leaf32, opened32, closed32 ); + + OVersatileViewItem* item; + OVersatileViewItem* item2; + + for ( int i = 0; i < 5; ++i ) + { + counter.sprintf( "%d", i ); + item = new OVersatileViewItem( vv, "Item", "Text", "Some more", counter ); + item->setRenameEnabled( true ); + item2 = new OVersatileViewItem( item, "OSubitem", "123", "...", counter ); + item2->setRenameEnabled( true ); + + } + + connect( vv, SIGNAL( selectionChanged() ), this, SLOT( selectionChanged() ) ); + connect( vv, SIGNAL( selectionChanged( OVersatileViewItem * ) ), this, SLOT( selectionChanged( OVersatileViewItem * ) ) ); + connect( vv, SIGNAL( currentChanged( OVersatileViewItem * ) ), this, SLOT( currentChanged( OVersatileViewItem * ) ) ); + connect( vv, SIGNAL( clicked( OVersatileViewItem * ) ), this, SLOT( clicked( OVersatileViewItem * ) ) ); + connect( vv, SIGNAL( pressed( OVersatileViewItem * ) ), this, SLOT( pressed( OVersatileViewItem * ) ) ); + + connect( vv, SIGNAL( doubleClicked( OVersatileViewItem * ) ), this, SLOT( doubleClicked( OVersatileViewItem * ) ) ); + connect( vv, SIGNAL( returnPressed( OVersatileViewItem * ) ), this, SLOT( returnPressed( OVersatileViewItem * ) ) ); + + connect( vv, SIGNAL( onItem( OVersatileViewItem * ) ), this, SLOT( onItem( OVersatileViewItem * ) ) ); + connect( vv, SIGNAL( onViewport() ), this, SLOT( onViewport() ) ); + + connect( vv, SIGNAL( expanded( OVersatileViewItem * ) ), this, SLOT( expanded( OVersatileViewItem * ) ) ); + connect( vv, SIGNAL( collapsed( OVersatileViewItem * ) ), this, SLOT( collapsed( OVersatileViewItem * ) ) ); + + connect( vv, SIGNAL( moved() ), this, SLOT( moved() ) ); + + connect( vv, SIGNAL( contextMenuRequested( OVersatileViewItem *, const QPoint&, int ) ), this, SLOT( contextMenuRequested( OVersatileViewItem *, const QPoint&, int ) ) ); + +} + +OVersatileViewDemo::~OVersatileViewDemo() +{ +} + +void OVersatileViewDemo::selectionChanged() +{ + qDebug( "received signal selectionChanged()" ); +} +void OVersatileViewDemo::selectionChanged( OVersatileViewItem * item ) +{ + qDebug( "received signal selectionChanged(OVersatileViewItem*)" ); +} +void OVersatileViewDemo::currentChanged( OVersatileViewItem * item ) +{ + qDebug( "received signal currentChanged( OVersatileViewItem * )" ); +} +void OVersatileViewDemo::clicked( OVersatileViewItem * item ) +{ + qDebug( "received signal clicked( OVersatileViewItem * )" ); +} +void OVersatileViewDemo::pressed( OVersatileViewItem * item ) +{ + qDebug( "received signal pressed( OVersatileViewItem * )" ); +} + +void OVersatileViewDemo::doubleClicked( OVersatileViewItem *item ) +{ + qDebug( "received signal doubleClicked( OVersatileViewItem *item )" ); +} +void OVersatileViewDemo::returnPressed( OVersatileViewItem *item ) +{ + qDebug( "received signal returnPressed( OVersatileViewItem *item )" ); +} + +void OVersatileViewDemo::onItem( OVersatileViewItem *item ) +{ + qDebug( "received signal onItem( OVersatileViewItem *item )" ); +} +void OVersatileViewDemo::onViewport() +{ + qDebug( "received signal onViewport()" ); +} + +void OVersatileViewDemo::expanded( OVersatileViewItem *item ) +{ + qDebug( "received signal expanded( OVersatileViewItem *item )" ); +} + +void OVersatileViewDemo::collapsed( OVersatileViewItem *item ) +{ + qDebug( "received signal collapsed( OVersatileViewItem *item )" ); +} + +void OVersatileViewDemo::moved() +{ + qDebug( "received signal moved( OVersatileViewItem *item )" ); +} + +void OVersatileViewDemo::contextMenuRequested( OVersatileViewItem *item, const QPoint& pos, int col ) +{ + qDebug( "received signal contextMenuRequested( OVersatileViewItem *item )" ); +} diff --git a/libopie2/examples/opieui/oversatileviewdemo/oversatileviewdemo.h b/libopie2/examples/opieui/oversatileviewdemo/oversatileviewdemo.h new file mode 100644 index 0000000..79318d0 --- a/dev/null +++ b/libopie2/examples/opieui/oversatileviewdemo/oversatileviewdemo.h @@ -0,0 +1,73 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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 OVERSATILEVIEWDEMO_H +#define OVERSATILEVIEWDEMO_H + +#include <qvbox.h> + +class OVersatileView; +class OVersatileViewItem; + +class OVersatileViewDemo: public QVBox +{ + Q_OBJECT + + public: + OVersatileViewDemo( QWidget* parent=0, const char* name=0, WFlags f=0 ); + virtual ~OVersatileViewDemo(); + + public slots: + void selectionChanged(); + void selectionChanged( OVersatileViewItem * ); + void currentChanged( OVersatileViewItem * ); + void clicked( OVersatileViewItem * ); + void pressed( OVersatileViewItem * ); + + void doubleClicked( OVersatileViewItem *item ); + void returnPressed( OVersatileViewItem *item ); + + void onItem( OVersatileViewItem *item ); + void onViewport(); + + void expanded( OVersatileViewItem *item ); + void collapsed( OVersatileViewItem *item ); + + void moved(); + + void contextMenuRequested( OVersatileViewItem *item, const QPoint&, int col ); + + private: + OVersatileView* vv; + +}; + +#endif diff --git a/libopie2/libopie2.control b/libopie2/libopie2.control new file mode 100644 index 0000000..eb90ab2 --- a/dev/null +++ b/libopie2/libopie2.control @@ -0,0 +1,10 @@ +Files: $OPIEDIR/lib/libopiecore2.so.1.8.1 $OPIEDIR/lib/libopiecore2.so.1.8 $OPIEDIR/lib/libopiecore2.so.1 $OPIEDIR/lib/libopienet2.so.1.8.1 $OPIEDIR/lib/libopienet2.so.1.8 $OPIEDIR/lib/libopienet2.so.1 $OPIEDIR/lib/libopieui2.so.1.8.1 $OPIEDIR/lib/libopieui2.so.1.8 $OPIEDIR/lib/libopieui2.so.1 +Priority: optional +Section: opie/system +Maintainer: Opie Team <opie@handhelds.org> +Architecture: arm +Version: 1.8.1 +Depends: libqpe1 +Provides: libopie2 +Replaces: libopie2 +Description: Opie library 2.0 diff --git a/libopie2/libopie2.postinst b/libopie2/libopie2.postinst new file mode 100755 index 0000000..0c37b3d --- a/dev/null +++ b/libopie2/libopie2.postinst @@ -0,0 +1,4 @@ +#!/bin/sh + +[ -x /sbin/ldconfig ] && /sbin/ldconfig +exit 0 diff --git a/libopie2/libopie2.pro b/libopie2/libopie2.pro new file mode 100644 index 0000000..0b52abc --- a/dev/null +++ b/libopie2/libopie2.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +unix:SUBDIRS = opiecore opiedb opiepim opieui opienet examples + +include ( $(OPIEDIR)/include.pro ) diff --git a/libopie2/opiecore/.cvsignore b/libopie2/opiecore/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/opiecore/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/opiecore/config.in b/libopie2/opiecore/config.in new file mode 100644 index 0000000..f4483a2 --- a/dev/null +++ b/libopie2/opiecore/config.in @@ -0,0 +1,6 @@ + config LIBOPIE2CORE + boolean "libopie2core (application, configuration and debug related classes)" + default "n" + depends ( LIBQPE || LIBQPE-X11 ) + comment "libopie2core needs a libqpe (yet)" + depends !( LIBQPE || LIBQPE-X11 ) diff --git a/libopie2/opiecore/oapplication.cpp b/libopie2/opiecore/oapplication.cpp new file mode 100644 index 0000000..a0abcc2 --- a/dev/null +++ b/libopie2/opiecore/oapplication.cpp @@ -0,0 +1,110 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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/oapplication.h> +#include <opie2/oconfig.h> + +OApplication* OApplication::_instance = 0; + +/**************************************************************************************************/ +/* OApplicationPrivate +/**************************************************************************************************/ + +class OApplicationPrivate +{ + public: + OApplicationPrivate() {}; + ~OApplicationPrivate() {}; +}; + +/**************************************************************************************************/ +/* OApplication +/**************************************************************************************************/ + + +OApplication::OApplication( int& argc, char** argv, const QCString& rAppName ) + :OApplicationBaseClass( argc, argv ), + _appname( rAppName ), + _config( 0 ) +{ + init(); +} + + +OApplication::~OApplication() +{ + delete d; + if ( _config ) + delete _config; + OApplication::_instance = 0; + // after deconstruction of the one-and-only application object, + // the construction of another object is allowed +} + + +OConfig* OApplication::config() +{ + if ( not _config ) + { + _config = new OConfig( _appname ); + } + return _config; +} + + +void OApplication::init() +{ + d = new OApplicationPrivate(); + if ( !OApplication::_instance ) + { + OApplication::_instance = this; + } + else + { + qFatal( "OApplication: Can't create more than one OApplication object. Aborting." ); + } +} + +void OApplication::setMainWidget( QWidget* widget ) +{ + showMainWidget( widget ); +} + +void OApplication::showMainWidget( QWidget* widget, bool nomax ) +{ + #ifdef Q_WS_QWS + QPEApplication::showMainWidget( widget, nomax ); + #else + QApplication::setMainWidget( widget ); + widget->show(); + #endif + widget->setCaption( _appname ); + +} diff --git a/libopie2/opiecore/oapplication.h b/libopie2/opiecore/oapplication.h new file mode 100644 index 0000000..736e786 --- a/dev/null +++ b/libopie2/opiecore/oapplication.h @@ -0,0 +1,114 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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 OAPPLICATION_H +#define OAPPLICATION_H + +#define oApp OApplication::oApplication() + +#ifdef QWS + #include <qpe/qpeapplication.h> + #define OApplicationBaseClass QPEApplication +#else + #include <qapplication.h> + #define OApplicationBaseClass QApplication +#endif + +class OApplicationPrivate; +class OConfig; + +class OApplication: public OApplicationBaseClass +{ + public: + + /** + * Constructor. Parses command-line arguments and sets the window caption. + * + * @param rAppName application name. Will be used for finding the + * associated message, icon and configuration files + * + */ + OApplication( int& argc, char** argv, const QCString& rAppName ); + /** + * Destructor. Destroys the application object and its children. + */ + virtual ~OApplication(); + + /** + * Returns the current application object. + * + * This is similar to the global @ref QApplication pointer qApp. It + * allows access to the single global OApplication object, since + * more than one cannot be created in the same application. It + * saves you the trouble of having to pass the pointer explicitly + * to every function that may require it. + * @return the current application object + */ + static const OApplication* oApplication() { return _instance; }; + + /** + * Returns the application name as given during creation. + * + * @return A reference to the application name + */ + const QCString& appName() const { return _appname; }; + + /** + * Returns the application session config object. + * + * @return A pointer to the application's instance specific + * @ref OConfig object. + * @see OConfig + */ + OConfig* config(); + + /** + * Sets the main widget - reimplemented to call showMainWidget() + * on Qt/Embedded. + */ + virtual void setMainWidget( QWidget *mainWidget ); + + /** + * Shows the main widget - reimplemented to call setMainWidget() + * on platforms other than Qt/Embedded. + */ + virtual void showMainWidget( QWidget* widget, bool nomax = false ); + + protected: + void init(); + + private: + const QCString _appname; + static OApplication* _instance; + OConfig* _config; + OApplicationPrivate* d; +}; + +#endif // OAPPLICATION_H diff --git a/libopie2/opiecore/oconfig.cpp b/libopie2/opiecore/oconfig.cpp new file mode 100644 index 0000000..40edbc7 --- a/dev/null +++ b/libopie2/opiecore/oconfig.cpp @@ -0,0 +1,201 @@ +/* + This file is part of the Opie Project + + (C) 2003 Michael Lauer <mickey@tm.informatik.uni-frankfurt.de> + Inspired by the config classes from the KDE Project which are + =. (C) 1997 Matthias Kalle Dalheimer <kalle@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. +*/ + +/* QT */ + +#include <qfont.h> +#include <qcolor.h> + +/* OPIE */ + +#include <opie2/oconfig.h> + +OConfig::OConfig( const QString &name, Domain domain ) + :Config( name, domain ) +{ +} + +OConfig::~OConfig() +{ +} + +QColor OConfig::readColorEntry( const QString& key, const QColor* pDefault ) const +{ + QColor aRetColor; + int nRed = 0, nGreen = 0, nBlue = 0; + + QString aValue = readEntry( key ); + if( !aValue.isEmpty() ) + { + if ( aValue.at(0) == '#' ) + { + aRetColor.setNamedColor(aValue); + } + else + { + bool bOK; + + // find first part (red) + int nIndex = aValue.find( ',' ); + + if( nIndex == -1 ) + { + // return a sensible default -- Bernd + if( pDefault ) + aRetColor = *pDefault; + return aRetColor; + } + + nRed = aValue.left( nIndex ).toInt( &bOK ); + + // find second part (green) + int nOldIndex = nIndex; + nIndex = aValue.find( ',', nOldIndex+1 ); + + if( nIndex == -1 ) + { + // return a sensible default -- Bernd + if( pDefault ) + aRetColor = *pDefault; + return aRetColor; + } + nGreen = aValue.mid( nOldIndex+1, + nIndex-nOldIndex-1 ).toInt( &bOK ); + + // find third part (blue) + nBlue = aValue.right( aValue.length()-nIndex-1 ).toInt( &bOK ); + + aRetColor.setRgb( nRed, nGreen, nBlue ); + } + } + else { + + if( pDefault ) + aRetColor = *pDefault; + } + + return aRetColor; +} + +// FIXME: The whole font handling has to be revised for Opie + +QFont OConfig::readFontEntry( const QString& key, const QFont* pDefault ) const +{ + /* + QFont aRetFont; + + QString aValue = readEntry( key ); + if( !aValue.isNull() ) { + if ( aValue.contains( ',' ) > 5 ) { + // KDE3 and upwards entry + if ( !aRetFont.fromString( aValue ) && pDefault ) + aRetFont = *pDefault; + } + else { + // backward compatibility with older font formats + // ### remove KDE 3.1 ? + // find first part (font family) + int nIndex = aValue.find( ',' ); + if( nIndex == -1 ){ + if( pDefault ) + aRetFont = *pDefault; + return aRetFont; + } + aRetFont.setFamily( aValue.left( nIndex ) ); + + // find second part (point size) + int nOldIndex = nIndex; + nIndex = aValue.find( ',', nOldIndex+1 ); + if( nIndex == -1 ){ + if( pDefault ) + aRetFont = *pDefault; + return aRetFont; + } + + aRetFont.setPointSize( aValue.mid( nOldIndex+1, + nIndex-nOldIndex-1 ).toInt() ); + + // find third part (style hint) + nOldIndex = nIndex; + nIndex = aValue.find( ',', nOldIndex+1 ); + + if( nIndex == -1 ){ + if( pDefault ) + aRetFont = *pDefault; + return aRetFont; + } + + aRetFont.setStyleHint( (QFont::StyleHint)aValue.mid( nOldIndex+1, nIndex-nOldIndex-1 ).toUInt() ); + + // find fourth part (char set) + nOldIndex = nIndex; + nIndex = aValue.find( ',', nOldIndex+1 ); + + if( nIndex == -1 ){ + if( pDefault ) + aRetFont = *pDefault; + return aRetFont; + } + + QString chStr=aValue.mid( nOldIndex+1, + nIndex-nOldIndex-1 ); + // find fifth part (weight) + nOldIndex = nIndex; + nIndex = aValue.find( ',', nOldIndex+1 ); + + if( nIndex == -1 ){ + if( pDefault ) + aRetFont = *pDefault; + return aRetFont; + } + + aRetFont.setWeight( aValue.mid( nOldIndex+1, + nIndex-nOldIndex-1 ).toUInt() ); + + // find sixth part (font bits) + uint nFontBits = aValue.right( aValue.length()-nIndex-1 ).toUInt(); + + aRetFont.setItalic( nFontBits & 0x01 ); + aRetFont.setUnderline( nFontBits & 0x02 ); + aRetFont.setStrikeOut( nFontBits & 0x04 ); + aRetFont.setFixedPitch( nFontBits & 0x08 ); + aRetFont.setRawMode( nFontBits & 0x20 ); + } + } + else + { + if( pDefault ) + aRetFont = *pDefault; + } + return aRetFont; + */ + return QFont("Helvetica",10); +} diff --git a/libopie2/opiecore/oconfig.h b/libopie2/opiecore/oconfig.h new file mode 100644 index 0000000..afe14b1 --- a/dev/null +++ b/libopie2/opiecore/oconfig.h @@ -0,0 +1,167 @@ +/* + This file is part of the Opie Project + + (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + Inspired by the config classes from the KDE Project which are + =. (C) 1997 Matthias Kalle Dalheimer <kalle@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 OCONFIG_H +#define OCONFIG_H + +//FIXME: Implement for X11 or reuse libqpe/Config there also? + +#include <qpe/config.h> + +class QColor; +class QFont; + +/** + * A Configuration class based on the Qtopia @ref Config class + * featuring additional handling of color and font entries + */ + +class OConfig : public Config +{ + public: + + /** + * Constructs a OConfig object. + * + * @param name A file to parse. + */ + OConfig( const QString &name, Domain domain = User ); + + /** + * Destructs the OConfig object. + * + * Writes back any dirty configuration entries, and destroys + * dynamically created objects. + */ + virtual ~OConfig(); + + /** + * Returns the name of the group in which we are + * searching for keys and from which we are retrieving entries. + * + * @return The current group. + */ + const QString& group() { return git.key(); }; + + /** + * Reads a @ref QColor entry. + * + * Read the value of an entry specified by @p pKey in the current group + * and interpret it as a color. + * + * @param pKey The key to search for. + * @param pDefault A default value (null QColor by default) returned if the + * key was not found or if the value cannot be interpreted. + * @return The value for this key. + */ + QColor readColorEntry( const QString& key, const QColor* pDefault ) const; + + /** + * Reads a @ref QFont value. + * + * Read the value of an entry specified by @p pKey in the current group + * and interpret it as a font object. + * + * @param pKey The key to search for. + * @param pDefault A default value (null QFont by default) returned if the + * key was not found or if the read value cannot be interpreted. + * @return The value for this key. + */ + QFont readFontEntry( const QString& key, const QFont* pDefault ) const; + +}; + +/** + * Helper class to facilitate working with @ref OConfig / @ref OSimpleConfig + * groups. + * + * Careful programmers always set the group of a + * @ref OConfig object to the group they want to read from + * and set it back to the old one of afterwards. This is usually + * written as: + * <pre> + * + * QString oldgroup config()->group(); + * config()->setGroup( "TheGroupThatIWant" ); + * ... + * config()->writeEntry( "Blah", "Blubb" ); + * + * config()->setGroup( oldgroup ); + * </pre> + * + * In order to facilitate this task, you can use + * OConfigGroupSaver. Simply construct such an object ON THE STACK + * when you want to switch to a new group. Then, when the object goes + * out of scope, the group will automatically be restored. If you + * want to use several different groups within a function or method, + * you can still use OConfigGroupSaver: Simply enclose all work with + * one group (including the creation of the OConfigGroupSaver object) + * in one block. + * + * @author Matthias Kalle Dalheimer <Kalle@kde.org> + * @version $Id$ + * @see OConfig + * @short Helper class for easier use of OConfig groups + */ + +class OConfigGroupSaver +{ + public: + /** + * Constructor. You pass a pointer to the OConfigBase-derived + * object you want to work with and a string indicating the _new_ + * group. + * @param config The OConfig-derived object this + * OConfigGroupSaver works on. + * @param group The new group that the config object should switch to. + */ + OConfigGroupSaver( OConfig* config, QString group ) :_config(config), _oldgroup(config->group() ) + { _config->setGroup( group ); } + + OConfigGroupSaver( OConfig* config, const char *group ) :_config(config), _oldgroup(config->group()) + { _config->setGroup( group ); } + + OConfigGroupSaver( OConfig* config, const QCString &group ) : _config(config), _oldgroup(config->group()) + { _config->setGroup( group ); } + + ~OConfigGroupSaver() { _config->setGroup( _oldgroup ); } + + OConfig* config() { return _config; }; + + private: + OConfig* _config; + QString _oldgroup; + + OConfigGroupSaver( const OConfigGroupSaver& ); + OConfigGroupSaver& operator=( const OConfigGroupSaver& ); +}; + +#endif // OCONFIG_H diff --git a/libopie2/opiecore/odebug.cpp b/libopie2/opiecore/odebug.cpp new file mode 100644 index 0000000..b4eaf2d --- a/dev/null +++ b/libopie2/opiecore/odebug.cpp @@ -0,0 +1,628 @@ +/* + This file is part of the Opie Project + (C) 2003 Michael 'Mickey' Lauer (mickey@tm.informatik.uni-frankfurt.de) + Inspired by the KDE debug classes, which are + (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) + (C) 2002 Holger Freyther (freyther@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 this header without OPIE_NO_DEBUG defined to avoid having the oDebugInfo +// functions inlined to noops (which would then conflict with their definition here). + +#include <opie2/odebug.h> + +#ifdef OPIE_NO_DEBUG +#undef odDebug +#undef odBacktrace +#endif + +/* OPIE */ + +#include <opie2/oapplication.h> +#include <opie2/oglobalsettings.h> +#include <opie2/oconfig.h> + +/* QT */ + +#include <qbrush.h> +#include <qdatetime.h> +#include <qfile.h> +#include <qhostaddress.h> +#include <qmessagebox.h> +#include <qintdict.h> +#include <qpoint.h> +#include <qrect.h> +#include <qregion.h> +#include <qsize.h> +#include <qsocketdevice.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qtextstream.h> + +/* UNIX */ + +#include <stdlib.h> // abort +#include <unistd.h> // getpid +#include <stdarg.h> // vararg stuff +#include <ctype.h> // isprint +#include <syslog.h> +#include <errno.h> +#include <string.h> + +#ifndef OPIE_NO_BACKTRACE +#include <execinfo.h> +#endif + + +/*====================================================================================== + * debug levels + *======================================================================================*/ + +enum DebugLevels { + ODEBUG_INFO = 0, + ODEBUG_WARN = 1, + ODEBUG_ERROR = 2, + ODEBUG_FATAL = 3 +}; + +/*====================================================================================== + * oDebug private data + *======================================================================================*/ + +/*====================================================================================== + * the main debug function + *======================================================================================*/ + +static void oDebugBackend( unsigned short level, unsigned int area, const char *data) +{ + //qDebug( "oDebugBackend: Level=%d, Area=%d, Data=%s", level, area, data ); + + // ML: OPIE doesn't use areacodes at the moment. See the KDE debug classes for an + // ML: example use. I think it's not necessary to implement such a strategy here. + // ML: Comments? + + int priority = 0; + QString caption; + QString lev; + switch( level ) + { + case ODEBUG_INFO: lev = "(Info)"; caption = "Info"; priority = LOG_INFO; break; + case ODEBUG_WARN: lev = "(Warn)"; caption = "Warning"; priority = LOG_WARNING; break; + case ODEBUG_FATAL: lev = "(Fatal)"; caption = "Fatal Error"; priority = LOG_CRIT; break; + default: qDebug( "oDebugBackend: Warning: Unknown debug level! - defaulting to ODEBUG_ERROR." ); + case ODEBUG_ERROR: lev = "(Error)"; caption = "Error"; priority = LOG_ERR; break; + } + + short output = OGlobalSettings::debugMode(); + if (!oApp && (output == 1)) + { + qDebug( "oDebugBackend: Warning: no oapplication object - can't use MsgBox" ); + output = 2; // need an application object to use MsgBox + } + + QString areaName = (oApp) ? oApp->appName() : "<unknown>"; + + // Output + switch( output ) + { + case -1: // ignore + { + return; + } + case 0: // File + { + QString outputFilename = OGlobalSettings::debugOutput(); + + const int BUFSIZE = 4096; + char buf[BUFSIZE] = ""; + buf[BUFSIZE-1] = '\0'; + int nSize; + + nSize = snprintf( buf, BUFSIZE-1, "%s: %s", (const char*) areaName, data); + + QFile outputFile( outputFilename ); + if ( outputFile.open( IO_WriteOnly | IO_Append ) ) + { + if ( ( nSize == -1 ) || ( nSize >= BUFSIZE ) ) + { + outputFile.writeBlock( buf, BUFSIZE-1 ); + } + else + { + outputFile.writeBlock( buf, nSize ); + } + } + else + { + qDebug( "ODebug: can't write to file '%s' (%s)", (const char*) outputFilename, strerror(errno) ); + } + break; + } // automatic close of file here + + case 1: // Message Box + { + // Since we are in opiecore here, we cannot use OMsgBox and use + // QMessageBox instead + + caption += QString("(") + areaName + ")"; + QMessageBox::warning( 0L, caption, data, ("&OK") ); // tr? + break; + } + + case 2: // Shell + { + FILE *output = stderr; + fprintf( output, "%s: ", (const char*) areaName ); + fputs( data, output); + break; + } + + case 3: // syslog + { + syslog( priority, "%s", data); + break; + } + + case 4: // socket + { + QString destination = OGlobalSettings::debugOutput(); + if ( destination && destination.find(":") != -1 ) + { + QString host = destination.left( destination.find(":") ); + QString port = destination.right( destination.length()-host.length()-1 ); + QHostAddress addr; + addr.setAddress( host ); + // TODO: sanity check the address + QString line; + line.sprintf( "%s: %s", (const char*) areaName, (const char*) data ); + QSocketDevice s( QSocketDevice::Datagram ); + int result = s.writeBlock( (const char*) line, line.length(), addr, port.toInt() ); + if ( result == -1 ) + { + qDebug( "ODebug: can't send to address '%s:%d' (%s)", (const char*) host, port.toInt(), strerror(errno) ); + } + } + break; + } + } + + // check if we should abort + + /* + + if( ( nLevel == ODEBUG_FATAL ) + && ( !oDebug_data->config || oDebug_data->config->readNumEntry( "AbortFatal", 1 ) ) ) + abort(); + + */ +} + +/*====================================================================================== + * odbgstream + *======================================================================================*/ + +odbgstream& perror( odbgstream &s) +{ + return s << QString::fromLocal8Bit(strerror(errno)); +} + +odbgstream odDebug(int area) +{ + return odbgstream(area, ODEBUG_INFO); +} +odbgstream odDebug(bool cond, int area) +{ + if (cond) return odbgstream(area, ODEBUG_INFO); + else return odbgstream(0, 0, false); +} + +odbgstream odError(int area) +{ + return odbgstream("ERROR: ", area, ODEBUG_ERROR); +} + +odbgstream odError(bool cond, int area) +{ + if (cond) return odbgstream("ERROR: ", area, ODEBUG_ERROR); else return odbgstream(0,0,false); +} + +odbgstream odWarning(int area) +{ + return odbgstream("WARNING: ", area, ODEBUG_WARN); +} + +odbgstream odWarning(bool cond, int area) +{ + if (cond) return odbgstream("WARNING: ", area, ODEBUG_WARN); else return odbgstream(0,0,false); +} + +odbgstream odFatal(int area) +{ + return odbgstream("FATAL: ", area, ODEBUG_FATAL); +} + +odbgstream odFatal(bool cond, int area) +{ + if (cond) return odbgstream("FATAL: ", area, ODEBUG_FATAL); else return odbgstream(0,0,false); +} + +odbgstream::odbgstream(unsigned int _area, unsigned int _level, bool _print) + :area(_area), level(_level), print(_print) +{ +} + + +odbgstream::odbgstream(const char * initialString, unsigned int _area, unsigned int _level, bool _print) + :output(QString::fromLatin1(initialString)), area(_area), level(_level), print(_print) +{ +} + + +odbgstream::odbgstream(odbgstream &str) + :output(str.output), area(str.area), level(str.level), print(str.print) +{ + str.output.truncate(0); +} + + +odbgstream::odbgstream(const odbgstream &str) + :output(str.output), area(str.area), level(str.level), print(str.print) +{ +} + +odbgstream& odbgstream::operator<<(bool i) +{ + if (!print) return *this; + output += QString::fromLatin1(i ? "true" : "false"); + return *this; +} + + +odbgstream& odbgstream::operator<<(short i) +{ + if (!print) return *this; + QString tmp; tmp.setNum(i); output += tmp; + return *this; +} + + +odbgstream& odbgstream::operator<<(unsigned short i) +{ + if (!print) return *this; + QString tmp; tmp.setNum(i); output += tmp; + return *this; +} + + +odbgstream& odbgstream::operator<<(unsigned char i) +{ + return operator<<( static_cast<char>( i ) ); +} + + +odbgstream& odbgstream::operator<<(int i) +{ + if (!print) return *this; + QString tmp; tmp.setNum(i); output += tmp; + return *this; +} + + +odbgstream& odbgstream::operator<<(unsigned int i) +{ + if (!print) return *this; + QString tmp; tmp.setNum(i); output += tmp; + return *this; +} + + +odbgstream& odbgstream::operator<<(long i) +{ + if (!print) return *this; + QString tmp; tmp.setNum(i); output += tmp; + return *this; +} + + +odbgstream& odbgstream::operator<<(unsigned long i) +{ + if (!print) return *this; + QString tmp; tmp.setNum(i); output += tmp; + return *this; +} + + +odbgstream& odbgstream::operator<<(const QString& string) +{ + if (!print) return *this; + output += string; + if (output.at(output.length() -1 ) == '\n') + flush(); + return *this; +} + + +odbgstream& odbgstream::operator<<(const char *string) +{ + if (!print) return *this; + output += QString::fromUtf8(string); + if (output.at(output.length() - 1) == '\n') + flush(); + return *this; +} + + +odbgstream& odbgstream::operator<<(const QCString& string) +{ + *this << string.data(); + return *this; +} + + +odbgstream& odbgstream::operator<<(const void * p) +{ + form("%p", p); + return *this; +} + +odbgstream& odbgstream::operator<<(double d) +{ + QString tmp; tmp.setNum(d); output += tmp; + return *this; +} + +/* +odbgstream::odbgstream &form(const char *format, ...) +#ifdef __GNUC__ + __attribute__ ( ( format ( printf, 2, 3 ) ) ) +#endif + ; +*/ + +void odbgstream::flush() +{ + if ( output.isEmpty() || !print ) + { + return; + } + else + { + oDebugBackend( level, area, output.local8Bit().data() ); + output = QString::null; + } +} + +odbgstream& odbgstream::form(const char *format, ...) +{ + char buf[4096]; + va_list arguments; + va_start( arguments, format ); + buf[sizeof(buf)-1] = '\0'; + vsnprintf( buf, sizeof(buf)-1, format, arguments ); + va_end(arguments); + *this << buf; + return *this; +} + +odbgstream::~odbgstream() +{ + if (!output.isEmpty()) + { + fprintf(stderr, "ASSERT: debug output not ended with \\n\n"); + *this << "\n"; + } +} + +odbgstream& odbgstream::operator<<(char ch) +{ + if (!print) return *this; + if (!isprint(ch)) + { + output += "\\x" + QString::number( static_cast<uint>( ch ) + 0x100, 16 ).right(2); + } + else + { + output += ch; + if (ch == '\n') flush(); + } + return *this; +} + +odbgstream& odbgstream::operator<<( QWidget* widget ) +{ + QString string, temp; + // ----- + if(widget==0) + { + string=(QString)"[Null pointer]"; + } else + { + temp.setNum((ulong)widget, 16); + string=(QString)"["+widget->className()+" pointer " + "(0x" + temp + ")"; + if(widget->name(0)==0) + { + string += " to unnamed widget, "; + } else + { + string += (QString)" to widget " + widget->name() + ", "; + } + string += "geometry=" + + QString().setNum(widget->width()) + + "x"+QString().setNum(widget->height()) + + "+"+QString().setNum(widget->x()) + + "+"+QString().setNum(widget->y()) + + "]"; + } + if (!print) return *this; + + output += string; + if (output.at(output.length()-1) == '\n') + { + flush(); + } + return *this; +} + +/* + * either use 'output' directly and do the flush if needed + * or use the QString operator which calls the char* operator + * + */ +odbgstream& odbgstream::operator<<( const QDateTime& time) +{ + *this << time.toString(); + return *this; +} + + +odbgstream& odbgstream::operator<<( const QDate& date) +{ + *this << date.toString(); + + return *this; +} + + +odbgstream& odbgstream::operator<<( const QTime& time ) +{ + *this << time.toString(); + return *this; +} + + +odbgstream& odbgstream::operator<<( const QPoint& p ) +{ + *this << "(" << p.x() << ", " << p.y() << ")"; + return *this; +} + + +odbgstream& odbgstream::operator<<( const QSize& s ) +{ + *this << "[" << s.width() << "x" << s.height() << "]"; + return *this; +} + + +odbgstream& odbgstream::operator<<( const QRect& r ) +{ + *this << "[" << r.left() << ", " << r.top() << " - " << r.right() << ", " << r.bottom() << "]"; + return *this; +} + + +odbgstream& odbgstream::operator<<( const QRegion& reg ) +{ + /* Qt2 doesn't have a QMemArray... :( + *this << "[ "; + QMemArray<QRect>rs=reg.rects(); + for (uint i=0;i<rs.size();++i) + *this << QString("[%1, %2 - %3, %4] ").arg(rs[i].left()).arg(rs[i].top()).arg(rs[i].right()).arg(rs[i].bottom() ) ; + *this <<"]"; + */ + return *this; +} + + +odbgstream& odbgstream::operator<<( const QStringList& l ) +{ + *this << "("; + *this << l.join(","); + *this << ")"; + + return *this; +} + + +odbgstream& odbgstream::operator<<( const QColor& c ) +{ + if ( c.isValid() ) + *this << c.name(); + else + *this << "(invalid/default)"; + return *this; +} + + +odbgstream& odbgstream::operator<<( const QBrush& b) +{ + static const char* const s_brushStyles[] = { + "NoBrush", "SolidPattern", "Dense1Pattern", "Dense2Pattern", "Dense3Pattern", + "Dense4Pattern", "Dense5Pattern", "Dense6Pattern", "Dense7Pattern", + "HorPattern", "VerPattern", "CrossPattern", "BDiagPattern", "FDiagPattern", + "DiagCrossPattern" }; + + *this <<"[ style: "; + *this <<s_brushStyles[ b.style() ]; + *this <<" color: "; + // can't use operator<<(str, b.color()) because that terminates a odbgstream (flushes) + if ( b.color().isValid() ) + *this <<b.color().name() ; + else + *this <<"(invalid/default)"; + if ( b.pixmap() ) + *this <<" has a pixmap"; + *this <<" ]"; + return *this; +} + + + +QString odBacktrace( int levels ) +{ + QString s; +#ifndef OPIE_NO_BACKTRACE + void* trace[256]; + int n = backtrace(trace, 256); + char** strings = backtrace_symbols (trace, n); + + if ( levels != -1 ) + n = QMIN( n, levels ); + s = "[\n"; + + for (int i = 0; i < n; ++i) + s += QString::number(i) + + QString::fromLatin1(": ") + + QString::fromLatin1(strings[i]) + QString::fromLatin1("\n"); + s += "]\n"; + free (strings); +#endif + return s; +} + +void odClearDebugConfig() +{ + /* + delete oDebug_data->config; + oDebug_data->config = 0; + */ +} + +#ifdef OPIE_NO_DEBUG +#define odDebug ondDebug +#define odBacktrace ondBacktrace +#endif diff --git a/libopie2/opiecore/odebug.h b/libopie2/opiecore/odebug.h new file mode 100644 index 0000000..85941fd --- a/dev/null +++ b/libopie2/opiecore/odebug.h @@ -0,0 +1,474 @@ +/* + This file is part of the Opie Project + (C) 2003 Michael 'Mickey' Lauer (mickey@tm.informatik.uni-frankfurt.de) + Inspired by the KDE debug classes, which are + (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) + (C) 2002 Holger Freyther (freyther@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 ODEBUG_H +#define ODEBUG_H + +#include <qstring.h> + +class QWidget; +class QDateTime; +class QDate; +class QTime; +class QPoint; +class QSize; +class QRect; +class QRegion; +class QStringList; +class QColor; +class QBrush; + +class odbgstream; +class ondbgstream; + +#ifdef __GNUC__ +#define o_funcinfo "[" << __PRETTY_FUNCTION__ << "] " +#else +#define o_funcinfo "[" << __FILE__ << ":" << __LINE__ << "] " +#endif + +#define o_lineinfo "[" << __FILE__ << ":" << __LINE__ << "] " + +#define owarn odWarning() +#define oerr odError() +#define odebug odDebug() +#define ofatal odFatal() +#define oendl "\n" + +class odbgstreamprivate; +/** + * odbgstream is a text stream that allows you to print debug messages. + * Using the overloaded "<<" operator you can send messages. Usually + * you do not create the odbgstream yourself, but use @ref odDebug() (odebug) + * @ref odWarning() (owarn), @ref odError() (oerr) or @ref odFatal (ofatal) to obtain one. + * + * Example: + * <pre> + * int i = 5; + * odebug << "The value of i is " << i << oendl; + * </pre> + * @see odbgstream + */ + +/*====================================================================================== + * odbgstream + *======================================================================================*/ + +class odbgstream +{ + public: + /** + * @internal + */ + odbgstream(unsigned int _area, unsigned int _level, bool _print = true); + odbgstream(const char * initialString, unsigned int _area, unsigned int _level, bool _print = true); + odbgstream(odbgstream &str); + odbgstream(const odbgstream &str); + virtual ~odbgstream(); + + /** + * Prints the given value. + * @param i the boolean to print (as "true" or "false") + * @return this stream + */ + odbgstream &operator<<(bool i); + /** + * Prints the given value. + * @param i the short to print + * @return this stream + */ + odbgstream &operator<<(short i); + /** + * Prints the given value. + * @param i the unsigned short to print + * @return this stream + */ + odbgstream &operator<<(unsigned short i); + /** + * Prints the given value. + * @param i the char to print + * @return this stream + */ + odbgstream &operator<<(char i); + /** + * Prints the given value. + * @param i the unsigned char to print + * @return this stream + */ + odbgstream &operator<<(unsigned char i); + /** + * Prints the given value. + * @param i the int to print + * @return this stream + */ + odbgstream &operator<<(int i); + /** + * Prints the given value. + * @param i the unsigned int to print + * @return this stream + */ + odbgstream &operator<<(unsigned int i); + /** + * Prints the given value. + * @param i the long to print + * @return this stream + */ + odbgstream &operator<<(long i); + /** + * Prints the given value. + * @param i the unsigned long to print + * @return this stream + */ + odbgstream &operator<<(unsigned long i); + /** + * Flushes the output. + */ + virtual void flush(); + /** + * Prints the given value. + * @param string the string to print + * @return this stream + */ + odbgstream &operator<<(const QString& string); + /** + * Prints the given value. + * @param string the string to print + * @return this stream + */ + odbgstream &operator<<(const char *string); + /** + * Prints the given value. + * @param string the string to print + * @return this stream + */ + odbgstream &operator<<(const QCString& string); + /** + * Prints the given value. + * @param p a pointer to print (in number form) + * @return this stream + */ + odbgstream& operator<<(const void * p); + /** + * Prints the given value. + * @param d the double to print + * @return this stream + */ + odbgstream& operator<<(double d); + /** + * Prints the string @p format which can contain + * printf-style formatted values. + * @param format the printf-style format + * @return this stream + */ + odbgstream &form(const char *format, ...); + /** Operator to print out basic information about a QWidget. + * Output of class names only works if the class is moc'ified. + * @param widget the widget to print + * @return this stream + */ + odbgstream& operator<< (QWidget* widget); + + /** + * Prints the given value. + * @param dateTime the datetime to print + * @return this stream + */ + odbgstream& operator<< ( const QDateTime& dateTime ); + + /** + * Prints the given value. + * @param date the date to print + * @return this stream + */ + odbgstream& operator<< ( const QDate& date ); + + /** + * Prints the given value. + * @param time the time to print + * @return this stream + */ + odbgstream& operator<< ( const QTime& time ); + + /** + * Prints the given value. + * @param point the point to print + * @return this stream + */ + odbgstream& operator<< ( const QPoint& point ); + + /** + * Prints the given value. + * @param size the QSize to print + * @return this stream + */ + odbgstream& operator<< ( const QSize& size ); + + /** + * Prints the given value. + * @param rect the QRect to print + * @return this stream + */ + odbgstream& operator<< ( const QRect& rect); + + /** + * Prints the given value. + * @param region the QRegion to print + * @return this stream + */ + odbgstream& operator<< ( const QRegion& region); + + /** + * Prints the given value. + * @param list the stringlist to print + * @return this stream + */ + odbgstream& operator<< ( const QStringList& list); + + /** + * Prints the given value. + * @param color the color to print + * @return this stream + */ + odbgstream& operator<< ( const QColor& color); + + /** + * Prints the given value. + * @param brush the brush to print + * @return this stream + */ + odbgstream& operator<< ( const QBrush& brush ); + + private: + QString output; + unsigned int area, level; + bool print; + odbgstreamprivate* d; +}; + +/** + * Prints an "\n". + * @param s the debug stream to write to + * @return the debug stream (@p s) + */ +inline odbgstream& endl( odbgstream &s) { s << "\n"; return s; } +/** + * Flushes the stream. + * @param s the debug stream to write to + * @return the debug stream (@p s) + */ +inline odbgstream& flush( odbgstream &s) { s.flush(); return s; } + +odbgstream &perror( odbgstream &s); + +/** + * ondbgstream is a dummy variant of @ref odbgstream. All functions do + * nothing. + * @see ondDebug() + */ +class ondbgstream { + public: + /// Empty constructor. + ondbgstream() {} + ~ondbgstream() {} + /** + * Does nothing. + * @return this stream + */ + ondbgstream &operator<<(short int ) { return *this; } + /** + * Does nothing. + * @return this stream + */ + ondbgstream &operator<<(unsigned short int ) { return *this; } + /** + * Does nothing. + * @return this stream + */ + ondbgstream &operator<<(char ) { return *this; } + /** + * Does nothing. + * @return this stream + */ + ondbgstream &operator<<(unsigned char ) { return *this; } + /** + * Does nothing. + * @return this stream + */ + ondbgstream &operator<<(int ) { return *this; } + /** + * Does nothing. + * @return this stream + */ + ondbgstream &operator<<(unsigned int ) { return *this; } + /** + * Does nothing. + */ + void flush() {} + /** + * Does nothing. + * @return this stream + */ + ondbgstream &operator<<(const QString& ) { return *this; } + /** + * Does nothing. + * @return this stream + */ + ondbgstream &operator<<(const QCString& ) { return *this; } + /** + * Does nothing. + * @return this stream + */ + ondbgstream &operator<<(const char *) { return *this; } + /** + * Does nothing. + * @return this stream + */ + ondbgstream& operator<<(const void *) { return *this; } + /** + * Does nothing. + * @return this stream + */ + ondbgstream& operator<<(void *) { return *this; } + /** + * Does nothing. + * @return this stream + */ + ondbgstream& operator<<(double) { return *this; } + /** + * Does nothing. + * @return this stream + */ + ondbgstream& operator<<(long) { return *this; } + /** + * Does nothing. + * @return this stream + */ + ondbgstream& operator<<(unsigned long) { return *this; } + /** + * Does nothing. + * @return this stream + */ + ondbgstream& operator << (QWidget*) { return *this; } + /** + * Does nothing. + * @return this stream + */ + ondbgstream &form(const char *, ...) { return *this; } + + ondbgstream& operator<<( const QDateTime& ) { return *this; } + ondbgstream& operator<<( const QDate& ) { return *this; } + ondbgstream& operator<<( const QTime& ) { return *this; } + ondbgstream& operator<<( const QPoint & ) { return *this; } + ondbgstream& operator<<( const QSize & ) { return *this; } + ondbgstream& operator<<( const QRect & ) { return *this; } + ondbgstream& operator<<( const QRegion & ) { return *this; } + ondbgstream& operator<<( const QStringList & ) { return *this; } + ondbgstream& operator<<( const QColor & ) { return *this; } + ondbgstream& operator<<( const QBrush & ) { return *this; } +}; + +/*====================================================================================== + * related functions + *======================================================================================*/ + +/** + * Does nothing. + * @param a stream + * @return the given @p s + */ +inline ondbgstream& endl( ondbgstream & s) { return s; } +/** + * Does nothing. + * @param a stream + * @return the given @p s + */ +inline ondbgstream& flush( ondbgstream & s) { return s; } +inline ondbgstream& perror( ondbgstream & s) { return s; } + +/** + * Returns a debug stream. You can use it to print debug + * information. + * @param area an id to identify the output, 0 for default + */ +odbgstream odDebug(int area = 0); +odbgstream odDebug(bool cond, int area = 0); +/** + * Returns a backtrace. + * @param levels the number of levels (-1 for unlimited) of the backtrace + * @return a backtrace + */ +QString odBacktrace(int levels = -1); +/** + * Returns a dummy debug stream. The stream does not print anything. + * @param area an id to identify the output, 0 for default + * @see odDebug() + */ +inline ondbgstream ondDebug(int = 0) { return ondbgstream(); } +inline ondbgstream ondDebug(bool , int = 0) { return ondbgstream(); } +inline QString ondBacktrace() { return QString::null; } +inline QString ondBacktrace(int) { return QString::null; } + +/** + * Returns a warning stream. You can use it to print warning + * information. + * @param area an id to identify the output, 0 for default + */ +odbgstream odWarning(int area = 0); +odbgstream odWarning(bool cond, int area = 0); +/** + * Returns an error stream. You can use it to print error + * information. + * @param area an id to identify the output, 0 for default + */ +odbgstream odError(int area = 0); +odbgstream odError(bool cond, int area = 0); +/** + * Returns a fatal error stream. You can use it to print fatal error + * information. + * @param area an id to identify the output, 0 for default + */ +odbgstream odFatal(int area = 0); +odbgstream odFatal(bool cond, int area = 0); + +/** + * Deletes the odebugrc cache and therefore forces KDebug to reread the + * config file + */ +void odClearDebugConfig(); + +#ifdef OPIE_NO_DEBUG +#define odDebug ondDebug +#define odBacktrace ondBacktrace +#endif + +#endif + diff --git a/libopie2/opiecore/oglobal.cpp b/libopie2/opiecore/oglobal.cpp new file mode 100644 index 0000000..2eb4108 --- a/dev/null +++ b/libopie2/opiecore/oglobal.cpp @@ -0,0 +1,36 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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/oglobal.h> + +OConfig* OGlobal::config() +{ + return &globalconfig; +} diff --git a/libopie2/opiecore/oglobal.h b/libopie2/opiecore/oglobal.h new file mode 100644 index 0000000..8345c6a --- a/dev/null +++ b/libopie2/opiecore/oglobal.h @@ -0,0 +1,48 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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 OGLOBAL_H +#define OGLOBAL_H + +#include <qpe/global.h> +#include <opie2/oconfig.h> + +static OConfig globalconfig = OConfig( "global" ); + +//FIXME: Is it wise or even necessary to inherit OGlobal from Global? + +class OGlobal : public Global +{ + public: + + static OConfig* config(); +}; + +#endif // OGLOBAL_H diff --git a/libopie2/opiecore/oglobalsettings.cpp b/libopie2/opiecore/oglobalsettings.cpp new file mode 100644 index 0000000..184ee69 --- a/dev/null +++ b/libopie2/opiecore/oglobalsettings.cpp @@ -0,0 +1,547 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael Lauer <mickey@tm.informatik.uni-frankfurt.de> + Inspired by the KDE globalsettings which are + Copyright (C) 2000 David Faure <faure@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. +*/ + +/* OPIE */ + +#include <opie2/oglobalsettings.h> +#include <opie2/oconfig.h> +#include <opie2/oglobal.h> + +/* QT */ + +#include <qdir.h> +#include <qpixmap.h> +#include <qfontinfo.h> + +/* UNIX */ + +#include <stdlib.h> + +QString* OGlobalSettings::s_desktopPath = 0; +QString* OGlobalSettings::s_autostartPath = 0; +QString* OGlobalSettings::s_trashPath = 0; +QString* OGlobalSettings::s_documentPath = 0; +QFont *OGlobalSettings::_generalFont = 0; +QFont *OGlobalSettings::_fixedFont = 0; +QFont *OGlobalSettings::_toolBarFont = 0; +QFont *OGlobalSettings::_menuFont = 0; +QFont *OGlobalSettings::_windowTitleFont = 0; +QFont *OGlobalSettings::_taskbarFont = 0; + +QColor *OGlobalSettings::OpieGray = 0; +QColor *OGlobalSettings::OpieHighlight = 0; +QColor *OGlobalSettings::OpieAlternate = 0; + +OGlobalSettings::OMouseSettings *OGlobalSettings::s_mouseSettings = 0; + +//FIXME: Add manipulators to the accessors + +int OGlobalSettings::dndEventDelay() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, "General" ); + return c->readNumEntry("DndDelay", 2); +} + +bool OGlobalSettings::singleClick() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, "OPIE" ); + return c->readBoolEntry("SingleClick", OPIE_DEFAULT_SINGLECLICK); +} + +bool OGlobalSettings::insertTearOffHandle() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, "OPIE" ); + return c->readBoolEntry("InsertTearOffHandle", OPIE_DEFAULT_INSERTTEAROFFHANDLES); +} + +bool OGlobalSettings::changeCursorOverIcon() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, "OPIE" ); + return c->readBoolEntry("ChangeCursor", OPIE_DEFAULT_CHANGECURSOR); +} + +bool OGlobalSettings::visualActivate() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, "OPIE" ); + return c->readBoolEntry("VisualActivate", OPIE_DEFAULT_VISUAL_ACTIVATE); +} + +unsigned int OGlobalSettings::visualActivateSpeed() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, "OPIE" ); + return + c->readNumEntry( + "VisualActivateSpeed", + OPIE_DEFAULT_VISUAL_ACTIVATE_SPEED + ); +} + +int OGlobalSettings::autoSelectDelay() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, "OPIE" ); + return c->readNumEntry("AutoSelectDelay", OPIE_DEFAULT_AUTOSELECTDELAY); +} + +OGlobalSettings::Completion OGlobalSettings::completionMode() +{ + int completion; + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, "General" ); + completion = c->readNumEntry("completionMode", -1); + if ((completion < (int) CompletionNone) || + (completion > (int) CompletionPopupAuto)) + { + completion = (int) CompletionPopup; // Default + } + return (Completion) completion; +} + + +bool OGlobalSettings::showContextMenusOnPress () +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs (c, "ContextMenus"); + + return cgs.config()->readBoolEntry("ShowOnPress", true); +} + + +int OGlobalSettings::contextMenuKey () +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs (c, "Shortcuts"); + + //OShortcut cut (cgs.config()->readEntry ("PopupMenuContext", "Menu")); + //return cut.keyCodeQt(); + + return 0; // FIXME +} + + +OGlobalSettings::Debug OGlobalSettings::debugMode() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, "General" ); + int debug = c->readNumEntry( "debugMode", -1 ); + if ( (debug < (int) DebugNone) || (debug > (int) DebugSocket) ) + { + debug = (int) DebugStdErr; // Default + } + return (Debug) debug; +} + + +QString OGlobalSettings::debugOutput() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, "General" ); + QString deflt = QString::null; + switch( debugMode() ) + { + case DebugNone: break; // no additional information needed + case DebugFiles: deflt = "/var/log/opiedebug.log"; break; // file to save output in + case DebugMsgBox: break; // no additional information needed + case DebugStdErr: break; // no additional information needed + case DebugSysLog: break; // no additional information needed + case DebugSocket: deflt = "127.0.0.1:8913"; break; // address to send packets to + } + + return c->readEntry( "debugOutput"+ QString::number(debugMode()), deflt ); +} + + +QColor OGlobalSettings::toolBarHighlightColor() +{ + initColors(); + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("Toolbar style") ); + return c->readColorEntry("HighlightColor", OpieHighlight); +} + +QColor OGlobalSettings::inactiveTitleColor() +{ + if (!OpieGray) OpieGray = new QColor(220, 220, 220); + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("WM") ); + return c->readColorEntry( "inactiveBackground", OpieGray ); +} + +QColor OGlobalSettings::inactiveTextColor() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("WM") ); + return c->readColorEntry( "inactiveForeground", &Qt::darkGray ); +} + +QColor OGlobalSettings::activeTitleColor() +{ + initColors(); + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("WM") ); + return c->readColorEntry( "activeBackground", OpieHighlight); +} + +QColor OGlobalSettings::activeTextColor() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("WM") ); + return c->readColorEntry( "activeForeground", &Qt::white ); +} + +int OGlobalSettings::contrast() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("OPIE") ); + return c->readNumEntry( "contrast", 7 ); +} + +// following functions should work in OPIE - how to sync with appearance changes? + +QColor OGlobalSettings::baseColor() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("Appearance") ); + return c->readColorEntry( "Base", &Qt::white ); +} + +QColor OGlobalSettings::textColor() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("Appearance") ); + return c->readColorEntry( "Text", &Qt::black ); +} + +QColor OGlobalSettings::highlightedTextColor() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("Appearance") ); + return c->readColorEntry( "HighlightedText", &Qt::white ); +} + +QColor OGlobalSettings::highlightColor() +{ + initColors(); + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("Appearance") ); + return c->readColorEntry( "Highlight", OpieHighlight ); +} + +QColor OGlobalSettings::alternateBackgroundColor() +{ + initColors(); + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("Appearance") ); + *OpieAlternate = calculateAlternateBackgroundColor( baseColor() ); + return c->readColorEntry( "alternateBackground", OpieAlternate ); +} + +QColor OGlobalSettings::calculateAlternateBackgroundColor(const QColor& base) +{ + if (base == Qt::white) + return QColor(238,246,255); + else + { + int h, s, v; + base.hsv( &h, &s, &v ); + if (v > 128) + return base.dark(106); + else if (base != Qt::black) + return base.light(110); + + return QColor(32,32,32); + } +} + +QColor OGlobalSettings::linkColor() +{ + initColors(); + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("Appearance") ); + return c->readColorEntry( "linkColor", OpieGray ); +} + +QColor OGlobalSettings::visitedLinkColor() +{ + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("Appearance") ); + return c->readColorEntry( "visitedLinkColor", &Qt::magenta ); +} + +// FIXME: font stuff currently uses a different format in OPIE, so the +// functions below are not yet applicable. The whole font stuff for OPIE +// has to be revised anyway + +QFont OGlobalSettings::generalFont() +{ + if (_generalFont) + return *_generalFont; + + _generalFont = new QFont("helvetica", 10); + _generalFont->setPixelSize(10); + _generalFont->setStyleHint(QFont::SansSerif); + + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("Appearance") ); + *_generalFont = c->readFontEntry("font", _generalFont); + + return *_generalFont; +} + +QFont OGlobalSettings::fixedFont() +{ + if (_fixedFont) + return *_fixedFont; + + _fixedFont = new QFont("courier", 12); + _fixedFont->setPixelSize(12); + _fixedFont->setStyleHint(QFont::TypeWriter); + + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("General") ); + *_fixedFont = c->readFontEntry("fixed", _fixedFont); + + return *_fixedFont; +} + +QFont OGlobalSettings::toolBarFont() +{ + if(_toolBarFont) + return *_toolBarFont; + + _toolBarFont = new QFont("helvetica", 10); + _toolBarFont->setPixelSize(10); + _toolBarFont->setStyleHint(QFont::SansSerif); + + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("General") ); + *_toolBarFont = c->readFontEntry("toolBarFont", _toolBarFont); + + return *_toolBarFont; +} + +QFont OGlobalSettings::menuFont() +{ + if(_menuFont) + return *_menuFont; + + _menuFont = new QFont("helvetica", 12); + _menuFont->setPixelSize(12); + _menuFont->setStyleHint(QFont::SansSerif); + + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("General") ); + *_menuFont = c->readFontEntry("menuFont", _menuFont); + + return *_menuFont; +} + +QFont OGlobalSettings::windowTitleFont() +{ + if(_windowTitleFont) + return *_windowTitleFont; + + _windowTitleFont = new QFont("helvetica", 12, QFont::Bold); + _windowTitleFont->setPixelSize(12); + _windowTitleFont->setStyleHint(QFont::SansSerif); + + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("WM") ); + *_windowTitleFont = c->readFontEntry("activeFont", _windowTitleFont); // inconsistency + + return *_windowTitleFont; +} + +QFont OGlobalSettings::taskbarFont() +{ + if(_taskbarFont) + return *_taskbarFont; + + _taskbarFont = new QFont("helvetica", 8); + _taskbarFont->setPixelSize(8); + _taskbarFont->setStyleHint(QFont::SansSerif); + + OConfig *c = OGlobal::config(); + OConfigGroupSaver cgs( c, QString::fromLatin1("General") ); + *_taskbarFont = c->readFontEntry("taskbarFont", _taskbarFont); + + return *_taskbarFont; +} + +// FIXME: the whole path stuff has to be revised for OPIE + +void OGlobalSettings::initStatic() // should be called initPaths(). Don't put anything else here. +{ + if ( s_desktopPath != 0 ) + return; + + s_desktopPath = new QString(); + s_autostartPath = new QString(); + s_trashPath = new QString(); + s_documentPath = new QString(); + + OConfig *config = OGlobal::config(); + //bool dollarExpansion = config->isDollarExpansion(); + //config->setDollarExpansion(true); + OConfigGroupSaver cgs( config, "Paths" ); + + // Desktop Path + *s_desktopPath = QDir::homeDirPath() + "/" + "Desktop" + "/"; + *s_desktopPath = config->readEntry( "Desktop", *s_desktopPath); + if ( (*s_desktopPath)[0] != '/' ) + s_desktopPath->prepend( QDir::homeDirPath() + "/" ); + *s_desktopPath = QDir::cleanDirPath( *s_desktopPath ); + if ( s_desktopPath->right(1) != "/") + *s_desktopPath += "/"; + + // Trash Path + *s_trashPath = *s_desktopPath + QObject::tr("Trash") + "/"; + *s_trashPath = config->readEntry( "Trash" , *s_trashPath); + if ( (*s_trashPath)[0] != '/' ) + s_trashPath->prepend( QDir::homeDirPath() + "/" ); + *s_trashPath = QDir::cleanDirPath( *s_trashPath ); + if ( s_trashPath->right(1) != "/") + *s_trashPath += "/"; + // We need to save it in any case, in case the language changes later on, + if ( !config->hasKey( "Trash" ) ) + { + //config->writePathEntry( "Trash", *s_trashPath, true, true ); + config->writeEntry( "Trash", *s_trashPath ); + //config->sync(); + } + +/* // Autostart Path + *s_autostartPath = OGlobal::dirs()->localkdedir() + "Autostart" + "/"; + *s_autostartPath = config->readEntry( "Autostart" , *s_autostartPath); + if ( (*s_autostartPath)[0] != '/' ) + s_autostartPath->prepend( QDir::homeDirPath() + "/" ); + *s_autostartPath = QDir::cleanDirPath( *s_autostartPath ); + if ( s_autostartPath->right(1) != "/") + *s_autostartPath += "/"; +*/ + // Document Path + *s_documentPath = QString::null; + *s_documentPath = config->readEntry( "Documents" , *s_documentPath); + if ( (*s_documentPath)[0] != '/' ) + s_documentPath->prepend( QDir::homeDirPath() + "/" ); + *s_documentPath = QDir::cleanDirPath( *s_documentPath ); + if ( s_documentPath->right(1) != "/") + *s_documentPath += "/"; + + //config->setDollarExpansion(dollarExpansion); + + // Make sure this app gets the notifications about those paths + //if (kapp) + //kapp->addKipcEventMask(KIPC::SettingsChanged); +} + +void OGlobalSettings::initColors() +{ + if ( not OpieHighlight ) OpieHighlight = new QColor( 156, 118, 32 ); + if ( not OpieAlternate ) OpieAlternate = new QColor( 238, 246, 255 ); + if ( not OpieGray ) OpieGray = new QColor( 220, 210, 215 ); +} + +void OGlobalSettings::rereadFontSettings() +{ + delete _generalFont; + _generalFont = 0L; + delete _fixedFont; + _fixedFont = 0L; + delete _menuFont; + _menuFont = 0L; + delete _toolBarFont; + _toolBarFont = 0L; + delete _windowTitleFont; + _windowTitleFont = 0L; + delete _taskbarFont; + _taskbarFont = 0L; +} + +void OGlobalSettings::rereadPathSettings() +{ + qDebug( "OGlobalSettings::rereadPathSettings" ); + delete s_autostartPath; + s_autostartPath = 0L; + delete s_trashPath; + s_trashPath = 0L; + delete s_desktopPath; + s_desktopPath = 0L; + delete s_documentPath; + s_documentPath = 0L; +} + +OGlobalSettings::OMouseSettings & OGlobalSettings::mouseSettings() +{ + if ( ! s_mouseSettings ) + { + s_mouseSettings = new OMouseSettings; + OMouseSettings & s = *s_mouseSettings; // for convenience + + OConfigGroupSaver cgs( OGlobal::config(), "Mouse" ); + QString setting = OGlobal::config()->readEntry("MouseButtonMapping"); + if (setting == "RightHanded") + s.handed = OMouseSettings::RightHanded; + else if (setting == "LeftHanded") + s.handed = OMouseSettings::LeftHanded; + else + { + + // FIXME: Implement for Opie / Qt Embedded + + } + } + return *s_mouseSettings; +} + +void OGlobalSettings::rereadMouseSettings() +{ + delete s_mouseSettings; + s_mouseSettings = 0L; +} + +// FIXME: This won't be necessary, or will it? :-D + +bool OGlobalSettings::isMultiHead() +{ + QCString multiHead = getenv("OPIE_MULTIHEAD"); + if (!multiHead.isEmpty()) { + return (multiHead.lower() == "true"); + } + return false; +} diff --git a/libopie2/opiecore/oglobalsettings.h b/libopie2/opiecore/oglobalsettings.h new file mode 100644 index 0000000..6481251 --- a/dev/null +++ b/libopie2/opiecore/oglobalsettings.h @@ -0,0 +1,368 @@ +/* + This file is part of the Opie Project + Copyright (C) 2003 Michael Lauer <mickey@tm.informatik.uni-frankfurt.de> + Inspired by KDE OGlobalSettings + Copyright (C) 2000 David Faure <faure@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 OGLOBALSETTINGS_H +#define OGLOBALSETTINGS_H + +#include <qstring.h> +#include <qcolor.h> +#include <qfont.h> + +#define OPIE_DEFAULT_SINGLECLICK true +#define OPIE_DEFAULT_INSERTTEAROFFHANDLES true +#define OPIE_DEFAULT_AUTOSELECTDELAY -1 +#define OPIE_DEFAULT_CHANGECURSOR true +#define OPIE_DEFAULT_LARGE_CURSOR false +#define OPIE_DEFAULT_VISUAL_ACTIVATE true +#define OPIE_DEFAULT_VISUAL_ACTIVATE_SPEED 50 + +//FIXME: There's still a whole lot of stuff in here which has to be revised +//FIXME: before public usage... lack of time to do it at once - so it will +//FIXME: happen step-by-step. ML. + +/** + * Access the OPIE global configuration settings. + * + */ +class OGlobalSettings +{ + public: + + /** + * Returns a threshold in pixels for drag & drop operations. + * As long as the mouse movement has not exceeded this number + * of pixels in either X or Y direction no drag operation may + * be started. This prevents spurious drags when the user intended + * to click on something but moved the mouse a bit while doing so. + * + * For this to work you must save the position of the mouse (oldPos) + * in the @ref QWidget::mousePressEvent(). + * When the position of the mouse (newPos) + * in a @ref QWidget::mouseMoveEvent() exceeds this threshold + * you may start a drag + * which should originate from oldPos. + * + * Example code: + * <pre> + * void OColorCells::mousePressEvent( QMouseEvent *e ) + * { + * mOldPos = e->pos(); + * } + * + * void OColorCells::mouseMoveEvent( QMouseEvent *e ) + * { + * if( !(e->state() && LeftButton)) return; + * + * int delay = OGlobalSettings::dndEventDelay(); + * QPoint newPos = e->pos(); + * if(newPos.x() > mOldPos.x()+delay || newPos.x() < mOldPos.x()-delay || + * newPos.y() > mOldPos.y()+delay || newPos.y() < mOldPos.y()-delay) + * { + * // Drag color object + * int cell = posToCell(mOldPos); // Find color at mOldPos + * if ((cell != -1) && colors[cell].isValid()) + * { + * OColorDrag *d = OColorDrag::makeDrag( colors[cell], this); + * d->dragCopy(); + * } + * } + * } + * </pre> + * + */ + + static int dndEventDelay(); + + /** + * Returns whether OPIE runs in single (default) or double click + * mode. + * + * @return @p true if single click mode, or @p false if double click mode. + * + * see @ref http://opie.handhelds.org/documentation/standards/opie/style/mouse/index.html + **/ + static bool singleClick(); + + /** + * Returns whether tear-off handles are inserted in OPopupMenus. + **/ + static bool insertTearOffHandle(); + + /** + * @return the OPIE setting for "change cursor over icon" + */ + static bool changeCursorOverIcon(); + + /** + * @return whether to show some feedback when an item (specifically an + * icon) is activated. + */ + static bool visualActivate(); + static unsigned int visualActivateSpeed(); + + /** + * Returns the OPIE setting for the auto-select option + * + * @return the auto-select delay or -1 if auto-select is disabled. + */ + static int autoSelectDelay(); + + /** + * Returns the OPIE setting for the shortcut key to open + * context menus. + * + * @return the key that pops up context menus. + */ + static int contextMenuKey(); + + /** + * Returns the OPIE setting for context menus. + * + * @return whether context menus should be shown on button press + * or button release (click). + */ + static bool showContextMenusOnPress (); + + /** + * This enum describes the completion mode used for by the @ref OCompletion class. + * See <a href="http://opie.handhelds.org/documentation/standards/opie/style/keys/completion.html"> + * the styleguide</a>. + **/ + enum Completion { + /** + * No completion is used. + */ + CompletionNone=1, + /** + * Text is automatically filled in whenever possible. + */ + CompletionAuto, + /** + * Same as automatic except shortest match is used for completion. + */ + CompletionMan, + /** + * Complete text much in the same way as a typical *nix shell would. + */ + CompletionShell, + /** + * Lists all possible matches in a popup list-box to choose from. + */ + CompletionPopup, + /** + * Lists all possible matches in a popup list-box to choose from, and automatically + * fill the result whenever possible. + */ + CompletionPopupAuto + }; + /** + * Returns the preferred completion mode setting. + * + * @return @ref Completion. Default is @p CompletionPopup. + */ + static Completion completionMode(); + + /** + * This enum describes the debug mode used for by the @ref odbgstream class. + * See <a href="http://opie.handhelds.org/documentation/standards/opie/style/debug/debug.html"> + * the styleguide</a>. + **/ + enum Debug { + /** + * Debug messages are ignored. + */ + DebugNone=-1, + /** + * Debug output is sent to files /var/log/***. + */ + DebugFiles=0, + /** + * Debug output is written in a QMessageBox. + */ + DebugMsgBox=1, + /** + * Debug output is sent to stderr. + */ + DebugStdErr=2, + /** + * Debug output is sent to syslog. + */ + DebugSysLog=3, + /** + * Debug output is sent via udp over a socket. + */ + DebugSocket=4 + }; + /** + * Returns the preferred debug mode setting. + * + * @return @ref Debug. Default is @p DebugStdErr. + */ + static Debug debugMode(); + + /** + * Returns additional information for debug output (dependent on the debug mode). + * + * @return Additional debug output information. + */ + static QString debugOutput(); + /** + * This is a structure containing the possible mouse settings. + */ + struct OMouseSettings + { + enum { RightHanded = 0, LeftHanded = 1 }; + int handed; // left or right + }; + + /** + * This returns the current mouse settings. + */ + static OMouseSettings & mouseSettings(); + + /** + * The path to the desktop directory of the current user. + */ + static QString desktopPath() { initStatic(); return *s_desktopPath; } + + /** + * The path to the autostart directory of the current user. + */ + static QString autostartPath() { initStatic(); return *s_autostartPath; } + + /** + * The path to the trash directory of the current user. + */ + static QString trashPath() { initStatic(); return *s_trashPath; } + + /** + * The path where documents are stored of the current user. + */ + static QString documentPath() { initStatic(); return *s_documentPath; } + + + /** + * The default color to use when highlighting toolbar buttons + */ + static QColor toolBarHighlightColor(); + static QColor inactiveTitleColor(); + static QColor inactiveTextColor(); + static QColor activeTitleColor(); + static QColor activeTextColor(); + static int contrast(); + + /** + * The default colors to use for text and links. + */ + static QColor baseColor(); // Similair to QColorGroup::base() + static QColor textColor(); // Similair to QColorGroup::text() + static QColor linkColor(); + static QColor visitedLinkColor(); + static QColor highlightedTextColor(); // Similair to QColorGroup::hightlightedText() + static QColor highlightColor(); // Similair to QColorGroup::highlight() + + /** + * Returns the alternate background color used by @ref OListView with + * @ref OListViewItem. Any other list that uses alternating background + * colors should use this too, to obey to the user's preferences. Returns + * an invalid color if the user doesn't want alternating backgrounds. + * @see #calculateAlternateBackgroundColor + */ + static QColor alternateBackgroundColor(); + /** + * Calculates a color based on @p base to be used as alternating + * color for e.g. listviews. + * @see #alternateBackgroundColor + */ + static QColor calculateAlternateBackgroundColor(const QColor& base); + + + static QFont generalFont(); + static QFont fixedFont(); + static QFont toolBarFont(); + static QFont menuFont(); + static QFont windowTitleFont(); + static QFont taskbarFont(); + + /** + * Returns if the user specified multihead. In case the display + * has multiple screens, the return value of this function specifies + * if the user wants OPIE to run on all of them or just on the primary + */ + static bool isMultiHead(); + +private: + /** + * reads in all paths from kdeglobals + */ + static void initStatic(); + /** + * initialise kde2Blue + */ + static void initColors(); + /** + * drop cached values for fonts (called by OApplication) + */ + static void rereadFontSettings(); + /** + * drop cached values for paths (called by OApplication) + */ + static void rereadPathSettings(); + /** + * drop cached values for mouse settings (called by OApplication) + */ + static void rereadMouseSettings(); + + + static QString* s_desktopPath; + static QString* s_autostartPath; + static QString* s_trashPath; + static QString* s_documentPath; + static QFont *_generalFont; + static QFont *_fixedFont; + static QFont *_toolBarFont; + static QFont *_menuFont; + static QFont *_windowTitleFont; + static QFont *_taskbarFont; + static QColor * kde2Gray; + static QColor * kde2Blue; + static QColor * kde2AlternateColor; + static OMouseSettings *s_mouseSettings; + + static QColor * OpieGray; + static QColor * OpieBlue; + static QColor * OpieAlternate; + static QColor * OpieHighlight; + + friend class OApplication; +}; + +#endif diff --git a/libopie2/opiecore/opiecore.pro b/libopie2/opiecore/opiecore.pro new file mode 100644 index 0000000..ed7d6d7 --- a/dev/null +++ b/libopie2/opiecore/opiecore.pro @@ -0,0 +1,31 @@ +TEMPLATE = lib +CONFIG += qt warn_on debug +DESTDIR = $(OPIEDIR)/lib +HEADERS = oapplication.h \ + oconfig.h \ + ocompletionbase.h \ + ocompletion.h \ + odebug.h \ + oglobal.h \ + oglobalsettings.h \ + osortablevaluelist.h + +SOURCES = oapplication.cpp \ + oconfig.cpp \ + ocompletionbase.cpp \ + ocompletion.cpp \ + odebug.cpp \ + oglobal.cpp \ + oglobalsettings.cpp + +INTERFACES = +TARGET = opiecore2 +VERSION = 1.8.1 +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += $(OPIEDIR)/include +LIBS = -lqpe +MOC_DIR = moc +OBJECTS_DIR = obj + +include ( $(OPIEDIR)/include.pro ) + diff --git a/libopie2/opiedb/config.in b/libopie2/opiedb/config.in new file mode 100644 index 0000000..0205a83 --- a/dev/null +++ b/libopie2/opiedb/config.in @@ -0,0 +1,7 @@ + config LIBOPIE2DB + boolean "libopie2db (database related classes)" + default "n" + depends ( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE + comment "libopie2db needs a libqpe and libopie2core" + depends !(( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE) + diff --git a/libopie2/opiedb/opiedb.pro b/libopie2/opiedb/opiedb.pro new file mode 100644 index 0000000..0d0ab78 --- a/dev/null +++ b/libopie2/opiedb/opiedb.pro @@ -0,0 +1,17 @@ +TEMPLATE = lib +CONFIG += qt warn_on debug +DESTDIR = $(OPIEDIR)/lib +HEADERS = + +SOURCES = +INTERFACES = +TARGET = opiedb2 +VERSION = 1.8.1 +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += $(OPIEDIR)/include + +MOC_DIR = moc +OBJECTS_DIR = obj + +include ( $(OPIEDIR)/include.pro ) + diff --git a/libopie2/opienet/.cvsignore b/libopie2/opienet/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/opienet/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/opienet/802_11_user.h b/libopie2/opienet/802_11_user.h new file mode 100644 index 0000000..0b3f198 --- a/dev/null +++ b/libopie2/opienet/802_11_user.h @@ -0,0 +1,419 @@ +#ifndef IEEE_802_11 +#define IEEE_802_11 + +enum ieee_802_11_link_status_failure_reason { + reserved0, Unspecified=1, Previous_not_valid, + Sender_Quits_ESS_or_IBSS, + Due_Inactivity, AP_Overload, + Class_2_from_NonAuth, + Class_3_from_NonAuth, + Sender_Quits_BSS, + Association_requester_not_authenticated, + Reserved10 +}; + + +#define IEEE_802_11_LINK_STATUS_FAILURE_REASON_STRINGS \ +{ \ + {reserved0, 0xff," Reserved reason "},\ + {Unspecified, 0xff," Unspecified Reason "},\ + {Previous_not_valid, 0xff," Previous Authentication no longer valid "},\ + {Sender_Quits_ESS_or_IBSS,0xff," Deauthenticated because sending station is leaving (has left) IBSS or ESS "},\ + {Due_Inactivity, 0xff," Disassociated due to inactivity "},\ + {AP_Overload, 0xff," Disassociated because AP is unable to handle all currently associated stations "},\ + {Class_2_from_NonAuth, 0xff," Class 2 frame received from non-Authenticated station"},\ + {Class_3_from_NonAuth, 0xff," Class 3 frame received from nonAssociated station"},\ + {Sender_Quits_BSS, 0xff," Disassociated because sending station is leaving (has left) BSS"},\ + {Association_requester_not_authenticated,0xff," Station requesting (Re)Association is not Authenticated with responding station"},\ + {Reserved10, 0xff," Reserved"},\ + {0,0,NULL}\ +}; + + + +struct ieee_802_11_header { + u_int16_t frame_control;// needs to be subtyped + u_int16_t duration; + u_int8_t mac1[6]; + u_int8_t mac2[6]; + u_int8_t mac3[6]; + u_int16_t SeqCtl; + u_int8_t mac4[6]; +// u_int16_t gapLen; +// u_int8_t gap[8]; +}; + + +struct ieee_802_3_header { + + u_int16_t status; + u_int16_t payload_length; + u_int8_t dst_mac[6]; + u_int8_t src_mac[6]; + +}; + +#define P80211_OUI_LEN 3 + +struct ieee_802_11_snap_header { + + u_int8_t dsap; /* always 0xAA */ + u_int8_t ssap; /* always 0xAA */ + u_int8_t ctrl; /* always 0x03 */ + u_int8_t oui[P80211_OUI_LEN]; /* organizational universal id */ + +} __attribute__ ((packed)); + +#define P80211_LLC_OUI_LEN 3 + +struct ieee_802_11_802_1H_header { + + u_int8_t dsap; + u_int8_t ssap; /* always 0xAA */ + u_int8_t ctrl; /* always 0x03 */ + u_int8_t oui[P80211_OUI_LEN]; /* organizational universal id */ + u_int16_t unknown1; /* packet type ID fields */ + u_int16_t unknown2; /* here is something like length in some cases */ +} __attribute__ ((packed)); + +struct ieee_802_11_802_2_header { + + u_int8_t dsap; + u_int8_t ssap; /* always 0xAA */ + u_int8_t ctrl; /* always 0x03 */ + u_int8_t oui[P80211_OUI_LEN]; /* organizational universal id */ + u_int16_t type; /* packet type ID field */ + +} __attribute__ ((packed)); + + + +// following is incoplete and may be incorrect and need reorganization + +#define ieee_802_11_frame_type_Management 0x00 +#define ieee_802_11_frame_type_Control 0x01 +#define ieee_802_11_frame_type_Data 0x10 +#define ieee_802_11_frame_type_Reserved 0x11 + +#define ieee_802_11_frame_subtype_Association_Req 0x0 // Association Request +#define ieee_802_11_frame_subtype_Association_Resp 0x1 // Association Response +#define ieee_802_11_frame_subtype_Reassociation_Req 0x2 // Reassociation Request +#define ieee_802_11_frame_subtype_Reassociation_Resp 0x3 // Reassociation Response +#define ieee_802_11_frame_subtype_Probe_Req 0x4 // Probe Request +#define ieee_802_11_frame_subtype_Probe_Resp 0x5 // Probe Response +#define ieee_802_11_frame_subtype_Beacon 0x8 // Beacon +#define ieee_802_11_frame_subtype_ATIM 0x9 // ATIM +#define ieee_802_11_frame_subtype_Disassociation 0xA // Disassociation +#define ieee_802_11_frame_subtype_Authentication 0xB // Authentication +#define ieee_802_11_frame_subtype_Deauthentication 0xC // Deauthentication +#define ieee_802_11_frame_subtype_PS_Poll 0xA // PS-Poll +#define ieee_802_11_frame_subtype_RTS 0xB // RTS +#define ieee_802_11_frame_subtype_CTS 0xC // CTS +#define ieee_802_11_frame_subtype_ACK 0xD // ACK +#define ieee_802_11_frame_subtype_CFEnd 0xE // CF-End +#define ieee_802_11_frame_subtype_CFEnd_CFAck 0xF // CF-End + CF-Ack +#define ieee_802_11_frame_subtype_Data 0x0 // Data +#define ieee_802_11_frame_subtype_Data_CFAck 0x1 // Data + CF-Ack +#define ieee_802_11_frame_subtype_Data_CF_Poll 0x2 // Data + CF-Poll +#define ieee_802_11_frame_subtype_Data_CF_AckCF_Poll 0x3 // Data + CF-Ack + CF-Poll +#define ieee_802_11_frame_subtype_NullFunction 0x4 // Null Function (no data) +#define ieee_802_11_frame_subtype_CF_Ack 0x5 // CF-Ack (no data) +#define ieee_802_11_frame_subtype_CF_Poll 0x6 // CF-Poll (no data) +#define ieee_802_11_frame_subtype_CF_AckCF_Poll 0x7 // CF-Ack + CF-Poll (no data) + + +#define ieee_802_11_frame_subtype_strings {\ + { ieee_802_11_frame_subtype_Association_Req, 0xF,"f Association Request"},\ + { ieee_802_11_frame_subtype_Association_Resp, 0xF,"1 Association Response"},\ + { ieee_802_11_frame_subtype_Reassociation_Req, 0xF,"2 Reassociation Request"},\ + { ieee_802_11_frame_subtype_Reassociation_Resp, 0xF,"3 Reassociation Response"},\ + { ieee_802_11_frame_subtype_Probe_Req , 0xF,"4 Probe Request"},\ + { ieee_802_11_frame_subtype_Probe_Resp , 0xF,"5 Probe Response"},\ + { ieee_802_11_frame_subtype_Beacon , 0xF,"8 Beacon"},\ + { ieee_802_11_frame_subtype_ATIM , 0xF,"9 ATIM"},\ + { ieee_802_11_frame_subtype_Disassociation, 0xF,"A Disassociation"},\ + { ieee_802_11_frame_subtype_Authentication, 0xF,"B Authentication"},\ + { ieee_802_11_frame_subtype_Deauthentication, 0xF,"C Deauthentication"},\ + { ieee_802_11_frame_subtype_PS_Poll , 0xF,"A PS-Poll"},\ + { ieee_802_11_frame_subtype_RTS , 0xF,"B RTS"},\ + { ieee_802_11_frame_subtype_CTS , 0xF,"C CTS"},\ + { ieee_802_11_frame_subtype_ACK , 0xF,"D ACK"},\ + { ieee_802_11_frame_subtype_CFEnd , 0xF,"E CF-End"},\ + { ieee_802_11_frame_subtype_CFEnd_CFAck , 0xF,"F CF-End + CF-Ack"},\ + { ieee_802_11_frame_subtype_Data , 0xF,"0 Data"},\ + { ieee_802_11_frame_subtype_Data_CFAck , 0xF,"1 Data + CF-Ack"},\ + { ieee_802_11_frame_subtype_Data_CFPoll , 0xF,"2 Data + CF-Poll"},\ + { ieee_802_11_frame_subtype_Data_CFAck_CFPoll, 0xF,"3 Data + CF-Ack + CF-Poll"},\ + { ieee_802_11_frame_subtype_Null_Function , 0xF,"4 Null Function (no data)"},\ + { ieee_802_11_frame_subtype_CFAck , 0xF,"5 CF-Ack (no data)"},\ + { ieee_802_11_frame_subtype_CFPoll , 0xF,"6 CF-Poll (no data)"},\ + { ieee_802_11_frame_subtype_CFAck_CFPoll, 0xF,"y7 CF-Ack + CF-Poll (no data)"},\ + { 0,0,NULL}\ +} +struct ieee_802_11_frame_subtype_class { + u_int8_t subtype; + u_int8_t mask; + u_int8_t klass; + u_int8_t type; +}; +#define ieee_802_11_frame_subtype_classes {\ + { ieee_802_11_frame_subtype_Association_Req, 0xF,2,ieee_802_11_frame_type_Management},\ + { ieee_802_11_frame_subtype_Association_Resp, 0xF,2,ieee_802_11_frame_type_Management},\ + { ieee_802_11_frame_subtype_Reassociation_Req, 0xF,2,ieee_802_11_frame_type_Management},\ + { ieee_802_11_frame_subtype_Reassociation_Resp, 0xF,2,ieee_802_11_frame_type_Management},\ + { ieee_802_11_frame_subtype_Probe_Req , 0xF,1,ieee_802_11_frame_type_Management},\ + { ieee_802_11_frame_subtype_Probe_Resp , 0xF,1,ieee_802_11_frame_type_Management},\ + { ieee_802_11_frame_subtype_Beacon , 0xF,1,ieee_802_11_frame_type_Management},\ + { ieee_802_11_frame_subtype_ATIM , 0xF,1,ieee_802_11_frame_type_Management},\ + { ieee_802_11_frame_subtype_Disassociation, 0xF,2,ieee_802_11_frame_type_Management},\ + { ieee_802_11_frame_subtype_Authentication, 0xF,1,ieee_802_11_frame_type_Management},\ + { ieee_802_11_frame_subtype_Deauthentication, 0xF,3,ieee_802_11_frame_type_Management},\ + { ieee_802_11_frame_subtype_PS-Poll , 0xF,3,ieee_802_11_frame_type_Control},\ + { ieee_802_11_frame_subtype_RTS , 0xF,1,ieee_802_11_frame_type_Control},\ + { ieee_802_11_frame_subtype_CTS , 0xF,1,ieee_802_11_frame_type_Control},\ + { ieee_802_11_frame_subtype_ACK , 0xF,1,ieee_802_11_frame_type_Control},\ + { ieee_802_11_frame_subtype_CFEnd , 0xF,1,ieee_802_11_frame_type_Control},\ + { ieee_802_11_frame_subtype_CFEnd_CFAck , 0xF,1,ieee_802_11_frame_type_Control},\ + { ieee_802_11_frame_subtype_Data , 0xF,3,ieee_802_11_frame_type_Data},\ + { ieee_802_11_frame_subtype_Data_CFAck , 0xF,3,ieee_802_11_frame_type_Data},\ + { ieee_802_11_frame_subtype_Data_CF_Poll 0xF,3,ieee_802_11_frame_type_Data},\ + { ieee_802_11_frame_subtype_Data_CF_AckCF_Poll, 0xF,3,ieee_802_11_frame_type_Data},\ + { ieee_802_11_frame_subtype_NullFunction 0xF,1,ieee_802_11_frame_type_Data},\ + { ieee_802_11_frame_subtype_CF_Ack , 0xF,1,ieee_802_11_frame_type_Data},\ + { ieee_802_11_frame_subtype_CF_Poll , 0xF,1,ieee_802_11_frame_type_Data},\ + { ieee_802_11_frame_subtype_CF_AckCF_Poll, 0xF,1,ieee_802_11_frame_type_Data},\ + { 0,0,NULL}\ +} + +#define IEEE802_11_FC_LEN 2 + +#define T_MGMT 0x0 /* management */ +#define T_CTRL 0x1 /* control */ +#define T_DATA 0x2 /* data */ +#define T_RESV 0x3 /* reserved */ + +#define ST_ASSOC_REQUEST 0x0 +#define ST_ASSOC_RESPONSE 0x1 +#define ST_REASSOC_REQUEST 0x2 +#define ST_REASSOC_RESPONSE 0x3 +#define ST_PROBE_REQUEST 0x4 +#define ST_PROBE_RESPONSE 0x5 +/* RESERVED 0x6 */ +/* RESERVED 0x7 */ +#define ST_BEACON 0x8 +#define ST_ATIM 0x9 +#define ST_DISASSOC 0xA +#define ST_AUTH 0xB +#define ST_DEAUTH 0xC +/* RESERVED 0xD */ +/* RESERVED 0xE */ +/* RESERVED 0xF */ + + +#define CTRL_PS_POLL 0xA +#define CTRL_RTS 0xB +#define CTRL_CTS 0xC +#define CTRL_ACK 0xD +#define CTRL_CF_END 0xE +#define CTRL_END_ACK 0xF + +/* + * Bits in the frame control field. + */ +#define FC_VERSION(fc) ((fc) & 0x3) +#define FC_TYPE(fc) (((fc) >> 2) & 0x3) +#define FC_SUBTYPE(fc) (((fc) >> 4) & 0xF) +#define FC_TO_DS(fc) ((fc) & 0x0100) +#define FC_FROM_DS(fc) ((fc) & 0x0200) +#define FC_MORE_FLAG(fc) ((fc) & 0x0400) +#define FC_RETRY(fc) ((fc) & 0x0800) +#define FC_POWER_MGMT(fc) ((fc) & 0x1000) +#define FC_MORE_DATA(fc) ((fc) & 0x2000) +#define FC_WEP(fc) ((fc) & 0x4000) +#define FC_ORDER(fc) ((fc) & 0x8000) + + +struct ieee_802_11_mgmt_header { + u_int16_t fc; + u_int16_t duration; + u_int8_t da[6]; + u_int8_t sa[6]; + u_int8_t bssid[6]; + u_int16_t seq_ctrl; +}; + + +struct ieee_802_11_data_header { + u_int16_t frame_control; + u_int16_t duration; + u_int8_t mac1[6]; + u_int8_t mac2[6]; + u_int8_t mac3[6]; + u_int16_t SeqCtl; + u_int8_t mac4[6]; +// u_int16_t gapLen; +// u_int8_t gap[8]; +}; + +#define CAPABILITY_ESS(cap) ((cap) & 0x0001) +#define CAPABILITY_IBSS(cap) ((cap) & 0x0002) +#define CAPABILITY_CFP(cap) ((cap) & 0x0004) +#define CAPABILITY_CFP_REQ(cap) ((cap) & 0x0008) +#define CAPABILITY_PRIVACY(cap) ((cap) & 0x0010) + +struct ssid_t { + u_int8_t element_id; + u_int8_t length; + u_char ssid[33]; /* 32 + 1 for null */ +}; + + +struct rates_t { + u_int8_t element_id; + u_int8_t length; + u_int8_t rate[8]; +}; + + +struct challenge_t { + u_int8_t element_id; + u_int8_t length; + u_int8_t text[254]; /* 1-253 + 1 for null */ +}; + + +struct fh_t { + u_int8_t element_id; + u_int8_t length; + u_int16_t dwell_time; + u_int8_t hop_set; + u_int8_t hop_pattern; + u_int8_t hop_index; +}; + + +struct ds_t { + u_int8_t element_id; + u_int8_t length; + u_int8_t channel; +}; + + +struct cf_t { + u_int8_t element_id; + u_int8_t length; + u_int8_t count; + u_int8_t period; + u_int16_t max_duration; + u_int16_t dur_remaing; +}; + + +struct tim_t { + u_int8_t element_id; + u_int8_t length; + u_int8_t count; + u_int8_t period; + u_int8_t bitmap_control; + u_int8_t bitmap[251]; +}; + +#define E_SSID 0 +#define E_RATES 1 +#define E_FH 2 +#define E_DS 3 +#define E_CF 4 +#define E_TIM 5 +#define E_IBSS 6 +#define E_CHALLENGE 16 +#define E_CISCO 133 + + +struct ieee_802_11_mgmt_body { + u_int8_t timestamp[8]; + u_int16_t beacon_interval; +// u_int16_t listen_interval; +// u_int16_t status_code; +// u_int16_t aid; +// u_char ap[6]; +// u_int16_t reason_code; +// u_int16_t auth_alg; +// u_int16_t auth_trans_seq_num; +// struct challenge_t challenge; + u_int16_t capability_info; + struct ssid_t ssid; + struct rates_t rates; + struct ds_t ds; + struct cf_t cf; + struct fh_t fh; + struct tim_t tim; +}; + + +struct ieee_802_11_data_body { +//FIXME +}; + +struct ctrl_rts_t { + u_int16_t fc; + u_int16_t duration; + u_int8_t ra[6]; + u_int8_t ta[6]; + u_int8_t fcs[4]; +}; + +#define CTRL_RTS_LEN (2+2+6+6+4) + +struct ctrl_cts_t { + u_int16_t fc; + u_int16_t duration; + u_int8_t ra[6]; + u_int8_t fcs[4]; +}; + +#define CTRL_CTS_LEN (2+2+6+4) + +struct ctrl_ack_t { + u_int16_t fc; + u_int16_t duration; + u_int8_t ra[6]; + u_int8_t fcs[4]; +}; + +#define CTRL_ACK_LEN (2+2+6+4) + +struct ctrl_ps_poll_t { + u_int16_t fc; + u_int16_t aid; + u_int8_t bssid[6]; + u_int8_t ta[6]; + u_int8_t fcs[4]; +}; + +#define CTRL_PS_POLL_LEN (2+2+6+6+4) + +struct ctrl_end_t { + u_int16_t fc; + u_int16_t duration; + u_int8_t ra[6]; + u_int8_t bssid[6]; + u_int8_t fcs[4]; +}; + +#define CTRL_END_LEN (2+2+6+6+4) + +struct ctrl_end_ack_t { + u_int16_t fc; + u_int16_t duration; + u_int8_t ra[6]; + u_int8_t bssid[6]; + u_int8_t fcs[4]; +}; + +#define CTRL_END_ACK_LEN (2+2+6+6+4) + +#define IV_IV(iv) ((iv) & 0xFFFFFF) +#define IV_PAD(iv) (((iv) >> 24) & 0x3F) +#define IV_KEYID(iv) (((iv) >> 30) & 0x03) + +#endif diff --git a/libopie2/opienet/config.in b/libopie2/opienet/config.in new file mode 100644 index 0000000..5b235da --- a/dev/null +++ b/libopie2/opienet/config.in @@ -0,0 +1,7 @@ + config LIBOPIE2NET + boolean "libopie2net (network and packet capturing related classes)" + default "n" + depends ( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE + comment "libopie2net needs a libqpe and libopie2core" + depends !(( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE) + diff --git a/libopie2/opienet/onetutils.cpp b/libopie2/opienet/onetutils.cpp new file mode 100644 index 0000000..8006f41 --- a/dev/null +++ b/libopie2/opienet/onetutils.cpp @@ -0,0 +1,101 @@ +/* + This file is part of the Opie Project + + (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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/onetutils.h> + +#include <net/if.h> + +#include <cstdio> +using namespace std; + +/*====================================================================================== + * OMacAddress + *======================================================================================*/ + +// static initializer for broadcast and unknown MAC Adresses +const unsigned char __broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +const OMacAddress& OMacAddress::broadcast = OMacAddress( __broadcast ); +const unsigned char __unknown[6] = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }; +const OMacAddress& OMacAddress::unknown = OMacAddress( __unknown ); + + +//TODO: Incorporate Ethernet Manufacturer database here! + +OMacAddress::OMacAddress( unsigned char* p ) +{ + memcpy( _bytes, p, 6 ); // D'OH! memcpy in my sources... eeek... +} + + +OMacAddress::OMacAddress( const unsigned char* p ) +{ + memcpy( _bytes, p, 6 ); +} + + +OMacAddress::OMacAddress( struct ifreq& ifr ) +{ + memcpy( _bytes, ifr.ifr_hwaddr.sa_data, 6 ); +} + + +OMacAddress::~OMacAddress() +{ +} + + +QString OMacAddress::toString() const +{ + QString s; + s.sprintf( "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", + _bytes[0]&0xff, _bytes[1]&0xff, _bytes[2]&0xff, + _bytes[3]&0xff, _bytes[4]&0xff, _bytes[5]&0xff ); + return s; +} + + +bool operator==( const OMacAddress &m1, const OMacAddress &m2 ) +{ + return memcmp( &m1._bytes, &m2._bytes, 6 ) == 0; +} + +void dumpBytes( const unsigned char* data, int num ) +{ + printf( "Dumping %d bytes @ %0x", num, data ); + printf( "-------------------------------------------\n" ); + + for ( int i = 0; i < num; ++i ) + { + printf( "%02x ", data[i] ); + if ( !((i+1) % 32) ) printf( "\n" ); + } + printf( "\n\n" ); +} diff --git a/libopie2/opienet/onetutils.h b/libopie2/opienet/onetutils.h new file mode 100644 index 0000000..0dabe8d --- a/dev/null +++ b/libopie2/opienet/onetutils.h @@ -0,0 +1,125 @@ +/* + This file is part of the Opie Project + + (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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 ONETUTILS_H +#define ONETUTILS_H + +#include <qdict.h> +#include <qmap.h> +#include <qstring.h> +#include <qhostaddress.h> + +struct ifreq; + +/*====================================================================================== + * OMacAddress + *======================================================================================*/ + +class OMacAddress +{ + public: + OMacAddress( unsigned char* ); + OMacAddress( const unsigned char* ); + OMacAddress( struct ifreq& ); + ~OMacAddress(); + + QString toString() const; + + public: + static const OMacAddress& broadcast; // ff:ff:ff:ff:ff:ff + static const OMacAddress& unknown; // 44:44:44:44:44:44 + + private: + unsigned char _bytes[6]; + + friend bool operator==( const OMacAddress &m1, const OMacAddress &m2 ); + +}; + +bool operator==( const OMacAddress &m1, const OMacAddress &m2 ); + + +/*====================================================================================== + * OHostAddress + *======================================================================================*/ + +class OHostAddress : public QHostAddress +{ + public: + OHostAddress(); + ~OHostAddress(); +}; + + +/*====================================================================================== + * Miscellaneous + *======================================================================================*/ + +/* dump bytes */ + +void dumpBytes( const unsigned char* data, int num ); + +/* Network to host order macros */ + +#ifdef LBL_ALIGN +#define EXTRACT_16BITS(p) \ + ((u_int16_t)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | \ + (u_int16_t)*((const u_int8_t *)(p) + 1))) +#define EXTRACT_32BITS(p) \ + ((u_int32_t)((u_int32_t)*((const u_int8_t *)(p) + 0) << 24 | \ + (u_int32_t)*((const u_int8_t *)(p) + 1) << 16 | \ + (u_int32_t)*((const u_int8_t *)(p) + 2) << 8 | \ + (u_int32_t)*((const u_int8_t *)(p) + 3))) +#else +#define EXTRACT_16BITS(p) \ + ((u_int16_t)ntohs(*(const u_int16_t *)(p))) +#define EXTRACT_32BITS(p) \ + ((u_int32_t)ntohl(*(const u_int32_t *)(p))) +#endif + +#define EXTRACT_24BITS(p) \ + ((u_int32_t)((u_int32_t)*((const u_int8_t *)(p) + 0) << 16 | \ + (u_int32_t)*((const u_int8_t *)(p) + 1) << 8 | \ + (u_int32_t)*((const u_int8_t *)(p) + 2))) + +/* Little endian protocol host order macros */ +#define EXTRACT_LE_8BITS(p) (*(p)) +#define EXTRACT_LE_16BITS(p) \ + ((u_int16_t)((u_int16_t)*((const u_int8_t *)(p) + 1) << 8 | \ + (u_int16_t)*((const u_int8_t *)(p) + 0))) +#define EXTRACT_LE_32BITS(p) \ + ((u_int32_t)((u_int32_t)*((const u_int8_t *)(p) + 3) << 24 | \ + (u_int32_t)*((const u_int8_t *)(p) + 2) << 16 | \ + (u_int32_t)*((const u_int8_t *)(p) + 1) << 8 | \ + (u_int32_t)*((const u_int8_t *)(p) + 0))) + +#endif // ONETUTILS_H + diff --git a/libopie2/opienet/onetwork.cpp b/libopie2/opienet/onetwork.cpp new file mode 100644 index 0000000..1d3b9fe --- a/dev/null +++ b/libopie2/opienet/onetwork.cpp @@ -0,0 +1,774 @@ +/* + This file is part of the Opie Project + Copyright (C) 2003 by the Wellenreiter team: + Martin J. Muench <mjm@remote-exploit.org> + Max Moser <mmo@remote-exploit.org + Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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. + +*/ + +/* OPIE */ + +#include <opie2/onetwork.h> + +/* QT */ + +#include <qfile.h> +#include <qtextstream.h> + +/* UNIX */ + +#include <arpa/inet.h> +#include <cerrno> +#include <cstring> +#include <cstdlib> +#include <math.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> +#include <linux/wireless.h> + +using namespace std; + +/*====================================================================================== + * ONetwork + *======================================================================================*/ + +ONetwork* ONetwork::_instance = 0; + +ONetwork::ONetwork() +{ + qDebug( "ONetwork::ONetwork()" ); + synchronize(); +} + +void ONetwork::synchronize() +{ + // gather available interfaces by inspecting /proc/net/dev + // we could use SIOCGIFCONF here, but we aren't interested in virtual (e.g. eth0:0) devices + + _interfaces.clear(); + QString str; + QFile f( "/proc/net/dev" ); + bool hasFile = f.open( IO_ReadOnly ); + if ( !hasFile ) + { + qDebug( "ONetwork: /proc/net/dev not existing. No network devices available" ); + return; + } + QTextStream s( &f ); + s.readLine(); + s.readLine(); + while ( !s.atEnd() ) + { + s >> str; + str.truncate( str.find( ':' ) ); + qDebug( "ONetwork: found interface '%s'", (const char*) str ); + ONetworkInterface* iface; + if ( isWirelessInterface( str ) ) + { + iface = new OWirelessNetworkInterface( str ); + qDebug( "ONetwork: interface '%s' has Wireless Extensions", (const char*) str ); + } + else + { + iface = new ONetworkInterface( str ); + } + _interfaces.insert( str, iface ); + s.readLine(); + } +} + + +ONetworkInterface* ONetwork::interface( QString iface ) const +{ + return _interfaces[iface]; +} + + +ONetwork* ONetwork::instance() +{ + if ( !_instance ) _instance = new ONetwork(); + return _instance; +} + + +ONetwork::InterfaceIterator ONetwork::iterator() const +{ + return ONetwork::InterfaceIterator( _interfaces ); +} + + +bool ONetwork::isWirelessInterface( const char* name ) const +{ + int sfd = socket( AF_INET, SOCK_DGRAM, 0 ); + iwreqstruct iwr; + memset( &iwr, 0, sizeof( iwreqstruct ) ); + strcpy( (char*) &iwr.ifr_name, name ); + int result = ::ioctl( sfd, SIOCGIWNAME, &iwr ); + if ( result == -1 ) + qDebug( "ONetwork::ioctl(): SIOCGIWNAME failed: %d (%s)", result, strerror( errno ) ); + else + qDebug( "ONetwork::ioctl(): SIOCGIWNAME ok." ); + return ( result != -1 ); +} + +/*====================================================================================== + * ONetworkInterface + *======================================================================================*/ + +ONetworkInterface::ONetworkInterface( const QString& name ) + :_name( name ), _sfd( socket( AF_INET, SOCK_DGRAM, 0 ) ), _mon( 0 ) +{ + qDebug( "ONetworkInterface::ONetworkInterface()" ); + init(); +} + + +ifreqstruct& ONetworkInterface::ifr() const +{ + return _ifr; +} + + +void ONetworkInterface::init() +{ + qDebug( "ONetworkInterface::init()" ); + + memset( &_ifr, 0, sizeof( struct ifreq ) ); + + if ( _sfd == -1 ) + { + qDebug( "ONetworkInterface::init(): Warning - can't get socket for device '%s'", (const char*) _name ); + return; + } +} + + +bool ONetworkInterface::ioctl( int call, ifreqstruct& ifreq ) const +{ + int result = ::ioctl( _sfd, call, &ifreq ); + if ( result == -1 ) + qDebug( "ONetworkInterface::ioctl(): Call %d - Status: Failed: %d (%s)", call, result, strerror( errno ) ); + else + qDebug( "ONetworkInterface::ioctl(): Call %d - Status: Ok.", call ); + return ( result != -1 ); +} + + +bool ONetworkInterface::ioctl( int call ) const +{ + strcpy( _ifr.ifr_name, (const char*) _name ); + return ioctl( call, _ifr ); +} + + +bool ONetworkInterface::isLoopback() const +{ + ioctl( SIOCGIFFLAGS ); + return _ifr.ifr_flags & IFF_LOOPBACK; +} + + +bool ONetworkInterface::setUp( bool b ) +{ + ioctl( SIOCGIFFLAGS ); + if ( b ) _ifr.ifr_flags |= IFF_UP; + else _ifr.ifr_flags &= (~IFF_UP); + return ioctl( SIOCSIFFLAGS ); +} + + +bool ONetworkInterface::isUp() const +{ + ioctl( SIOCGIFFLAGS ); + return _ifr.ifr_flags & IFF_UP; +} + + +QString ONetworkInterface::ipV4Address() const +{ + if ( ioctl( SIOCGIFADDR ) ) + { + struct sockaddr_in *sa = (struct sockaddr_in *) &_ifr.ifr_addr; + //FIXME: Use QHostAddress here + return QString( inet_ntoa( sa->sin_addr ) ); + } + else + return "<unknown>"; +} + + +OMacAddress ONetworkInterface::macAddress() const +{ + if ( ioctl( SIOCGIFHWADDR ) ) + { + return OMacAddress( _ifr ); + } + else + { + return OMacAddress::unknown; + } +} + + +void ONetworkInterface::setMonitoring( OMonitoringInterface* m ) +{ + _mon = m; + qDebug( "ONetwork::setMonitoring(): Installed monitoring interface '%s'", (const char*) m->name() ); +} + + +OMonitoringInterface* ONetworkInterface::monitoring() const +{ + return _mon; +} + + +const QString& ONetworkInterface::name() const +{ + return _name; +} + + +ONetworkInterface::~ONetworkInterface() +{ + qDebug( "ONetworkInterface::~ONetworkInterface()" ); + if ( _sfd != -1 ) ::close( _sfd ); +} + + +bool ONetworkInterface::setPromiscuousMode( bool b ) +{ + ioctl( SIOCGIFFLAGS ); + if ( b ) _ifr.ifr_flags |= IFF_PROMISC; + else _ifr.ifr_flags &= (~IFF_PROMISC); + return ioctl( SIOCSIFFLAGS ); +} + + +bool ONetworkInterface::promiscuousMode() const +{ + ioctl( SIOCGIFFLAGS ); + return _ifr.ifr_flags & IFF_PROMISC; +} + + +bool ONetworkInterface::isWireless() const +{ + return ioctl( SIOCGIWNAME ); +} + + +/*====================================================================================== + * OChannelHopper + *======================================================================================*/ + +OChannelHopper::OChannelHopper( OWirelessNetworkInterface* iface ) + :QObject( 0, "Mickey's funky hopper" ), + _iface( iface ), _interval( 0 ), _channel( 0 ), _tid( 0 ) +{ +} + + +OChannelHopper::~OChannelHopper() +{ +} + + +void OChannelHopper::timerEvent( QTimerEvent* ) +{ + //FIXME: Get available channels from OWirelessNetworkInterface + if ( --_channel < 0 ) _channel = 13; + _iface->setChannel( _channel ); + qDebug( "OChannelHopper::timerEvent(): set channel %d on interface '%s'", + _channel, (const char*) _iface->name() ); +} + + +void OChannelHopper::setInterval( int interval ) +{ + if ( interval == _interval ) + return; + + if ( _interval ) + killTimer( _tid ); + + _interval = interval; + + if ( _interval ) + { + _tid = startTimer( interval ); + } +} + + +int OChannelHopper::interval() const +{ + return _interval; +} + + +/*====================================================================================== + * OWirelessNetworkInterface + *======================================================================================*/ + +OWirelessNetworkInterface::OWirelessNetworkInterface( const QString& name ) + :ONetworkInterface( name ), _hopper( this ) +{ + qDebug( "OWirelessNetworkInterface::OWirelessNetworkInterface()" ); + init(); +} + + +OWirelessNetworkInterface::~OWirelessNetworkInterface() +{ +} + + +iwreqstruct& OWirelessNetworkInterface::iwr() const +{ + return _iwr; +} + + +void OWirelessNetworkInterface::init() +{ + qDebug( "OWirelessNetworkInterface::init()" ); + + memset( &_iwr, 0, sizeof( struct iwreq ) ); + + // IEEE802.11(b) radio frequency channels + //FIXME: get these directly from the interface + //FIXME: check if these channels are off-by-one + + iwrangestruct range; + _iwr.u.data.pointer = (char*) ⦥ + _iwr.u.data.length = sizeof( iwrangestruct ); + if ( !wioctl( SIOCGIWRANGE ) ) + { + qDebug( "OWirelessNetworkInterface::init(): SIOCGIWRANGE failed (%s)", strerror( errno ) ); + return; + } + + //TODO: Find out what the difference between num_channel and + // num_frequency is about. + + for ( int i = 0; i < range.num_frequency; ++i ) + { + int freq = (int) ( double( range.freq[i].m ) * pow( 10, range.freq[i].e ) / 1000000.0 ); + _channels.insert( freq, i ); + } +} + + +QString OWirelessNetworkInterface::associatedAP() const +{ + //FIXME: use OMacAddress + QString mac; + + if ( ioctl( SIOCGIWAP ) ) + { + mac.sprintf( "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", + _ifr.ifr_hwaddr.sa_data[0]&0xff, + _ifr.ifr_hwaddr.sa_data[1]&0xff, + _ifr.ifr_hwaddr.sa_data[2]&0xff, + _ifr.ifr_hwaddr.sa_data[3]&0xff, + _ifr.ifr_hwaddr.sa_data[4]&0xff, + _ifr.ifr_hwaddr.sa_data[5]&0xff ); + } + else + { + mac = "<Unknown>"; + } + return mac; +} + + +int OWirelessNetworkInterface::channel() const +{ + if ( !wioctl( SIOCGIWFREQ ) ) + { + return -1; + } + else + { + //FIXME: This is off-by-one !? Why? + return _channels[ static_cast<int>(double( _iwr.u.freq.m ) * pow( 10, _iwr.u.freq.e ) / 1000000) ]; + } +} + + +void OWirelessNetworkInterface::setChannel( int c ) const +{ + if ( !_mon ) + { + memset( &_iwr, 0, sizeof( iwreqstruct ) ); + _iwr.u.freq.m = c; + _iwr.u.freq.e = 0; + wioctl( SIOCSIWFREQ ); + } + else + { + _mon->setChannel( c ); + } +} + + +double OWirelessNetworkInterface::frequency() const +{ + if ( !wioctl( SIOCGIWFREQ ) ) + { + return -1.0; + } + else + { + return double( _iwr.u.freq.m ) * pow( 10, _iwr.u.freq.e ) / 1000000000.0; + } +} + + +int OWirelessNetworkInterface::channels() const +{ + return _channels.count(); +} + + +void OWirelessNetworkInterface::setChannelHopping( int interval ) +{ + _hopper.setInterval( interval ); +} + + +int OWirelessNetworkInterface::channelHopping() const +{ + return _hopper.interval(); +} + + +void OWirelessNetworkInterface::setMonitorMode( bool b ) +{ + if ( _mon ) + _mon->setEnabled( b ); + else + qDebug( "ONetwork(): can't switch monitor mode without installed monitoring interface" ); +} + +bool OWirelessNetworkInterface::monitorMode() const +{ + return _mon ? _mon->enabled() : false; +} + + +QString OWirelessNetworkInterface::nickName() const +{ + char str[IW_ESSID_MAX_SIZE]; + _iwr.u.data.pointer = &str[0]; + _iwr.u.data.length = IW_ESSID_MAX_SIZE; + if ( !wioctl( SIOCGIWNICKN ) ) + { + return "<unknown>"; + } + else + { + str[_iwr.u.data.length] = 0x0; // some drivers (e.g. wlan-ng) don't zero-terminate the string + return str; + } +} + + +QString OWirelessNetworkInterface::SSID() const +{ + char str[IW_ESSID_MAX_SIZE]; + _iwr.u.essid.pointer = &str[0]; + _iwr.u.essid.length = IW_ESSID_MAX_SIZE; + if ( !wioctl( SIOCGIWESSID ) ) + { + return "<unknown>"; + } + else + { + return str; + } +} + + +void OWirelessNetworkInterface::setSSID( const QString& ssid ) +{ + _iwr.u.essid.pointer = const_cast<char*>( (const char*) ssid ); + _iwr.u.essid.length = ssid.length(); + wioctl( SIOCSIWESSID ); +} + + +bool OWirelessNetworkInterface::wioctl( int call, iwreqstruct& iwreq ) const +{ + int result = ::ioctl( _sfd, call, &iwreq ); + if ( result == -1 ) + qDebug( "ONetworkInterface::wioctl(): Call %d - Status: Failed: %d (%s)", call, result, strerror( errno ) ); + else + qDebug( "ONetworkInterface::wioctl(): Call %d - Status: Ok.", call ); + return ( result != -1 ); +} + + +bool OWirelessNetworkInterface::wioctl( int call ) const +{ + strcpy( _iwr.ifr_name, (const char*) _name ); + return wioctl( call, _iwr ); +} + + +/*====================================================================================== + * OMonitoringInterface + *======================================================================================*/ + +OMonitoringInterface::OMonitoringInterface( ONetworkInterface* iface ) + :_enabled( false ), _if( static_cast<OWirelessNetworkInterface*>( iface ) ) +{ +} + + +OMonitoringInterface::~OMonitoringInterface() +{ +} + + +void OMonitoringInterface::setChannel( int c ) +{ + // use standard WE channel switching protocol + memset( &_if->_iwr, 0, sizeof( iwreqstruct ) ); + _if->_iwr.u.freq.m = c; + _if->_iwr.u.freq.e = 0; + _if->wioctl( SIOCSIWFREQ ); +} + + +bool OMonitoringInterface::enabled() const +{ + return _enabled; +} + +void OMonitoringInterface::setEnabled( bool b ) +{ + // open a packet capturer here or leave this to + // the client code? + + /* + + if ( b ) + { + OPacketCapturer* opcap = new OPacketCapturer(); + opcap->open( _if->name() ); + } + */ + + _enabled = b; + +} + +/*====================================================================================== + * OCiscoMonitoringInterface + *======================================================================================*/ + +OCiscoMonitoringInterface::OCiscoMonitoringInterface( ONetworkInterface* iface ) + :OMonitoringInterface( iface ) +{ + iface->setMonitoring( this ); +} + + +OCiscoMonitoringInterface::~OCiscoMonitoringInterface() +{ +} + + +void OCiscoMonitoringInterface::setEnabled( bool b ) +{ + QString fname; + fname.sprintf( "/proc/driver/aironet/%s", (const char*) _if->name() ); + QFile f( fname ); + if ( !f.exists() ) return; + + if ( f.open( IO_WriteOnly ) ) + { + QTextStream s( &f ); + s << "Mode: r"; + s << "Mode: y"; + s << "XmitPower: 1"; + + OMonitoringInterface::setEnabled( b ); + + } + + // flushing and closing will be done automatically when f goes out of scope +} + + +QString OCiscoMonitoringInterface::name() const +{ + return "cisco"; +} + + +void OCiscoMonitoringInterface::setChannel( int ) +{ + // cisco devices automatically switch channels when in monitor mode +} + + +/*====================================================================================== + * OWlanNGMonitoringInterface + *======================================================================================*/ + + +OWlanNGMonitoringInterface::OWlanNGMonitoringInterface( ONetworkInterface* iface ) + :OMonitoringInterface( iface ) +{ + iface->setMonitoring( this ); +} + + +OWlanNGMonitoringInterface::~OWlanNGMonitoringInterface() +{ +} + + +void OWlanNGMonitoringInterface::setEnabled( bool b ) +{ + //FIXME: do nothing if its already in the same mode + + QString enable = b ? "true" : "false"; + QString cmd; + cmd.sprintf( "$(which wlanctl-ng) %s lnxreq_wlansniff channel=%d enable=%s", (const char*) _if->name(), 1, (const char*) enable ); + system( cmd ); + + OMonitoringInterface::setEnabled( b ); +} + + +QString OWlanNGMonitoringInterface::name() const +{ + return "wlan-ng"; +} + + +void OWlanNGMonitoringInterface::setChannel( int ) +{ + // wlan-ng devices automatically switch channels when in monitor mode +} + + +/*====================================================================================== + * OHostAPMonitoringInterface + *======================================================================================*/ + +OHostAPMonitoringInterface::OHostAPMonitoringInterface( ONetworkInterface* iface ) + :OMonitoringInterface( iface ) +{ + iface->setMonitoring( this ); +} + +OHostAPMonitoringInterface::~OHostAPMonitoringInterface() +{ +} + +void OHostAPMonitoringInterface::setEnabled( bool b ) +{ + // IW_MODE_MONITOR was introduced in Wireless Extensions Version 15 + // Wireless Extensions < Version 15 need iwpriv commandos for monitoring + + #if WIRELESS_EXT > 14 + _if->_iwr.u.mode = IW_MODE_MONITOR; + _if->wioctl( SIOCSIWMODE ); + #else + int* args = (int*) &_if._iwr.u.name; + args[0] = 2; + args[1] = 0; + _if->wioctl( SIOCDEVPRIVATE ); + #endif + + OMonitoringInterface::setEnabled( b ); +} + + +QString OHostAPMonitoringInterface::name() const +{ + return "hostap"; +} + + +/*====================================================================================== + * OOrinocoNetworkInterface + *======================================================================================*/ + +OOrinocoMonitoringInterface::OOrinocoMonitoringInterface( ONetworkInterface* iface ) + :OMonitoringInterface( iface ) +{ + iface->setMonitoring( this ); +} + + +OOrinocoMonitoringInterface::~OOrinocoMonitoringInterface() +{ +} + + +void OOrinocoMonitoringInterface::setChannel( int c ) +{ + // call iwpriv <device> monitor 2 <channel> + int* args = (int*) &_if->_iwr.u.name; + args[0] = 2; + args[1] = c; + _if->wioctl( SIOCIWFIRSTPRIV + 0x8 ); +} + + +void OOrinocoMonitoringInterface::setEnabled( bool b ) +{ + if ( b ) + { + setChannel( 1 ); + } + else + { + // call iwpriv <device> monitor 0 0 + int* args = (int*) &_if->_iwr.u.name; + args[0] = 0; + args[1] = 0; + _if->wioctl( SIOCIWFIRSTPRIV + 0x8 ); + } + + OMonitoringInterface::setEnabled( b ); +} + + +QString OOrinocoMonitoringInterface::name() const +{ + return "orinoco"; +} diff --git a/libopie2/opienet/onetwork.h b/libopie2/opienet/onetwork.h new file mode 100644 index 0000000..9a68a74 --- a/dev/null +++ b/libopie2/opienet/onetwork.h @@ -0,0 +1,307 @@ +/* + This file is part of the Opie Project + Copyright (C) 2003 by the Wellenreiter team: + Martin J. Muench <mjm@remote-exploit.org> + Max Moser <mmo@remote-exploit.org + Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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 ONETWORK_H +#define ONETWORK_H + +/* QT */ + +#include <qdict.h> +#include <qmap.h> +#include <qobject.h> +#include <qhostaddress.h> + +/* OPIE */ + +#include <opie2/onetutils.h> + +// ML: Yeah, I hate to include kernel headers, but it's necessary here +// ML: Recent RedHat and MandrakePatches to the Kernel and WE broke something +// ML: #include <net/if.h> e.g. conflicts with #include <linux/wireless.h> +#define IFNAMSIZ 16 +#include <linux/wireless.h> +#include <net/if.h> + +class ONetworkInterface; +class OWirelessNetworkInterface; +class OChannelHopper; +class OMonitoringInterface; + +typedef struct ifreq ifreqstruct; +typedef struct iwreq iwreqstruct; +typedef struct iw_event iweventstruct; +typedef struct iw_freq iwfreqstruct; +typedef struct iw_priv_args iwprivargsstruct; +typedef struct iw_range iwrangestruct; + +/*====================================================================================== + * ONetwork + *======================================================================================*/ + +class ONetwork : public QObject +{ + Q_OBJECT + + public: + typedef QDict<ONetworkInterface> InterfaceMap; + typedef QDictIterator<ONetworkInterface> InterfaceIterator; + + public: + static ONetwork* instance(); + InterfaceIterator iterator() const; + bool isWirelessInterface( const char* ) const; + ONetworkInterface* interface( QString ) const; + + protected: + ONetwork(); + void synchronize(); + + private: + static ONetwork* _instance; + InterfaceMap _interfaces; +}; + + +/*====================================================================================== + * ONetworkInterface + *======================================================================================*/ + +class ONetworkInterface +{ + friend class OMonitoringInterface; + friend class OCiscoMonitoringInterface; + friend class OWlanNGMonitoringInterface; + friend class OHostAPMonitoringInterface; + friend class OOrinocoMonitoringInterface; + + public: + ONetworkInterface( const QString& name ); + virtual ~ONetworkInterface(); + + const QString& name() const; + void setMonitoring( OMonitoringInterface* ); + OMonitoringInterface* monitoring() const; + bool setPromiscuousMode( bool ); + bool promiscuousMode() const; + bool setUp( bool ); + bool isUp() const; + bool isLoopback() const; + bool isWireless() const; + QString ipV4Address() const; + OMacAddress macAddress() const; + + protected: + const QString _name; + const int _sfd; + mutable ifreqstruct _ifr; + OMonitoringInterface* _mon; + + protected: + ifreqstruct& ifr() const; + virtual void init(); + bool ioctl( int call ) const; + bool ioctl( int call, ifreqstruct& ) const; +}; + +/*====================================================================================== + * OChannelHopper + *======================================================================================*/ + +class OChannelHopper : public QObject +{ + public: + OChannelHopper( OWirelessNetworkInterface* ); + virtual ~OChannelHopper(); + virtual void timerEvent( QTimerEvent* ); + void setInterval( int ); + int interval() const; + + private: + OWirelessNetworkInterface* _iface; + int _interval; + int _channel; + int _tid; +}; + + +/*====================================================================================== + * OWirelessNetworkInterface + *======================================================================================*/ + +class OWirelessNetworkInterface : public ONetworkInterface +{ + friend class OMonitoringInterface; + friend class OCiscoMonitoringInterface; + friend class OWlanNGMonitoringInterface; + friend class OHostAPMonitoringInterface; + friend class OOrinocoMonitoringInterface; + + public: + enum Mode { AdHoc, Managed, Monitor }; + + OWirelessNetworkInterface( const QString& name ); + virtual ~OWirelessNetworkInterface(); + + virtual void setChannel( int ) const; + virtual int channel() const; + virtual double frequency() const; + virtual int channels() const; + //virtual double frequency(int) const; + + virtual void setMode( Mode ) {}; + virtual bool mode() const {}; + + virtual void setMonitorMode( bool ); + virtual bool monitorMode() const; + + virtual void setChannelHopping( int interval ); + virtual int channelHopping() const; + + virtual void setNickName( const QString& ) {}; + virtual QString nickName() const; + + virtual bool isAssociated() const {}; + virtual QString associatedAP() const; + + virtual void setSSID( const QString& ); + virtual QString SSID() const; + + protected: + mutable iwreqstruct _iwr; + QMap<int,int> _channels; + + protected: + virtual void init(); + iwreqstruct& iwr() const; + bool wioctl( int call ) const; + bool wioctl( int call, iwreqstruct& ) const; + + private: + OChannelHopper _hopper; +}; + + +/*====================================================================================== + * OMonitoringInterface + *======================================================================================*/ + + +class OMonitoringInterface +{ + public: + OMonitoringInterface(); + OMonitoringInterface( ONetworkInterface* ); + virtual ~OMonitoringInterface(); + + public: + virtual void setEnabled( bool ); + virtual bool enabled() const; + virtual void setChannel( int ); + + virtual QString name() const = 0; + + protected: + bool _enabled; + const OWirelessNetworkInterface* _if; + +}; + + +/*====================================================================================== + * OCiscoMonitoring + *======================================================================================*/ + + +class OCiscoMonitoringInterface : public OMonitoringInterface +{ + public: + OCiscoMonitoringInterface( ONetworkInterface* ); + virtual ~OCiscoMonitoringInterface(); + + virtual void setEnabled( bool ); + virtual QString name() const; + virtual void setChannel( int ); + +}; + +/*====================================================================================== + * OWlanNGMonitoringInterface + *======================================================================================*/ + +class OWlanNGMonitoringInterface : public OMonitoringInterface +{ + public: + OWlanNGMonitoringInterface( ONetworkInterface* ); + virtual ~OWlanNGMonitoringInterface(); + + public: + virtual void setEnabled( bool ); + virtual QString name() const; + virtual void setChannel( int ); + +}; + +/*====================================================================================== + * OHostAPMonitoringInterface + *======================================================================================*/ + +class OHostAPMonitoringInterface : public OMonitoringInterface +{ + public: + OHostAPMonitoringInterface( ONetworkInterface* ); + virtual ~OHostAPMonitoringInterface(); + + public: + virtual void setEnabled( bool ); + virtual QString name() const; + }; + +/*====================================================================================== + * OOrinocoMonitoringInterface + *======================================================================================*/ + +class OOrinocoMonitoringInterface : public OMonitoringInterface +{ + public: + OOrinocoMonitoringInterface( ONetworkInterface* ); + virtual ~OOrinocoMonitoringInterface(); + + public: + virtual void setChannel( int ); + virtual void setEnabled( bool ); + virtual QString name() const; + +}; + +#endif // ONETWORK_H + diff --git a/libopie2/opienet/opcap.cpp b/libopie2/opienet/opcap.cpp new file mode 100644 index 0000000..48f874f --- a/dev/null +++ b/libopie2/opienet/opcap.cpp @@ -0,0 +1,609 @@ +/* + This file is part of the Opie Project + Copyright (C) 2003 by the Wellenreiter team: + Martin J. Muench <mjm@remote-exploit.org> + Max Moser <mmo@remote-exploit.org + Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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. + +*/ + +/* OPIE */ + +#include <opie2/opcap.h> + +/* QT */ + +#include <qapplication.h> // don't use oapplication here (will decrease reusability in other projects) +#include <qsocketnotifier.h> + +/*====================================================================================== + * OPacket + *======================================================================================*/ + +OPacket::OPacket( packetheaderstruct header, const unsigned char* data, QObject* parent ) + :QObject( parent, "Generic" ), _hdr( header ), _data( data ) +{ + qDebug( "OPacket::OPacket(): (Len %d, CapLen %d)" /*, ctime((const time_t*) header.ts.tv_sec)*/, header.len, header.caplen ); + + if ( packetCapturer()->dataLink() == DLT_EN10MB ) + { + qDebug( "OPacket::OPacket(): Received Packet. Datalink = ETHERNET" ); + new OEthernetPacket( (const struct ether_header*) data, this ); + } + else + { + qDebug( "OPacket::OPacket(): Received Packet. Datalink = IEEE802.11" ); + new OWaveLanPacket( (const struct ieee_802_11_header*) data, this ); + } +} + + +OPacket::~OPacket() +{ +} + + +OPacketCapturer* OPacket::packetCapturer() const +{ + return parent()->inherits( "OPacketCapturer" ) ? static_cast<OPacketCapturer*>( parent() ) : 0; +} + + +timevalstruct OPacket::timeval() const +{ + return _hdr.ts; +} + + +int OPacket::caplen() const +{ + return _hdr.caplen; +} + + +void OPacket::dump() const +{ + printf( "OPacket::dump()\n" ); + printf( "----------------\n" ); + + for ( int i = 0; i < _hdr.caplen; ++i ) + { + printf( "%02x ", _data[i] ); + if ( !((i+1) % 32) ) printf( "\n" ); + } + printf( "\n\n" ); +} + + + +int OPacket::len() const +{ + return _hdr.len; +} + +/*====================================================================================== + * OEthernetPacket + *======================================================================================*/ + +OEthernetPacket::OEthernetPacket( const struct ether_header* data, QObject* parent ) + :QObject( parent, "Ethernet" ), _ether( data ) + +{ + + qDebug( "Source = %s", (const char*) sourceAddress().toString() ); + qDebug( "Destination = %s", (const char*) destinationAddress().toString() ); + + if ( sourceAddress() == OMacAddress::broadcast ) + qDebug( "Source is broadcast address" ); + if ( destinationAddress() == OMacAddress::broadcast ) + qDebug( "Destination is broadcast address" ); + + switch ( type() ) + { + case ETHERTYPE_IP: new OIPPacket( (const struct iphdr*) (data+1), this ); break; + case ETHERTYPE_ARP: { qDebug( "OPacket::OPacket(): Received Ethernet Packet : Type = ARP" ); break; } + case ETHERTYPE_REVARP: { qDebug( "OPacket::OPacket(): Received Ethernet Packet : Type = RARP" ); break; } + default: qDebug( "OPacket::OPacket(): Received Ethernet Packet : Type = UNKNOWN" ); + } + +} + + +OEthernetPacket::~OEthernetPacket() +{ +} + + +OMacAddress OEthernetPacket::sourceAddress() const +{ + return OMacAddress( _ether->ether_shost ); +} + + +OMacAddress OEthernetPacket::destinationAddress() const +{ + return OMacAddress( _ether->ether_dhost ); +} + +int OEthernetPacket::type() const +{ + return ntohs( _ether->ether_type ); +} + + +/*====================================================================================== + * OIPPacket + *======================================================================================*/ + + +OIPPacket::OIPPacket( const struct iphdr* data, QObject* parent ) + :QObject( parent, "IP" ), _iphdr( data ) + +{ + qDebug( "OIPPacket::OIPPacket(): decoding IP header..." ); + + //qDebug( "FromAddress: %s", (const char*) inet_ntoa( *src ) ); + //qDebug( " ToAddress: %s", (const char*) inet_ntoa( *dst ) ); + + qDebug( "FromAddress: %s", (const char*) fromIPAddress().toString() ); + qDebug( " toAddress: %s", (const char*) toIPAddress().toString() ); + + switch ( protocol() ) + { + case IPPROTO_UDP: new OUDPPacket( (const struct udphdr*) (data+1), this ); break; + case IPPROTO_TCP: new OTCPPacket( (const struct tcphdr*) (data+1), this ); break; + default: qDebug( "OIPPacket::OIPPacket(): unknown IP protocol type = %d", protocol() ); + } + +} + +OIPPacket::~OIPPacket() +{ +} + + +QHostAddress OIPPacket::fromIPAddress() const +{ + return EXTRACT_32BITS( &_iphdr->saddr ); +} + + +QHostAddress OIPPacket::toIPAddress() const +{ + return EXTRACT_32BITS( &_iphdr->saddr ); +} + + +int OIPPacket::tos() const +{ + return _iphdr->tos; +} + + +int OIPPacket::len() const +{ + return EXTRACT_16BITS( &_iphdr->tot_len ); +} + + +int OIPPacket::id() const +{ + return EXTRACT_16BITS( &_iphdr->id ); +} + + +int OIPPacket::offset() const +{ + return EXTRACT_16BITS( &_iphdr->frag_off ); +} + + +int OIPPacket::ttl() const +{ + return _iphdr->ttl; +} + + +int OIPPacket::protocol() const +{ + return _iphdr->protocol; +} + + +int OIPPacket::checksum() const +{ + return EXTRACT_16BITS( &_iphdr->check ); +} + +/*====================================================================================== + * OUDPPacket + *======================================================================================*/ + + +OUDPPacket::OUDPPacket( const struct udphdr* data, QObject* parent ) + :QObject( parent, "UDP" ), _udphdr( data ) + +{ + qDebug( "OUDPPacket::OUDPPacket(): decoding UDP header..." ); +} + +OUDPPacket::~OUDPPacket() +{ +} + + +/*====================================================================================== + * OTCPPacket + *======================================================================================*/ + + +OTCPPacket::OTCPPacket( const struct tcphdr* data, QObject* parent ) + :QObject( parent, "TCP" ), _tcphdr( data ) + +{ + qDebug( "OTCPPacket::OTCPPacket(): decoding TCP header..." ); +} + +OTCPPacket::~OTCPPacket() +{ +} + + +/*====================================================================================== + * OWaveLanPacket + *======================================================================================*/ + + +OWaveLanPacket::OWaveLanPacket( const struct ieee_802_11_header* data, QObject* parent ) + :QObject( parent, "802.11" ), _wlanhdr( data ) + +{ + qDebug( "OWaveLanPacket::OWaveLanPacket(): decoding IEEE 802.11 header..." ); + qDebug( "type: %0X", type() ); + qDebug( "subType: %0X", subType() ); + qDebug( "duration: %d", duration() ); + qDebug( "powermanagement: %d", usesPowerManagement() ); + qDebug( "wep: %d", usesWep() ); + qDebug( "MAC1: %s", (const char*) macAddress1().toString() ); + qDebug( "MAC2: %s", (const char*) macAddress2().toString() ); + qDebug( "MAC3: %s", (const char*) macAddress3().toString() ); + qDebug( "MAC4: %s", (const char*) macAddress4().toString() ); + + switch ( type() ) + { + case T_MGMT: new OWaveLanManagementPacket( (const struct ieee_802_11_mgmt_header*) data, this ); break; + case T_DATA: new OWaveLanDataPacket( (const struct ieee_802_11_data_header*) data, this ); break; + //case T_CTRL: new OWaveLanControlPacket( (const struct ieee_802_11_ctrl_header*) data, this ); break; + default: qDebug( "OWaveLanPacket::OWaveLanPacket(): Warning: Unknown type!" ); + } +} + +OWaveLanPacket::~OWaveLanPacket() +{ +} + + +int OWaveLanPacket::duration() const +{ + return _wlanhdr->duration; +} + + +OMacAddress OWaveLanPacket::macAddress1() const +{ + return OMacAddress( _wlanhdr->mac1 ); +} + + +OMacAddress OWaveLanPacket::macAddress2() const +{ + return OMacAddress( _wlanhdr->mac2 ); +} + + +OMacAddress OWaveLanPacket::macAddress3() const +{ + return OMacAddress( _wlanhdr->mac3 ); +} + + +OMacAddress OWaveLanPacket::macAddress4() const +{ + return OMacAddress( _wlanhdr->mac4 ); +} + + +int OWaveLanPacket::subType() const +{ + return FC_SUBTYPE( EXTRACT_LE_16BITS( &_wlanhdr->frame_control ) ); +} + + +int OWaveLanPacket::type() const +{ + return FC_TYPE( EXTRACT_LE_16BITS( &_wlanhdr->frame_control ) ); +} + + +int OWaveLanPacket::version() const +{ + return FC_VERSION( EXTRACT_LE_16BITS( &_wlanhdr->frame_control ) ); +} + + +bool OWaveLanPacket::fromDS() const +{ + return FC_FROM_DS( EXTRACT_LE_16BITS( &_wlanhdr->frame_control ) ); +} + + +bool OWaveLanPacket::toDS() const +{ + return FC_TO_DS( EXTRACT_LE_16BITS( &_wlanhdr->frame_control ) ); +} + + +bool OWaveLanPacket::usesPowerManagement() const +{ + return FC_POWER_MGMT( EXTRACT_LE_16BITS( &_wlanhdr->frame_control ) ); +} + + +bool OWaveLanPacket::usesWep() const +{ + return FC_WEP( EXTRACT_LE_16BITS( &_wlanhdr->frame_control ) ); +} + + +/*====================================================================================== + * OWaveLanManagementPacket + *======================================================================================*/ + +OWaveLanManagementPacket::OWaveLanManagementPacket( const struct ieee_802_11_mgmt_header* data, OWaveLanPacket* parent ) + :QObject( parent, "802.11 Management" ), _header( data ), + _body( (const struct ieee_802_11_mgmt_body*) (data+1) ) +{ + qDebug( "OWaveLanManagementPacket::OWaveLanManagementPacket(): decoding frame..." ); + + switch ( ((OWaveLanPacket*) this->parent() )->subType() ) + { + case ST_BEACON: + { + qDebug( "TYPE: BEACON FRAME" ); + qDebug( "ESSID: %s", (const char*) SSID() ); + break; + } + } +} + + +OWaveLanManagementPacket::~OWaveLanManagementPacket() +{ +} + + +QString OWaveLanManagementPacket::SSID() const +{ + int length = _body->ssid.length; + if ( length > 32 ) length = 32; + char essid[length+1]; + memcpy( &essid, _body->ssid.ssid, length ); + essid[length] = 0x0; + return essid; +} + + +/*====================================================================================== + * OWaveLanDataPacket + *======================================================================================*/ + +OWaveLanDataPacket::OWaveLanDataPacket( const struct ieee_802_11_data_header* data, OWaveLanPacket* parent ) + :QObject( parent, "802.11 Data" ), _header( data ) +{ + //qDebug( "size of header = %d", sizeof( struct ieee_802_11_data_header ) ); + //qDebug( "header: %0x", data ); + const unsigned char* payload = (const unsigned char*) data + sizeof( struct ieee_802_11_data_header ); + //qDebug( "payload: %0x", payload ); + + if (!( ( (OWaveLanPacket*) this->parent())->duration() )) payload -= 6; // compensation for missing last address + + new OLLCPacket( (const struct ieee_802_11_802_2_header*) payload, this ); +} + + +OWaveLanDataPacket::~OWaveLanDataPacket() +{ +} + + +/*====================================================================================== + * OLLCPacket + *======================================================================================*/ + +OLLCPacket::OLLCPacket( const struct ieee_802_11_802_2_header* data, QObject* parent ) + :QObject( parent, "802.11 802_2" ), _header( data ) +{ + qDebug( "OLLCPacket::OLLCPacket(): decoding frame..." ); + + if ( !(_header->oui[0] || _header->oui[1] || _header->oui[2]) ) + { + qDebug( "OLLCPacket::OLLCPacket(): contains an encapsulated Ethernet frame (type=%04X)", EXTRACT_16BITS( &_header->type ) ); + + switch ( EXTRACT_16BITS( &_header->type ) ) // defined in linux/if_ether.h + { + case ETH_P_IP: new OIPPacket( (const struct iphdr*) (data+1), this ); break; + default: qDebug( "OLLCPacket::OLLCPacket(): Unknown Encapsulation Type" ); + } + + } +} + + +OLLCPacket::~OLLCPacket() +{ +} + +/*====================================================================================== + * OPacketCapturer + *======================================================================================*/ + +OPacketCapturer::OPacketCapturer( QObject* parent, const char* name ) + :QObject( parent, name ), _name( QString::null ), _open( false ), + _pch( 0 ) +{ +} + + +OPacketCapturer::~OPacketCapturer() +{ + if ( _open ) + { + qDebug( "OPacketCapturer::~OPacketCapturer(): pcap still open, autoclosing." ); + close(); + } +} + + +void OPacketCapturer::setBlocking( bool b ) +{ + if ( pcap_setnonblock( _pch, 1-b, _errbuf ) != -1 ) + { + qDebug( "OPacketCapturer::setBlocking(): blocking mode changed successfully." ); + } + else + { + qDebug( "OPacketCapturer::setBlocking(): can't change blocking mode: %s", _errbuf ); + } +} + + +bool OPacketCapturer::blocking() const +{ + int b = pcap_getnonblock( _pch, _errbuf ); + if ( b == -1 ) + { + qDebug( "OPacketCapturer::blocking(): can't get blocking mode: %s", _errbuf ); + return -1; + } + return !b; +} + + +void OPacketCapturer::close() +{ + if ( _open ) + { + pcap_close( _pch ); + _open = false; + } +} + + +int OPacketCapturer::dataLink() const +{ + return pcap_datalink( _pch ); +} + + +int OPacketCapturer::fileno() const +{ + if ( _open ) + { + return pcap_fileno( _pch ); + } + else + { + return -1; + } +} + + +OPacket* OPacketCapturer::next() +{ + packetheaderstruct header; + const unsigned char* pdata = pcap_next( _pch, &header ); + if ( header.len ) + return new OPacket( header, pdata, this ); + else + return 0; +} + + +bool OPacketCapturer::open( const QString& name ) +{ + if ( _open ) + { + if ( name == _name ) // ignore opening an already openend device + { + return true; + } + else // close the last opened device + { + close(); + } + } + + _name = name; + + pcap_t* handle = pcap_open_live( const_cast<char*>( (const char*) name ), 1024, 0, 0, &_errbuf[0] ); + + if ( handle ) + { + qDebug( "OPacketCapturer::open(): libpcap opened successfully." ); + _pch = handle; + _open = true; + + // in case we have a qapp, create a socket notifier + if ( qApp ) + { + QSocketNotifier* sn = new QSocketNotifier( fileno(), QSocketNotifier::Read, this ); + connect( sn, SIGNAL( activated(int) ), this, SLOT( readyToReceive() ) ); + } + + return true; + } + else + { + qDebug( "OPacketCapturer::open(): can't open libpcap: %s", _errbuf ); + return false; + } + +} + + +bool OPacketCapturer::isOpen() const +{ + return _open; +} + + +void OPacketCapturer::readyToReceive() +{ + qDebug( "OPacketCapturer::readyToReceive(): about to emit 'receivePacket(...)'" ); + emit receivedPacket( next() ); +} + diff --git a/libopie2/opienet/opcap.h b/libopie2/opienet/opcap.h new file mode 100644 index 0000000..65c550c --- a/dev/null +++ b/libopie2/opienet/opcap.h @@ -0,0 +1,294 @@ +/* + This file is part of the Opie Project + Copyright (C) 2003 by the Wellenreiter team: + Martin J. Muench <mjm@remote-exploit.org> + Max Moser <mmo@remote-exploit.org + Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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 OPCAP_H +#define OPCAP_H + +/* LINUX */ +extern "C" // work around a bpf/pcap conflict in recent headers +{ + #include <pcap.h> +} +#include <netinet/ether.h> +#include <netinet/ip.h> +#include <netinet/udp.h> +#include <netinet/tcp.h> +#include <time.h> + +/* QT */ +#include <qhostaddress.h> +#include <qobject.h> +#include <qstring.h> + +/* OPIE */ +#include <opie2/onetutils.h> +#include "802_11_user.h" + +/* TYPEDEFS */ +typedef struct timeval timevalstruct; +typedef struct pcap_pkthdr packetheaderstruct; + +/* FORWARDS */ +class OPacketCapturer; + +/*====================================================================================== + * OPacket - A frame on the wire + *======================================================================================*/ + +class OPacket : public QObject +{ + Q_OBJECT + + public: + OPacket( packetheaderstruct, const unsigned char*, QObject* parent ); + virtual ~OPacket(); + + timevalstruct timeval() const; + + OPacketCapturer* packetCapturer() const; + + int caplen() const; + int len() const; + void dump() const; + + private: + const packetheaderstruct _hdr; // pcap packet header + const unsigned char* _data; // pcap packet data +}; + +/*====================================================================================== + * OEthernetPacket - DLT_EN10MB frame + *======================================================================================*/ + +class OEthernetPacket : public QObject +{ + Q_OBJECT + + public: + OEthernetPacket( const struct ether_header*, QObject* parent = 0 ); + virtual ~OEthernetPacket(); + + OMacAddress sourceAddress() const; + OMacAddress destinationAddress() const; + int type() const; + + private: + const struct ether_header* _ether; +}; + + +/*====================================================================================== + * OWaveLanPacket - DLT_IEEE802_11 frame + *======================================================================================*/ + +class OWaveLanPacket : public QObject +{ + Q_OBJECT + + public: + OWaveLanPacket( const struct ieee_802_11_header*, QObject* parent = 0 ); + virtual ~OWaveLanPacket(); + + int duration() const; + bool fromDS() const; + bool toDS() const; + virtual OMacAddress macAddress1() const; + virtual OMacAddress macAddress2() const; + virtual OMacAddress macAddress3() const; + virtual OMacAddress macAddress4() const; + bool usesPowerManagement() const; + int type() const; + int subType() const; + int version() const; + bool usesWep() const; + + private: + const struct ieee_802_11_header* _wlanhdr; +}; + + +/*====================================================================================== + * OWaveLanManagementPacket - type: management (T_MGMT) + *======================================================================================*/ + +class OWaveLanManagementPacket : public QObject +{ + Q_OBJECT + + public: + OWaveLanManagementPacket( const struct ieee_802_11_mgmt_header*, OWaveLanPacket* parent = 0 ); + virtual ~OWaveLanManagementPacket(); + + QString SSID() const; + + private: + const struct ieee_802_11_mgmt_header* _header; + const struct ieee_802_11_mgmt_body* _body; +}; + + +/*====================================================================================== + * OWaveLanDataPacket - type: data (T_DATA) + *======================================================================================*/ + +class OWaveLanDataPacket : public QObject +{ + Q_OBJECT + + public: + OWaveLanDataPacket( const struct ieee_802_11_data_header*, OWaveLanPacket* parent = 0 ); + virtual ~OWaveLanDataPacket(); + + private: + const struct ieee_802_11_data_header* _header; +}; + +/*====================================================================================== + * OLLCPacket - IEEE 802.2 Link Level Control + *======================================================================================*/ + +class OLLCPacket : public QObject +{ + Q_OBJECT + + public: + OLLCPacket( const struct ieee_802_11_802_2_header* data, QObject* parent = 0 ); + virtual ~OLLCPacket(); + + private: + const struct ieee_802_11_802_2_header* _header; +}; + +/*====================================================================================== + * OIPPacket + *======================================================================================*/ + +class OIPPacket : public QObject +{ + Q_OBJECT + + public: + OIPPacket( const struct iphdr*, QObject* parent = 0 ); + virtual ~OIPPacket(); + + QHostAddress fromIPAddress() const; + QHostAddress toIPAddress() const; + + int tos() const; + int len() const; + int id() const; + int offset() const; + int ttl() const; + int protocol() const; + int checksum() const; + + private: + const struct iphdr* _iphdr; +}; + +/*====================================================================================== + * OUDPPacket + *======================================================================================*/ + +class OUDPPacket : public QObject +{ + Q_OBJECT + + public: + OUDPPacket( const struct udphdr*, QObject* parent = 0 ); + virtual ~OUDPPacket(); + + int fromPort() const; + int toPort() const; + + private: + const struct udphdr* _udphdr; +}; + +/*====================================================================================== + * OTCPPacket + *======================================================================================*/ + +class OTCPPacket : public QObject +{ + Q_OBJECT + + public: + OTCPPacket( const struct tcphdr*, QObject* parent = 0 ); + virtual ~OTCPPacket(); + + int fromPort() const; + int toPort() const; + + private: + const struct tcphdr* _tcphdr; +}; + + +/*====================================================================================== + * OPacketCapturer + *======================================================================================*/ + +class OPacketCapturer : public QObject +{ + Q_OBJECT + + public: + OPacketCapturer( QObject* parent = 0, const char* name = 0 ); + ~OPacketCapturer(); + + void setBlocking( bool ); + bool blocking() const; + + void close(); + int dataLink() const; + int fileno() const; + OPacket* next(); + bool open( const QString& name ); + bool isOpen() const; + + signals: + void receivedPacket( OPacket* ); + + protected slots: + void readyToReceive(); + + protected: + QString _name; // devicename + bool _open; // check this before doing pcap calls + pcap_t* _pch; // pcap library handle + mutable char _errbuf[PCAP_ERRBUF_SIZE]; +}; + +#endif // OPCAP_H + diff --git a/libopie2/opienet/opienet.pro b/libopie2/opienet/opienet.pro new file mode 100644 index 0000000..e73afbf --- a/dev/null +++ b/libopie2/opienet/opienet.pro @@ -0,0 +1,18 @@ +TEMPLATE = lib +CONFIG += qt warn_on debug +DESTDIR = $(OPIEDIR)/lib +HEADERS = onetutils.cpp onetwork.h opcap.h + +SOURCES = onetutils.cpp onetwork.cpp opcap.cpp +INTERFACES = +TARGET = opienet2 +VERSION = 1.8.1 +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += $(OPIEDIR)/include +LIBS += -lpcap + +MOC_DIR = moc +OBJECTS_DIR = obj + +include ( $(OPIEDIR)/include.pro ) + diff --git a/libopie2/opiepim/.cvsignore b/libopie2/opiepim/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/opiepim/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/opiepim/config.in b/libopie2/opiepim/config.in new file mode 100644 index 0000000..79b8f46 --- a/dev/null +++ b/libopie2/opiepim/config.in @@ -0,0 +1,7 @@ + config LIBOPIE2PIM + boolean "libopie2pim (pim related classes)" + default "n" + depends ( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE + comment "libopie2pim needs a libqpe and libopie2core" + depends !(( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE) + diff --git a/libopie2/opiepim/opiepim.pro b/libopie2/opiepim/opiepim.pro new file mode 100644 index 0000000..7fc7bb7 --- a/dev/null +++ b/libopie2/opiepim/opiepim.pro @@ -0,0 +1,17 @@ +TEMPLATE = lib +CONFIG += qt warn_on debug +DESTDIR = $(OPIEDIR)/lib +HEADERS = + +SOURCES = +INTERFACES = +TARGET = opiepim2 +VERSION = 1.8.1 +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += $(OPIEDIR)/include + +MOC_DIR = moc +OBJECTS_DIR = obj + +include ( $(OPIEDIR)/include.pro ) + diff --git a/libopie2/opieui/.cvsignore b/libopie2/opieui/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/opieui/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/opieui/config.in b/libopie2/opieui/config.in new file mode 100644 index 0000000..d40b5d9 --- a/dev/null +++ b/libopie2/opieui/config.in @@ -0,0 +1,7 @@ + config LIBOPIE2UI + boolean "libopie2ui (user interface related classes)" + default "n" + depends ( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE + comment "libopie2ui needs a libqpe and libopie2core" + depends !(( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE) + diff --git a/libopie2/opieui/odialog.cpp b/libopie2/opieui/odialog.cpp new file mode 100644 index 0000000..00a7a7e --- a/dev/null +++ b/libopie2/opieui/odialog.cpp @@ -0,0 +1,53 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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/odialog.h> + +int ODialog::mMarginSize = 5; // 11 like in KDialog is probably too much for PDA +int ODialog::mSpacingSize = 2; // 6 like in KDialog is probably too much for PDA + +ODialog::ODialog(QWidget *parent, const char *name, bool modal, WFlags f) + : QDialog(parent, name, modal, f) +{ +} + +int ODialog::marginHint() +{ + return( mMarginSize ); +} + + +int ODialog::spacingHint() +{ + return( mSpacingSize ); +} + +// Placeholder for even more sophisticed things diff --git a/libopie2/opieui/odialog.h b/libopie2/opieui/odialog.h new file mode 100644 index 0000000..38f25e8 --- a/dev/null +++ b/libopie2/opieui/odialog.h @@ -0,0 +1,89 @@ +/* + This file is part of the Opie Project + + (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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 ODIALOG_H +#define ODIALOG_H + +class QLayoutItem; + +#include <qdialog.h> + +/** + * Dialog with extended nonmodal support and methods for OPIE standard + * compliance. + * + * The @ref marginHint() and @ref spacingHint() sizes shall be used + * whenever you layout the interior of a dialog. One special note. If + * you make your own action buttons (OK, Cancel etc), the space + * beteween the buttons shall be @ref spacingHint(), whereas the space + * above, below, to the right and to the left shall be @ref marginHint(). + * If you add a separator line above the buttons, there shall be a + * @ref marginHint() between the buttons and the separator and a + * @ref marginHint() above the separator as well. + * + * @author Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + */ + +class ODialog : public QDialog +{ + Q_OBJECT + + public: + + /** + * Constructor. + * + * Takes the same arguments as @ref QDialog. + */ + ODialog(QWidget *parent = 0, const char *name = 0, + bool modal = false, WFlags f = 0); + + /** + * Return the number of pixels you shall use between a + * dialog edge and the outermost widget(s) according to the KDE standard. + **/ + static int marginHint(); + + /** + * Return the number of pixels you shall use between + * widgets inside a dialog according to the KDE standard. + */ + static int spacingHint(); + + private: + static int mMarginSize; + static int mSpacingSize; + + //class ODialogPrivate; + //ODialogPrivate *d; + +}; +#endif // ODIALOG_H diff --git a/libopie2/opieui/oimageeffect.cpp b/libopie2/opieui/oimageeffect.cpp new file mode 100644 index 0000000..3c28bbe --- a/dev/null +++ b/libopie2/opieui/oimageeffect.cpp @@ -0,0 +1,3794 @@ +/* This file is part of the KDE libraries + Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley <mosfet@kde.org> + (C) 1998, 1999 Christian Tibirna <ctibirna@total.net> + (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org> + (C) 2000 Josef Weidendorfer <weidendo@in.tum.de> + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +// $Id$ + +#include <math.h> + +#include <qimage.h> +#include <stdlib.h> +#include <iostream> + +#include "oimageeffect.h" + +#define MaxRGB 255L +#define DegreesToRadians(x) ((x)*M_PI/180.0) + +using namespace std; + +inline unsigned int intensityValue(unsigned int color) +{ + return((unsigned int)((0.299*qRed(color) + + 0.587*qGreen(color) + + 0.1140000000000001*qBlue(color)))); +} + +//====================================================================== +// +// Gradient effects +// +//====================================================================== + +QImage OImageEffect::gradient(const QSize &size, const QColor &ca, + const QColor &cb, GradientType eff, int ncols) +{ + int rDiff, gDiff, bDiff; + int rca, gca, bca, rcb, gcb, bcb; + + QImage image(size, 32); + + if (size.width() == 0 || size.height() == 0) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::gradient: invalid image" << endl; +#endif + return image; + } + + register int x, y; + + rDiff = (rcb = cb.red()) - (rca = ca.red()); + gDiff = (gcb = cb.green()) - (gca = ca.green()); + bDiff = (bcb = cb.blue()) - (bca = ca.blue()); + + if( eff == VerticalGradient || eff == HorizontalGradient ){ + + uint *p; + uint rgb; + + register int rl = rca << 16; + register int gl = gca << 16; + register int bl = bca << 16; + + if( eff == VerticalGradient ) { + + int rcdelta = ((1<<16) / size.height()) * rDiff; + int gcdelta = ((1<<16) / size.height()) * gDiff; + int bcdelta = ((1<<16) / size.height()) * bDiff; + + for ( y = 0; y < size.height(); y++ ) { + p = (uint *) image.scanLine(y); + + rl += rcdelta; + gl += gcdelta; + bl += bcdelta; + + rgb = qRgb( (rl>>16), (gl>>16), (bl>>16) ); + + for( x = 0; x < size.width(); x++ ) { + *p = rgb; + p++; + } + } + + } + else { // must be HorizontalGradient + + unsigned int *o_src = (unsigned int *)image.scanLine(0); + unsigned int *src = o_src; + + int rcdelta = ((1<<16) / size.width()) * rDiff; + int gcdelta = ((1<<16) / size.width()) * gDiff; + int bcdelta = ((1<<16) / size.width()) * bDiff; + + for( x = 0; x < size.width(); x++) { + + rl += rcdelta; + gl += gcdelta; + bl += bcdelta; + + *src++ = qRgb( (rl>>16), (gl>>16), (bl>>16)); + } + + src = o_src; + + // Believe it or not, manually copying in a for loop is faster + // than calling memcpy for each scanline (on the order of ms...). + // I think this is due to the function call overhead (mosfet). + + for (y = 1; y < size.height(); ++y) { + + p = (unsigned int *)image.scanLine(y); + src = o_src; + for(x=0; x < size.width(); ++x) + *p++ = *src++; + } + } + } + + else { + + float rfd, gfd, bfd; + float rd = rca, gd = gca, bd = bca; + + unsigned char *xtable[3]; + unsigned char *ytable[3]; + + unsigned int w = size.width(), h = size.height(); + xtable[0] = new unsigned char[w]; + xtable[1] = new unsigned char[w]; + xtable[2] = new unsigned char[w]; + ytable[0] = new unsigned char[h]; + ytable[1] = new unsigned char[h]; + ytable[2] = new unsigned char[h]; + w*=2, h*=2; + + if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) { + // Diagonal dgradient code inspired by BlackBox (mosfet) + // BlackBox dgradient is (C) Brad Hughes, <bhughes@tcac.net> and + // Mike Cole <mike@mydot.com>. + + rfd = (float)rDiff/w; + gfd = (float)gDiff/w; + bfd = (float)bDiff/w; + + int dir; + for (x = 0; x < size.width(); x++, rd+=rfd, gd+=gfd, bd+=bfd) { + dir = eff == DiagonalGradient? x : size.width() - x - 1; + xtable[0][dir] = (unsigned char) rd; + xtable[1][dir] = (unsigned char) gd; + xtable[2][dir] = (unsigned char) bd; + } + rfd = (float)rDiff/h; + gfd = (float)gDiff/h; + bfd = (float)bDiff/h; + rd = gd = bd = 0; + for (y = 0; y < size.height(); y++, rd+=rfd, gd+=gfd, bd+=bfd) { + ytable[0][y] = (unsigned char) rd; + ytable[1][y] = (unsigned char) gd; + ytable[2][y] = (unsigned char) bd; + } + + for (y = 0; y < size.height(); y++) { + unsigned int *scanline = (unsigned int *)image.scanLine(y); + for (x = 0; x < size.width(); x++) { + scanline[x] = qRgb(xtable[0][x] + ytable[0][y], + xtable[1][x] + ytable[1][y], + xtable[2][x] + ytable[2][y]); + } + } + } + + else if (eff == RectangleGradient || + eff == PyramidGradient || + eff == PipeCrossGradient || + eff == EllipticGradient) + { + int rSign = rDiff>0? 1: -1; + int gSign = gDiff>0? 1: -1; + int bSign = bDiff>0? 1: -1; + + rfd = (float)rDiff / size.width(); + gfd = (float)gDiff / size.width(); + bfd = (float)bDiff / size.width(); + + rd = (float)rDiff/2; + gd = (float)gDiff/2; + bd = (float)bDiff/2; + + for (x = 0; x < size.width(); x++, rd-=rfd, gd-=gfd, bd-=bfd) + { + xtable[0][x] = (unsigned char) abs((int)rd); + xtable[1][x] = (unsigned char) abs((int)gd); + xtable[2][x] = (unsigned char) abs((int)bd); + } + + rfd = (float)rDiff/size.height(); + gfd = (float)gDiff/size.height(); + bfd = (float)bDiff/size.height(); + + rd = (float)rDiff/2; + gd = (float)gDiff/2; + bd = (float)bDiff/2; + + for (y = 0; y < size.height(); y++, rd-=rfd, gd-=gfd, bd-=bfd) + { + ytable[0][y] = (unsigned char) abs((int)rd); + ytable[1][y] = (unsigned char) abs((int)gd); + ytable[2][y] = (unsigned char) abs((int)bd); + } + unsigned int rgb; + int h = (size.height()+1)>>1; + for (y = 0; y < h; y++) { + unsigned int *sl1 = (unsigned int *)image.scanLine(y); + unsigned int *sl2 = (unsigned int *)image.scanLine(QMAX(size.height()-y-1, y)); + + int w = (size.width()+1)>>1; + int x2 = size.width()-1; + + for (x = 0; x < w; x++, x2--) { + rgb = 0; + if (eff == PyramidGradient) { + rgb = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]), + gcb-gSign*(xtable[1][x]+ytable[1][y]), + bcb-bSign*(xtable[2][x]+ytable[2][y])); + } + if (eff == RectangleGradient) { + rgb = qRgb(rcb - rSign * + QMAX(xtable[0][x], ytable[0][y]) * 2, + gcb - gSign * + QMAX(xtable[1][x], ytable[1][y]) * 2, + bcb - bSign * + QMAX(xtable[2][x], ytable[2][y]) * 2); + } + if (eff == PipeCrossGradient) { + rgb = qRgb(rcb - rSign * + QMIN(xtable[0][x], ytable[0][y]) * 2, + gcb - gSign * + QMIN(xtable[1][x], ytable[1][y]) * 2, + bcb - bSign * + QMIN(xtable[2][x], ytable[2][y]) * 2); + } + if (eff == EllipticGradient) { + rgb = qRgb(rcb - rSign * + (int)sqrt((xtable[0][x]*xtable[0][x] + + ytable[0][y]*ytable[0][y])*2.0), + gcb - gSign * + (int)sqrt((xtable[1][x]*xtable[1][x] + + ytable[1][y]*ytable[1][y])*2.0), + bcb - bSign * + (int)sqrt((xtable[2][x]*xtable[2][x] + + ytable[2][y]*ytable[2][y])*2.0)); + } + + sl1[x] = sl2[x] = rgb; + sl1[x2] = sl2[x2] = rgb; + } + } + } + + delete [] xtable[0]; + delete [] xtable[1]; + delete [] xtable[2]; + delete [] ytable[0]; + delete [] ytable[1]; + delete [] ytable[2]; + } + + // dither if necessary + if (ncols && (QPixmap::defaultDepth() < 15 )) { + if ( ncols < 2 || ncols > 256 ) + ncols = 3; + QColor *dPal = new QColor[ncols]; + for (int i=0; i<ncols; i++) { + dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ), + gca + gDiff * i / ( ncols - 1 ), + bca + bDiff * i / ( ncols - 1 ) ); + } + dither(image, dPal, ncols); + delete [] dPal; + } + + return image; +} + + +// ----------------------------------------------------------------------------- + +//CT this was (before Dirk A. Mueller's speedup changes) +// merely the same code as in the above method, but it's supposedly +// way less performant since it introduces a lot of supplementary tests +// and simple math operations for the calculus of the balance. +// (surprizingly, it isn't less performant, in the contrary :-) +// Yes, I could have merged them, but then the excellent performance of +// the balanced code would suffer with no other gain than a mere +// source code and byte code size economy. + +QImage OImageEffect::unbalancedGradient(const QSize &size, const QColor &ca, + const QColor &cb, GradientType eff, int xfactor, int yfactor, + int ncols) +{ + int dir; // general parameter used for direction switches + + bool _xanti = false , _yanti = false; + + if (xfactor < 0) _xanti = true; // negative on X direction + if (yfactor < 0) _yanti = true; // negative on Y direction + + xfactor = abs(xfactor); + yfactor = abs(yfactor); + + if (!xfactor) xfactor = 1; + if (!yfactor) yfactor = 1; + + if (xfactor > 200 ) xfactor = 200; + if (yfactor > 200 ) yfactor = 200; + + + // float xbal = xfactor/5000.; + // float ybal = yfactor/5000.; + float xbal = xfactor/30./size.width(); + float ybal = yfactor/30./size.height(); + float rat; + + int rDiff, gDiff, bDiff; + int rca, gca, bca, rcb, gcb, bcb; + + QImage image(size, 32); + + if (size.width() == 0 || size.height() == 0) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::unbalancedGradient : invalid image\n"; +#endif + return image; + } + + register int x, y; + unsigned int *scanline; + + rDiff = (rcb = cb.red()) - (rca = ca.red()); + gDiff = (gcb = cb.green()) - (gca = ca.green()); + bDiff = (bcb = cb.blue()) - (bca = ca.blue()); + + if( eff == VerticalGradient || eff == HorizontalGradient){ + QColor cRow; + + uint *p; + uint rgbRow; + + if( eff == VerticalGradient) { + for ( y = 0; y < size.height(); y++ ) { + dir = _yanti ? y : size.height() - 1 - y; + p = (uint *) image.scanLine(dir); + rat = 1 - exp( - (float)y * ybal ); + + cRow.setRgb( rcb - (int) ( rDiff * rat ), + gcb - (int) ( gDiff * rat ), + bcb - (int) ( bDiff * rat ) ); + + rgbRow = cRow.rgb(); + + for( x = 0; x < size.width(); x++ ) { + *p = rgbRow; + p++; + } + } + } + else { + + unsigned int *src = (unsigned int *)image.scanLine(0); + for(x = 0; x < size.width(); x++ ) + { + dir = _xanti ? x : size.width() - 1 - x; + rat = 1 - exp( - (float)x * xbal ); + + src[dir] = qRgb(rcb - (int) ( rDiff * rat ), + gcb - (int) ( gDiff * rat ), + bcb - (int) ( bDiff * rat )); + } + + // Believe it or not, manually copying in a for loop is faster + // than calling memcpy for each scanline (on the order of ms...). + // I think this is due to the function call overhead (mosfet). + + for(y = 1; y < size.height(); ++y) + { + scanline = (unsigned int *)image.scanLine(y); + for(x=0; x < size.width(); ++x) + scanline[x] = src[x]; + } + } + } + + else { + int w=size.width(), h=size.height(); + + unsigned char *xtable[3]; + unsigned char *ytable[3]; + xtable[0] = new unsigned char[w]; + xtable[1] = new unsigned char[w]; + xtable[2] = new unsigned char[w]; + ytable[0] = new unsigned char[h]; + ytable[1] = new unsigned char[h]; + ytable[2] = new unsigned char[h]; + + if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) + { + for (x = 0; x < w; x++) { + dir = _xanti ? x : w - 1 - x; + rat = 1 - exp( - (float)x * xbal ); + + xtable[0][dir] = (unsigned char) ( rDiff/2 * rat ); + xtable[1][dir] = (unsigned char) ( gDiff/2 * rat ); + xtable[2][dir] = (unsigned char) ( bDiff/2 * rat ); + } + + for (y = 0; y < h; y++) { + dir = _yanti ? y : h - 1 - y; + rat = 1 - exp( - (float)y * ybal ); + + ytable[0][dir] = (unsigned char) ( rDiff/2 * rat ); + ytable[1][dir] = (unsigned char) ( gDiff/2 * rat ); + ytable[2][dir] = (unsigned char) ( bDiff/2 * rat ); + } + + for (y = 0; y < h; y++) { + unsigned int *scanline = (unsigned int *)image.scanLine(y); + for (x = 0; x < w; x++) { + scanline[x] = qRgb(rcb - (xtable[0][x] + ytable[0][y]), + gcb - (xtable[1][x] + ytable[1][y]), + bcb - (xtable[2][x] + ytable[2][y])); + } + } + } + + else if (eff == RectangleGradient || + eff == PyramidGradient || + eff == PipeCrossGradient || + eff == EllipticGradient) + { + int rSign = rDiff>0? 1: -1; + int gSign = gDiff>0? 1: -1; + int bSign = bDiff>0? 1: -1; + + for (x = 0; x < w; x++) + { + dir = _xanti ? x : w - 1 - x; + rat = 1 - exp( - (float)x * xbal ); + + xtable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat))); + xtable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat))); + xtable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat))); + } + + for (y = 0; y < h; y++) + { + dir = _yanti ? y : h - 1 - y; + + rat = 1 - exp( - (float)y * ybal ); + + ytable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat))); + ytable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat))); + ytable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat))); + } + + for (y = 0; y < h; y++) { + unsigned int *scanline = (unsigned int *)image.scanLine(y); + for (x = 0; x < w; x++) { + if (eff == PyramidGradient) + { + scanline[x] = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]), + gcb-gSign*(xtable[1][x]+ytable[1][y]), + bcb-bSign*(xtable[2][x]+ytable[2][y])); + } + if (eff == RectangleGradient) + { + scanline[x] = qRgb(rcb - rSign * + QMAX(xtable[0][x], ytable[0][y]) * 2, + gcb - gSign * + QMAX(xtable[1][x], ytable[1][y]) * 2, + bcb - bSign * + QMAX(xtable[2][x], ytable[2][y]) * 2); + } + if (eff == PipeCrossGradient) + { + scanline[x] = qRgb(rcb - rSign * + QMIN(xtable[0][x], ytable[0][y]) * 2, + gcb - gSign * + QMIN(xtable[1][x], ytable[1][y]) * 2, + bcb - bSign * + QMIN(xtable[2][x], ytable[2][y]) * 2); + } + if (eff == EllipticGradient) + { + scanline[x] = qRgb(rcb - rSign * + (int)sqrt((xtable[0][x]*xtable[0][x] + + ytable[0][y]*ytable[0][y])*2.0), + gcb - gSign * + (int)sqrt((xtable[1][x]*xtable[1][x] + + ytable[1][y]*ytable[1][y])*2.0), + bcb - bSign * + (int)sqrt((xtable[2][x]*xtable[2][x] + + ytable[2][y]*ytable[2][y])*2.0)); + } + } + } + } + + if (ncols && (QPixmap::defaultDepth() < 15 )) { + if ( ncols < 2 || ncols > 256 ) + ncols = 3; + QColor *dPal = new QColor[ncols]; + for (int i=0; i<ncols; i++) { + dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ), + gca + gDiff * i / ( ncols - 1 ), + bca + bDiff * i / ( ncols - 1 ) ); + } + dither(image, dPal, ncols); + delete [] dPal; + } + + delete [] xtable[0]; + delete [] xtable[1]; + delete [] xtable[2]; + delete [] ytable[0]; + delete [] ytable[1]; + delete [] ytable[2]; + + } + + return image; +} + + +//====================================================================== +// +// Intensity effects +// +//====================================================================== + + +/* This builds a 256 byte unsigned char lookup table with all + * the possible percent values prior to applying the effect, then uses + * integer math for the pixels. For any image larger than 9x9 this will be + * less expensive than doing a float operation on the 3 color components of + * each pixel. (mosfet) + */ + +QImage& OImageEffect::intensity(QImage &image, float percent) +{ + if (image.width() == 0 || image.height() == 0) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::intensity : invalid image\n"; +#endif + return image; + } + + int segColors = image.depth() > 8 ? 256 : image.numColors(); + unsigned char *segTbl = new unsigned char[segColors]; + int pixels = image.depth() > 8 ? image.width()*image.height() : + image.numColors(); + unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() : + (unsigned int *)image.colorTable(); + + bool brighten = (percent >= 0); + if(percent < 0) + percent = -percent; + + if(brighten){ // keep overflow check out of loops + for(int i=0; i < segColors; ++i){ + int tmp = (int)(i*percent); + if(tmp > 255) + tmp = 255; + segTbl[i] = tmp; + } + } + else{ + for(int i=0; i < segColors; ++i){ + int tmp = (int)(i*percent); + if(tmp < 0) + tmp = 0; + segTbl[i] = tmp; + } + } + + if(brighten){ // same here + for(int i=0; i < pixels; ++i){ + int r = qRed(data[i]); + int g = qGreen(data[i]); + int b = qBlue(data[i]); + int a = qAlpha(data[i]); + r = r + segTbl[r] > 255 ? 255 : r + segTbl[r]; + g = g + segTbl[g] > 255 ? 255 : g + segTbl[g]; + b = b + segTbl[b] > 255 ? 255 : b + segTbl[b]; + data[i] = qRgba(r, g, b,a); + } + } + else{ + for(int i=0; i < pixels; ++i){ + int r = qRed(data[i]); + int g = qGreen(data[i]); + int b = qBlue(data[i]); + int a = qAlpha(data[i]); + r = r - segTbl[r] < 0 ? 0 : r - segTbl[r]; + g = g - segTbl[g] < 0 ? 0 : g - segTbl[g]; + b = b - segTbl[b] < 0 ? 0 : b - segTbl[b]; + data[i] = qRgba(r, g, b, a); + } + } + delete [] segTbl; + + return image; +} + +QImage& OImageEffect::channelIntensity(QImage &image, float percent, + RGBComponent channel) +{ + if (image.width() == 0 || image.height() == 0) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::channelIntensity : invalid image\n"; +#endif + return image; + } + + int segColors = image.depth() > 8 ? 256 : image.numColors(); + unsigned char *segTbl = new unsigned char[segColors]; + int pixels = image.depth() > 8 ? image.width()*image.height() : + image.numColors(); + unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() : + (unsigned int *)image.colorTable(); + bool brighten = (percent >= 0); + if(percent < 0) + percent = -percent; + + if(brighten){ // keep overflow check out of loops + for(int i=0; i < segColors; ++i){ + int tmp = (int)(i*percent); + if(tmp > 255) + tmp = 255; + segTbl[i] = tmp; + } + } + else{ + for(int i=0; i < segColors; ++i){ + int tmp = (int)(i*percent); + if(tmp < 0) + tmp = 0; + segTbl[i] = tmp; + } + } + + if(brighten){ // same here + if(channel == Red){ // and here ;-) + for(int i=0; i < pixels; ++i){ + int c = qRed(data[i]); + c = c + segTbl[c] > 255 ? 255 : c + segTbl[c]; + data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i])); + } + } + if(channel == Green){ + for(int i=0; i < pixels; ++i){ + int c = qGreen(data[i]); + c = c + segTbl[c] > 255 ? 255 : c + segTbl[c]; + data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i])); + } + } + else{ + for(int i=0; i < pixels; ++i){ + int c = qBlue(data[i]); + c = c + segTbl[c] > 255 ? 255 : c + segTbl[c]; + data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i])); + } + } + + } + else{ + if(channel == Red){ + for(int i=0; i < pixels; ++i){ + int c = qRed(data[i]); + c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; + data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i])); + } + } + if(channel == Green){ + for(int i=0; i < pixels; ++i){ + int c = qGreen(data[i]); + c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; + data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i])); + } + } + else{ + for(int i=0; i < pixels; ++i){ + int c = qBlue(data[i]); + c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; + data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i])); + } + } + } + delete [] segTbl; + + return image; +} + +// Modulate an image with an RBG channel of another image +// +QImage& OImageEffect::modulate(QImage &image, QImage &modImage, bool reverse, + ModulationType type, int factor, RGBComponent channel) +{ + if (image.width() == 0 || image.height() == 0 || + modImage.width() == 0 || modImage.height() == 0) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::modulate : invalid image\n"; +#endif + return image; + } + + int r, g, b, h, s, v, a; + QColor clr; + int mod=0; + unsigned int x1, x2, y1, y2; + register int x, y; + + // for image, we handle only depth 32 + if (image.depth()<32) image = image.convertDepth(32); + + // for modImage, we handle depth 8 and 32 + if (modImage.depth()<8) modImage = modImage.convertDepth(8); + + unsigned int *colorTable2 = (modImage.depth()==8) ? + modImage.colorTable():0; + unsigned int *data1, *data2; + unsigned char *data2b; + unsigned int color1, color2; + + x1 = image.width(); y1 = image.height(); + x2 = modImage.width(); y2 = modImage.height(); + + for (y = 0; y < (int)y1; y++) { + data1 = (unsigned int *) image.scanLine(y); + data2 = (unsigned int *) modImage.scanLine( y%y2 ); + data2b = (unsigned char *) modImage.scanLine( y%y2 ); + + x=0; + while(x < (int)x1) { + color2 = (colorTable2) ? colorTable2[*data2b] : *data2; + if (reverse) { + color1 = color2; + color2 = *data1; + } + else + color1 = *data1; + + if (type == Intensity || type == Contrast) { + r = qRed(color1); + g = qGreen(color1); + b = qBlue(color1); + if (channel != All) { + mod = (channel == Red) ? qRed(color2) : + (channel == Green) ? qGreen(color2) : + (channel == Blue) ? qBlue(color2) : + (channel == Gray) ? qGray(color2) : 0; + mod = mod*factor/50; + } + + if (type == Intensity) { + if (channel == All) { + r += r * factor/50 * qRed(color2)/256; + g += g * factor/50 * qGreen(color2)/256; + b += b * factor/50 * qBlue(color2)/256; + } + else { + r += r * mod/256; + g += g * mod/256; + b += b * mod/256; + } + } + else { // Contrast + if (channel == All) { + r += (r-128) * factor/50 * qRed(color2)/128; + g += (g-128) * factor/50 * qGreen(color2)/128; + b += (b-128) * factor/50 * qBlue(color2)/128; + } + else { + r += (r-128) * mod/128; + g += (g-128) * mod/128; + b += (b-128) * mod/128; + } + } + + if (r<0) r=0; if (r>255) r=255; + if (g<0) g=0; if (g>255) g=255; + if (b<0) b=0; if (b>255) b=255; + a = qAlpha(*data1); + *data1 = qRgba(r, g, b, a); + } + else if (type == Saturation || type == HueShift) { + clr.setRgb(color1); + clr.hsv(&h, &s, &v); + mod = (channel == Red) ? qRed(color2) : + (channel == Green) ? qGreen(color2) : + (channel == Blue) ? qBlue(color2) : + (channel == Gray) ? qGray(color2) : 0; + mod = mod*factor/50; + + if (type == Saturation) { + s -= s * mod/256; + if (s<0) s=0; if (s>255) s=255; + } + else { // HueShift + h += mod; + while(h<0) h+=360; + h %= 360; + } + + clr.setHsv(h, s, v); + a = qAlpha(*data1); + *data1 = clr.rgb() | ((uint)(a & 0xff) << 24); + } + data1++; data2++; data2b++; x++; + if ( (x%x2) ==0) { data2 -= x2; data2b -= x2; } + } + } + return image; +} + + + +//====================================================================== +// +// Blend effects +// +//====================================================================== + + +// Nice and fast direct pixel manipulation +QImage& OImageEffect::blend(const QColor& clr, QImage& dst, float opacity) +{ + if (dst.width() <= 0 || dst.height() <= 0) + return dst; + + if (opacity < 0.0 || opacity > 1.0) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1]\n"; +#endif + return dst; + } + + int depth = dst.depth(); + if (depth != 32) + dst = dst.convertDepth(32); + + int pixels = dst.width() * dst.height(); + int rcol, gcol, bcol; + clr.rgb(&rcol, &gcol, &bcol); + +#ifdef WORDS_BIGENDIAN // ARGB (skip alpha) + register unsigned char *data = (unsigned char *)dst.bits() + 1; +#else // BGRA + register unsigned char *data = (unsigned char *)dst.bits(); +#endif + + for (register int i=0; i<pixels; i++) + { +#ifdef WORDS_BIGENDIAN + *(data++) += (unsigned char)((rcol - *data) * opacity); + *(data++) += (unsigned char)((gcol - *data) * opacity); + *(data++) += (unsigned char)((bcol - *data) * opacity); +#else + *(data++) += (unsigned char)((bcol - *data) * opacity); + *(data++) += (unsigned char)((gcol - *data) * opacity); + *(data++) += (unsigned char)((rcol - *data) * opacity); +#endif + data++; // skip alpha + } + return dst; +} + +// Nice and fast direct pixel manipulation +QImage& OImageEffect::blend(QImage& src, QImage& dst, float opacity) +{ + if (src.width() <= 0 || src.height() <= 0) + return dst; + if (dst.width() <= 0 || dst.height() <= 0) + return dst; + + if (src.width() != dst.width() || src.height() != dst.height()) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::blend : src and destination images are not the same size\n"; +#endif + return dst; + } + + if (opacity < 0.0 || opacity > 1.0) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1]\n"; +#endif + return dst; + } + + if (src.depth() != 32) src = src.convertDepth(32); + if (dst.depth() != 32) dst = dst.convertDepth(32); + + int pixels = src.width() * src.height(); +#ifdef WORDS_BIGENDIAN // ARGB (skip alpha) + register unsigned char *data1 = (unsigned char *)dst.bits() + 1; + register unsigned char *data2 = (unsigned char *)src.bits() + 1; +#else // BGRA + register unsigned char *data1 = (unsigned char *)dst.bits(); + register unsigned char *data2 = (unsigned char *)src.bits(); +#endif + + for (register int i=0; i<pixels; i++) + { +#ifdef WORDS_BIGENDIAN + *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); + *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); + *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); +#else + *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); + *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); + *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); +#endif + data1++; // skip alpha + data2++; + } + + return dst; +} + + +QImage& OImageEffect::blend(QImage &image, float initial_intensity, + const QColor &bgnd, GradientType eff, + bool anti_dir) +{ + if (image.width() == 0 || image.height() == 0 || image.depth()!=32 ) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::blend : invalid image\n"; +#endif + return image; + } + + int r_bgnd = bgnd.red(), g_bgnd = bgnd.green(), b_bgnd = bgnd.blue(); + int r, g, b; + int ind; + + unsigned int xi, xf, yi, yf; + unsigned int a; + + // check the boundaries of the initial intesity param + float unaffected = 1; + if (initial_intensity > 1) initial_intensity = 1; + if (initial_intensity < -1) initial_intensity = -1; + if (initial_intensity < 0) { + unaffected = 1. + initial_intensity; + initial_intensity = 0; + } + + + float intensity = initial_intensity; + float var = 1. - initial_intensity; + + if (anti_dir) { + initial_intensity = intensity = 1.; + var = -var; + } + + register int x, y; + + unsigned int *data = (unsigned int *)image.bits(); + + int image_width = image.width(); //Those can't change + int image_height = image.height(); + + + if( eff == VerticalGradient || eff == HorizontalGradient ) { + + // set the image domain to apply the effect to + xi = 0, xf = image_width; + yi = 0, yf = image_height; + if (eff == VerticalGradient) { + if (anti_dir) yf = (int)(image_height * unaffected); + else yi = (int)(image_height * (1 - unaffected)); + } + else { + if (anti_dir) xf = (int)(image_width * unaffected); + else xi = (int)(image_height * (1 - unaffected)); + } + + var /= (eff == VerticalGradient?yf-yi:xf-xi); + + int ind_base; + for (y = yi; y < (int)yf; y++) { + intensity = eff == VerticalGradient? intensity + var : + initial_intensity; + ind_base = image_width * y ; + for (x = xi; x < (int)xf ; x++) { + if (eff == HorizontalGradient) intensity += var; + ind = x + ind_base; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + } + } + } + else if (eff == DiagonalGradient || eff == CrossDiagonalGradient) { + float xvar = var / 2 / image_width; // / unaffected; + float yvar = var / 2 / image_height; // / unaffected; + float tmp; + + for (x = 0; x < image_width ; x++) { + tmp = xvar * (eff == DiagonalGradient? x : image.width()-x-1); + ind = x; + for (y = 0; y < image_height ; y++) { + intensity = initial_intensity + tmp + yvar * y; + + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + + ind += image_width; + } + } + } + + else if (eff == RectangleGradient || eff == EllipticGradient) { + float xvar; + float yvar; + + for (x = 0; x < image_width / 2 + image_width % 2; x++) { + xvar = var / image_width * (image_width - x*2/unaffected-1); + for (y = 0; y < image_height / 2 + image_height % 2; y++) { + yvar = var / image_height * (image_height - y*2/unaffected -1); + + if (eff == RectangleGradient) + intensity = initial_intensity + QMAX(xvar, yvar); + else + intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar); + if (intensity > 1) intensity = 1; + if (intensity < 0) intensity = 0; + + //NW + ind = x + image_width * y ; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + + //NE + ind = image_width - x - 1 + image_width * y ; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + } + } + + //CT loop is doubled because of stupid central row/column issue. + // other solution? + for (x = 0; x < image_width / 2; x++) { + xvar = var / image_width * (image_width - x*2/unaffected-1); + for (y = 0; y < image_height / 2; y++) { + yvar = var / image_height * (image_height - y*2/unaffected -1); + + if (eff == RectangleGradient) + intensity = initial_intensity + QMAX(xvar, yvar); + else + intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar); + if (intensity > 1) intensity = 1; + if (intensity < 0) intensity = 0; + + //SW + ind = x + image_width * (image_height - y -1) ; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + + //SE + ind = image_width-x-1 + image_width * (image_height - y - 1) ; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + } + } + } +#ifndef NDEBUG + else cerr << "OImageEffect::blend effect not implemented" << endl; +#endif + return image; +} + +// Not very efficient as we create a third big image... +// +QImage& OImageEffect::blend(QImage &image1, QImage &image2, + GradientType gt, int xf, int yf) +{ + if (image1.width() == 0 || image1.height() == 0 || + image2.width() == 0 || image2.height() == 0) + return image1; + + QImage image3; + + image3 = OImageEffect::unbalancedGradient(image1.size(), + QColor(0,0,0), QColor(255,255,255), + gt, xf, yf, 0); + + return blend(image1,image2,image3, Red); // Channel to use is arbitrary +} + +// Blend image2 into image1, using an RBG channel of blendImage +// +QImage& OImageEffect::blend(QImage &image1, QImage &image2, + QImage &blendImage, RGBComponent channel) +{ + if (image1.width() == 0 || image1.height() == 0 || + image2.width() == 0 || image2.height() == 0 || + blendImage.width() == 0 || blendImage.height() == 0) { +#ifndef NDEBUG + cerr << "OImageEffect::blend effect invalid image" << endl; +#endif + return image1; + } + + int r, g, b; + int ind1, ind2, ind3; + + unsigned int x1, x2, x3, y1, y2, y3; + unsigned int a; + + register int x, y; + + // for image1 and image2, we only handle depth 32 + if (image1.depth()<32) image1 = image1.convertDepth(32); + if (image2.depth()<32) image2 = image2.convertDepth(32); + + // for blendImage, we handle depth 8 and 32 + if (blendImage.depth()<8) blendImage = blendImage.convertDepth(8); + + unsigned int *colorTable3 = (blendImage.depth()==8) ? + blendImage.colorTable():0; + + unsigned int *data1 = (unsigned int *)image1.bits(); + unsigned int *data2 = (unsigned int *)image2.bits(); + unsigned int *data3 = (unsigned int *)blendImage.bits(); + unsigned char *data3b = (unsigned char *)blendImage.bits(); + unsigned int color3; + + x1 = image1.width(); y1 = image1.height(); + x2 = image2.width(); y2 = image2.height(); + x3 = blendImage.width(); y3 = blendImage.height(); + + for (y = 0; y < (int)y1; y++) { + ind1 = x1*y; + ind2 = x2*(y%y2); + ind3 = x3*(y%y3); + + x=0; + while(x < (int)x1) { + color3 = (colorTable3) ? colorTable3[data3b[ind3]] : data3[ind3]; + + a = (channel == Red) ? qRed(color3) : + (channel == Green) ? qGreen(color3) : + (channel == Blue) ? qBlue(color3) : qGray(color3); + + r = (a*qRed(data1[ind1]) + (256-a)*qRed(data2[ind2]))/256; + g = (a*qGreen(data1[ind1]) + (256-a)*qGreen(data2[ind2]))/256; + b = (a*qBlue(data1[ind1]) + (256-a)*qBlue(data2[ind2]))/256; + + a = qAlpha(data1[ind1]); + data1[ind1] = qRgba(r, g, b, a); + + ind1++; ind2++; ind3++; x++; + if ( (x%x2) ==0) ind2 -= x2; + if ( (x%x3) ==0) ind3 -= x3; + } + } + return image1; +} + + +//====================================================================== +// +// Hash effects +// +//====================================================================== + +unsigned int OImageEffect::lHash(unsigned int c) +{ + unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c); + unsigned char nr, ng, nb; + nr =(r >> 1) + (r >> 2); nr = nr > r ? 0 : nr; + ng =(g >> 1) + (g >> 2); ng = ng > g ? 0 : ng; + nb =(b >> 1) + (b >> 2); nb = nb > b ? 0 : nb; + + return qRgba(nr, ng, nb, a); +} + + +// ----------------------------------------------------------------------------- + +unsigned int OImageEffect::uHash(unsigned int c) +{ + unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c); + unsigned char nr, ng, nb; + nr = r + (r >> 3); nr = nr < r ? ~0 : nr; + ng = g + (g >> 3); ng = ng < g ? ~0 : ng; + nb = b + (b >> 3); nb = nb < b ? ~0 : nb; + + return qRgba(nr, ng, nb, a); +} + + +// ----------------------------------------------------------------------------- + +QImage& OImageEffect::hash(QImage &image, Lighting lite, unsigned int spacing) +{ + if (image.width() == 0 || image.height() == 0) { +#ifndef NDEBUG + cerr << "OImageEffect::hash effect invalid image" << endl; +#endif + return image; + } + + register int x, y; + unsigned int *data = (unsigned int *)image.bits(); + unsigned int ind; + + //CT no need to do it if not enough space + if ((lite == NorthLite || + lite == SouthLite)&& + (unsigned)image.height() < 2+spacing) return image; + if ((lite == EastLite || + lite == WestLite)&& + (unsigned)image.height() < 2+spacing) return image; + + if (lite == NorthLite || lite == SouthLite) { + for (y = 0 ; y < image.height(); y = y + 2 + spacing) { + for (x = 0; x < image.width(); x++) { + ind = x + image.width() * y; + data[ind] = lite==NorthLite?uHash(data[ind]):lHash(data[ind]); + + ind = ind + image.width(); + data[ind] = lite==NorthLite?lHash(data[ind]):uHash(data[ind]); + } + } + } + + else if (lite == EastLite || lite == WestLite) { + for (y = 0 ; y < image.height(); y++) { + for (x = 0; x < image.width(); x = x + 2 + spacing) { + ind = x + image.width() * y; + data[ind] = lite==EastLite?uHash(data[ind]):lHash(data[ind]); + + ind++; + data[ind] = lite==EastLite?lHash(data[ind]):uHash(data[ind]); + } + } + } + + else if (lite == NWLite || lite == SELite) { + for (y = 0 ; y < image.height(); y++) { + for (x = 0; + x < (int)(image.width() - ((y & 1)? 1 : 0) * spacing); + x = x + 2 + spacing) { + ind = x + image.width() * y + ((y & 1)? 1 : 0); + data[ind] = lite==NWLite?uHash(data[ind]):lHash(data[ind]); + + ind++; + data[ind] = lite==NWLite?lHash(data[ind]):uHash(data[ind]); + } + } + } + + else if (lite == SWLite || lite == NELite) { + for (y = 0 ; y < image.height(); y++) { + for (x = 0 + ((y & 1)? 1 : 0); x < image.width(); x = x + 2 + spacing) { + ind = x + image.width() * y - ((y & 1)? 1 : 0); + data[ind] = lite==SWLite?uHash(data[ind]):lHash(data[ind]); + + ind++; + data[ind] = lite==SWLite?lHash(data[ind]):uHash(data[ind]); + } + } + } + + return image; +} + + +//====================================================================== +// +// Flatten effects +// +//====================================================================== + +QImage& OImageEffect::flatten(QImage &img, const QColor &ca, + const QColor &cb, int ncols) +{ + if (img.width() == 0 || img.height() == 0) + return img; + + // a bitmap is easy... + if (img.depth() == 1) { + img.setColor(0, ca.rgb()); + img.setColor(1, cb.rgb()); + return img; + } + + int r1 = ca.red(); int r2 = cb.red(); + int g1 = ca.green(); int g2 = cb.green(); + int b1 = ca.blue(); int b2 = cb.blue(); + int min = 0, max = 255; + + QRgb col; + + // Get minimum and maximum greylevel. + if (img.numColors()) { + // pseudocolor + for (int i = 0; i < img.numColors(); i++) { + col = img.color(i); + int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; + min = QMIN(min, mean); + max = QMAX(max, mean); + } + } else { + // truecolor + for (int y=0; y < img.height(); y++) + for (int x=0; x < img.width(); x++) { + col = img.pixel(x, y); + int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; + min = QMIN(min, mean); + max = QMAX(max, mean); + } + } + + // Conversion factors + float sr = ((float) r2 - r1) / (max - min); + float sg = ((float) g2 - g1) / (max - min); + float sb = ((float) b2 - b1) / (max - min); + + + // Repaint the image + if (img.numColors()) { + for (int i=0; i < img.numColors(); i++) { + col = img.color(i); + int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; + int r = (int) (sr * (mean - min) + r1 + 0.5); + int g = (int) (sg * (mean - min) + g1 + 0.5); + int b = (int) (sb * (mean - min) + b1 + 0.5); + img.setColor(i, qRgba(r, g, b, qAlpha(col))); + } + } else { + for (int y=0; y < img.height(); y++) + for (int x=0; x < img.width(); x++) { + col = img.pixel(x, y); + int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; + int r = (int) (sr * (mean - min) + r1 + 0.5); + int g = (int) (sg * (mean - min) + g1 + 0.5); + int b = (int) (sb * (mean - min) + b1 + 0.5); + img.setPixel(x, y, qRgba(r, g, b, qAlpha(col))); + } + } + + + // Dither if necessary + if ( (ncols <= 0) || ((img.numColors() != 0) && (img.numColors() <= ncols))) + return img; + + if (ncols == 1) ncols++; + if (ncols > 256) ncols = 256; + + QColor *pal = new QColor[ncols]; + sr = ((float) r2 - r1) / (ncols - 1); + sg = ((float) g2 - g1) / (ncols - 1); + sb = ((float) b2 - b1) / (ncols - 1); + + for (int i=0; i<ncols; i++) + pal[i] = QColor(r1 + int(sr*i), g1 + int(sg*i), b1 + int(sb*i)); + + dither(img, pal, ncols); + + delete[] pal; + return img; +} + + +//====================================================================== +// +// Fade effects +// +//====================================================================== + +QImage& OImageEffect::fade(QImage &img, float val, const QColor &color) +{ + if (img.width() == 0 || img.height() == 0) + return img; + + // We don't handle bitmaps + if (img.depth() == 1) + return img; + + unsigned char tbl[256]; + for (int i=0; i<256; i++) + tbl[i] = (int) (val * i + 0.5); + + int red = color.red(); + int green = color.green(); + int blue = color.blue(); + + QRgb col; + int r, g, b, cr, cg, cb; + + if (img.depth() <= 8) { + // pseudo color + for (int i=0; i<img.numColors(); i++) { + col = img.color(i); + cr = qRed(col); cg = qGreen(col); cb = qBlue(col); + if (cr > red) + r = cr - tbl[cr - red]; + else + r = cr + tbl[red - cr]; + if (cg > green) + g = cg - tbl[cg - green]; + else + g = cg + tbl[green - cg]; + if (cb > blue) + b = cb - tbl[cb - blue]; + else + b = cb + tbl[blue - cb]; + img.setColor(i, qRgba(r, g, b, qAlpha(col))); + } + + } else { + // truecolor + for (int y=0; y<img.height(); y++) { + QRgb *data = (QRgb *) img.scanLine(y); + for (int x=0; x<img.width(); x++) { + col = *data; + cr = qRed(col); cg = qGreen(col); cb = qBlue(col); + if (cr > red) + r = cr - tbl[cr - red]; + else + r = cr + tbl[red - cr]; + if (cg > green) + g = cg - tbl[cg - green]; + else + g = cg + tbl[green - cg]; + if (cb > blue) + b = cb - tbl[cb - blue]; + else + b = cb + tbl[blue - cb]; + *data++ = qRgba(r, g, b, qAlpha(col)); + } + } + } + + return img; +} + +//====================================================================== +// +// Color effects +// +//====================================================================== + +// This code is adapted from code (C) Rik Hemsley <rik@kde.org> +// +// The formula used (r + b + g) /3 is different from the qGray formula +// used by Qt. This is because our formula is much much faster. If, +// however, it turns out that this is producing sub-optimal images, +// then it will have to change (kurt) +// +// It does produce lower quality grayscale ;-) Use fast == true for the fast +// algorithm, false for the higher quality one (mosfet). +QImage& OImageEffect::toGray(QImage &img, bool fast) +{ + if (img.width() == 0 || img.height() == 0) + return img; + + if(fast){ + if (img.depth() == 32) { + register uchar * r(img.bits()); + register uchar * g(img.bits() + 1); + register uchar * b(img.bits() + 2); + + uchar * end(img.bits() + img.numBytes()); + + while (r != end) { + + *r = *g = *b = (((*r + *g) >> 1) + *b) >> 1; // (r + b + g) / 3 + + r += 4; + g += 4; + b += 4; + } + } + else + { + for (int i = 0; i < img.numColors(); i++) + { + register uint r = qRed(img.color(i)); + register uint g = qGreen(img.color(i)); + register uint b = qBlue(img.color(i)); + + register uint gray = (((r + g) >> 1) + b) >> 1; + img.setColor(i, qRgba(gray, gray, gray, qAlpha(img.color(i)))); + } + } + } + else{ + int pixels = img.depth() > 8 ? img.width()*img.height() : + img.numColors(); + unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() : + (unsigned int *)img.colorTable(); + int val, i; + for(i=0; i < pixels; ++i){ + val = qGray(data[i]); + data[i] = qRgba(val, val, val, qAlpha(data[i])); + } + } + return img; +} + +// CT 29Jan2000 - desaturation algorithms +QImage& OImageEffect::desaturate(QImage &img, float desat) +{ + if (img.width() == 0 || img.height() == 0) + return img; + + if (desat < 0) desat = 0.; + if (desat > 1) desat = 1.; + int pixels = img.depth() > 8 ? img.width()*img.height() : + img.numColors(); + unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() : + (unsigned int *)img.colorTable(); + int h, s, v, i; + QColor clr; // keep constructor out of loop (mosfet) + for(i=0; i < pixels; ++i){ + clr.setRgb(data[i]); + clr.hsv(&h, &s, &v); + clr.setHsv(h, (int)(s * (1. - desat)), v); + data[i] = clr.rgb(); + } + return img; +} + +// Contrast stuff (mosfet) +QImage& OImageEffect::contrast(QImage &img, int c) +{ + if (img.width() == 0 || img.height() == 0) + return img; + + if(c > 255) + c = 255; + if(c < -255) + c = -255; + int pixels = img.depth() > 8 ? img.width()*img.height() : + img.numColors(); + unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() : + (unsigned int *)img.colorTable(); + int i, r, g, b; + for(i=0; i < pixels; ++i){ + r = qRed(data[i]); + g = qGreen(data[i]); + b = qBlue(data[i]); + if(qGray(data[i]) <= 127){ + if(r - c <= 255) + r -= c; + if(g - c <= 255) + g -= c; + if(b - c <= 255) + b -= c; + } + else{ + if(r + c <= 255) + r += c; + if(g + c <= 255) + g += c; + if(b + c <= 255) + b += c; + } + data[i] = qRgba(r, g, b, qAlpha(data[i])); + } + return(img); +} + +//====================================================================== +// +// Dithering effects +// +//====================================================================== + +// adapted from kFSDither (C) 1997 Martin Jones (mjones@kde.org) +// +// Floyd-Steinberg dithering +// Ref: Bitmapped Graphics Programming in C++ +// Marv Luse, Addison-Wesley Publishing, 1993. +QImage& OImageEffect::dither(QImage &img, const QColor *palette, int size) +{ + if (img.width() == 0 || img.height() == 0 || + palette == 0 || img.depth() <= 8) + return img; + + QImage dImage( img.width(), img.height(), 8, size ); + int i; + + dImage.setNumColors( size ); + for ( i = 0; i < size; i++ ) + dImage.setColor( i, palette[ i ].rgb() ); + + int *rerr1 = new int [ img.width() * 2 ]; + int *gerr1 = new int [ img.width() * 2 ]; + int *berr1 = new int [ img.width() * 2 ]; + + memset( rerr1, 0, sizeof( int ) * img.width() * 2 ); + memset( gerr1, 0, sizeof( int ) * img.width() * 2 ); + memset( berr1, 0, sizeof( int ) * img.width() * 2 ); + + int *rerr2 = rerr1 + img.width(); + int *gerr2 = gerr1 + img.width(); + int *berr2 = berr1 + img.width(); + + for ( int j = 0; j < img.height(); j++ ) + { + uint *ip = (uint * )img.scanLine( j ); + uchar *dp = dImage.scanLine( j ); + + for ( i = 0; i < img.width(); i++ ) + { + rerr1[i] = rerr2[i] + qRed( *ip ); + rerr2[i] = 0; + gerr1[i] = gerr2[i] + qGreen( *ip ); + gerr2[i] = 0; + berr1[i] = berr2[i] + qBlue( *ip ); + berr2[i] = 0; + ip++; + } + + *dp++ = nearestColor( rerr1[0], gerr1[0], berr1[0], palette, size ); + + for ( i = 1; i < img.width()-1; i++ ) + { + int indx = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size ); + *dp = indx; + + int rerr = rerr1[i]; + rerr -= palette[indx].red(); + int gerr = gerr1[i]; + gerr -= palette[indx].green(); + int berr = berr1[i]; + berr -= palette[indx].blue(); + + // diffuse red error + rerr1[ i+1 ] += ( rerr * 7 ) >> 4; + rerr2[ i-1 ] += ( rerr * 3 ) >> 4; + rerr2[ i ] += ( rerr * 5 ) >> 4; + rerr2[ i+1 ] += ( rerr ) >> 4; + + // diffuse green error + gerr1[ i+1 ] += ( gerr * 7 ) >> 4; + gerr2[ i-1 ] += ( gerr * 3 ) >> 4; + gerr2[ i ] += ( gerr * 5 ) >> 4; + gerr2[ i+1 ] += ( gerr ) >> 4; + + // diffuse red error + berr1[ i+1 ] += ( berr * 7 ) >> 4; + berr2[ i-1 ] += ( berr * 3 ) >> 4; + berr2[ i ] += ( berr * 5 ) >> 4; + berr2[ i+1 ] += ( berr ) >> 4; + + dp++; + } + + *dp = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size ); + } + + delete [] rerr1; + delete [] gerr1; + delete [] berr1; + + img = dImage; + return img; +} + +int OImageEffect::nearestColor( int r, int g, int b, const QColor *palette, int size ) +{ + if (palette == 0) + return 0; + + int dr = palette[0].red() - r; + int dg = palette[0].green() - g; + int db = palette[0].blue() - b; + + int minDist = dr*dr + dg*dg + db*db; + int nearest = 0; + + for (int i = 1; i < size; i++ ) + { + dr = palette[i].red() - r; + dg = palette[i].green() - g; + db = palette[i].blue() - b; + + int dist = dr*dr + dg*dg + db*db; + + if ( dist < minDist ) + { + minDist = dist; + nearest = i; + } + } + + return nearest; +} + +bool OImageEffect::blend( + const QImage & upper, + const QImage & lower, + QImage & output +) +{ + if ( + upper.width() > lower.width() || + upper.height() > lower.height() || + upper.depth() != 32 || + lower.depth() != 32 + ) + { +#ifndef NDEBUG + cerr << "OImageEffect::blend : Sizes not correct\n" ; +#endif + return false; + } + + output = lower.copy(); + + register uchar *i, *o; + register int a; + register int col; + register int w = upper.width(); + int row(upper.height() - 1); + + do { + + i = upper.scanLine(row); + o = output.scanLine(row); + + col = w << 2; + --col; + + do { + + while (!(a = i[col]) && (col != 3)) { + --col; --col; --col; --col; + } + + --col; + o[col] += ((i[col] - o[col]) * a) >> 8; + + --col; + o[col] += ((i[col] - o[col]) * a) >> 8; + + --col; + o[col] += ((i[col] - o[col]) * a) >> 8; + + } while (col--); + + } while (row--); + + return true; +} + +#if 0 +// Not yet... +bool OImageEffect::blend( + const QImage & upper, + const QImage & lower, + QImage & output, + const QRect & destRect +) +{ + output = lower.copy(); + return output; +} + +#endif + +bool OImageEffect::blend( + int &x, int &y, + const QImage & upper, + const QImage & lower, + QImage & output +) +{ + int cx=0, cy=0, cw=upper.width(), ch=upper.height(); + + if ( upper.width() + x > lower.width() || + upper.height() + y > lower.height() || + x < 0 || y < 0 || + upper.depth() != 32 || lower.depth() != 32 ) + { + if ( x > lower.width() || y > lower.height() ) return false; + if ( upper.width()<=0 || upper.height() <= 0 ) return false; + if ( lower.width()<=0 || lower.height() <= 0 ) return false; + + if (x<0) {cx=-x; cw+=x; x=0; }; + if (cw + x > lower.width()) { cw=lower.width()-x; }; + if (y<0) {cy=-y; ch+=y; y=0; }; + if (ch + y > lower.height()) { ch=lower.height()-y; }; + + if ( cx >= upper.width() || cy >= upper.height() ) return true; + if ( cw <= 0 || ch <= 0 ) return true; + } + + output.create(cw,ch,32); +// output.setAlphaBuffer(true); // I should do some benchmarks to see if + // this is worth the effort + + register QRgb *i, *o, *b; + + register int a; + register int j,k; + for (j=0; j<ch; j++) + { + b=reinterpret_cast<QRgb *>(&lower.scanLine(y+j) [ (x+cw) << 2 ]); + i=reinterpret_cast<QRgb *>(&upper.scanLine(cy+j)[ (cx+cw) << 2 ]); + o=reinterpret_cast<QRgb *>(&output.scanLine(j) [ cw << 2 ]); + + k=cw-1; + --b; --i; --o; + do + { + while ( !(a=qAlpha(*i)) && k>0 ) + { + i--; +// *o=0; + *o=*b; + --o; --b; + k--; + }; +// *o=0xFF; + *o = qRgb(qRed(*b) + (((qRed(*i) - qRed(*b)) * a) >> 8), + qGreen(*b) + (((qGreen(*i) - qGreen(*b)) * a) >> 8), + qBlue(*b) + (((qBlue(*i) - qBlue(*b)) * a) >> 8)); + --i; --o; --b; + } while (k--); + } + + return true; +} + +bool OImageEffect::blendOnLower( + int x, int y, + const QImage & upper, + const QImage & lower +) +{ + int cx=0, cy=0, cw=upper.width(), ch=upper.height(); + + if ( upper.depth() != 32 || lower.depth() != 32 ) return false; + if ( x + cw > lower.width() || + y + ch > lower.height() || + x < 0 || y < 0 ) + { + if ( x > lower.width() || y > lower.height() ) return true; + if ( upper.width()<=0 || upper.height() <= 0 ) return true; + if ( lower.width()<=0 || lower.height() <= 0 ) return true; + + if (x<0) {cx=-x; cw+=x; x=0; }; + if (cw + x > lower.width()) { cw=lower.width()-x; }; + if (y<0) {cy=-y; ch+=y; y=0; }; + if (ch + y > lower.height()) { ch=lower.height()-y; }; + + if ( cx >= upper.width() || cy >= upper.height() ) return true; + if ( cw <= 0 || ch <= 0 ) return true; + } + + register uchar *i, *b; + register int a; + register int k; + + for (int j=0; j<ch; j++) + { + b=&lower.scanLine(y+j) [ (x+cw) << 2 ]; + i=&upper.scanLine(cy+j)[ (cx+cw) << 2 ]; + + k=cw-1; + --b; --i; + do + { +#ifndef WORDS_BIGENDIAN + while ( !(a=*i) && k>0 ) +#else + while ( !(a=*(i-3)) && k>0 ) +#endif + { + i-=4; b-=4; k--; + }; + +#ifndef WORDS_BIGENDIAN + --i; --b; + *b += ( ((*i - *b) * a) >> 8 ); + --i; --b; + *b += ( ((*i - *b) * a) >> 8 ); + --i; --b; + *b += ( ((*i - *b) * a) >> 8 ); + --i; --b; +#else + *b += ( ((*i - *b) * a) >> 8 ); + --i; --b; + *b += ( ((*i - *b) * a) >> 8 ); + --i; --b; + *b += ( ((*i - *b) * a) >> 8 ); + i -= 2; b -= 2; +#endif + } while (k--); + } + + return true; +} + +// For selected icons +QImage& OImageEffect::selectedImage( QImage &img, const QColor &col ) +{ + return blend( col, img, 0.5); +} + +// +// =================================================================== +// Effects originally ported from ImageMagick for PixiePlus, plus a few +// new ones. (mosfet 12/29/01) +// =================================================================== +// + +void OImageEffect::normalize(QImage &img) +{ + int *histogram, threshold_intensity, intense; + int x, y, i; + + unsigned int gray_value; + unsigned int *normalize_map; + unsigned int high, low; + + // allocate histogram and normalize map + histogram = (int *)calloc(MaxRGB+1, sizeof(int)); + normalize_map = (unsigned int *)malloc((MaxRGB+1)*sizeof(unsigned int)); + if(!normalize_map || !histogram){ + qWarning("Unable to allocate normalize histogram and map"); + free(normalize_map); + free(histogram); + return; + } + + // form histogram + if(img.depth() > 8){ // DirectClass + unsigned int *data; + for(y=0; y < img.height(); ++y){ + data = (unsigned int *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + gray_value = intensityValue(data[x]); + histogram[gray_value]++; + } + } + } + else{ // PsudeoClass + unsigned char *data; + unsigned int *cTable = img.colorTable(); + for(y=0; y < img.height(); ++y){ + data = (unsigned char *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + gray_value = intensityValue(*(cTable+data[x])); + histogram[gray_value]++; + } + } + } + + // find histogram boundaries by locating the 1 percent levels + threshold_intensity = (img.width()*img.height())/100; + intense = 0; + for(low=0; low < MaxRGB; ++low){ + intense+=histogram[low]; + if(intense > threshold_intensity) + break; + } + intense=0; + for(high=MaxRGB; high != 0; --high){ + intense+=histogram[high]; + if(intense > threshold_intensity) + break; + } + + if (low == high){ + // Unreasonable contrast; use zero threshold to determine boundaries. + threshold_intensity=0; + intense=0; + for(low=0; low < MaxRGB; ++low){ + intense+=histogram[low]; + if(intense > threshold_intensity) + break; + } + intense=0; + for(high=MaxRGB; high != 0; --high) + { + intense+=histogram[high]; + if(intense > threshold_intensity) + break; + } + if(low == high) + return; // zero span bound + } + + // Stretch the histogram to create the normalized image mapping. + for(i=0; i <= MaxRGB; i++){ + if (i < (int) low) + normalize_map[i]=0; + else{ + if(i > (int) high) + normalize_map[i]=MaxRGB; + else + normalize_map[i]=(MaxRGB-1)*(i-low)/(high-low); + } + } + // Normalize + if(img.depth() > 8){ // DirectClass + unsigned int *data; + for(y=0; y < img.height(); ++y){ + data = (unsigned int *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + data[x] = qRgba(normalize_map[qRed(data[x])], + normalize_map[qGreen(data[x])], + normalize_map[qBlue(data[x])], + qAlpha(data[x])); + } + } + } + else{ // PsudeoClass + int colors = img.numColors(); + unsigned int *cTable = img.colorTable(); + for(i=0; i < colors; ++i){ + cTable[i] = qRgba(normalize_map[qRed(cTable[i])], + normalize_map[qGreen(cTable[i])], + normalize_map[qBlue(cTable[i])], + qAlpha(cTable[i])); + } + } + free(histogram); + free(normalize_map); +} + + +void OImageEffect::equalize(QImage &img) +{ + int *histogram, *map, *equalize_map; + int x, y, i, j; + + unsigned int high, low; + + // allocate histogram and maps + histogram = (int *)calloc(MaxRGB+1, sizeof(int)); + map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int)); + equalize_map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int)); + + if(!histogram || !map || !equalize_map){ + qWarning("Unable to allocate equalize histogram and maps"); + free(histogram); + free(map); + free(equalize_map); + return; + } + // form histogram + if(img.depth() > 8){ // DirectClass + unsigned int *data; + for(y=0; y < img.height(); ++y){ + data = (unsigned int *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + histogram[intensityValue(data[x])]++; + } + } + } + else{ // PsudeoClass + unsigned char *data; + unsigned int *cTable = img.colorTable(); + for(y=0; y < img.height(); ++y){ + data = (unsigned char *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + histogram[intensityValue(*(cTable+data[x]))]++; + } + } + } + + // integrate the histogram to get the equalization map. + j=0; + for(i=0; i <= MaxRGB; i++){ + j+=histogram[i]; + map[i]=j; + } + free(histogram); + if(map[MaxRGB] == 0){ + free(equalize_map); + free(map); + return; + } + // equalize + low=map[0]; + high=map[MaxRGB]; + for(i=0; i <= MaxRGB; i++) + equalize_map[i]=(unsigned int) + ((((double) (map[i]-low))*MaxRGB)/QMAX(high-low,1)); + free(map); + // stretch the histogram + if(img.depth() > 8){ // DirectClass + unsigned int *data; + for(y=0; y < img.height(); ++y){ + data = (unsigned int *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + data[x] = qRgba(equalize_map[qRed(data[x])], + equalize_map[qGreen(data[x])], + equalize_map[qBlue(data[x])], + qAlpha(data[x])); + } + } + } + else{ // PsudeoClass + int colors = img.numColors(); + unsigned int *cTable = img.colorTable(); + for(i=0; i < colors; ++i){ + cTable[i] = qRgba(equalize_map[qRed(cTable[i])], + equalize_map[qGreen(cTable[i])], + equalize_map[qBlue(cTable[i])], + qAlpha(cTable[i])); + } + } + free(equalize_map); +} + +QImage OImageEffect::sample(QImage &src, int w, int h) +{ + if(w == src.width() && h == src.height()) + return(src); + + double *x_offset, *y_offset; + int j, k, y; + register int x; + QImage dest(w, h, src.depth()); + + x_offset = (double *)malloc(w*sizeof(double)); + y_offset = (double *)malloc(h*sizeof(double)); + if(!x_offset || !y_offset){ + qWarning("Unable to allocate pixels buffer"); + free(x_offset); + free(y_offset); + return(src); + } + + // init pixel offsets + for(x=0; x < w; ++x) + x_offset[x] = x*src.width()/((double)w); + for(y=0; y < h; ++y) + y_offset[y] = y*src.height()/((double)h); + + // sample each row + if(src.depth() > 8){ // DirectClass source image + unsigned int *srcData, *destData; + unsigned int *pixels; + pixels = (unsigned int *)malloc(src.width()*sizeof(unsigned int)); + if(!pixels){ + qWarning("Unable to allocate pixels buffer"); + free(pixels); + free(x_offset); + free(y_offset); + return(src); + } + j = (-1); + for(y=0; y < h; ++y){ + destData = (unsigned int *)dest.scanLine(y); + if(j != y_offset[y]){ + // read a scan line + j = (int)(y_offset[y]); + srcData = (unsigned int *)src.scanLine(j); + (void)memcpy(pixels, srcData, src.width()*sizeof(unsigned int)); + } + // sample each column + for(x=0; x < w; ++x){ + k = (int)(x_offset[x]); + destData[x] = pixels[k]; + } + } + free(pixels); + } + else{ // PsudeoClass source image + unsigned char *srcData, *destData; + unsigned char *pixels; + pixels = (unsigned char *)malloc(src.width()*sizeof(unsigned char)); + if(!pixels){ + qWarning("Unable to allocate pixels buffer"); + free(pixels); + free(x_offset); + free(y_offset); + return(src); + } + // copy colortable + dest.setNumColors(src.numColors()); + (void)memcpy(dest.colorTable(), src.colorTable(), + src.numColors()*sizeof(unsigned int)); + + // sample image + j = (-1); + for(y=0; y < h; ++y){ + destData = (unsigned char *)dest.scanLine(y); + if(j != y_offset[y]){ + // read a scan line + j = (int)(y_offset[y]); + srcData = (unsigned char *)src.scanLine(j); + (void)memcpy(pixels, srcData, src.width()*sizeof(unsigned char)); + } + // sample each column + for(x=0; x < w; ++x){ + k = (int)(x_offset[x]); + destData[x] = pixels[k]; + } + } + free(pixels); + } + free(x_offset); + free(y_offset); + return(dest); +} + +void OImageEffect::threshold(QImage &img, unsigned int threshold) +{ + int i, count; + unsigned int *data; + if(img.depth() > 8){ // DirectClass + count = img.width()*img.height(); + data = (unsigned int *)img.bits(); + } + else{ // PsudeoClass + count = img.numColors(); + data = (unsigned int *)img.colorTable(); + } + for(i=0; i < count; ++i) + data[i] = intensityValue(data[i]) < threshold ? Qt::black.rgb() : Qt::white.rgb(); +} + +QImage OImageEffect::charcoal(QImage &src, double factor) +{ + QImage dest(src); + dest.detach(); + toGray(dest); + dest = edge(dest, factor); + dest = blur(dest, factor); + normalize(dest); + dest.invertPixels(false); + return(dest); +} + +void OImageEffect::hull(const int x_offset, const int y_offset, + const int polarity, const int columns, + const int rows, + unsigned int *f, unsigned int *g) +{ + int x, y; + + unsigned int *p, *q, *r, *s; + unsigned int v; + if(f == NULL || g == NULL) + return; + p=f+(columns+2); + q=g+(columns+2); + r=p+(y_offset*(columns+2)+x_offset); + for (y=0; y < rows; y++){ + p++; + q++; + r++; + if(polarity > 0) + for (x=0; x < columns; x++){ + v=(*p); + if (*r > v) + v++; + *q=v; + p++; + q++; + r++; + } + else + for(x=0; x < columns; x++){ + v=(*p); + if (v > (unsigned int) (*r+1)) + v--; + *q=v; + p++; + q++; + r++; + } + p++; + q++; + r++; + } + p=f+(columns+2); + q=g+(columns+2); + r=q+(y_offset*(columns+2)+x_offset); + s=q-(y_offset*(columns+2)+x_offset); + for(y=0; y < rows; y++){ + p++; + q++; + r++; + s++; + if(polarity > 0) + for(x=0; x < (int) columns; x++){ + v=(*q); + if (((unsigned int) (*s+1) > v) && (*r > v)) + v++; + *p=v; + p++; + q++; + r++; + s++; + } + else + for (x=0; x < columns; x++){ + v=(*q); + if (((unsigned int) (*s+1) < v) && (*r < v)) + v--; + *p=v; + p++; + q++; + r++; + s++; + } + p++; + q++; + r++; + s++; + } +} + +QImage OImageEffect::despeckle(QImage &src) +{ + int i, j, x, y; + unsigned int *blue_channel, *red_channel, *green_channel, *buffer, + *alpha_channel; + int packets; + static const int + X[4]= {0, 1, 1,-1}, + Y[4]= {1, 0, 1, 1}; + + unsigned int *destData; + QImage dest(src.width(), src.height(), 32); + + packets = (src.width()+2)*(src.height()+2); + red_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); + green_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); + blue_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); + alpha_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); + buffer = (unsigned int *)calloc(packets, sizeof(unsigned int)); + if(!red_channel || ! green_channel || ! blue_channel || ! alpha_channel || + !buffer){ + free(red_channel); + free(green_channel); + free(blue_channel); + free(alpha_channel); + free(buffer); + return(src); + } + + // copy image pixels to color component buffers + j = src.width()+2; + if(src.depth() > 8){ // DirectClass source image + unsigned int *srcData; + for(y=0; y < src.height(); ++y){ + srcData = (unsigned int *)src.scanLine(y); + ++j; + for(x=0; x < src.width(); ++x){ + red_channel[j] = qRed(srcData[x]); + green_channel[j] = qGreen(srcData[x]); + blue_channel[j] = qBlue(srcData[x]); + alpha_channel[j] = qAlpha(srcData[x]); + ++j; + } + ++j; + } + } + else{ // PsudeoClass source image + unsigned char *srcData; + unsigned int *cTable = src.colorTable(); + unsigned int pixel; + for(y=0; y < src.height(); ++y){ + srcData = (unsigned char *)src.scanLine(y); + ++j; + for(x=0; x < src.width(); ++x){ + pixel = *(cTable+srcData[x]); + red_channel[j] = qRed(pixel); + green_channel[j] = qGreen(pixel); + blue_channel[j] = qBlue(pixel); + alpha_channel[j] = qAlpha(pixel); + ++j; + } + ++j; + } + } + // reduce speckle in red channel + for(i=0; i < 4; i++){ + hull(X[i],Y[i],1,src.width(),src.height(),red_channel,buffer); + hull(-X[i],-Y[i],1,src.width(),src.height(),red_channel,buffer); + hull(-X[i],-Y[i],-1,src.width(),src.height(),red_channel,buffer); + hull(X[i],Y[i],-1,src.width(),src.height(),red_channel,buffer); + } + // reduce speckle in green channel + for (i=0; i < packets; i++) + buffer[i]=0; + for (i=0; i < 4; i++){ + hull(X[i],Y[i],1,src.width(),src.height(),green_channel,buffer); + hull(-X[i],-Y[i],1,src.width(),src.height(),green_channel,buffer); + hull(-X[i],-Y[i],-1,src.width(),src.height(),green_channel,buffer); + hull(X[i],Y[i],-1,src.width(),src.height(),green_channel,buffer); + } + // reduce speckle in blue channel + for (i=0; i < packets; i++) + buffer[i]=0; + for (i=0; i < 4; i++){ + hull(X[i],Y[i],1,src.width(),src.height(),blue_channel,buffer); + hull(-X[i],-Y[i],1,src.width(),src.height(),blue_channel,buffer); + hull(-X[i],-Y[i],-1,src.width(),src.height(),blue_channel,buffer); + hull(X[i],Y[i],-1,src.width(),src.height(),blue_channel,buffer); + } + // copy color component buffers to despeckled image + j = dest.width()+2; + for(y=0; y < dest.height(); ++y) + { + destData = (unsigned int *)dest.scanLine(y); + ++j; + for (x=0; x < dest.width(); ++x) + { + destData[x] = qRgba(red_channel[j], green_channel[j], + blue_channel[j], alpha_channel[j]); + ++j; + } + ++j; + } + free(buffer); + free(red_channel); + free(green_channel); + free(blue_channel); + free(alpha_channel); + return(dest); +} + +unsigned int OImageEffect::generateNoise(unsigned int pixel, + NoiseType noise_type) +{ +#define NoiseEpsilon 1.0e-5 +#define NoiseMask 0x7fff +#define SigmaUniform 4.0 +#define SigmaGaussian 4.0 +#define SigmaImpulse 0.10 +#define SigmaLaplacian 10.0 +#define SigmaMultiplicativeGaussian 0.5 +#define SigmaPoisson 0.05 +#define TauGaussian 20.0 + + double alpha, beta, sigma, value; + alpha=(double) (rand() & NoiseMask)/NoiseMask; + if (alpha == 0.0) + alpha=1.0; + switch(noise_type){ + case UniformNoise: + default: + { + value=(double) pixel+SigmaUniform*(alpha-0.5); + break; + } + case GaussianNoise: + { + double tau; + + beta=(double) (rand() & NoiseMask)/NoiseMask; + sigma=sqrt(-2.0*log(alpha))*cos(2.0*M_PI*beta); + tau=sqrt(-2.0*log(alpha))*sin(2.0*M_PI*beta); + value=(double) pixel+ + (sqrt((double) pixel)*SigmaGaussian*sigma)+(TauGaussian*tau); + break; + } + case MultiplicativeGaussianNoise: + { + if (alpha <= NoiseEpsilon) + sigma=MaxRGB; + else + sigma=sqrt(-2.0*log(alpha)); + beta=(rand() & NoiseMask)/NoiseMask; + value=(double) pixel+ + pixel*SigmaMultiplicativeGaussian*sigma*cos(2.0*M_PI*beta); + break; + } + case ImpulseNoise: + { + if (alpha < (SigmaImpulse/2.0)) + value=0; + else + if (alpha >= (1.0-(SigmaImpulse/2.0))) + value=MaxRGB; + else + value=pixel; + break; + } + case LaplacianNoise: + { + if (alpha <= 0.5) + { + if (alpha <= NoiseEpsilon) + value=(double) pixel-MaxRGB; + else + value=(double) pixel+SigmaLaplacian*log(2.0*alpha); + break; + } + beta=1.0-alpha; + if (beta <= (0.5*NoiseEpsilon)) + value=(double) pixel+MaxRGB; + else + value=(double) pixel-SigmaLaplacian*log(2.0*beta); + break; + } + case PoissonNoise: + { + register int + i; + + for (i=0; alpha > exp(-SigmaPoisson*pixel); i++) + { + beta=(double) (rand() & NoiseMask)/NoiseMask; + alpha=alpha*beta; + } + value=i/SigmaPoisson; + break; + } + } + if(value < 0.0) + return(0); + if(value > MaxRGB) + return(MaxRGB); + return((unsigned int) (value+0.5)); +} + +QImage OImageEffect::addNoise(QImage &src, NoiseType noise_type) +{ + int x, y; + QImage dest(src.width(), src.height(), 32); + unsigned int *destData; + + if(src.depth() > 8){ // DirectClass source image + unsigned int *srcData; + for(y=0; y < src.height(); ++y){ + srcData = (unsigned int *)src.scanLine(y); + destData = (unsigned int *)dest.scanLine(y); + for(x=0; x < src.width(); ++x){ + destData[x] = qRgba(generateNoise(qRed(srcData[x]), noise_type), + generateNoise(qGreen(srcData[x]), noise_type), + generateNoise(qBlue(srcData[x]), noise_type), + qAlpha(srcData[x])); + } + } + } + else{ // PsudeoClass source image + unsigned char *srcData; + unsigned int *cTable = src.colorTable(); + unsigned int pixel; + for(y=0; y < src.height(); ++y){ + srcData = (unsigned char *)src.scanLine(y); + destData = (unsigned int *)dest.scanLine(y); + for(x=0; x < src.width(); ++x){ + pixel = *(cTable+srcData[x]); + destData[x] = qRgba(generateNoise(qRed(pixel), noise_type), + generateNoise(qGreen(pixel), noise_type), + generateNoise(qBlue(pixel), noise_type), + qAlpha(pixel)); + } + } + + } + return(dest); +} + +unsigned int OImageEffect::interpolateColor(QImage *image, double x_offset, + double y_offset, + unsigned int background) +{ + double alpha, beta; + unsigned int p, q, r, s; + int x, y; + + x = (int)x_offset; + y = (int)y_offset; + if((x < -1) || (x >= image->width()) || (y < -1) || (y >= image->height())) + return(background); + if(image->depth() > 8){ + if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) { + unsigned int *t = (unsigned int *)image->scanLine(y); + p = t[x]; + q = t[x+1]; + r = t[x+image->width()]; + s = t[x+image->width()+1]; + } + else{ + unsigned int *t = (unsigned int *)image->scanLine(y); + p = background; + if((x >= 0) && (y >= 0)){ + p = t[x]; + } + q = background; + if(((x+1) < image->width()) && (y >= 0)){ + q = t[x+1]; + } + r = background; + if((x >= 0) && ((y+1) < image->height())){ + t = (unsigned int *)image->scanLine(y+1); + r = t[x+image->width()]; + } + s = background; + if(((x+1) < image->width()) && ((y+1) < image->height())){ + t = (unsigned int *)image->scanLine(y+1); + s = t[x+image->width()+1]; + } + + } + } + else{ + unsigned int *colorTable = (unsigned int *)image->colorTable(); + if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) { + unsigned char *t; + t = (unsigned char *)image->scanLine(y); + p = *(colorTable+t[x]); + q = *(colorTable+t[x+1]); + t = (unsigned char *)image->scanLine(y+1); + r = *(colorTable+t[x]); + s = *(colorTable+t[x+1]); + } + else{ + unsigned char *t; + p = background; + if((x >= 0) && (y >= 0)){ + t = (unsigned char *)image->scanLine(y); + p = *(colorTable+t[x]); + } + q = background; + if(((x+1) < image->width()) && (y >= 0)){ + t = (unsigned char *)image->scanLine(y); + q = *(colorTable+t[x+1]); + } + r = background; + if((x >= 0) && ((y+1) < image->height())){ + t = (unsigned char *)image->scanLine(y+1); + r = *(colorTable+t[x]); + } + s = background; + if(((x+1) < image->width()) && ((y+1) < image->height())){ + t = (unsigned char *)image->scanLine(y+1); + s = *(colorTable+t[x+1]); + } + + } + + } + x_offset -= floor(x_offset); + y_offset -= floor(y_offset); + alpha = 1.0-x_offset; + beta = 1.0-y_offset; + + return(qRgba((unsigned char)(beta*(alpha*qRed(p)+x_offset*qRed(q))+y_offset*(alpha*qRed(r)+x_offset*qRed(s))), + (unsigned char)(beta*(alpha*qGreen(p)+x_offset*qGreen(q))+y_offset*(alpha*qGreen(r)+x_offset*qGreen(s))), + (unsigned char)(beta*(alpha*qBlue(p)+x_offset*qBlue(q))+y_offset*(alpha*qBlue(r)+x_offset*qBlue(s))), + (unsigned char)(beta*(alpha*qAlpha(p)+x_offset*qAlpha(q))+y_offset*(alpha*qAlpha(r)+x_offset*qAlpha(s))))); +} + +QImage OImageEffect::implode(QImage &src, double factor, + unsigned int background) +{ + double amount, distance, radius; + double x_center, x_distance, x_scale; + double y_center, y_distance, y_scale; + unsigned int *destData; + int x, y; + + QImage dest(src.width(), src.height(), 32); + + // compute scaling factor + x_scale = 1.0; + y_scale = 1.0; + x_center = (double)0.5*src.width(); + y_center = (double)0.5*src.height(); + radius=x_center; + if(src.width() > src.height()) + y_scale = (double)src.width()/src.height(); + else if(src.width() < src.height()){ + x_scale = (double) src.height()/src.width(); + radius = y_center; + } + amount=factor/10.0; + if(amount >= 0) + amount/=10.0; + if(src.depth() > 8){ // DirectClass source image + unsigned int *srcData; + for(y=0; y < src.height(); ++y){ + srcData = (unsigned int *)src.scanLine(y); + destData = (unsigned int *)dest.scanLine(y); + y_distance=y_scale*(y-y_center); + for(x=0; x < src.width(); ++x){ + destData[x] = srcData[x]; + x_distance = x_scale*(x-x_center); + distance= x_distance*x_distance+y_distance*y_distance; + if(distance < (radius*radius)){ + double factor; + // Implode the pixel. + factor=1.0; + if(distance > 0.0) + factor= + pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount); + destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center, + factor*y_distance/y_scale+y_center, + background); + } + } + } + } + else{ // PsudeoClass source image + unsigned char *srcData; + unsigned char idx; + unsigned int *cTable = src.colorTable(); + for(y=0; y < src.height(); ++y){ + srcData = (unsigned char *)src.scanLine(y); + destData = (unsigned int *)dest.scanLine(y); + y_distance=y_scale*(y-y_center); + for(x=0; x < src.width(); ++x){ + idx = srcData[x]; + destData[x] = cTable[idx]; + x_distance = x_scale*(x-x_center); + distance= x_distance*x_distance+y_distance*y_distance; + if(distance < (radius*radius)){ + double factor; + // Implode the pixel. + factor=1.0; + if(distance > 0.0) + factor= + pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount); + destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center, + factor*y_distance/y_scale+y_center, + background); + } + } + } + + } + return(dest); +} + +QImage OImageEffect::rotate(QImage &img, RotateDirection r) +{ + QImage dest; + int x, y; + if(img.depth() > 8){ + unsigned int *srcData, *destData; + switch(r){ + case Rotate90: + dest.create(img.height(), img.width(), img.depth()); + for(y=0; y < img.height(); ++y){ + srcData = (unsigned int *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + destData = (unsigned int *)dest.scanLine(x); + destData[img.height()-y-1] = srcData[x]; + } + } + break; + case Rotate180: + dest.create(img.width(), img.height(), img.depth()); + for(y=0; y < img.height(); ++y){ + srcData = (unsigned int *)img.scanLine(y); + destData = (unsigned int *)dest.scanLine(img.height()-y-1); + for(x=0; x < img.width(); ++x) + destData[img.width()-x-1] = srcData[x]; + } + break; + case Rotate270: + dest.create(img.height(), img.width(), img.depth()); + for(y=0; y < img.height(); ++y){ + srcData = (unsigned int *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + destData = (unsigned int *)dest.scanLine(img.width()-x-1); + destData[y] = srcData[x]; + } + } + break; + default: + dest = img; + break; + } + } + else{ + unsigned char *srcData, *destData; + unsigned int *srcTable, *destTable; + switch(r){ + case Rotate90: + dest.create(img.height(), img.width(), img.depth()); + dest.setNumColors(img.numColors()); + srcTable = (unsigned int *)img.colorTable(); + destTable = (unsigned int *)dest.colorTable(); + for(x=0; x < img.numColors(); ++x) + destTable[x] = srcTable[x]; + for(y=0; y < img.height(); ++y){ + srcData = (unsigned char *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + destData = (unsigned char *)dest.scanLine(x); + destData[img.height()-y-1] = srcData[x]; + } + } + break; + case Rotate180: + dest.create(img.width(), img.height(), img.depth()); + dest.setNumColors(img.numColors()); + srcTable = (unsigned int *)img.colorTable(); + destTable = (unsigned int *)dest.colorTable(); + for(x=0; x < img.numColors(); ++x) + destTable[x] = srcTable[x]; + for(y=0; y < img.height(); ++y){ + srcData = (unsigned char *)img.scanLine(y); + destData = (unsigned char *)dest.scanLine(img.height()-y-1); + for(x=0; x < img.width(); ++x) + destData[img.width()-x-1] = srcData[x]; + } + break; + case Rotate270: + dest.create(img.height(), img.width(), img.depth()); + dest.setNumColors(img.numColors()); + srcTable = (unsigned int *)img.colorTable(); + destTable = (unsigned int *)dest.colorTable(); + for(x=0; x < img.numColors(); ++x) + destTable[x] = srcTable[x]; + for(y=0; y < img.height(); ++y){ + srcData = (unsigned char *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + destData = (unsigned char *)dest.scanLine(img.width()-x-1); + destData[y] = srcData[x]; + } + } + break; + default: + dest = img; + break; + } + + } + return(dest); +} + +void OImageEffect::solarize(QImage &img, double factor) +{ + int i, count; + int threshold; + unsigned int *data; + + threshold = (int)(factor*(MaxRGB+1)/100.0); + if(img.depth() < 32){ + data = (unsigned int *)img.colorTable(); + count = img.numColors(); + } + else{ + data = (unsigned int *)img.bits(); + count = img.width()*img.height(); + } + for(i=0; i < count; ++i){ + data[i] = qRgba(qRed(data[i]) > threshold ? MaxRGB-qRed(data[i]) : qRed(data[i]), + qGreen(data[i]) > threshold ? MaxRGB-qGreen(data[i]) : qGreen(data[i]), + qBlue(data[i]) > threshold ? MaxRGB-qBlue(data[i]) : qBlue(data[i]), + qAlpha(data[i])); + } +} + +QImage OImageEffect::spread(QImage &src, unsigned int amount) +{ + int quantum, x, y; + int x_distance, y_distance; + if(src.width() < 3 || src.height() < 3) + return(src); + QImage dest(src); + dest.detach(); + quantum=(amount+1) >> 1; + if(src.depth() > 8){ // DirectClass source image + unsigned int *p, *q; + for(y=0; y < src.height(); y++){ + q = (unsigned int *)dest.scanLine(y); + for(x=0; x < src.width(); x++){ + x_distance = x + ((rand() & (amount+1))-quantum); + y_distance = y + ((rand() & (amount+1))-quantum); + x_distance = QMIN(x_distance, src.width()-1); + y_distance = QMIN(y_distance, src.height()-1); + if(x_distance < 0) + x_distance = 0; + if(y_distance < 0) + y_distance = 0; + p = (unsigned int *)src.scanLine(y_distance); + p += x_distance; + *q++=(*p); + } + } + } + else{ // PsudeoClass source image + // just do colortable values + unsigned char *p, *q; + for(y=0; y < src.height(); y++){ + q = (unsigned char *)dest.scanLine(y); + for(x=0; x < src.width(); x++){ + x_distance = x + ((rand() & (amount+1))-quantum); + y_distance = y + ((rand() & (amount+1))-quantum); + x_distance = QMIN(x_distance, src.width()-1); + y_distance = QMIN(y_distance, src.height()-1); + if(x_distance < 0) + x_distance = 0; + if(y_distance < 0) + y_distance = 0; + p = (unsigned char *)src.scanLine(y_distance); + p += x_distance; + *q++=(*p); + } + } + } + return(dest); +} + +QImage OImageEffect::swirl(QImage &src, double degrees, + unsigned int background) +{ + double cosine, distance, factor, radius, sine, x_center, x_distance, + x_scale, y_center, y_distance, y_scale; + int x, y; + unsigned int *q; + QImage dest(src.width(), src.height(), 32); + + // compute scaling factor + x_center = src.width()/2.0; + y_center = src.height()/2.0; + radius = QMAX(x_center,y_center); + x_scale=1.0; + y_scale=1.0; + if(src.width() > src.height()) + y_scale=(double)src.width()/src.height(); + else if(src.width() < src.height()) + x_scale=(double)src.height()/src.width(); + degrees=DegreesToRadians(degrees); + // swirl each row + if(src.depth() > 8){ // DirectClass source image + unsigned int *p; + for(y=0; y < src.height(); y++){ + p = (unsigned int *)src.scanLine(y); + q = (unsigned int *)dest.scanLine(y); + y_distance = y_scale*(y-y_center); + for(x=0; x < src.width(); x++){ + // determine if the pixel is within an ellipse + *q=(*p); + x_distance = x_scale*(x-x_center); + distance = x_distance*x_distance+y_distance*y_distance; + if (distance < (radius*radius)){ + // swirl + factor = 1.0-sqrt(distance)/radius; + sine = sin(degrees*factor*factor); + cosine = cos(degrees*factor*factor); + *q = interpolateColor(&src, + (cosine*x_distance-sine*y_distance)/x_scale+x_center, + (sine*x_distance+cosine*y_distance)/y_scale+y_center, + background); + } + p++; + q++; + } + } + } + else{ // PsudeoClass source image + unsigned char *p; + unsigned int *cTable = (unsigned int *)src.colorTable(); + for(y=0; y < src.height(); y++){ + p = (unsigned char *)src.scanLine(y); + q = (unsigned int *)dest.scanLine(y); + y_distance = y_scale*(y-y_center); + for(x=0; x < src.width(); x++){ + // determine if the pixel is within an ellipse + *q = *(cTable+(*p)); + x_distance = x_scale*(x-x_center); + distance = x_distance*x_distance+y_distance*y_distance; + if (distance < (radius*radius)){ + // swirl + factor = 1.0-sqrt(distance)/radius; + sine = sin(degrees*factor*factor); + cosine = cos(degrees*factor*factor); + *q = interpolateColor(&src, + (cosine*x_distance-sine*y_distance)/x_scale+x_center, + (sine*x_distance+cosine*y_distance)/y_scale+y_center, + background); + } + p++; + q++; + } + } + + } + return(dest); +} + +QImage OImageEffect::wave(QImage &src, double amplitude, double wavelength, + unsigned int background) +{ + double *sine_map; + int x, y; + unsigned int *q; + + QImage dest(src.width(), src.height() + (int)(2*fabs(amplitude)), 32); + // allocate sine map + sine_map = (double *)malloc(dest.width()*sizeof(double)); + if(!sine_map) + return(src); + for(x=0; x < dest.width(); ++x) + sine_map[x]=fabs(amplitude)+amplitude*sin((2*M_PI*x)/wavelength); + // wave image + for(y=0; y < dest.height(); ++y){ + q = (unsigned int *)dest.scanLine(y); + for (x=0; x < dest.width(); x++){ + *q=interpolateColor(&src, x, (int)(y-sine_map[x]), background); + ++q; + } + } + free(sine_map); + return(dest); +} + +QImage OImageEffect::oilPaint(QImage &src, int radius) +{ + // TODO 8bpp src! + if(src.depth() < 32){ + qWarning("Oil Paint source image < 32bpp. Convert before using!"); + return(src); + } + int j, k, i, x, y; + unsigned int *histogram; + unsigned int *s; + unsigned int count; + + unsigned int *srcData, *destData; + + QImage dest(src); + dest.detach(); + histogram = (unsigned int *) malloc((MaxRGB+1)*sizeof(unsigned int)); + if(!histogram) + return(src); + // paint each row + k=0; + for(y = radius; y < src.height(); ++y){ + srcData = (unsigned int *)src.scanLine(y-radius); + destData = (unsigned int *)dest.scanLine(y); + srcData += radius*src.width()+radius; + destData += radius; + for(x=radius; x < src.width()-radius; ++x){ + // determine most frequent color + count = 0; + for(i=0; i < MaxRGB+1; ++i) + histogram[i] = 0; + for(i=0; i < radius; ++i){ + s = srcData-(radius-1)*src.width()-i-1; + for(j =0; j < (2*i+1); ++j){ + k = intensityValue(*s); + histogram[k]++; + if(histogram[k] > count){ + *destData = *s; + count = histogram[k]; + } + ++s; + } + s = srcData+(radius-i)*src.width()-i-1; + for(j =0; j < (2*i+1); ++j){ + k = intensityValue(*s); + histogram[k]++; + if(histogram[k] > count){ + *destData = *s; + count = histogram[k]; + } + ++s; + } + } + s = srcData-radius; + for(j =0; j < (2*i+1); ++j){ + k = intensityValue(*s); + histogram[k]++; + if(histogram[k] > count){ + *destData = *s; + count = histogram[k]; + } + ++s; + } + ++srcData; + ++destData; + } + } + free(histogram); + return(dest); +} + +// +// The following methods work by computing a value from neighboring pixels +// (mosfet 12/28/01) +// + +QImage OImageEffect::edge(QImage &src, double factor) +{ +#define Edge(weight) \ + total_red+=(weight)*qRed(*s); \ + total_green+=(weight)*qGreen(*s); \ + total_blue+=(weight)*qBlue(*s); \ + total_opacity+=(weight)*qAlpha(*s); \ + s++; + +#define Edge256(weight) \ + total_red+=(weight)*qRed(*(cTable+(*s))); \ + total_green+=(weight)*qGreen(*(cTable+(*s))); \ + total_blue+=(weight)*qBlue(*(cTable+(*s))); \ + total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \ + s++; + + if(src.width() < 3 || src.height() < 3) + return(src); + + double total_blue, total_green, total_opacity, total_red, weight; + + int x, y; + + unsigned int *q; + + QImage dest(src.width(), src.height(), 32); + weight=factor/8.0; + if(src.depth() > 8){ // DirectClass source image + unsigned int *p, *s; + for(y=0; y < src.height(); ++y){ + p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); + q = (unsigned int *)dest.scanLine(y); + // edge detect this row of pixels. + *q++=(*(p+src.width())); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + total_opacity=0.0; + s=p; + Edge(-weight/8); Edge(-weight/8) Edge(-weight/8); + s=p+src.width(); + Edge(-weight/8); Edge(weight); Edge(-weight/8); + s=p+2*src.width(); + Edge(-weight/8); Edge(-weight/8); Edge(-weight/8); + *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), + (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), + (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), + (unsigned char)((total_opacity < 0) ? 0 : (total_opacity > MaxRGB) ? MaxRGB : total_opacity)); + p++; + q++; + } + p++; + *q++=(*p); + } + } + else{ // PsudeoClass source image + unsigned char *p, *p2, *p3, *s; + unsigned int *cTable = src.colorTable(); + int scanLineIdx; + for(y=0; y < src.height(); ++y){ + scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); + p = (unsigned char *)src.scanLine(scanLineIdx); + p2 = (unsigned char *)src.scanLine(scanLineIdx+1); + p3 = (unsigned char *)src.scanLine(scanLineIdx+2); + q = (unsigned int *)dest.scanLine(y); + // edge detect this row of pixels. + *q++=(*(cTable+(*p2))); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + total_opacity=0.0; + s=p; + Edge256(-weight/8); Edge256(-weight/8) Edge256(-weight/8); + s=p2; + Edge256(-weight/8); Edge256(weight); Edge256(-weight/8); + s=p3; + Edge256(-weight/8); Edge256(-weight/8); Edge256(-weight/8); + *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), + (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), + (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), + (unsigned char)((total_opacity < 0) ? 0 : (total_opacity > MaxRGB) ? MaxRGB : total_opacity)); + p++; + p2++; + p3++; + q++; + } + p++; + *q++=(*(cTable+(*p))); + } + } + return(dest); +} + +QImage OImageEffect::sharpen(QImage &src, double factor) +{ +#define Sharpen(weight) \ + total_red+=(weight)*qRed(*s); \ + total_green+=(weight)*qGreen(*s); \ + total_blue+=(weight)*qBlue(*s); \ + total_opacity+=(weight)*qAlpha(*s); \ + s++; + +#define Sharpen256(weight) \ + total_red+=(weight)*qRed(*(cTable+(*s))); \ + total_green+=(weight)*qGreen(*(cTable+(*s))); \ + total_blue+=(weight)*qBlue(*(cTable+(*s))); \ + total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \ + s++; + + if(src.width() < 3 || src.height() < 3) + return(src); + + double total_blue, total_green, total_opacity, total_red; + double quantum, weight; + unsigned char r, g, b, a; + + int x, y; + unsigned int *q; + + QImage dest(src.width(), src.height(), 32); + weight = ((100.0-factor)/2.0+13.0); + quantum = QMAX(weight-12.0, 1.0); + if(src.depth() > 8){ // DirectClass source image + unsigned int *p, *s; + for(y=0; y < src.height(); ++y){ + p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); + q = (unsigned int *)dest.scanLine(y); + // sharpen this row of pixels. + *q++=(*(p+src.width())); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + total_opacity=0.0; + s=p; + Sharpen(-1); Sharpen(-2); Sharpen(-1); + s=p+src.width(); + Sharpen(-2); Sharpen(weight); Sharpen(-2); + s=p+2*src.width(); + Sharpen(-1); Sharpen(-2); Sharpen(-1); + if(total_red < 0) + r=0; + else if(total_red > (int)(MaxRGB*quantum)) + r = (unsigned char)MaxRGB; + else + r = (unsigned char)((total_red+(quantum/2.0))/quantum); + + if(total_green < 0) + g = 0; + else if(total_green > (int)(MaxRGB*quantum)) + g = (unsigned char)MaxRGB; + else + g = (unsigned char)((total_green+(quantum/2.0))/quantum); + + if(total_blue < 0) + b = 0; + else if(total_blue > (int)(MaxRGB*quantum)) + b = (unsigned char)MaxRGB; + else + b = (unsigned char)((total_blue+(quantum/2.0))/quantum); + + if(total_opacity < 0) + a = 0; + else if(total_opacity > (int)(MaxRGB*quantum)) + a = (unsigned char)MaxRGB; + else + a= (unsigned char)((total_opacity+(quantum/2.0))/quantum); + + *q = qRgba(r, g, b, a); + + p++; + q++; + } + p++; + *q++=(*p); + } + } + else{ // PsudeoClass source image + unsigned char *p, *p2, *p3, *s; + unsigned int *cTable = src.colorTable(); + int scanLineIdx; + for(y=0; y < src.height(); ++y){ + scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); + p = (unsigned char *)src.scanLine(scanLineIdx); + p2 = (unsigned char *)src.scanLine(scanLineIdx+1); + p3 = (unsigned char *)src.scanLine(scanLineIdx+2); + q = (unsigned int *)dest.scanLine(y); + // sharpen this row of pixels. + *q++=(*(cTable+(*p2))); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + total_opacity=0.0; + s=p; + Sharpen256(-1); Sharpen256(-2); Sharpen256(-1); + s=p2; + Sharpen256(-2); Sharpen256(weight); Sharpen256(-2); + s=p3; + Sharpen256(-1); Sharpen256(-2); Sharpen256(-1); + if(total_red < 0) + r=0; + else if(total_red > (int)(MaxRGB*quantum)) + r = (unsigned char)MaxRGB; + else + r = (unsigned char)((total_red+(quantum/2.0))/quantum); + + if(total_green < 0) + g = 0; + else if(total_green > (int)(MaxRGB*quantum)) + g = (unsigned char)MaxRGB; + else + g = (unsigned char)((total_green+(quantum/2.0))/quantum); + + if(total_blue < 0) + b = 0; + else if(total_blue > (int)(MaxRGB*quantum)) + b = (unsigned char)MaxRGB; + else + b = (unsigned char)((total_blue+(quantum/2.0))/quantum); + + if(total_opacity < 0) + a = 0; + else if(total_opacity > (int)(MaxRGB*quantum)) + a = (unsigned char)MaxRGB; + else + a = (unsigned char)((total_opacity+(quantum/2.0))/quantum); + + *q = qRgba(r, g, b, a); + + p++; + p2++; + p3++; + q++; + } + p++; + *q++=(*(cTable+(*p))); + } + } + return(dest); +} + +QImage OImageEffect::emboss(QImage &src) +{ +#define Emboss(weight) \ + total_red+=(weight)*qRed(*s); \ + total_green+=(weight)*qGreen(*s); \ + total_blue+=(weight)*qBlue(*s); \ + s++; + +#define Emboss256(weight) \ + total_red+=(weight)*qRed(*(cTable+(*s))); \ + total_green+=(weight)*qGreen(*(cTable+(*s))); \ + total_blue+=(weight)*qBlue(*(cTable+(*s))); \ + s++; + + if(src.width() < 3 || src.height() < 3) + return(src); + + double total_blue, total_green, total_red; + int x, y; + unsigned int *q; + + QImage dest(src.width(), src.height(), 32); + if(src.depth() > 8){ // DirectClass source image + unsigned int *p, *s; + for(y=0; y < src.height(); ++y){ + p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); + q = (unsigned int *)dest.scanLine(y); + // emboss this row of pixels. + *q++=(*(p+src.width())); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + s=p; + Emboss(-1); Emboss(-2); Emboss( 0); + s=p+src.width(); + Emboss(-2); Emboss( 0); Emboss( 2); + s=p+2*src.width(); + Emboss( 0); Emboss( 2); Emboss( 1); + total_red += (MaxRGB+1)/2; + total_green += (MaxRGB+1)/2; + total_blue += (MaxRGB+1)/2; + *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), + (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), + (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), + 255); + p++; + q++; + } + p++; + *q++=(*p); + } + } + else{ // PsudeoClass source image + unsigned char *p, *p2, *p3, *s; + unsigned int *cTable = src.colorTable(); + int scanLineIdx; + for(y=0; y < src.height(); ++y){ + scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); + p = (unsigned char *)src.scanLine(scanLineIdx); + p2 = (unsigned char *)src.scanLine(scanLineIdx+1); + p3 = (unsigned char *)src.scanLine(scanLineIdx+2); + q = (unsigned int *)dest.scanLine(y); + // emboss this row of pixels. + *q++=(*(cTable+(*p2))); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + s=p; + Emboss256(-1); Emboss256(-2); Emboss256(0); + s=p2; + Emboss256(-2); Emboss256(0); Emboss256(2); + s=p3; + Emboss256(0); Emboss256(2); Emboss256(1); + total_red += (MaxRGB+1)/2; + total_green += (MaxRGB+1)/2; + total_blue += (MaxRGB+1)/2; + *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), + (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), + (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), + 255); + p++; + p2++; + p3++; + q++; + } + p++; + *q++=(*(cTable+(*p))); + } + } + toGray(dest); + normalize(dest); + return(dest); +} + +QImage OImageEffect::shade(QImage &src, bool color_shading, double azimuth, + double elevation) +{ + struct PointInfo{ + double x, y, z; + }; + + double distance, normal_distance, shade; + int x, y; + + struct PointInfo light, normal; + + unsigned int *q; + + QImage dest(src.width(), src.height(), 32); + + azimuth = DegreesToRadians(azimuth); + elevation = DegreesToRadians(elevation); + light.x = MaxRGB*cos(azimuth)*cos(elevation); + light.y = MaxRGB*sin(azimuth)*cos(elevation); + light.z = MaxRGB*sin(elevation); + normal.z= 2*MaxRGB; // constant Z of surface normal + + if(src.depth() > 8){ // DirectClass source image + unsigned int *p, *s0, *s1, *s2; + for(y=0; y < src.height(); ++y){ + p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); + q = (unsigned int *)dest.scanLine(y); + // shade this row of pixels. + *q++=(*(p+src.width())); + p++; + s0 = p; + s1 = p + src.width(); + s2 = p + 2*src.width(); + for(x=1; x < src.width()-1; ++x){ + // determine the surface normal and compute shading. + normal.x=intensityValue(*(s0-1))+intensityValue(*(s1-1))+intensityValue(*(s2-1))- + (double) intensityValue(*(s0+1))-(double) intensityValue(*(s1+1))- + (double) intensityValue(*(s2+1)); + normal.y=intensityValue(*(s2-1))+intensityValue(*s2)+intensityValue(*(s2+1))- + (double) intensityValue(*(s0-1))-(double) intensityValue(*s0)- + (double) intensityValue(*(s0+1)); + if((normal.x == 0) && (normal.y == 0)) + shade=light.z; + else{ + shade=0.0; + distance=normal.x*light.x+normal.y*light.y+normal.z*light.z; + if (distance > 0.0){ + normal_distance= + normal.x*normal.x+normal.y*normal.y+normal.z*normal.z; + if(fabs(normal_distance) > 0.0000001) + shade=distance/sqrt(normal_distance); + } + } + if(!color_shading){ + *q = qRgba((unsigned char)(shade), + (unsigned char)(shade), + (unsigned char)(shade), + qAlpha(*s1)); + } + else{ + *q = qRgba((unsigned char)((shade*qRed(*s1))/(MaxRGB+1)), + (unsigned char)((shade*qGreen(*s1))/(MaxRGB+1)), + (unsigned char)((shade*qBlue(*s1))/(MaxRGB+1)), + qAlpha(*s1)); + } + ++s0; + ++s1; + ++s2; + q++; + } + *q++=(*s1); + } + } + else{ // PsudeoClass source image + unsigned char *p, *s0, *s1, *s2; + int scanLineIdx; + unsigned int *cTable = (unsigned int *)src.colorTable(); + for(y=0; y < src.height(); ++y){ + scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); + p = (unsigned char *)src.scanLine(scanLineIdx); + q = (unsigned int *)dest.scanLine(y); + // shade this row of pixels. + s0 = p; + s1 = (unsigned char *) src.scanLine(scanLineIdx+1); + s2 = (unsigned char *) src.scanLine(scanLineIdx+2); + *q++=(*(cTable+(*s1))); + ++p; + ++s0; + ++s1; + ++s2; + for(x=1; x < src.width()-1; ++x){ + // determine the surface normal and compute shading. + normal.x=intensityValue(*(cTable+(*(s0-1))))+intensityValue(*(cTable+(*(s1-1))))+intensityValue(*(cTable+(*(s2-1))))- + (double) intensityValue(*(cTable+(*(s0+1))))-(double) intensityValue(*(cTable+(*(s1+1))))- + (double) intensityValue(*(cTable+(*(s2+1)))); + normal.y=intensityValue(*(cTable+(*(s2-1))))+intensityValue(*(cTable+(*s2)))+intensityValue(*(cTable+(*(s2+1))))- + (double) intensityValue(*(cTable+(*(s0-1))))-(double) intensityValue(*(cTable+(*s0)))- + (double) intensityValue(*(cTable+(*(s0+1)))); + if((normal.x == 0) && (normal.y == 0)) + shade=light.z; + else{ + shade=0.0; + distance=normal.x*light.x+normal.y*light.y+normal.z*light.z; + if (distance > 0.0){ + normal_distance= + normal.x*normal.x+normal.y*normal.y+normal.z*normal.z; + if(fabs(normal_distance) > 0.0000001) + shade=distance/sqrt(normal_distance); + } + } + if(!color_shading){ + *q = qRgba((unsigned char)(shade), + (unsigned char)(shade), + (unsigned char)(shade), + qAlpha(*(cTable+(*s1)))); + } + else{ + *q = qRgba((unsigned char)((shade*qRed(*(cTable+(*s1))))/(MaxRGB+1)), + (unsigned char)((shade*qGreen(*(cTable+(*s1))))/(MaxRGB+1)), + (unsigned char)((shade*qBlue(*(cTable+(*s1))))/(MaxRGB+1)), + qAlpha(*s1)); + } + ++s0; + ++s1; + ++s2; + q++; + } + *q++=(*(cTable+(*s1))); + } + } + return(dest); +} + +QImage OImageEffect::blur(QImage &src, double factor) +{ + +#define Blur(weight) \ + total_red+=(weight)*qRed(*s); \ + total_green+=(weight)*qGreen(*s); \ + total_blue+=(weight)*qBlue(*s); \ + total_opacity+=(weight)*qAlpha(*s); \ + s++; + +#define Blur256(weight) \ + total_red+=(weight)*qRed(*(cTable+(*s))); \ + total_green+=(weight)*qGreen(*(cTable+(*s))); \ + total_blue+=(weight)*qBlue(*(cTable+(*s))); \ + total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \ + s++; + + if(src.width() < 3 || src.height() < 3) + return(src); + + double quantum, total_blue, total_green, total_opacity, total_red, weight; + + int x, y; + unsigned int *q; + + QImage dest(src.width(), src.height(), 32); + weight=((100.0-factor)/2)+1; + quantum = QMAX(weight+12.0, 1.0); + if(src.depth() > 8){ // DirectClass source image + unsigned int *p, *s; + for(y=0; y < src.height(); ++y){ + p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); + q = (unsigned int *)dest.scanLine(y); + // blur this row of pixels. + *q++=(*(p+src.width())); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + total_opacity=0.0; + s=p; + Blur(1); Blur(2); Blur(1); + s=p+src.width(); + Blur(2); Blur(weight); Blur(2); + s=p+2*src.width(); + Blur(1); Blur(2); Blur(1); + *q = qRgba((unsigned char)((total_red+(quantum/2))/quantum), + (unsigned char)((total_green+(quantum/2))/quantum), + (unsigned char)((total_blue+(quantum/2))/quantum), + (unsigned char)((total_opacity+(quantum/2))/quantum)); + p++; + q++; + } + p++; + *q++=(*p); + } + } + else{ // PsudeoClass source image + unsigned char *p, *p2, *p3, *s; + unsigned int *cTable = src.colorTable(); + int scanLineIdx; + for(y=0; y < src.height(); ++y){ + scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); + p = (unsigned char *)src.scanLine(scanLineIdx); + p2 = (unsigned char *)src.scanLine(scanLineIdx+1); + p3 = (unsigned char *)src.scanLine(scanLineIdx+2); + q = (unsigned int *)dest.scanLine(y); + // blur this row of pixels. + *q++=(*(cTable+(*p2))); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + total_opacity=0.0; + s=p; + Blur256(1); Blur256(2); Blur256(1); + s=p2; + Blur256(2); Blur256(weight); Blur256(2); + s=p3; + Blur256(1); Blur256(2); Blur256(1); + *q = qRgba((unsigned char)((total_red+(quantum/2))/quantum), + (unsigned char)((total_green+(quantum/2))/quantum), + (unsigned char)((total_blue+(quantum/2))/quantum), + (unsigned char)((total_opacity+(quantum/2))/quantum)); + p++; + p2++; + p3++; + q++; + } + p++; + *q++=(*(cTable+(*p))); + } + } + return(dest); +} + +// High quality, expensive HSV contrast. You can do a faster one by just +// taking a grayscale threshold (ie: 128) and incrementing RGB color +// channels above it and decrementing those below it, but this gives much +// better results. (mosfet 12/28/01) +void OImageEffect::contrastHSV(QImage &img, bool sharpen) +{ + int i, sign; + unsigned int *data; + int count; + double brightness, scale, theta; + QColor c; + int h, s, v; + + sign = sharpen ? 1 : -1; + scale=0.5000000000000001; + if(img.depth() > 8){ + count = img.width()*img.height(); + data = (unsigned int *)img.bits(); + } + else{ + count = img.numColors(); + data = (unsigned int *)img.colorTable(); + } + for(i=0; i < count; ++i){ + c.setRgb(data[i]); + c.hsv(&h, &s, &v); + brightness = v/255.0; + theta=(brightness-0.5)*M_PI; + brightness+=scale*(((scale*((sin(theta)+1.0)))-brightness)*sign); + if (brightness > 1.0) + brightness=1.0; + else + if (brightness < 0) + brightness=0.0; + v = (int)(brightness*255); + c.setHsv(h, s, v); + data[i] = qRgba(c.red(), c.green(), c.blue(), qAlpha(data[i])); + } +} + + + + diff --git a/libopie2/opieui/oimageeffect.h b/libopie2/opieui/oimageeffect.h new file mode 100644 index 0000000..313ea50 --- a/dev/null +++ b/libopie2/opieui/oimageeffect.h @@ -0,0 +1,558 @@ +//FIXME: Revise for Opie - do we really need such fancy stuff on PDA's? +//FIXME: Maybe not on SL5xxx, but surely on C700 :)) + +/* This file is part of the KDE libraries + Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley <mosfet@interaccess.com> + (C) 1998, 1999 Christian Tibirna <ctibirna@total.net> + (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org> + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +// $Id$ + +#ifndef OIMAGEEFFECT_H +#define OIMAGEEFFECT_H + +class QImage; +class QSize; +class QColor; + +/** + * This class includes various @ref QImage based graphical effects. + * + * Everything is + * static, so there is no need to create an instance of this class. You can + * just call the static methods. They are encapsulated here merely to provide + * a common namespace. + */ + +class OImageEffect +{ +public: + enum GradientType { VerticalGradient, HorizontalGradient, + DiagonalGradient, CrossDiagonalGradient, + PyramidGradient, RectangleGradient, + PipeCrossGradient, EllipticGradient }; + enum RGBComponent { Red, Green, Blue, Gray, All }; + + enum Lighting {NorthLite, NWLite, WestLite, SWLite, + SouthLite, SELite, EastLite, NELite}; + + enum ModulationType { Intensity, Saturation, HueShift, Contrast }; + + enum NoiseType { UniformNoise=0, GaussianNoise, MultiplicativeGaussianNoise, + ImpulseNoise, LaplacianNoise, PoissonNoise}; + + enum RotateDirection{ Rotate90, Rotate180, Rotate270 }; + + /** + * Create a gradient from color a to color b of the specified type. + * + * @param size The desired size of the gradient. + * @param ca Color a + * @param cb Color b + * @param type The type of gradient. + * @param ncols The number of colors to use when not running on a + * truecolor display. The gradient will be dithered to this number of + * colors. Pass 0 to prevent dithering. + */ + static QImage gradient(const QSize &size, const QColor &ca, + const QColor &cb, GradientType type, int ncols=3); + + /** + * Create an unbalanced gradient. + + * An unbalanced gradient is a gradient where the transition from + * color a to color b is not linear, but in this case, exponential. + * + * @param size The desired size of the gradient. + * @param ca Color a + * @param cb Color b + * @param type The type of gradient. + * @param xfactor The x decay length. Use a value between -200 and 200. + * @param yfactor The y decay length. + * @param ncols The number of colors. See OPixmapEffect:gradient. + */ + static QImage unbalancedGradient(const QSize &size, const QColor &ca, + const QColor &cb, GradientType type, int xfactor = 100, + int yfactor = 100, int ncols = 3); + + /** + * Blends a color into the destination image, using an opacity + * value for blending one into another. Very fast direct pixel + * manipulation is used. + * + * @author Karol Szwed (gallium@kde.org) + * @param clr source color to be blended into the destination image. + * @param dst destination image in which the source will be blended into. + * @param opacity opacity (in percent) which determines how much the source + * color will be blended into the destination image. + * @return The destination image (dst) containing the result. + */ + static QImage& blend(const QColor& clr, QImage& dst, float opacity); + + /** + * Blend the src image into the destination image, using an opacity + * value for blending one into another. Very fast direct pixel + * manipulation is used. + * + * @author Karol Szwed (gallium@kde.org) + * @param src source image to be blended into the destination image. + * @param dst destination image in which the source will be blended into. + * @param opacity opacity (in percent) which determines how much the source + * image will be blended into the destination image. + * @return The destination image (dst) containing the result. + */ + static QImage& blend(QImage& src, QImage& dst, float opacity); + + /** + * Blend the provided image into a background of the indicated color. + * + * @param initial_intensity this parameter takes values from -1 to 1: + * a) if positive: how much to fade the image in its + * less affected spot + * b) if negative: roughly indicates how much of the image + * remains unaffected + * @param bgnd indicates the color of the background to blend in + * @param eff lets you choose what kind of blending you like + * @param anti_dir blend in the opposite direction (makes no much sense + * with concentric blending effects) + * @param image must be 32bpp + */ + static QImage& blend(QImage &image, float initial_intensity, + const QColor &bgnd, GradientType eff, + bool anti_dir=false); + + /** + * Blend an image into another one, using a gradient type + * for blending from one to another. + * + * @param image1 source1 and result of blending + * @param image2 source2 of blending + * @param gt gradient type for blending between source1 and source2 + * @param xf x decay length for unbalanced gradient tpye + * @param yf y decay length for unbalanced gradient tpye + */ + static QImage& blend(QImage &image1,QImage &image2, + GradientType gt, int xf=100, int yf=100); + + /** + * Blend an image into another one, using a color channel of a + * third image for the decision of blending from one to another. + * + * @param image1 Source 1 and result of blending + * @param image2 Source 2 of blending + * @param blendImage If the gray value of of pixel is 0, the result + * for this pixel is that of image1; for a gray value + * of 1, the pixel of image2 is used; for a value + * inbetween, a corresponding blending is used. + * @param channel The RBG channel to use for the blending decision. + */ + static QImage& blend(QImage &image1, QImage &image2, + QImage &blendImage, RGBComponent channel); + + /** + * Blend an image into another one, using alpha in the expected way. + * @author Rik Hemsley (rikkus) <rik@kde.org> + */ + static bool blend(const QImage & upper, const QImage & lower, QImage & output); +// Not yet... static bool blend(const QImage & image1, const QImage & image2, QImage & output, const QRect & destRect); + + /** + * Blend an image into another one, using alpha in the expected way and + * over coordinates @p x and @p y with respect to the lower image. + * The output is a QImage which is the @p upper image already blended + * with the @p lower one, so its size will be (in general) the same than + * @p upper instead of the same size than @p lower like the method above. + * In fact, the size of @p output is like upper's one only when it can be + * painted on lower, if there has to be some clipping, output's size will + * be the clipped area and x and y will be set to the correct up-left corner + * where the clipped rectangle begins. + */ + static bool blend(int &x, int &y, const QImage & upper, const QImage & lower, QImage & output); + /** + * Blend an image into another one, using alpha in the expected way and + * over coordinates @p x and @p y with respect to the lower image. + * The output is painted in the own @p lower image. This is an optimization + * of the blend method above provided by convenience. + */ + static bool blendOnLower(int x, int y, const QImage & upper, const QImage & lower); + + /** + * Modifies the intensity of a pixmap's RGB channel component. + * + * @author Daniel M. Duley (mosfet) + * @param image The QImage to process. + * @param percent Percent value. Use a negative value to dim. + * @param channel Which channel(s) should be modified + * @return The @p image, provided for convenience. + */ + static QImage& channelIntensity(QImage &image, float percent, + RGBComponent channel); + + /** + * Fade an image to a certain background color. + * + * The number of colors will not be changed. + * + * @param image The QImage to process. + * @param val The strength of the effect. 0 <= val <= 1. + * @param color The background color. + * @return Returns the @ref image(), provided for convenience. + */ + static QImage& fade(QImage &img, float val, const QColor &color); + + + /** + * This recolors a pixmap. The most dark color will become color a, + * the most bright one color b, and in between. + * + * @param image A QImage to process. + * @param ca Color a + * @param cb Color b + */ + static QImage& flatten(QImage &image, const QColor &ca, + const QColor &cb, int ncols=0); + + /** + * Build a hash on any given @ref QImage + * + * @param image The QImage to process + * @param lite The hash faces the indicated lighting (cardinal poles). + * @param spacing How many unmodified pixels inbetween hashes. + * @return Returns the @ref image(), provided for convenience. + */ + static QImage& hash(QImage &image, Lighting lite=NorthLite, + unsigned int spacing=0); + + /** + * Either brighten or dim the image by a specified percent. + * For example, .50 will modify the colors by 50%. + * + * @author Daniel M. Duley (mosfet) + * @param image The QImage to process. + * @param percent The percent value. Use a negative value to dim. + * @return Returns The @ref image(), provided for convenience. + */ + static QImage& intensity(QImage &image, float percent); + + /** + * Modulate the image with a color channel of another image. + * + * @param image The QImage to modulate and result. + * @param modImage The QImage to use for modulation. + * @param reverse Invert the meaning of image/modImage; result is image! + * @param type The modulation Type to use. + * @param factor The modulation amplitude; with 0 no effect [-200;200]. + * @param channel The RBG channel of image2 to use for modulation. + * @return Returns the @ref image(), provided for convenience. + */ + static QImage& modulate(QImage &image, QImage &modImage, bool reverse, + ModulationType type, int factor, RGBComponent channel); + + /** + * Convert an image to grayscale. + * + * @author Daniel M. Duley (mosfet) + * @param image The @ref QImage to process. + * @param fast Set to @p true in order to use a faster but non-photographic + * quality algorithm. Appropriate for things such as toolbar icons. + * @return Returns the @ref image(), provided for convenience. + */ + static QImage& toGray(QImage &image, bool fast = false); + + /** + * Desaturate an image evenly. + * + * @param image The QImage to process. + * @param desat A value between 0 and 1 setting the degree of desaturation + * @return Returns the @ref image(), provided for convenience. + */ + static QImage& desaturate(QImage &image, float desat = 0.3); + + /** + * Fast, but low quality contrast of an image. Also see contrastHSV. + * + * @author Daniel M. Duley (mosfet) + * @param image The QImage to process. + * @param c A contrast value between -255 to 255. + * @return The @ref image(), provided for convenience. + */ + static QImage& contrast(QImage &image, int c); + + /** + * Dither an image using Floyd-Steinberg dithering for low-color + * situations. + * + * @param image The QImage to process. + * @param palette The color palette to use + * @param size The size of the palette + * @return Returns the @ref image(), provided for convenience. + */ + static QImage& dither(QImage &img, const QColor *palette, int size); + + /** + * Calculate the image for a selected image, for instance a selected icon + * on the desktop. + * @param img the QImage to select + * @param col the selected color, usually from QColorGroup::highlight(). + */ + static QImage& selectedImage( QImage &img, const QColor &col ); + + /** + * High quality, expensive HSV contrast. You can do a faster one by just + * taking a intensity threshold (ie: 128) and incrementing RGB color + * channels above it and decrementing those below it, but this gives much + * better results. + * + * @author Daniel M. Duley (mosfet) + * @param img The QImage to process. + * @param sharpen If true sharpness is increase, (spiffed). Otherwise + * it is decreased, (dulled). + */ + static void contrastHSV(QImage &img, bool sharpen=true); + + /** + * Normalizes the pixel values to span the full range of color values. + * This is a contrast enhancement technique. + * @author Daniel M. Duley (mosfet) + */ + static void normalize(QImage &img); + + /** + * Performs histogram equalization on the reference + * image. + * @author Daniel M. Duley (mosfet) + */ + static void equalize(QImage &img); + + /** + * Thresholds the reference image. You can also threshold images by using + * ThresholdDither in the various QPixmap/QImage convert methods, but this + * lets you specify a threshold value. + * + * @author Daniel M. Duley (mosfet) + * @param img The QImage to process. + * @param value The threshold value. + */ + static void threshold(QImage &img, unsigned int value=128); + + /** + * Produces a 'solarization' effect seen when exposing a photographic + * film to light during the development process. + * + * @author Daniel M. Duley (mosfet) + * @param img The QImage to process. + * @param factor The extent of the solarization (0-99.9) + */ + static void solarize(QImage &img, double factor=50.0); + + /** + * Embosses the source image. This involves highlighting the edges + * and applying various other enhancements in order to get a metal + * effect. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @return The embossed image. The original is not changed. + */ + static QImage emboss(QImage &src); + + /** + * Minimizes speckle noise in the source image using the 8 hull + * algorithm. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @return The despeckled image. The original is not changed. + */ + static QImage despeckle(QImage &src); + + /** + * Produces a neat little "charcoal" effect. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param factor The factor for detecting lines (0-99.0). + * @return The charcoal image. The original is not changed. + */ + static QImage charcoal(QImage &src, double factor=50.0); + + /** + * Rotates the image by the specified amount + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param r The rotate direction. + * @return The rotated image. The original is not changed. + */ + static QImage rotate(QImage &src, RotateDirection r); + + /** + * Scales an image using simple pixel sampling. This does not produce + * nearly as nice a result as QImage::smoothScale(), but has the + * advantage of being much faster - only a few milliseconds. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param w The new width. + * @param h The new height. + * @return The scaled image. The original is not changed. + */ + static QImage sample(QImage &src, int w, int h); + + /** + * Adds noise to an image. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param type The algorithm used to generate the noise. + * @return The image with noise added. The original is not changed. + */ + static QImage addNoise(QImage &src, NoiseType type = GaussianNoise); + + /** + * Blurs an image by convolving pixel neighborhoods. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param factor The percent weight to give to the center pixel. + * @return The blurred image. The original is not changed. + */ + static QImage blur(QImage &src, double factor=50.0); + + /** + * Detects edges in an image using pixel neighborhoods and an edge + * detection mask. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param factor The percent weight to give to the center pixel. + * @return The image with edges detected. The original is not changed. + */ + static QImage edge(QImage &src, double factor=50.0); + + /** + * Implodes an image by a specified percent. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param factor The extent of the implosion. + * @param background An RGBA value to use for the background. After the + * effect some pixels may be "empty". This value is used for those pixels. + * @return The imploded image. The original is not changed. + */ + static QImage implode(QImage &src, double factor=30.0, + unsigned int background = 0xFFFFFFFF); + /** + * Produces an oil painting effect. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param radius The radius of the pixel neighborhood used in applying the + * effect. + * @return The new image. The original is not changed. + */ + static QImage oilPaint(QImage &src, int radius=3); + + /** + * Sharpens the pixels in the image using pixel neighborhoods. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param factor The percent weight to give to the center pixel. + * @return The sharpened image. The original is not changed. + */ + static QImage sharpen(QImage &src, double factor=30.0); + + /** + * Randomly displaces pixels. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param amount The vicinity for choosing a random pixel to swap. + * @return The image with pixels displaced. The original is not changed. + */ + static QImage spread(QImage &src, unsigned int amount=3); + + /** + * Shades the image using a distance light source. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param color_shading If true do color shading, otherwise do grayscale. + * @param azimuth Determines the light source and direction. + * @param elevation Determines the light source and direction. + * @return The shaded image. The original is not changed. + */ + static QImage shade(QImage &src, bool color_shading=true, double azimuth=30.0, + double elevation=30.0); + /** + * Swirls the image by a specified amount + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param degrees The tightness of the swirl. + * @param background An RGBA value to use for the background. After the + * effect some pixels may be "empty". This value is used for those pixels. + * @return The swirled image. The original is not changed. + */ + static QImage swirl(QImage &src, double degrees=50.0, unsigned int background = + 0xFFFFFFFF); + + /** + * Modifies the pixels along a sine wave. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param amplitude The amplitude of the sine wave. + * @param wavelength The frequency of the sine wave. + * @return The new image. The original is not changed. + */ + static QImage wave(QImage &src, double amplitude=25.0, double frequency=150.0, + unsigned int background = 0xFFFFFFFF); + +private: + + /** + * Helper function to fast calc some altered (lighten, shaded) colors + * + */ + static unsigned int lHash(unsigned int c); + static unsigned int uHash(unsigned int c); + + /** + * Helper function to find the nearest color to the RBG triplet + */ + static int nearestColor( int r, int g, int b, const QColor *pal, int size ); + + static void hull(const int x_offset, const int y_offset, const int polarity, + const int width, const int height, + unsigned int *f, unsigned int *g); + static unsigned int generateNoise(unsigned int pixel, NoiseType type); + static unsigned int interpolateColor(QImage *image, double x, double y, + unsigned int background); +}; + +#endif diff --git a/libopie2/opieui/olistview.cpp b/libopie2/opieui/olistview.cpp new file mode 100644 index 0000000..2b2f09a --- a/dev/null +++ b/libopie2/opieui/olistview.cpp @@ -0,0 +1,423 @@ +/* + This file is part of the Opie Project + + =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + .=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 <qcolor.h> +#include <qheader.h> +#include <qpainter.h> +#include <qpixmap.h> + +/* OPIE */ + +#include <opie2/olistview.h> + +/*====================================================================================== + * OListView + *======================================================================================*/ + +OListView::OListView( QWidget *parent, const char *name ) + :QListView( parent, name ) +{ + //FIXME: get from global settings and calculate ==> see oglobalsettings.* + + m_alternateBackground = QColor( 238, 246, 255 ); + m_columnSeparator = QPen( QColor( 150, 160, 170 ), 0, DotLine ); + m_fullWidth = true; +} + +OListView::~OListView() +{ +} + +void OListView::setFullWidth( bool fullWidth ) +{ + m_fullWidth = m_fullWidth; + #if QT_VERSION > 290 + header()->setStretchEnabled( fullWidth, columns()-1 ); + #endif +} + +bool OListView::fullWidth() const +{ + return m_fullWidth; +} + +int OListView::addColumn( const QString& label, int width ) +{ + int result = QListView::addColumn( label, width ); + #if QT_VERSION > 290 + if (m_fullWidth) { + header()->setStretchEnabled( false, columns()-2 ); + header()->setStretchEnabled( true, columns()-1 ); + } + #endif + return result; +} + +int OListView::addColumn( const QIconSet& iconset, const QString& label, int width ) +{ + int result = QListView::addColumn( iconset, label, width ); + #if QT_VERSION > 290 + if (m_fullWidth) { + header()->setStretchEnabled( false, columns()-2 ); + header()->setStretchEnabled( true, columns()-1 ); + } + #endif + return result; +} + +void OListView::removeColumn( int index ) +{ + QListView::removeColumn(index); + #if QT_VERSION > 290 + if ( m_fullWidth && index == columns() ) + { + header()->setStretchEnabled( true, columns()-1 ); + } + #endif +} + +const QColor& OListView::alternateBackground() const +{ + return m_alternateBackground; +} + +void OListView::setAlternateBackground( const QColor &c ) +{ + m_alternateBackground = c; + repaint(); +} + +const QPen& OListView::columnSeparator() const +{ + return m_columnSeparator; +} + +void OListView::setColumnSeparator( const QPen& p ) +{ + m_columnSeparator = p; + repaint(); +} + +OListViewItem* OListView::childFactory() +{ + return new OListViewItem( this ); +} + +#ifndef QT_NO_DATASTREAM +void OListView::serializeTo( QDataStream& s ) const +{ + #warning Caution... the binary format is still under construction... + qDebug( "storing OListView..." ); + + // store number of columns and the labels + s << columns(); + for ( int i = 0; i < columns(); ++i ) + s << columnText( i ); + + // calculate the number of top-level items to serialize + int items = 0; + QListViewItem* item = firstChild(); + while ( item ) + { + item = item->nextSibling(); + items++; + } + + // store number of items and the items itself + s << items; + item = firstChild(); + for ( int i = 0; i < items; ++i ) + { + s << *static_cast<OListViewItem*>( item ); + item = item->nextSibling(); + } + + qDebug( "OListview stored." ); +} + +void OListView::serializeFrom( QDataStream& s ) +{ + #warning Caution... the binary format is still under construction... + qDebug( "loading OListView..." ); + + int cols; + s >> cols; + qDebug( "read number of columns = %d", cols ); + + while ( columns() < cols ) addColumn( QString::null ); + + for ( int i = 0; i < cols; ++i ) + { + QString coltext; + s >> coltext; + qDebug( "read text '%s' for column %d", (const char*) coltext, i ); + setColumnText( i, coltext ); + } + + int items; + s >> items; + qDebug( "read number of items = %d", items ); + + for ( int i = 0; i < items; ++i ) + { + OListViewItem* item = childFactory(); + s >> *item; + } + + qDebug( "OListView loaded." ); + +} + +QDataStream& operator<<( QDataStream& s, const OListView& lv ) +{ + lv.serializeTo( s ); +} + +QDataStream& operator>>( QDataStream& s, OListView& lv ) +{ + lv.serializeFrom( s ); +} +#endif // QT_NO_DATASTREAM + +/*====================================================================================== + * OListViewItem + *======================================================================================*/ + +OListViewItem::OListViewItem(QListView *parent) + : QListViewItem(parent) +{ + init(); +} + +OListViewItem::OListViewItem(QListViewItem *parent) + : QListViewItem(parent) +{ + init(); +} + +OListViewItem::OListViewItem(QListView *parent, QListViewItem *after) + : QListViewItem(parent, after) +{ + init(); +} + +OListViewItem::OListViewItem(QListViewItem *parent, QListViewItem *after) + : QListViewItem(parent, after) +{ + init(); +} + +OListViewItem::OListViewItem(QListView *parent, + QString label1, QString label2, QString label3, QString label4, + QString label5, QString label6, QString label7, QString label8) + : QListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8) +{ + init(); +} + +OListViewItem::OListViewItem(QListViewItem *parent, + QString label1, QString label2, QString label3, QString label4, + QString label5, QString label6, QString label7, QString label8) + : QListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8) +{ + init(); +} + +OListViewItem::OListViewItem(QListView *parent, QListViewItem *after, + QString label1, QString label2, QString label3, QString label4, + QString label5, QString label6, QString label7, QString label8) + : QListViewItem(parent, after, label1, label2, label3, label4, label5, label6, label7, label8) +{ + init(); +} + +OListViewItem::OListViewItem(QListViewItem *parent, QListViewItem *after, + QString label1, QString label2, QString label3, QString label4, + QString label5, QString label6, QString label7, QString label8) + : QListViewItem(parent, after, label1, label2, label3, label4, label5, label6, label7, label8) +{ + init(); +} + +OListViewItem::~OListViewItem() +{ +} + +void OListViewItem::init() +{ + m_known = false; +} + +const QColor &OListViewItem::backgroundColor() +{ + return isAlternate() ? static_cast<OListView*>(listView())->alternateBackground() : + listView()->viewport()->colorGroup().base(); +} + +bool OListViewItem::isAlternate() +{ + OListView *lv = static_cast<OListView*>( listView() ); + + // check if the item above is an OListViewItem + OListViewItem *above = static_cast<OListViewItem*>( itemAbove() ); + /*if (! itemAbove()->inherits( "OListViewItem" )) return false;*/ + + // check if we have a valid alternate background color + if (!(lv && lv->alternateBackground().isValid())) return false; + + m_known = above ? above->m_known : true; + if (m_known) + { + m_odd = above ? !above->m_odd : false; + } + else + { + OListViewItem *item; + bool previous = true; + if (parent()) + { + item = static_cast<OListViewItem *>(parent()); + if ( item /*&& item->inherits( "OListViewItem" )*/ ) previous = item->m_odd; + item = static_cast<OListViewItem *>(parent()->firstChild()); + /* if ( !item.inherits( "OListViewItem" ) item = 0; */ + } + else + { + item = static_cast<OListViewItem *>(lv->firstChild()); + } + + while(item) + { + item->m_odd = previous = !previous; + item->m_known = true; + item = static_cast<OListViewItem *>(item->nextSibling()); + /* if (!item.inherits( "OListViewItem" ) ) break; */ + } + } + return m_odd; +} + +void OListViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment) +{ + QColorGroup _cg = cg; + const QPixmap *pm = listView()->viewport()->backgroundPixmap(); + if (pm && !pm->isNull()) + { + _cg.setBrush( QColorGroup::Base, QBrush(backgroundColor(), *pm) ); + p->setBrushOrigin( -listView()->contentsX(), -listView()->contentsY() ); + } + else if ( isAlternate() ) + { + _cg.setColor( QColorGroup::Base, static_cast<OListView*>( listView() )->alternateBackground() ); + } + QListViewItem::paintCell( p, _cg, column, width, alignment ); + + //FIXME: Use styling here! + + const QPen& pen = static_cast<OListView*>( listView() )->columnSeparator(); + p->setPen( pen ); + p->drawLine( width-1, 0, width-1, height() ); +} + +OListViewItem* OListViewItem::childFactory() +{ + return new OListViewItem( this ); +} + +#ifndef QT_NO_DATASTREAM +void OListViewItem::serializeTo( QDataStream& s ) const +{ + #warning Caution... the binary format is still under construction... + qDebug( "storing OListViewItem..." ); + + // store item text + for ( int i = 0; i < listView()->columns(); ++i ) + { + s << text( i ); + } + + // calculate the number of children to serialize + int items = 0; + QListViewItem* item = firstChild(); + while ( item ) + { + item = item->nextSibling(); + items++; + } + + // store number of items and the items itself + s << items; + item = firstChild(); + for ( int i = 0; i < items; ++i ) + { + s << *static_cast<OListViewItem*>( item ); + item = item->nextSibling(); + } + + qDebug( "OListviewItem stored." ); +} +void OListViewItem::serializeFrom( QDataStream& s ) +{ + #warning Caution... the binary format is still under construction... + qDebug( "loading OListViewItem..." ); + + for ( int i = 0; i < listView()->columns(); ++i ) + { + QString coltext; + s >> coltext; + qDebug( "read text '%s' for column %d", (const char*) coltext, i ); + setText( i, coltext ); + } + + int items; + s >> items; + qDebug( "read number of items = %d", items ); + + for ( int i = 0; i < items; ++i ) + { + OListViewItem* item = childFactory(); + s >> (*item); + } + + qDebug( "OListViewItem loaded." ); +} + +QDataStream& operator<<( QDataStream& s, const OListViewItem& lvi ) +{ + lvi.serializeTo( s ); +} + +QDataStream& operator>>( QDataStream& s, OListViewItem& lvi ) +{ + lvi.serializeFrom( s ); +} +#endif // QT_NO_DATASTREAM diff --git a/libopie2/opieui/olistview.h b/libopie2/opieui/olistview.h new file mode 100644 index 0000000..bafc67c --- a/dev/null +++ b/libopie2/opieui/olistview.h @@ -0,0 +1,235 @@ +/* + This file is part of the Opie Project + + =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + .=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 OLISTVIEW_H +#define OLISTVIEW_H + +#include <qcolor.h> +#include <qlistview.h> +#include <qpen.h> +#include <qdatastream.h> + +class OListViewItem; + +/** + * A @ref QListView variant featuring visual and functional enhancements + * like an alternate background for odd rows, an autostretch mode + * for the width of the widget ( >= Qt 3 only ) and persistence capabilities. + * + * @author Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + * @short OListView list/tree widget. + */ + class OListView: public QListView +{ + public: + /** + * Constructor. + * + * The parameters @p parent and @p name are handled by + * @ref QListView, as usual. + */ + OListView ( QWidget *parent = 0, const char *name = 0 ); + + /** + * Destructor. + */ + virtual ~OListView(); + + /** + * Let the last column fit exactly all the available width. + */ + void setFullWidth( bool fullWidth ); + + /** + * Returns whether the last column is set to fit the available width. + */ + bool fullWidth() const; + + /** + * Reimplemented for full width support + */ + virtual int addColumn( const QString& label, int width = -1 ); + + /** + * Reimplemented for full width support + */ + virtual int addColumn( const QIconSet& iconset, const QString& label, int width = -1 ); + + /** + * Reimplemented for full width support + */ + virtual void removeColumn(int index); + + /** + * sets the alternate background background color. + * This only has an effect if the items are OListViewItems + * + * @param c the color to use for every other item. Set to an invalid + * color to disable alternate colors. + */ + void setAlternateBackground( const QColor &c ); + + /** + * sets the column separator pen. + * + * @param p the pen used to draw the column separator. + */ + void setColumnSeparator( const QPen &p ); + + /** + * @return the alternate background color + */ + const QColor& alternateBackground() const; + + /** + * @return the column separator pen + */ + const QPen& columnSeparator() const; + + /** + * create a list view item as child of this object + * @return the new object + */ + virtual OListViewItem* childFactory(); + + #ifndef QT_NO_DATASTREAM + /** + * serialize this object to a @ref QDataStream + * @param s the stream used to serialize this object. + */ + virtual void serializeTo( QDataStream& s ) const; + + /** + * serialize this object from a @ref QDataStream + * @param s the stream used to serialize this object. + */ + virtual void serializeFrom( QDataStream& s ); + #endif + + private: + QColor m_alternateBackground; + bool m_fullWidth; + QPen m_columnSeparator; +}; + +#ifndef QT_NO_DATASTREAM +/** + * \relates QListView + * Writes a listview to the stream and returns a reference to the stream. + */ +QDataStream& operator<<( QDataStream& s, const OListView& lv ); +/** + * \relates QListView + * Reads a listview from the stream and returns a reference to the stream. + */ +QDataStream& operator>>( QDataStream& s, OListView& lv ); +#endif // QT_NO_DATASTREAM + +//****************************** OListViewItem ****************************************************************** + +class OListViewItem: public QListViewItem +{ + public: + OListViewItem( QListView * parent ); + OListViewItem( QListViewItem * parent ); + OListViewItem( QListView * parent, QListViewItem * after ); + OListViewItem( QListViewItem * parent, QListViewItem * after ); + + OListViewItem( QListView * parent, + QString, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null ); + + OListViewItem( QListViewItem * parent, + QString, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null ); + + OListViewItem( QListView * parent, QListViewItem * after, + QString, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null ); + + OListViewItem( QListViewItem * parent, QListViewItem * after, + QString, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null ); + + virtual ~OListViewItem(); + + const QColor& backgroundColor(); + bool isAlternate(); + void paintCell( QPainter *p, const QColorGroup &cg, int column, int width, int alignment ); + void init(); + + /** + * create a list view item as child of this object + * @return the new object + */ + virtual OListViewItem* childFactory(); + + #ifndef QT_NO_DATASTREAM + /** + * serialize this object to or from a @ref QDataStream + * @param s the stream used to serialize this object. + */ + virtual void serializeTo( QDataStream& s ) const; + + /** + * serialize this object to or from a @ref QDataStream + * @param s the stream used to serialize this object. + */ + virtual void serializeFrom( QDataStream& s ); + #endif + + private: + bool m_known; + bool m_odd; +}; + +#ifndef QT_NO_DATASTREAM +/** + * \relates QListViewItem + * Writes a listview item and all subitems recursively to the stream + * and returns a reference to the stream. + */ +QDataStream& operator<<( QDataStream &s, const OListViewItem& lvi ); +/** + * \relates QListViewItem + * Reads a listview item from the stream and returns a reference to the stream. + */ +QDataStream& operator>>( QDataStream &s, OListViewItem& lvi ); +#endif // QT_NO_DATASTREAM + +#endif // OLISTVIEW_H diff --git a/libopie2/opieui/opieui.pro b/libopie2/opieui/opieui.pro new file mode 100644 index 0000000..dffbbde --- a/dev/null +++ b/libopie2/opieui/opieui.pro @@ -0,0 +1,46 @@ +TEMPLATE = lib +CONFIG += qt warn_on debug +DESTDIR = $(QTDIR)/lib +HEADERS = ocompletionbox.h \ + ocombobox.h \ + oeditlistbox.h \ + olineedit.h \ + olistview.h \ + oimageeffect.h \ + opixmapeffect.h \ + opopupmenu.h \ + opixmapprovider.h \ + oselector.h \ + oversatileview.h \ + oversatileviewitem.h \ + #ojanuswidget.h \ + odialog.h \ + oseparator.h + +SOURCES = ocompletionbox.cpp \ + ocombobox.cpp \ + oeditlistbox.cpp \ + olineedit.cpp \ + olistview.cpp \ + oimageeffect.cpp \ + opixmapeffect.cpp \ + opopupmenu.cpp \ + opixmapprovider.cpp \ + oselector.cpp \ + oversatileview.cpp \ + oversatileviewitem.cpp \ + #ojanuswidget.cpp \ + odialog.cpp \ + oseparator.cpp + +INTERFACES = +TARGET = opieui2 +VERSION = 1.8.1 +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += $(OPIEDIR)/include +LIBS += -lopiecore2 +MOC_DIR = moc +OBJECTS_DIR = obj + +include ( $(OPIEDIR)/include.pro ) + diff --git a/libopie2/opieui/opixmapeffect.cpp b/libopie2/opieui/opixmapeffect.cpp new file mode 100644 index 0000000..05f851d --- a/dev/null +++ b/libopie2/opieui/opixmapeffect.cpp @@ -0,0 +1,328 @@ +/* This file is part of the KDE libraries + Copyright (C) 1998, 1999 Christian Tibirna <ctibirna@total.net> + (C) 1998, 1999 Daniel M. Duley <mosfet@kde.org> + (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org> + +*/ + +// $Id$ + +/* QT */ + +#include <qimage.h> +#include <qpainter.h> + +/* OPIE */ + +#include <opie2/opixmapeffect.h> +#include <opie2/oimageeffect.h> + +//====================================================================== +// +// Gradient effects +// +//====================================================================== + + +OPixmap& OPixmapEffect::gradient(OPixmap &pixmap, const QColor &ca, + const QColor &cb, GradientType eff, int ncols) +{ + if(pixmap.depth() > 8 && + (eff == VerticalGradient || eff == HorizontalGradient)) { + + int rDiff, gDiff, bDiff; + int rca, gca, bca /*, rcb, gcb, bcb*/; + + register int x, y; + + rDiff = (/*rcb = */ cb.red()) - (rca = ca.red()); + gDiff = (/*gcb = */ cb.green()) - (gca = ca.green()); + bDiff = (/*bcb = */ cb.blue()) - (bca = ca.blue()); + + register int rl = rca << 16; + register int gl = gca << 16; + register int bl = bca << 16; + + int rcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * rDiff; + int gcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * gDiff; + int bcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * bDiff; + + QPainter p(&pixmap); + + // these for-loops could be merged, but the if's in the inner loop + // would make it slow + switch(eff) { + case VerticalGradient: + for ( y = 0; y < pixmap.height(); y++ ) { + rl += rcdelta; + gl += gcdelta; + bl += bcdelta; + + p.setPen(QColor(rl>>16, gl>>16, bl>>16)); + p.drawLine(0, y, pixmap.width()-1, y); + } + break; + case HorizontalGradient: + for( x = 0; x < pixmap.width(); x++) { + rl += rcdelta; + gl += gcdelta; + bl += bcdelta; + + p.setPen(QColor(rl>>16, gl>>16, bl>>16)); + p.drawLine(x, 0, x, pixmap.height()-1); + } + break; + default: + ; + } + } + else { + QImage image = OImageEffect::gradient(pixmap.size(), ca, cb, + (OImageEffect::GradientType) eff, ncols); + pixmap.convertFromImage(image); + } + + return pixmap; +} + + +// ----------------------------------------------------------------------------- + +OPixmap& OPixmapEffect::unbalancedGradient(OPixmap &pixmap, const QColor &ca, + const QColor &cb, GradientType eff, int xfactor, int yfactor, + int ncols) +{ + QImage image = OImageEffect::unbalancedGradient(pixmap.size(), ca, cb, + (OImageEffect::GradientType) eff, + xfactor, yfactor, ncols); + pixmap.convertFromImage(image); + + return pixmap; +} + + +//====================================================================== +// +// Intensity effects +// +//====================================================================== + + + +OPixmap& OPixmapEffect::intensity(OPixmap &pixmap, float percent) +{ + QImage image = pixmap.convertToImage(); + OImageEffect::intensity(image, percent); + pixmap.convertFromImage(image); + + return pixmap; +} + + +// ----------------------------------------------------------------------------- + +OPixmap& OPixmapEffect::channelIntensity(OPixmap &pixmap, float percent, + RGBComponent channel) +{ + QImage image = pixmap.convertToImage(); + OImageEffect::channelIntensity(image, percent, + (OImageEffect::RGBComponent) channel); + pixmap.convertFromImage(image); + + return pixmap; +} + + +//====================================================================== +// +// Blend effects +// +//====================================================================== + + +OPixmap& OPixmapEffect::blend(OPixmap &pixmap, float initial_intensity, + const QColor &bgnd, GradientType eff, + bool anti_dir, int ncols) +{ + + QImage image = pixmap.convertToImage(); + if (image.depth() <=8) + image = image.convertDepth(32); //Sloww.. + + OImageEffect::blend(image, initial_intensity, bgnd, + (OImageEffect::GradientType) eff, anti_dir); + + unsigned int tmp; + + if(pixmap.depth() <= 8 ) { + if ( ncols < 2 || ncols > 256 ) + ncols = 3; + QColor *dPal = new QColor[ncols]; + for (int i=0; i<ncols; i++) { + tmp = 0 + 255 * i / ( ncols - 1 ); + dPal[i].setRgb ( tmp, tmp, tmp ); + } + OImageEffect::dither(image, dPal, ncols); + pixmap.convertFromImage(image); + delete [] dPal; + } + else + pixmap.convertFromImage(image); + + return pixmap; +} + + +//====================================================================== +// +// Hash effects +// +//====================================================================== + +OPixmap& OPixmapEffect::hash(OPixmap &pixmap, Lighting lite, + unsigned int spacing, int ncols) +{ + QImage image = pixmap.convertToImage(); + OImageEffect::hash(image, (OImageEffect::Lighting) lite, spacing); + + unsigned int tmp; + + if(pixmap.depth() <= 8 ) { + if ( ncols < 2 || ncols > 256 ) + ncols = 3; + QColor *dPal = new QColor[ncols]; + for (int i=0; i<ncols; i++) { + tmp = 0 + 255 * i / ( ncols - 1 ); + dPal[i].setRgb ( tmp, tmp, tmp ); + } + OImageEffect::dither(image, dPal, ncols); + pixmap.convertFromImage(image); + delete [] dPal; + } + else + pixmap.convertFromImage(image); + + return pixmap; +} + + +//====================================================================== +// +// Pattern effects +// +//====================================================================== + +#if 0 +void OPixmapEffect::pattern(OPixmap &pixmap, const QColor &ca, + const QColor &cb, unsigned pat[8]) +{ + QImage img = pattern(pixmap.size(), ca, cb, pat); + pixmap.convertFromImage(img); +} +#endif + +// ----------------------------------------------------------------------------- + +OPixmap OPixmapEffect::pattern(const OPixmap& pmtile, QSize size, + const QColor &ca, const QColor &cb, int ncols) +{ + if (pmtile.depth() > 8) + ncols = 0; + + QImage img = pmtile.convertToImage(); + OImageEffect::flatten(img, ca, cb, ncols); + OPixmap pixmap; + pixmap.convertFromImage(img); + + return OPixmapEffect::createTiled(pixmap, size); +} + + +// ----------------------------------------------------------------------------- + +OPixmap OPixmapEffect::createTiled(const OPixmap& pixmap, QSize size) +{ + OPixmap pix; + + QPainter p(&pix); + p.drawTiledPixmap(0, 0, size.width(), size.height(), pixmap); + + return pix; +} + + +//====================================================================== +// +// Fade effects +// +//====================================================================== + +OPixmap& OPixmapEffect::fade(OPixmap &pixmap, double val, const QColor &color) +{ + QImage img = pixmap.convertToImage(); + OImageEffect::fade(img, val, color); + pixmap.convertFromImage(img); + + return pixmap; +} + + +// ----------------------------------------------------------------------------- +OPixmap& OPixmapEffect::toGray(OPixmap &pixmap, bool fast) +{ + QImage img = pixmap.convertToImage(); + OImageEffect::toGray(img, fast); + pixmap.convertFromImage(img); + + return pixmap; +} + +// ----------------------------------------------------------------------------- +OPixmap& OPixmapEffect::desaturate(OPixmap &pixmap, float desat) +{ + QImage img = pixmap.convertToImage(); + OImageEffect::desaturate(img, desat); + pixmap.convertFromImage(img); + + return pixmap; +} +// ----------------------------------------------------------------------------- +OPixmap& OPixmapEffect::contrast(OPixmap &pixmap, int c) +{ + QImage img = pixmap.convertToImage(); + OImageEffect::contrast(img, c); + pixmap.convertFromImage(img); + + return pixmap; +} + +//====================================================================== +// +// Dither effects +// +//====================================================================== + +// ----------------------------------------------------------------------------- +OPixmap& OPixmapEffect::dither(OPixmap &pixmap, const QColor *palette, int size) +{ + QImage img = pixmap.convertToImage(); + OImageEffect::dither(img, palette, size); + pixmap.convertFromImage(img); + + return pixmap; +} + +//====================================================================== +// +// Other effects +// +//====================================================================== + +OPixmap OPixmapEffect::selectedPixmap( const OPixmap &pix, const QColor &col ) +{ + QImage img = pix.convertToImage(); + OImageEffect::selectedImage(img, col); + OPixmap outPix; + outPix.convertFromImage(img); + return outPix; +} diff --git a/libopie2/opieui/opixmapeffect.h b/libopie2/opieui/opixmapeffect.h new file mode 100644 index 0000000..283fe2d --- a/dev/null +++ b/libopie2/opieui/opixmapeffect.h @@ -0,0 +1,215 @@ +/* This file is part of the KDE libraries + Copyright (C) 1998, 1999 Christian Tibirna <ctibirna@total.net> + (C) 1998, 1999 Daniel M. Duley <mosfet@kde.org> + (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org> + +*/ + +// $Id$ + +#ifndef __OPIXMAP_EFFECT_H +#define __OPIXMAP_EFFECT_H + + +#include <qsize.h> +typedef QPixmap OPixmap; +class QColor; + +/** + * This class includes various pixmap-based graphical effects. + * + * Everything is + * static, so there is no need to create an instance of this class. You can + * just call the static methods. They are encapsulated here merely to provide + * a common namespace. + */ +class OPixmapEffect +{ +public: + enum GradientType { VerticalGradient, HorizontalGradient, + DiagonalGradient, CrossDiagonalGradient, + PyramidGradient, RectangleGradient, + PipeCrossGradient, EllipticGradient }; + enum RGBComponent { Red, Green, Blue }; + + enum Lighting {NorthLite, NWLite, WestLite, SWLite, + SouthLite, SELite, EastLite, NELite}; + + /** + * Creates a gradient from color a to color b of the specified type. + * + * @param pixmap The pixmap to process. + * @param ca Color a. + * @param cb Color b. + * @param type The type of gradient. + * @param ncols The number of colors to use when not running on a + * truecolor display. The gradient will be dithered to this number of + * colors. Pass 0 to prevent dithering. + * @return Returns the generated pixmap, for convenience. + */ + static OPixmap& gradient(OPixmap& pixmap, const QColor &ca, const QColor &cb, + GradientType type, int ncols=3); + + /** + * Creates an unbalanced gradient. + * + * An unbalanced gradient is a gradient where the transition from + * color a to color b is not linear, but in this case, exponential. + * + * @param pixmap The pixmap that should be written. + * @param ca Color a. + * @param cb Color b. + * @param type The type of gradient. + * @param xfactor The x decay length. Use a value between -200 and 200. + * @param yfactor The y decay length. + * @param ncols The number of colors. See #gradient. + * @return The generated pixmap, for convencience. + */ + static OPixmap& unbalancedGradient(OPixmap& pixmap, const QColor &ca, + const QColor &cb, GradientType type, int xfactor = 100, + int yfactor = 100, int ncols=3); + + /** + * Creates a pixmap of a given size with the given pixmap. + * + * if the + * given size is bigger than the size of the pixmap, the pixmap is + * tiled. + * + * @param pixmap This is the source pixmap + * @param size The size the new pixmap should have. + * @return The generated, tiled pixmap. + */ + static OPixmap createTiled(const OPixmap& pixmap, QSize size); + + /** + * Either brightens or dims a pixmap by a specified ratio. + * + * @param pixmap The pixmap to process. + * @param ratio The ratio to use. Use negative value to dim. + * @return Returns The @ref pixmap(), provided for convenience. + */ + static OPixmap& intensity(OPixmap& pixmap, float ratio); + + /** + * Modifies the intensity of a pixmap's RGB channel component. + * + * @param pixmap The pixmap to process. + * @param ratio value. Use negative value to dim. + * @param channel Which channel(s) should be modified + * @return Returns the @ref pixmap(), provided for convenience. + */ + static OPixmap& channelIntensity(OPixmap& pixmap, float ratio, + RGBComponent channel); + + /** + * Blends the provided pixmap into a background of the indicated color. + * + * @param pixmap The pixmap to process. + * @param initial_intensity this parameter takes values from -1 to 1: + * @li If positive, it tells how much to fade the image in its + * less affected spot. + * @li If negative, it tells roughly indicates how much of the image + * remains unaffected + * @param bgnd Indicates the color of the background to blend in. + * @param eff Lets you choose what kind of blending you like. + * @param anti_dir Blend in the opposite direction (makes no much sense + * with concentric blending effects). + * @return Returns the @ref pixmap(), provided for convenience. + */ + static OPixmap& blend(OPixmap& pixmap, float initial_intensity, + const QColor &bgnd, GradientType eff, + bool anti_dir=false, int ncols=3); + + /** + * Builds a hash on any given pixmap. + * + * @param pixmap The pixmap to process. + * @param lite The hash faces the indicated lighting (cardinal poles) + * @param spacing How many unmodified pixels inbetween hashes. + * @return Returns The @ref pixmap(), provided for convenience. + */ + static OPixmap& hash(OPixmap& pixmap, Lighting lite=NorthLite, + unsigned int spacing=0, int ncols=3); + + /** + * Creates a pattern from a pixmap. + * + * The given pixmap is "flattened" + * between color a to color b. + * + * @param pixmap The pixmap to process. + * @param ca Color a. + * @param cb Color b. + * @param ncols The number of colors to use. The image will be + * dithered to this depth. Pass zero to prevent dithering. + * @return The @ref pixmap(), provided for convenience. + */ + static OPixmap pattern(const OPixmap& pixmap, QSize size, + const QColor &ca, const QColor &cb, int ncols=8); + + /** + * Recolors a pixmap. + * + * The most dark color will become color a, + * the most bright one color b, and in between. + * + * @param pixmap The pixmap to process. + * @param ca Color a. + * @param cb Color b. + * @param ncols The number of colors to use. Pass zero to prevent + * dithering. + * @return Returns the @ref pixmap(), provided for convenience. + */ + static OPixmap& fade(OPixmap& pixmap, double val, const QColor &color); + + /** + * Converts a pixmap to grayscale. + * + * @param pixmap The pixmap to process. + * @param fast Set to @p true in order to use a faster but non-photographic + * quality algorithm. Appropriate for things such as toolbar icons. + * @return Returns the @ref pixmap(), provided for convenience. + */ + static OPixmap& toGray(OPixmap& pixmap, bool fast=false); + + /** + * Desaturates a pixmap. + * + * @param pixmap The pixmap to process. + * @param desat A value between 0 and 1 setting the degree of desaturation + * @return Returns The @ref pixmap(), provided for convenience. + */ + static OPixmap& desaturate(OPixmap& pixmap, float desat = 0.3); + + /** + * Modifies the contrast of a pixmap. + * + * @param pixmap The pixmap to process. + * @param c A contrast value between -255 and 255. + * @return Returns the @ref pixmap(), provided for convenience. + */ + static OPixmap& contrast(OPixmap& pixmap, int c); + + /** + * Dithers a pixmap using Floyd-Steinberg dithering for low-color + * situations. + * + * @param pixmap The pixmap to process. + * @param palette The color palette to use. + * @param size The size of the palette. + * @return Returns the @ref pixmap(), provided for convenience. + */ + static OPixmap& dither(OPixmap &pixmap, const QColor *palette, int size); + + /** + * Calculate a 'selected' pixmap, for instance a selected icon + * on the desktop. + * @param pixmap the pixmap to select + * @param col the selected color, usually from QColorGroup::highlight(). + */ + static OPixmap selectedPixmap( const OPixmap &pixmap, const QColor &col ); +}; + + +#endif diff --git a/libopie2/opieui/opixmapprovider.cpp b/libopie2/opieui/opixmapprovider.cpp new file mode 100644 index 0000000..7be9e3b --- a/dev/null +++ b/libopie2/opieui/opixmapprovider.cpp @@ -0,0 +1,27 @@ +/* This file is part of the KDE libraries + + Copyright (c) 2000 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 (LGPL) 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. +*/ + +#include <opie2/opixmapprovider.h> + +OPixmapProvider::~OPixmapProvider() {} + +void OPixmapProvider::virtual_hook( int , void* ) +{ /*BASE::virtual_hook( id, data );*/ } + diff --git a/libopie2/opieui/opixmapprovider.h b/libopie2/opieui/opixmapprovider.h new file mode 100644 index 0000000..5b76647 --- a/dev/null +++ b/libopie2/opieui/opixmapprovider.h @@ -0,0 +1,54 @@ +/* This file is part of the KDE libraries + + Copyright (c) 2000 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 (LGPL) 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 OPIXMAPPROVIDER_H +#define OPIXMAPPROVIDER_H + +#include <qpixmap.h> + +/** + * A tiny abstract class with just one method: + * @ref pixmapFor() + * + * It will be called whenever an icon is searched for @p text. + * + * Used e.g. by @ref KHistoryCombo + * + * @author Carsten Pfeiffer <pfeiffer@kde.org> + * @short an abstract interface for looking up icons + */ +class OPixmapProvider +{ +public: + virtual ~OPixmapProvider(); + /** + * You may subclass this and return a pixmap of size @p size for @p text. + * @param text the text that is associated with the pixmap + * @param size the size of the icon in pixels, 0 for defaylt size. + * See @ref KIcon::StdSize. + * @return the pixmap for the arguments, or null if there is none + */ + virtual QPixmap pixmapFor( const QString& text, int size = 0 ) = 0; +protected: + virtual void virtual_hook( int id, void* data ); +}; + + +#endif // OPIXMAPPROVIDER_H diff --git a/libopie2/opieui/opopupmenu.cpp b/libopie2/opieui/opopupmenu.cpp new file mode 100644 index 0000000..ac73188 --- a/dev/null +++ b/libopie2/opieui/opopupmenu.cpp @@ -0,0 +1,604 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 Daniel M. Duley <mosfet@kde.org> + Copyright (C) 2002 Hamish Rodda <meddie@yoyo.its.monash.edu.au> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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 <qapplication.h> +#include <qcursor.h> +#include <qpainter.h> +#include <qdrawutil.h> +#include <qtimer.h> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qregexp.h> +#include <qstyle.h> + +/* OPIE */ + +#include <opie2/opopupmenu.h> +#include <opie2/oconfig.h> + +OPopupTitle::OPopupTitle(QWidget *parent, const char *name) + : QWidget(parent, name) +{ + setMinimumSize(16, fontMetrics().height()+8); +} + +OPopupTitle::OPopupTitle(OPixmapEffect::GradientType /* gradient */, + const QColor &/* color */, const QColor &/* textColor */, + QWidget *parent, const char *name) + : QWidget(parent, name) +{ + setMinimumSize(16, fontMetrics().height()+8); +} + +OPopupTitle::OPopupTitle(const OPixmap & /* background */, const QColor &/* color */, + const QColor &/* textColor */, QWidget *parent, + const char *name) + : QWidget(parent, name) +{ + setMinimumSize(16, fontMetrics().height()+8); +} + +void OPopupTitle::setTitle(const QString &text, const QPixmap *icon) +{ + titleStr = text; + if (icon) + miniicon = *icon; + else + miniicon.resize(0, 0); + + int w = miniicon.width()+fontMetrics().width(titleStr); + int h = QMAX( fontMetrics().height(), miniicon.height() ); + setMinimumSize( w+16, h+8 ); +} + +void OPopupTitle::setText( const QString &text ) +{ + titleStr = text; + int w = miniicon.width()+fontMetrics().width(titleStr); + int h = QMAX( fontMetrics().height(), miniicon.height() ); + setMinimumSize( w+16, h+8 ); +} + +void OPopupTitle::setIcon( const QPixmap &pix ) +{ + miniicon = pix; + int w = miniicon.width()+fontMetrics().width(titleStr); + int h = QMAX( fontMetrics().height(), miniicon.height() ); + setMinimumSize( w+16, h+8 ); +} + +void OPopupTitle::paintEvent(QPaintEvent *) +{ + QRect r(rect()); + QPainter p(this); + #if QT_VERSION > 290 + qApp->style().drawPrimitive(QStyle::PE_HeaderSection, &p, r, palette().active()); + #else + #warning OPopupMenu is not fully functional on Qt2 + #endif + + if (!miniicon.isNull()) + p.drawPixmap(4, (r.height()-miniicon.height())/2, miniicon); + + if (!titleStr.isNull()) + { + p.setPen(palette().active().text()); + QFont f = p.font(); + f.setBold(true); + p.setFont(f); + if(!miniicon.isNull()) + { + p.drawText(miniicon.width()+8, 0, width()-(miniicon.width()+8), + height(), AlignLeft | AlignVCenter | SingleLine, + titleStr); + } + else + { + p.drawText(0, 0, width(), height(), + AlignCenter | SingleLine, titleStr); + } + } + + p.setPen(palette().active().highlight()); + p.drawLine(0, 0, r.right(), 0); +} + +QSize OPopupTitle::sizeHint() const +{ + return(minimumSize()); +} + +class OPopupMenu::OPopupMenuPrivate +{ +public: + OPopupMenuPrivate () + : noMatches(false) + , shortcuts(false) + , autoExec(false) + , lastHitIndex(-1) + , m_ctxMenu(0) + {} + + ~OPopupMenuPrivate () + { + delete m_ctxMenu; + } + + QString m_lastTitle; + + // variables for keyboard navigation + QTimer clearTimer; + + bool noMatches : 1; + bool shortcuts : 1; + bool autoExec : 1; + + QString keySeq; + QString originalText; + + int lastHitIndex; + + // support for RMB menus on menus + QPopupMenu* m_ctxMenu; + static bool s_continueCtxMenuShow; + static int s_highlightedItem; + static OPopupMenu* s_contextedMenu; +}; + +int OPopupMenu::OPopupMenuPrivate::s_highlightedItem(-1); +OPopupMenu* OPopupMenu::OPopupMenuPrivate::s_contextedMenu(0); +bool OPopupMenu::OPopupMenuPrivate::s_continueCtxMenuShow(true); + +OPopupMenu::OPopupMenu(QWidget *parent, const char *name) + : QPopupMenu(parent, name) +{ + d = new OPopupMenuPrivate; + resetKeyboardVars(); + connect(&(d->clearTimer), SIGNAL(timeout()), SLOT(resetKeyboardVars())); +} + +OPopupMenu::~OPopupMenu() +{ + if (OPopupMenuPrivate::s_contextedMenu == this) + { + OPopupMenuPrivate::s_contextedMenu = 0; + OPopupMenuPrivate::s_highlightedItem = -1; + } + + delete d; +} + +int OPopupMenu::insertTitle(const QString &text, int id, int index) +{ + OPopupTitle *titleItem = new OPopupTitle(); + titleItem->setTitle(text); + int ret = insertItem(titleItem, id, index); + setItemEnabled(id, false); + return ret; +} + +int OPopupMenu::insertTitle(const QPixmap &icon, const QString &text, int id, + int index) +{ + OPopupTitle *titleItem = new OPopupTitle(); + titleItem->setTitle(text, &icon); + int ret = insertItem(titleItem, id, index); + setItemEnabled(id, false); + return ret; +} + +void OPopupMenu::changeTitle(int id, const QString &text) +{ + QMenuItem *item = findItem(id); + if(item){ + if(item->widget()) + ((OPopupTitle *)item->widget())->setTitle(text); +#ifndef NDEBUG + else + qWarning( "KPopupMenu: changeTitle() called with non-title id %d", id ); +#endif + } +#ifndef NDEBUG + else + qWarning( "KPopupMenu: changeTitle() called with invalid id %d", id ); +#endif +} + +void OPopupMenu::changeTitle(int id, const QPixmap &icon, const QString &text) +{ + QMenuItem *item = findItem(id); + if(item){ + if(item->widget()) + ((OPopupTitle *)item->widget())->setTitle(text, &icon); +#ifndef NDEBUG + else + qWarning( "KPopupMenu: changeTitle() called with non-title id %d", id ); +#endif + } +#ifndef NDEBUG + else + qWarning( "KPopupMenu: changeTitle() called with invalid id %d", id ); +#endif +} + +QString OPopupMenu::title(int id) const +{ + if(id == -1) // obsolete + return(d->m_lastTitle); + QMenuItem *item = findItem(id); + if(item){ + if(item->widget()) + return(((OPopupTitle *)item->widget())->title()); + else + qWarning("OPopupMenu: title() called with non-title id %d.", id); + } + else + qWarning("OPopupMenu: title() called with invalid id %d.", id); + return(QString::null); +} + +QPixmap OPopupMenu::titlePixmap(int id) const +{ + QMenuItem *item = findItem(id); + if(item){ + if(item->widget()) + return(((OPopupTitle *)item->widget())->icon()); + else + qWarning("KPopupMenu: titlePixmap() called with non-title id %d.", id); + } + else + qWarning("KPopupMenu: titlePixmap() called with invalid id %d.", id); + QPixmap tmp; + return(tmp); +} + +/** + * This is re-implemented for keyboard navigation. + */ +void OPopupMenu::closeEvent(QCloseEvent*e) +{ + if (d->shortcuts) + resetKeyboardVars(); + QPopupMenu::closeEvent(e); +} + +void OPopupMenu::keyPressEvent(QKeyEvent* e) +{ + if (!d->shortcuts) { + // continue event processing by Qpopup + //e->ignore(); + QPopupMenu::keyPressEvent(e); + return; + } + + int i = 0; + bool firstpass = true; + QString keyString = e->text(); + + // check for common commands dealt with by QPopup + int key = e->key(); + if (key == Key_Escape || key == Key_Return || key == Key_Enter + || key == Key_Up || key == Key_Down || key == Key_Left + || key == Key_Right || key == Key_F1) { + + resetKeyboardVars(); + // continue event processing by Qpopup + //e->ignore(); + QPopupMenu::keyPressEvent(e); + return; + } + + // check to see if the user wants to remove a key from the sequence (backspace) + // or clear the sequence (delete) + if (!d->keySeq.isNull()) { + + if (key == Key_Backspace) { + + if (d->keySeq.length() == 1) { + resetKeyboardVars(); + return; + } + + // keep the last sequence in keyString + keyString = d->keySeq.left(d->keySeq.length() - 1); + + // allow sequence matching to be tried again + resetKeyboardVars(); + + } else if (key == Key_Delete) { + resetKeyboardVars(); + + // clear active item + setActiveItem(0); + return; + + } else if (d->noMatches) { + // clear if there are no matches + resetKeyboardVars(); + + // clear active item + setActiveItem(0); + + } else { + // the key sequence is not a null string + // therefore the lastHitIndex is valid + i = d->lastHitIndex; + } + } else if (key == Key_Backspace && parentMenu) { + // backspace with no chars in the buffer... go back a menu. + hide(); + resetKeyboardVars(); + return; + } + + d->keySeq += keyString; + int seqLen = d->keySeq.length(); + + for (; i < (int)count(); i++) { + // compare typed text with text of this entry + int j = idAt(i); + + // don't search disabled entries + if (!isItemEnabled(j)) + continue; + + QString thisText; + + // retrieve the right text + // (the last selected item one may have additional ampersands) + if (i == d->lastHitIndex) + thisText = d->originalText; + else + thisText = text(j); + + // if there is an accelerator present, remove it + if ((int)accel(j) != 0) + thisText = thisText.replace(QRegExp("&"), ""); + + // chop text to the search length + thisText = thisText.left(seqLen); + + // do the search + if (thisText.find(d->keySeq, 0, false) == 0) { + + if (firstpass) { + // match + setActiveItem(i); + + // check to see if we're underlining a different item + if (d->lastHitIndex != i) + // yes; revert the underlining + changeItem(idAt(d->lastHitIndex), d->originalText); + + // set the original text if it's a different item + if (d->lastHitIndex != i || d->lastHitIndex == -1) + d->originalText = text(j); + + // underline the currently selected item + changeItem(j, underlineText(d->originalText, d->keySeq.length())); + + // remeber what's going on + d->lastHitIndex = i; + + // start/restart the clear timer + d->clearTimer.start(5000, true); + + // go around for another try, to see if we can execute + firstpass = false; + } else { + // don't allow execution + return; + } + } + + // fall through to allow execution + } + + if (!firstpass) { + if (d->autoExec) { + // activate anything + activateItemAt(d->lastHitIndex); + resetKeyboardVars(); + + } else if (findItem(idAt(d->lastHitIndex)) && + findItem(idAt(d->lastHitIndex))->popup()) { + // only activate sub-menus + activateItemAt(d->lastHitIndex); + resetKeyboardVars(); + } + + return; + } + + // no matches whatsoever, clean up + resetKeyboardVars(true); + //e->ignore(); + QPopupMenu::keyPressEvent(e); +} + +QString OPopupMenu::underlineText(const QString& text, uint length) +{ + QString ret = text; + for (uint i = 0; i < length; i++) { + if (ret[2*i] != '&') + ret.insert(2*i, "&"); + } + return ret; +} + +void OPopupMenu::resetKeyboardVars(bool noMatches /* = false */) +{ + // Clean up keyboard variables + if (d->lastHitIndex != -1) { + changeItem(idAt(d->lastHitIndex), d->originalText); + d->lastHitIndex = -1; + } + + if (!noMatches) { + d->keySeq = QString::null; + } + + d->noMatches = noMatches; +} + +void OPopupMenu::setKeyboardShortcutsEnabled(bool enable) +{ + d->shortcuts = enable; +} + +void OPopupMenu::setKeyboardShortcutsExecute(bool enable) +{ + d->autoExec = enable; +} +/** + * End keyboard navigation. + */ + +/** + * RMB menus on menus + */ +QPopupMenu* OPopupMenu::contextMenu() +{ + if (!d->m_ctxMenu) + { + d->m_ctxMenu = new QPopupMenu(this); + installEventFilter(this); + connect(d->m_ctxMenu, SIGNAL(aboutToHide()), this, SLOT(ctxMenuHiding())); + } + + return d->m_ctxMenu; +} + +void OPopupMenu::cancelContextMenuShow() +{ + OPopupMenuPrivate::s_continueCtxMenuShow = false; +} + +int OPopupMenu::contextMenuFocusItem() +{ + return OPopupMenuPrivate::s_highlightedItem; +} + +OPopupMenu* OPopupMenu::contextMenuFocus() +{ + return OPopupMenuPrivate::s_contextedMenu; +} + +void OPopupMenu::itemHighlighted(int /* whichItem */) +{ + if (!d->m_ctxMenu || !d->m_ctxMenu->isVisible()) + { + return; + } + + d->m_ctxMenu->hide(); + showCtxMenu(mapFromGlobal(QCursor::pos())); +} + +void OPopupMenu::showCtxMenu(QPoint pos) +{ + OPopupMenuPrivate::s_highlightedItem = idAt(pos); + + if (OPopupMenuPrivate::s_highlightedItem == -1) + { + OPopupMenuPrivate::s_contextedMenu = 0; + return; + } + + emit aboutToShowContextMenu(this, OPopupMenuPrivate::s_highlightedItem, d->m_ctxMenu); + + if (!OPopupMenuPrivate::s_continueCtxMenuShow) + { + OPopupMenuPrivate::s_continueCtxMenuShow = true; + return; + } + + OPopupMenuPrivate::s_contextedMenu = this; + d->m_ctxMenu->popup(this->mapToGlobal(pos)); + connect(this, SIGNAL(highlighted(int)), this, SLOT(itemHighlighted(int))); +} + +void OPopupMenu::ctxMenuHiding() +{ + disconnect(this, SIGNAL(highlighted(int)), this, SLOT(itemHighlighted(int))); + OPopupMenuPrivate::s_continueCtxMenuShow = true; +} + +bool OPopupMenu::eventFilter(QObject* obj, QEvent* event) +{ + if (d->m_ctxMenu && obj == this) + { + if (event->type() == QEvent::MouseButtonRelease) + { + if (d->m_ctxMenu->isVisible()) + { + return true; + } + } + #if QT_VERSION > 290 + else if (event->type() == QEvent::ContextMenu) + #else + else if ( (event->type() == QEvent::MouseButtonPress) && + ( (QMouseEvent*) event )->button() == QMouseEvent::RightButton ) + #endif + { + showCtxMenu(mapFromGlobal(QCursor::pos())); + return true; + } + } + + return QWidget::eventFilter(obj, event); +} + +void OPopupMenu::hideEvent(QHideEvent*) +{ + if (d->m_ctxMenu) + { + d->m_ctxMenu->hide(); + } +} +/** + * end of RMB menus on menus support + */ + +// Obsolete +OPopupMenu::OPopupMenu(const QString& title, QWidget *parent, const char *name) + : QPopupMenu(parent, name) +{ + d = new OPopupMenuPrivate; + setTitle(title); +} + +// Obsolete +void OPopupMenu::setTitle(const QString &title) +{ + OPopupTitle *titleItem = new OPopupTitle(); + titleItem->setTitle(title); + insertItem(titleItem); + d->m_lastTitle = title; +} + +void OPopupTitle::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +void OPopupMenu::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + diff --git a/libopie2/opieui/opopupmenu.h b/libopie2/opieui/opopupmenu.h new file mode 100644 index 0000000..94f05f4 --- a/dev/null +++ b/libopie2/opieui/opopupmenu.h @@ -0,0 +1,256 @@ +/* This file is part of the ODE libraries + Copyright (C) 2000 Daniel M. Duley <mosfet@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 version 2 as published by the Free Software Foundation. + + 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 _OPOPUP_H +#define _OPOPUP_H + +#define INCLUDE_MENUITEM_DEF + +/* QT */ + +#include <qpopupmenu.h> + +/* OPIE */ + +#include <opie2/opixmapeffect.h> + +/** + * Title widget for use in @ref OPopupMenu. + * + * You usually don't have to create this manually since + * @ref OPopupMenu::insertTitle will do it for you, but it is allowed if + * you wish to customize it's look. + * + * @author Daniel M. Duley <mosfet@kde.org> + * @short OPopupMenu title widget. + */ +class OPopupTitle : public QWidget +{ + Q_OBJECT + +public: + /** + * Constructs a title widget with the user specified gradient, pixmap, + * and colors. + */ + OPopupTitle(QWidget *parent=0, const char *name=0); + /** + * @deprecated + * Constructs a title widget with the specified gradient and colors. + */ + OPopupTitle(OPixmapEffect::GradientType gradient, const QColor &color, + const QColor &textColor, QWidget *parent=0, + const char *name=0); + /** + * @deprecated + * Constructs a title widget with the specified pixmap and colors. + */ + OPopupTitle(const OPixmap &background, const QColor &color, + const QColor &textColor, QWidget *parent=0, + const char *name=0); + /** + * Sets the title string and optional icon for the title widget. + * + * You will want to call this before inserting into a menu. + */ + void setTitle(const QString &text, const QPixmap *icon=NULL); + /** + * Returns the current title. + */ + QString title() const { return(titleStr); } + /** + * Returns the current icon. + */ + QPixmap icon() const { return(miniicon); } + + QSize sizeHint() const; + +public slots: + /// @since 3.1 + void setText( const QString &text ); + /// @since 3.1 + void setIcon( const QPixmap &pix ); + +protected: + void paintEvent(QPaintEvent *ev); + + QString titleStr; + QPixmap miniicon; + + // Remove in KDE4 + OPixmapEffect::GradientType grType; + QPixmap fill; + QColor fgColor, bgColor, grHigh, grLow; + bool useGradient; + +protected: + virtual void virtual_hook( int id, void* data ); +private: + class OPopupTitlePrivate; + OPopupTitlePrivate *d; +}; + +/** + * OPopupMenu is a class for menus with standard title items and keyboard + * accessibility for popups with many options and/or varying options. It acts + * identically to QPopupMenu, with the addition of insertTitle(), + * changeTitle(), setKeyboardShortcutsEnabled() and + * setKeyboardShortcutsExecute() methods. + * + * The titles support a text string, an icon, plus user defined gradients, + * colors, and background pixmaps. + * + * The keyboard search algorithm is incremental with additional underlining + * for user feedback. + * + * @short A menu with title items. + * @author Daniel M. Duley <mosfet@kde.org> + * @author Hamish Rodda <meddie@yoyo.its.monash.edu.au> + */ +class OPopupMenu : public QPopupMenu { + Q_OBJECT +public: + /** + * Constructs a OPopupMenu. + */ + OPopupMenu(QWidget *parent=0, const char *name=0); + + /** + * Destructs the object + */ + ~OPopupMenu(); + + /** + * Inserts a title item with no icon. + */ + int insertTitle(const QString &text, int id=-1, int index=-1); + /** + * Inserts a title item with the given icon and title. + */ + int insertTitle(const QPixmap &icon, const QString &text, int id=-1, + int index=-1); + /** + * Changes the title of the item at the specified id. If a icon was + * previously set it is cleared. + */ + void changeTitle(int id, const QString &text); + /** + * Changes the title and icon of the title item at the specified id. + */ + void changeTitle(int id, const QPixmap &icon, const QString &text); + /** + * Returns the title of the title item at the specified id. The default + * id of -1 is for backwards compatibility only, you should always specify + * the id. + */ + QString title(int id=-1) const; + /** + * Returns the icon of the title item at the specified id. + */ + QPixmap titlePixmap(int id) const; + + /** + * Enables keyboard navigation by searching for the entered key sequence. + * Also underlines the currently selected item, providing feedback on the search. + * + * Defaults to off. + * + * WARNING: calls to text() of currently keyboard-selected items will + * contain additional ampersand characters. + * + * WARNING: though pre-existing keyboard shortcuts will not interfere with the + * operation of this feature, they may be confusing to the user as the existing + * shortcuts will not work. + * @since 3.1 + */ + void setKeyboardShortcutsEnabled(bool enable); + + /** + * Enables execution of the menu item once it is uniquely specified. + * Defaults to off. + * @since 3.1 + */ + void setKeyboardShortcutsExecute(bool enable); + + /** + * Obsolete method provided for backwards compatibility only. Use the + * normal constructor and insertTitle instead. + */ + OPopupMenu(const QString &title, QWidget *parent=0, const char *name=0); + /** + * Obsolete method provided for backwards compatibility only. Use + * insertTitle and changeTitle instead. + */ + void setTitle(const QString &title); + + /** + * Returns the context menu associated with this menu + * @since 3.2 + */ + QPopupMenu* contextMenu(); + + /** + * Hides the context menu if shown + * @since 3.2 + */ + void cancelContextMenuShow(); + + /** + * Returns the OPopupMenu associated with the current context menu + * @since 3.2 + */ + static OPopupMenu* contextMenuFocus(); + + /** + * returns the ID of the menuitem associated with the current context menu + * @since 3.2 + */ + static int contextMenuFocusItem(); + +signals: + /** + * connect to this signal to be notified when a context menu is about to be shown + * @param menu The menu that the context menu is about to be shown for + * @param menuItem The menu item that the context menu is currently on + * @param ctxMenu The context menu itself + * @since 3.2 + */ + void aboutToShowContextMenu(OPopupMenu* menu, int menuItem, QPopupMenu* ctxMenu); + +protected: + virtual void closeEvent(QCloseEvent *); + virtual void keyPressEvent(QKeyEvent* e); + virtual bool eventFilter(QObject* obj, QEvent* event); + virtual void hideEvent(QHideEvent*); + + virtual void virtual_hook( int id, void* data ); + +protected slots: + /// @since 3.1 + QString underlineText(const QString& text, uint length); + /// @since 3.1 + void resetKeyboardVars(bool noMatches = false); + void itemHighlighted(int whichItem); + void showCtxMenu(QPoint pos); + void ctxMenuHiding(); + +private: + class OPopupMenuPrivate; + OPopupMenuPrivate *d; +}; + +#endif diff --git a/libopie2/opieui/oselector.cpp b/libopie2/opieui/oselector.cpp new file mode 100644 index 0000000..ec5af6b --- a/dev/null +++ b/libopie2/opieui/oselector.cpp @@ -0,0 +1,716 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Martin Jones (mjones@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 <qimage.h> +#include <qpainter.h> +#include <qdrawutil.h> + +/* OPIE */ + +#include <opie2/oimageeffect.h> +#include <opie2/oselector.h> + +#define STORE_W 8 +#define STORE_W2 STORE_W * 2 + +//----------------------------------------------------------------------------- +/* + * 2D value selector. + * The contents of the selector are drawn by derived class. + */ + +OXYSelector::OXYSelector( QWidget *parent, const char *name ) + : QWidget( parent, name ) +{ + xPos = 0; + yPos = 0; + minX = 0; + minY = 0; + maxX = 100; + maxY = 100; + store.setOptimization( QPixmap::BestOptim ); + store.resize( STORE_W2, STORE_W2 ); +} + + +OXYSelector::~OXYSelector() +{} + + +void OXYSelector::setRange( int _minX, int _minY, int _maxX, int _maxY ) +{ + px = 2; + py = 2; + minX = _minX; + minY = _minY; + maxX = _maxX; + maxY = _maxY; +} + +void OXYSelector::setValues( int _xPos, int _yPos ) +{ + xPos = _xPos; + yPos = _yPos; + + if ( xPos > maxX ) + xPos = maxX; + else if ( xPos < minX ) + xPos = minX; + + if ( yPos > maxY ) + yPos = maxY; + else if ( yPos < minY ) + yPos = minY; + + int xp = 2 + (width() - 4) * xPos / (maxX - minX); + int yp = height() - 2 - (height() - 4) * yPos / (maxY - minY); + + setPosition( xp, yp ); +} + +QRect OXYSelector::contentsRect() const +{ + return QRect( 2, 2, width()-4, height()-4 ); +} + +void OXYSelector::paintEvent( QPaintEvent *ev ) +{ + QRect cursorRect( px - STORE_W, py - STORE_W, STORE_W2, STORE_W2); + QRect paintRect = ev->rect(); + + QPainter painter; + painter.begin( this ); + + QBrush brush; + qDrawShadePanel( &painter, 0, 0, width(), height(), colorGroup(), + TRUE, 2, &brush ); + + drawContents( &painter ); + if (paintRect.contains(cursorRect)) + { + bitBlt( &store, 0, 0, this, px - STORE_W, py - STORE_W, + STORE_W2, STORE_W2, CopyROP ); + drawCursor( &painter, px, py ); + } + else if (paintRect.intersects(cursorRect)) + { + repaint( cursorRect, false); + } + + painter.end(); +} + +void OXYSelector::mousePressEvent( QMouseEvent *e ) +{ + int xVal, yVal; + valuesFromPosition( e->pos().x() - 2, e->pos().y() - 2, xVal, yVal ); + setValues( xVal, yVal ); + + emit valueChanged( xPos, yPos ); +} + +void OXYSelector::mouseMoveEvent( QMouseEvent *e ) +{ + int xVal, yVal; + valuesFromPosition( e->pos().x() - 2, e->pos().y() - 2, xVal, yVal ); + setValues( xVal, yVal ); + + emit valueChanged( xPos, yPos ); +} + +void OXYSelector::wheelEvent( QWheelEvent *e ) +{ + #if QT_VERSION > 290 + if ( e->orientation() == Qt::Horizontal ) + setValues( xValue() + e->delta()/120, yValue() ); + else + setValues( xValue(), yValue() + e->delta()/120 ); + + emit valueChanged( xPos, yPos ); + #endif +} + +void OXYSelector::valuesFromPosition( int x, int y, int &xVal, int &yVal ) const +{ + xVal = ( (maxX-minX) * (x-2) ) / ( width()-4 ); + yVal = maxY - ( ( (maxY-minY) * (y-2) ) / ( height()-4 ) ); + + if ( xVal > maxX ) + xVal = maxX; + else if ( xVal < minX ) + xVal = minX; + + if ( yVal > maxY ) + yVal = maxY; + else if ( yVal < minY ) + yVal = minY; +} + +void OXYSelector::setPosition( int xp, int yp ) +{ + if ( xp < 2 ) + xp = 2; + else if ( xp > width() - 2 ) + xp = width() - 2; + + if ( yp < 2 ) + yp = 2; + else if ( yp > height() - 2 ) + yp = height() - 2; + + QPainter painter; + painter.begin( this ); + + bitBlt( this, px - STORE_W, py - STORE_W, &store, 0, 0, + STORE_W2, STORE_W2, CopyROP ); + bitBlt( &store, 0, 0, this, xp - STORE_W, yp - STORE_W, + STORE_W2, STORE_W2, CopyROP ); + drawCursor( &painter, xp, yp ); + px = xp; + py = yp; + + painter.end(); +} + +void OXYSelector::drawContents( QPainter * ) +{} + + +void OXYSelector::drawCursor( QPainter *p, int xp, int yp ) +{ + p->setPen( QPen( white ) ); + + p->drawLine( xp - 6, yp - 6, xp - 2, yp - 2 ); + p->drawLine( xp - 6, yp + 6, xp - 2, yp + 2 ); + p->drawLine( xp + 6, yp - 6, xp + 2, yp - 2 ); + p->drawLine( xp + 6, yp + 6, xp + 2, yp + 2 ); +} + +//----------------------------------------------------------------------------- +/* + * 1D value selector with contents drawn by derived class. + * See OColorDialog for example. + */ + + +OSelector::OSelector( QWidget *parent, const char *name ) + : QWidget( parent, name ), QRangeControl() +{ + _orientation = Horizontal; + _indent = TRUE; +} + +OSelector::OSelector( Orientation o, QWidget *parent, const char *name ) + : QWidget( parent, name ), QRangeControl() +{ + _orientation = o; + _indent = TRUE; +} + + +OSelector::~OSelector() +{} + + +QRect OSelector::contentsRect() const +{ + if ( orientation() == Vertical ) + return QRect( 2, 5, width()-9, height()-10 ); + else + return QRect( 5, 2, width()-10, height()-9 ); +} + +void OSelector::paintEvent( QPaintEvent * ) +{ + QPainter painter; + + painter.begin( this ); + + drawContents( &painter ); + + QBrush brush; + + if ( indent() ) + { + if ( orientation() == Vertical ) + qDrawShadePanel( &painter, 0, 3, width()-5, height()-6, + colorGroup(), TRUE, 2, &brush ); + else + qDrawShadePanel( &painter, 3, 0, width()-6, height()-5, + colorGroup(), TRUE, 2, &brush ); + } + + QPoint pos = calcArrowPos( value() ); + drawArrow( &painter, TRUE, pos ); + + painter.end(); +} + +void OSelector::mousePressEvent( QMouseEvent *e ) +{ + moveArrow( e->pos() ); +} + +void OSelector::mouseMoveEvent( QMouseEvent *e ) +{ + moveArrow( e->pos() ); +} + +void OSelector::wheelEvent( QWheelEvent *e ) +{ + int val = value() + e->delta()/120; + emit valueChanged( val ); + setValue( val ); +} + +void OSelector::valueChange() +{ + QPainter painter; + QPoint pos; + + painter.begin( this ); + + pos = calcArrowPos( prevValue() ); + drawArrow( &painter, FALSE, pos ); + + pos = calcArrowPos( value() ); + drawArrow( &painter, TRUE, pos ); + + painter.end(); +} + +void OSelector::moveArrow( const QPoint &pos ) +{ + int val; + + if ( orientation() == Vertical ) + val = ( maxValue() - minValue() ) * (height()-pos.y()-3) + / (height()-10) + minValue(); + else + val = ( maxValue() - minValue() ) * (width()-pos.x()-3) + / (width()-10) + minValue(); + + if ( val > maxValue() ) + val = maxValue(); + if ( val < minValue() ) + val = minValue(); + + emit valueChanged( val ); + setValue( val ); +} + +QPoint OSelector::calcArrowPos( int val ) +{ + QPoint p; + + if ( orientation() == Vertical ) + { + p.setY( height() - ( (height()-10) * val + / ( maxValue() - minValue() ) + 5 ) ); + p.setX( width() - 5 ); + } + else + { + p.setX( width() - ( (width()-10) * val + / ( maxValue() - minValue() ) + 5 ) ); + p.setY( height() - 5 ); + } + + return p; +} + +void OSelector::drawContents( QPainter * ) +{} + +void OSelector::drawArrow( QPainter *painter, bool show, const QPoint &pos ) +{ + if ( show ) + { + QPointArray array(3); + + painter->setPen( QPen() ); + painter->setBrush( QBrush( colorGroup().buttonText() ) ); + if ( orientation() == Vertical ) + { + array.setPoint( 0, pos.x()+0, pos.y()+0 ); + array.setPoint( 1, pos.x()+5, pos.y()+5 ); + array.setPoint( 2, pos.x()+5, pos.y()-5 ); + } + else + { + array.setPoint( 0, pos.x()+0, pos.y()+0 ); + array.setPoint( 1, pos.x()+5, pos.y()+5 ); + array.setPoint( 2, pos.x()-5, pos.y()+5 ); + } + + painter->drawPolygon( array ); + } + else + { + if ( orientation() == Vertical ) + { + repaint(pos.x(), pos.y()-5, 6, 11, true); + } + else + { + repaint(pos.x()-5, pos.y(), 11, 6, true); + } + } +} + +//---------------------------------------------------------------------------- + +OGradientSelector::OGradientSelector( QWidget *parent, const char *name ) + : OSelector( parent, name ) +{ + init(); +} + + +OGradientSelector::OGradientSelector( Orientation o, QWidget *parent, + const char *name ) + : OSelector( o, parent, name ) +{ + init(); +} + + +OGradientSelector::~OGradientSelector() +{} + + +void OGradientSelector::init() +{ + color1.setRgb( 0, 0, 0 ); + color2.setRgb( 255, 255, 255 ); + + text1 = text2 = ""; +} + + +void OGradientSelector::drawContents( QPainter *painter ) +{ + QImage image( contentsRect().width(), contentsRect().height(), 32 ); + + QColor col; + float scale; + + int redDiff = color2.red() - color1.red(); + int greenDiff = color2.green() - color1.green(); + int blueDiff = color2.blue() - color1.blue(); + + if ( orientation() == Vertical ) + { + for ( int y = 0; y < image.height(); y++ ) + { + scale = 1.0 * y / image.height(); + col.setRgb( color1.red() + int(redDiff*scale), + color1.green() + int(greenDiff*scale), + color1.blue() + int(blueDiff*scale) ); + + unsigned int *p = (uint *) image.scanLine( y ); + for ( int x = 0; x < image.width(); x++ ) + *p++ = col.rgb(); + } + } + else + { + unsigned int *p = (uint *) image.scanLine( 0 ); + + for ( int x = 0; x < image.width(); x++ ) + { + scale = 1.0 * x / image.width(); + col.setRgb( color1.red() + int(redDiff*scale), + color1.green() + int(greenDiff*scale), + color1.blue() + int(blueDiff*scale) ); + *p++ = col.rgb(); + } + + for ( int y = 1; y < image.height(); y++ ) + memcpy( image.scanLine( y ), image.scanLine( y - 1), + sizeof( unsigned int ) * image.width() ); + } + + QColor ditherPalette[8]; + + for ( int s = 0; s < 8; s++ ) + ditherPalette[s].setRgb( color1.red() + redDiff * s / 8, + color1.green() + greenDiff * s / 8, + color1.blue() + blueDiff * s / 8 ); + + OImageEffect::dither( image, ditherPalette, 8 ); + + QPixmap p; + p.convertFromImage( image ); + + painter->drawPixmap( contentsRect().x(), contentsRect().y(), p ); + + if ( orientation() == Vertical ) + { + int yPos = contentsRect().top() + painter->fontMetrics().ascent() + 2; + int xPos = contentsRect().left() + (contentsRect().width() - + painter->fontMetrics().width( text2 )) / 2; + QPen pen( color2 ); + painter->setPen( pen ); + painter->drawText( xPos, yPos, text2 ); + + yPos = contentsRect().bottom() - painter->fontMetrics().descent() - 2; + xPos = contentsRect().left() + (contentsRect().width() - + painter->fontMetrics().width( text1 )) / 2; + pen.setColor( color1 ); + painter->setPen( pen ); + painter->drawText( xPos, yPos, text1 ); + } + else + { + int yPos = contentsRect().bottom()-painter->fontMetrics().descent()-2; + + QPen pen( color2 ); + painter->setPen( pen ); + painter->drawText( contentsRect().left() + 2, yPos, text1 ); + + pen.setColor( color1 ); + painter->setPen( pen ); + painter->drawText( contentsRect().right() - + painter->fontMetrics().width( text2 ) - 2, yPos, text2 ); + } +} + +//----------------------------------------------------------------------------- + +static QColor *standardPalette = 0; + +#define STANDARD_PAL_SIZE 17 + +OColor::OColor() +: QColor() +{ + r = 0; g = 0; b = 0; h = 0; s = 0; v = 0; +}; + +OColor::OColor( const OColor &col) +: QColor( col ) +{ + h = col.h; s = col.s; v = col.v; + r = col.r; g = col.g; b = col.b; +}; + +OColor::OColor( const QColor &col) +: QColor( col ) +{ + QColor::rgb(&r, &g, &b); + QColor::hsv(&h, &s, &v); +}; + +bool OColor::operator==(const OColor& col) const +{ + return (h == col.h) && (s == col.s) && (v == col.v) && + (r == col.r) && (g == col.g) && (b == col.b); +} + +OColor& OColor::operator=(const OColor& col) +{ + *(QColor *)this = col; + h = col.h; s = col.s; v = col.v; + r = col.r; g = col.g; b = col.b; + return *this; +} + +void +OColor::setHsv(int _h, int _s, int _v) +{ + h = _h; s = _s; v = _v; + QColor::setHsv(h, s, v); + QColor::rgb(&r, &g, &b); +}; + +void +OColor::setRgb(int _r, int _g, int _b) +{ + r = _r; g = _g; b = _b; + QColor::setRgb(r, g, b); + QColor::hsv(&h, &s, &v); +} + +void +OColor::rgb(int *_r, int *_g, int *_b) const +{ + *_r = r; *_g = g; *_b = b; +} + +void +OColor::hsv(int *_h, int *_s, int *_v) const +{ + *_h = h; *_s = s; *_v = v; +} + +static void createStandardPalette() +{ + if ( standardPalette ) + return; + + standardPalette = new QColor[STANDARD_PAL_SIZE]; + + int i = 0; + + standardPalette[i++] = Qt::red; + standardPalette[i++] = Qt::green; + standardPalette[i++] = Qt::blue; + standardPalette[i++] = Qt::cyan; + standardPalette[i++] = Qt::magenta; + standardPalette[i++] = Qt::yellow; + standardPalette[i++] = Qt::darkRed; + standardPalette[i++] = Qt::darkGreen; + standardPalette[i++] = Qt::darkBlue; + standardPalette[i++] = Qt::darkCyan; + standardPalette[i++] = Qt::darkMagenta; + standardPalette[i++] = Qt::darkYellow; + standardPalette[i++] = Qt::white; + standardPalette[i++] = Qt::lightGray; + standardPalette[i++] = Qt::gray; + standardPalette[i++] = Qt::darkGray; + standardPalette[i++] = Qt::black; +} + + +OHSSelector::OHSSelector( QWidget *parent, const char *name ) + : OXYSelector( parent, name ) +{ + setRange( 0, 0, 359, 255 ); +} + +void OHSSelector::updateContents() +{ + drawPalette(&pixmap); +} + +void OHSSelector::resizeEvent( QResizeEvent * ) +{ + updateContents(); +} + +void OHSSelector::drawContents( QPainter *painter ) +{ + painter->drawPixmap( contentsRect().x(), contentsRect().y(), pixmap ); +} + +void OHSSelector::drawPalette( QPixmap *pixmap ) +{ + int xSize = contentsRect().width(), ySize = contentsRect().height(); + QImage image( xSize, ySize, 32 ); + QColor col; + int h, s; + uint *p; + + for ( s = ySize-1; s >= 0; s-- ) + { + p = (uint *) image.scanLine( ySize - s - 1 ); + for( h = 0; h < xSize; h++ ) + { + col.setHsv( 359*h/(xSize-1), 255*s/(ySize-1), 192 ); + *p = col.rgb(); + p++; + } + } + + if ( QColor::numBitPlanes() <= 8 ) + { + createStandardPalette(); + OImageEffect::dither( image, standardPalette, STANDARD_PAL_SIZE ); + } + pixmap->convertFromImage( image ); +} + + +//----------------------------------------------------------------------------- + +OValueSelector::OValueSelector( QWidget *parent, const char *name ) + : OSelector( OSelector::Vertical, parent, name ), _hue(0), _sat(0) +{ + setRange( 0, 255 ); + pixmap.setOptimization( QPixmap::BestOptim ); +} + +OValueSelector::OValueSelector(Orientation o, QWidget *parent, const char *name + ) + : OSelector( o, parent, name), _hue(0), _sat(0) +{ + setRange( 0, 255 ); + pixmap.setOptimization( QPixmap::BestOptim ); +} + +void OValueSelector::updateContents() +{ + drawPalette(&pixmap); +} + +void OValueSelector::resizeEvent( QResizeEvent * ) +{ + updateContents(); +} + +void OValueSelector::drawContents( QPainter *painter ) +{ + painter->drawPixmap( contentsRect().x(), contentsRect().y(), pixmap ); +} + +void OValueSelector::drawPalette( QPixmap *pixmap ) +{ + int xSize = contentsRect().width(), ySize = contentsRect().height(); + QImage image( xSize, ySize, 32 ); + QColor col; + uint *p; + QRgb rgb; + + if ( orientation() == OSelector::Horizontal ) + { + for ( int v = 0; v < ySize; v++ ) + { + p = (uint *) image.scanLine( ySize - v - 1 ); + + for( int x = 0; x < xSize; x++ ) + { + col.setHsv( _hue, _sat, 255*x/(xSize-1) ); + rgb = col.rgb(); + *p++ = rgb; + } + } + } + + if( orientation() == OSelector::Vertical ) + { + for ( int v = 0; v < ySize; v++ ) + { + p = (uint *) image.scanLine( ySize - v - 1 ); + col.setHsv( _hue, _sat, 255*v/(ySize-1) ); + rgb = col.rgb(); + for ( int i = 0; i < xSize; i++ ) + *p++ = rgb; + } + } + + if ( QColor::numBitPlanes() <= 8 ) + { + createStandardPalette(); + OImageEffect::dither( image, standardPalette, STANDARD_PAL_SIZE ); + } + pixmap->convertFromImage( image ); +} diff --git a/libopie2/opieui/oselector.h b/libopie2/opieui/oselector.h new file mode 100644 index 0000000..f832239 --- a/dev/null +++ b/libopie2/opieui/oselector.h @@ -0,0 +1,518 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Martin Jones (mjones@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. +*/ +//----------------------------------------------------------------------------- +// Selector widgets for KDE Color Selector, but probably useful for other +// stuff also. + +#ifndef __OSELECT_H__ +#define __OSELECT_H__ + +#include <qwidget.h> +#include <qrangecontrol.h> +#include <qpixmap.h> + +/** + * OXYSelector is the base class for other widgets which + * provides the ability to choose from a two-dimensional + * range of values. The currently chosen value is indicated + * by a cross. An example is the @ref OHSSelector which + * allows to choose from a range of colors, and which is + * used in OColorDialog. + * + * A custom drawing routine for the widget surface has + * to be provided by the subclass. + */ +class OXYSelector : public QWidget +{ + Q_OBJECT + +public: + /** + * Constructs a two-dimensional selector widget which + * has a value range of [0..100] in both directions. + */ + OXYSelector( QWidget *parent=0, const char *name=0 ); + /** + * Destructs the widget. + */ + ~OXYSelector(); + + /** + * Sets the current values in horizontal and + * vertical direction. + */ + void setValues( int xPos, int yPos ); + /** + * Sets the range of possible values. + */ + void setRange( int minX, int minY, int maxX, int maxY ); + + /** + * @return the current value in horizontal direction. + */ + int xValue() const { return xPos; } + /** + * @return the current value in vertical direction. + */ + int yValue() const { return yPos; } + + /** + * @return the rectangle on which subclasses should draw. + */ + QRect contentsRect() const; + +signals: + /** + * This signal is emitted whenever the user chooses a value, + * e.g. by clicking with the mouse on the widget. + */ + void valueChanged( int x, int y ); + +protected: + /** + * Override this function to draw the contents of the widget. + * The default implementation does nothing. + * + * Draw within @ref contentsRect() only. + */ + virtual void drawContents( QPainter * ); + /** + * Override this function to draw the cursor which + * indicates the currently selected value pair. + */ + virtual void drawCursor( QPainter *p, int xp, int yp ); + /** + * @reimplemented + */ + virtual void paintEvent( QPaintEvent *e ); + /** + * @reimplemented + */ + virtual void mousePressEvent( QMouseEvent *e ); + /** + * @reimplemented + */ + virtual void mouseMoveEvent( QMouseEvent *e ); + /** + * @reimplemented + */ + virtual void wheelEvent( QWheelEvent * ); + /** + * Converts a pixel position to its corresponding values. + */ + void valuesFromPosition( int x, int y, int& xVal, int& yVal ) const; + +private: + void setPosition( int xp, int yp ); + int px; + int py; + int xPos; + int yPos; + int minX; + int maxX; + int minY; + int maxY; + QPixmap store; + +private: + class OXYSelectorPrivate; + OXYSelectorPrivate *d; +}; + + +/** + * OSelector is the base class for other widgets which + * provides the ability to choose from a one-dimensional + * range of values. An example is the @ref OGradientSelector + * which allows to choose from a range of colors. + * + * A custom drawing routine for the widget surface has + * to be provided by the subclass. + */ +class OSelector : public QWidget, public QRangeControl +{ + Q_OBJECT + Q_PROPERTY( int value READ value WRITE setValue ) + Q_PROPERTY( int minValue READ minValue WRITE setMinValue ) + Q_PROPERTY( int maxValue READ maxValue WRITE setMaxValue ) +public: + + /** + * Constructs a horizontal one-dimensional selection widget. + */ + OSelector( QWidget *parent=0, const char *name=0 ); + /** + * Constructs a one-dimensional selection widget with + * a given orientation. + */ + OSelector( Orientation o, QWidget *parent = 0L, const char *name = 0L ); + /* + * Destructs the widget. + */ + ~OSelector(); + + /** + * @return the orientation of the widget. + */ + Orientation orientation() const + { return _orientation; } + + /** + * @return the rectangle on which subclasses should draw. + */ + QRect contentsRect() const; + + /** + * Sets the indent option of the widget to i. + * This determines whether a shaded frame is drawn. + */ + void setIndent( bool i ) + { _indent = i; } + /** + * @return whether the indent option is set. + */ + bool indent() const + { return _indent; } + + /** + * Sets the value. + */ + void setValue(int value) + { QRangeControl::setValue(value); } + + /** + * @returns the value. + */ + int value() const + { return QRangeControl::value(); } + + /** + * Sets the min value. + */ + #if ( QT_VERSION > 290 ) + void setMinValue(int value) { QRangeControl::setMinValue(value); } + #else + void setMinValue(int value) { QRangeControl::setRange(value,QRangeControl::maxValue()); } + #endif + + /** + * @return the min value. + */ + int minValue() const + { return QRangeControl::minValue(); } + + /** + * Sets the max value. + */ + #if ( QT_VERSION > 290 ) + void setMaxValue(int value) { QRangeControl::setMaxValue(value); } + #else + void setMaxValue(int value) { QRangeControl::setRange(QRangeControl::minValue(),value); } + #endif + + /** + * @return the max value. + */ + int maxValue() const + { return QRangeControl::maxValue(); } + +signals: + /** + * This signal is emitted whenever the user chooses a value, + * e.g. by clicking with the mouse on the widget. + */ + void valueChanged( int value ); + +protected: + /** + * Override this function to draw the contents of the control. + * The default implementation does nothing. + * + * Draw only within contentsRect(). + */ + virtual void drawContents( QPainter * ); + /** + * Override this function to draw the cursor which + * indicates the current value. This function is + * always called twice, once with argument show=false + * to clear the old cursor, once with argument show=true + * to draw the new one. + */ + virtual void drawArrow( QPainter *painter, bool show, const QPoint &pos ); + + /** + * @reimplemented + */ + virtual void valueChange(); + /** + * @reimplemented + */ + virtual void paintEvent( QPaintEvent * ); + /** + * @reimplemented + */ + virtual void mousePressEvent( QMouseEvent *e ); + /** + * @reimplemented + */ + virtual void mouseMoveEvent( QMouseEvent *e ); + /** + * @reimplemented + */ + virtual void wheelEvent( QWheelEvent * ); + +private: + QPoint calcArrowPos( int val ); + void moveArrow( const QPoint &pos ); + + Orientation _orientation; + bool _indent; + +private: + class OSelectorPrivate; + OSelectorPrivate *d; +}; + + +/** + * The OGradientSelector widget allows the user to choose + * from a one-dimensional range of colors which is given as a + * gradient between two colors provided by the programmer. + */ +class OGradientSelector : public OSelector +{ + Q_OBJECT + + Q_PROPERTY( QColor firstColor READ firstColor WRITE setFirstColor ) + Q_PROPERTY( QColor secondColor READ secondColor WRITE setSecondColor ) + Q_PROPERTY( QString firstText READ firstText WRITE setFirstText ) + Q_PROPERTY( QString secondText READ secondText WRITE setSecondText ) + +public: + /** + * Constructs a horizontal color selector which + * contains a gradient between white and black. + */ + OGradientSelector( QWidget *parent=0, const char *name=0 ); + /** + * Constructs a colors selector with orientation o which + * contains a gradient between white and black. + */ + OGradientSelector( Orientation o, QWidget *parent=0, const char *name=0 ); + /** + * Destructs the widget. + */ + ~OGradientSelector(); + /** + * Sets the two colors which span the gradient. + */ + void setColors( const QColor &col1, const QColor &col2 ) + { color1 = col1; color2 = col2; update();} + void setText( const QString &t1, const QString &t2 ) + { text1 = t1; text2 = t2; update(); } + + /** + * Set each color on its own. + */ + void setFirstColor( const QColor &col ) + { color1 = col; update(); } + void setSecondColor( const QColor &col ) + { color2 = col; update(); } + + /** + * Set each description on its own + */ + void setFirstText( const QString &t ) + { text1 = t; update(); } + void setSecondText( const QString &t ) + { text2 = t; update(); } + + const QColor firstColor() const + { return color1; } + const QColor secondColor() const + { return color2; } + + const QString firstText() const + { return text1; } + const QString secondText() const + { return text2; } + +protected: + /** + * @reimplemented + */ + virtual void drawContents( QPainter * ); + + /** + * @reimplemented + */ + virtual QSize minimumSize() const + { return sizeHint(); } + +private: + void init(); + QColor color1; + QColor color2; + QString text1; + QString text2; + +private: + class OGradientSelectorPrivate; + OGradientSelectorPrivate *d; +}; + +/** + * Widget for Hue/Saturation selection. + * The actual values can be fetched using the inherited xValue and yValue + * methods. + * + * @see OXYSelector, OValueSelector, OColorDialog + * @author Martin Jones (mjones@kde.org) + * @version $Id$ +*/ +class OHSSelector : public OXYSelector +{ + Q_OBJECT + +public: + /** + * Constructs a hue/saturation selection widget. + */ + OHSSelector( QWidget *parent=0, const char *name=0 ); + +protected: + /** + * Draws the contents of the widget on a pixmap, + * which is used for buffering. + */ + virtual void drawPalette( QPixmap *pixmap ); + /** + * @reimplemented + */ + virtual void resizeEvent( QResizeEvent * ); + /** + * Reimplemented from OXYSelector. This drawing is + * buffered in a pixmap here. As real drawing + * routine, drawPalette() is used. + */ + virtual void drawContents( QPainter *painter ); + +private: + void updateContents(); + QPixmap pixmap; + +private: + class OHSSelectorPrivate; + OHSSelectorPrivate *d; +}; + + +class OValueSelectorPrivate; +/** + * Widget for color value selection. + * + * @see OHSSelector, OColorDialog + * @author Martin Jones (mjones@kde.org) + * @version $Id$ + */ +class OValueSelector : public OSelector +{ + Q_OBJECT + +public: + /** + * Constructs a widget for color selection. + */ + OValueSelector( QWidget *parent=0, const char *name=0 ); + /** + * Constructs a widget for color selection with a given orientation + */ + OValueSelector( Orientation o, QWidget *parent = 0, const char *name = 0 ); + + int hue() const + { return _hue; } + void setHue( int h ) + { _hue = h; } + int saturation() const + { return _sat; } + void setSaturation( int s ) + { _sat = s; } + + void updateContents(); +protected: + /** + * Draws the contents of the widget on a pixmap, + * which is used for buffering. + */ + virtual void drawPalette( QPixmap *pixmap ); + /** + * @reimplemented + */ + virtual void resizeEvent( QResizeEvent * ); + /** + * Reimplemented from OSelector. The drawing is + * buffered in a pixmap here. As real drawing + * routine, drawPalette() is used. + */ + virtual void drawContents( QPainter *painter ); + +private: + int _hue; + int _sat; + QPixmap pixmap; + +private: + class OValueSelectorPrivate; + OValueSelectorPrivate *d; +}; + + +class OColor : public QColor +{ +public: + OColor(); + OColor( const OColor &col); + OColor( const QColor &col); + + OColor& operator=( const OColor& col); + + bool operator==( const OColor& col) const; + + void setHsv(int _h, int _s, int _v); + void setRgb(int _r, int _g, int _b); + + void rgb(int *_r, int *_g, int *_b) const; + void hsv(int *_h, int *_s, int *_v) const; +protected: + int h; + int s; + int v; + int r; + int g; + int b; + +private: + class OColorPrivate; + OColorPrivate *d; +}; + + + +#endif // __OSELECT_H__ + diff --git a/libopie2/opieui/oseparator.cpp b/libopie2/opieui/oseparator.cpp new file mode 100644 index 0000000..85181dc --- a/dev/null +++ b/libopie2/opieui/oseparator.cpp @@ -0,0 +1,128 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + Copyright (C) 1997 Michael Roth <mroth@wirlweb.de> + =. + .=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 <qstyle.h> + +/* OPIE */ + +#include <opie2/oseparator.h> + +OSeparator::OSeparator(QWidget* parent, const char* name, WFlags f) + : QFrame(parent, name, f) +{ + setLineWidth(1); + setMidLineWidth(0); + setOrientation( HLine ); +} + + + +OSeparator::OSeparator(int orientation, QWidget* parent, const char* name, WFlags f) + : QFrame(parent, name, f) +{ + setLineWidth(1); + setMidLineWidth(0); + setOrientation( orientation ); +} + + + +void OSeparator::setOrientation(int orientation) +{ + switch(orientation) + { + case Vertical: + case VLine: + setFrameStyle( QFrame::VLine | QFrame::Sunken ); + setMinimumSize(2, 0); + break; + + default: + qWarning( "OSeparator::setOrientation(): invalid orientation, using default orientation HLine" ); + + case Horizontal: + case HLine: + setFrameStyle( QFrame::HLine | QFrame::Sunken ); + setMinimumSize(0, 2); + break; + } +} + + + +int OSeparator::orientation() const +{ + if ( frameStyle() & VLine ) + return VLine; + + if ( frameStyle() & HLine ) + return HLine; + + return 0; +} + +void OSeparator::drawFrame(QPainter *p) +{ + QPoint p1, p2; + QRect r = frameRect(); + const QColorGroup & g = colorGroup(); + + if ( frameStyle() & HLine ) { + p1 = QPoint( r.x(), r.height()/2 ); + p2 = QPoint( r.x()+r.width(), p1.y() ); + } + else { + p1 = QPoint( r.x()+r.width()/2, 0 ); + p2 = QPoint( p1.x(), r.height() ); + } + +#if QT_VERSION < 300 + style().drawSeparator( p, p1.x(), p1.y(), p2.x(), p2.y(), g, true, 1, midLineWidth() ); +#else + QStyleOption opt( lineWidth(), midLineWidth() ); + style().drawPrimitive( QStyle::PE_Separator, p, QRect( p1, p2 ), g, QStyle::Style_Sunken, opt ); +#endif +} + + +QSize OSeparator::sizeHint() const +{ + if ( frameStyle() & VLine ) + return QSize(2, 0); + + if ( frameStyle() & HLine ) + return QSize(0, 2); + + return QSize(-1, -1); +} diff --git a/libopie2/opieui/oseparator.h b/libopie2/opieui/oseparator.h new file mode 100644 index 0000000..e59b3f4 --- a/dev/null +++ b/libopie2/opieui/oseparator.h @@ -0,0 +1,90 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + Copyright (C) 1997 Michael Roth <mroth@wirlweb.de> + =. + .=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 OSEPARATOR_H +#define OSEPARATOR_H + +#include <qframe.h> + +/** + * Standard horizontal or vertical separator. + * + * @author Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + * @author Michael Roth <mroth@wirlweb.de> + * @version $Id$ +*/ +class OSeparator : public QFrame +{ + Q_OBJECT + Q_PROPERTY( int orientation READ orientation WRITE setOrientation ) + public: + /** + * Constructor. + **/ + OSeparator(QWidget* parent=0, const char* name=0, WFlags f=0); + /** + * Constructor. + * + * @param orientation Set the orientation of the separator. + * Possible values are HLine or Horizontal and VLine or Vertical. + **/ + OSeparator(int orientation, QWidget* parent=0, const char* name=0, + WFlags f=0); + + /** + * Returns the orientation of the separator. + * + * Possible values are VLine and HLine. + **/ + int orientation() const; + + /** + * Set the orientation of the separator to @p orient + * + * Possible values are VLine and HLine. + */ + void setOrientation(int orient); + + /** + * The recommended height (width) for a horizontal (vertical) separator. + **/ + virtual QSize sizeHint() const; + +protected: + virtual void drawFrame( QPainter * ); + +private: + class OSeparatorPrivate* d; +}; + + +#endif // OSEPARATOR_H diff --git a/libopie2/opieui/oversatileview.cpp b/libopie2/opieui/oversatileview.cpp new file mode 100644 index 0000000..32855be --- a/dev/null +++ b/libopie2/opieui/oversatileview.cpp @@ -0,0 +1,1179 @@ +/* + This file is part of the Opie Project + + =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + .=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 <qaction.h> +#include <qbrush.h> +#include <qfont.h> +#include <qiconset.h> +#include <qiconview.h> +#include <qlistview.h> +#include <qpalette.h> +#include <qpoint.h> +#include <qpopupmenu.h> +#include <qrect.h> +#include <qsize.h> +#include <qstring.h> +#include <qwidgetstack.h> + +/* OPIE */ + +#include <opie2/oversatileview.h> +#include <opie2/oversatileviewitem.h> +#include <opie2/olistview.h> + +/* XPM */ +static const char * view_icon_xpm[] = { +"16 16 16 1", +" c None", +". c #87BD88", +"+ c #8BBE8B", +"@ c #81BA81", +"# c #6DAF6D", +"$ c #87BD87", +"% c #FCFDFC", +"& c #AED0AE", +"* c #4E9C4C", +"= c #91BD91", +"- c #72B172", +"; c #448643", +"> c #519F50", +", c #499247", +"' c #356A35", +") c #686868", +" ", +" .+@# .+@# ", +" $%&* $%&* ", +" @=-; @=-; ", +" #>,' #>,' ", +" ", +" )))))) )))))) ", +" ", +" ", +" .+@# .+@# ", +" $%&* $%&* ", +" @=-; @=-; ", +" #>,' #>,' ", +" ", +" )))))) )))))) ", +" "}; + +/* XPM */ +static const char * view_tree_xpm[] = { +"16 16 17 1", +" c None", +". c #3A3A3A", +"+ c #87BD88", +"@ c #8BBE8B", +"# c #81BA81", +"$ c #6DAF6D", +"% c #87BD87", +"& c #FCFDFC", +"* c #AED0AE", +"= c #4E9C4C", +"- c #91BD91", +"; c #72B172", +"> c #448643", +", c #686868", +"' c #519F50", +") c #499247", +"! c #356A35", +" . ", +" . ", +" . +@#$ ", +" . %&*= ", +" .. #-;> ,, ,,,", +" . $')! ", +" . ", +" . ", +" . ", +" . +@#$ ", +" . %&*= ", +" .. #-;> ,, ,,,", +" $')! ", +" ", +" ", +" "}; + +OVersatileView::OVersatileView( QWidget* parent, const char* name, int mode ) + :QWidgetStack( parent, name ), + _viewmode( mode ), _warningpolicy( None ), + _treeleaf(), _treeopened(), _treeclosed(), + _iconleaf(), _iconopened(), _iconclosed() +{ + // + // Create child widgets and set some reasonable default styles + // + + _listview = new OListView( this, "oversatileview embedded listview" ); + _iconview = new QIconView( this, "oversatileview embedded iconview" ); + + _listview->setAllColumnsShowFocus( true ); + _listview->setRootIsDecorated( true ); + _listview->setShowSortIndicator( true ); + _iconview->setGridX( 90 ); + _iconview->setGridY( 42 ); + _iconview->setAutoArrange( true ); + + #ifdef QWS // TODO: Let this depend on current geometry (rotation) + _iconview->setArrangement( QIconView::TopToBottom ); + #else + _iconview->setArrangement( QIconView::LeftToRight ); + #endif + + _iconview->setResizeMode( QIconView::Adjust ); + + // qt-embedded: map stylus right on hold to right button press + + #ifdef QWS + ( (QPEApplication*) qApp)->setStylusOperation( _iconview->viewport(), QPEApplication::RightOnHold ); + ( (QPEApplication*) qApp)->setStylusOperation( _listview->viewport(), QPEApplication::RightOnHold ); + #endif + + setViewMode( mode ); // TODO: Read last style from config + // setSynchronization( true ); // TODO: Implement this + + // create context menu allowing to switch between the views + + _contextmenu = new QPopupMenu( 0, "oversatileview contextmenu" ); + _contextmenu->setCaption( "Style" ); + _contextmenu->setCheckable( true ); + QActionGroup* ag = new QActionGroup( _contextmenu, "style option group" ); + QAction* a1 = new QAction( "View Items in Icon Style", QIconSet( QPixmap( view_icon_xpm ) ), + "View Icons", 0, ag, "viewicon action", true ); + QAction* a2 = new QAction( "View Items in Tree Style", QIconSet( QPixmap( view_tree_xpm ) ), + "View Tree", 0, ag, "viewtree action", true ); + ag->addTo( _contextmenu ); + if ( mode == Icons ) + a1->setOn( true ); + else if ( mode == Tree ) + a2->setOn( true ); + connect( a1, SIGNAL( activated() ), this, SLOT( setIconViewMode() ) ); + connect( a2, SIGNAL( activated() ), this, SLOT( setTreeViewMode() ) ); + + #if (QT_VERSION >= 0x030000) + connect( _listview, SIGNAL( contextMenuRequested( QListViewItem*, const QPoint&, int ) ), this, SLOT( contextMenuRequested( QListViewItem*, const QPoint&, int ) ) ); + connect( _iconview, SIGNAL( contextMenuRequested( QIconViewItem*, const QPoint& ) ), this, SLOT( contextMenuRequested( QIconViewItem*, const QPoint& ) ) ); + #else + connect( _listview, SIGNAL( rightButtonPressed( QListViewItem*, const QPoint&, int ) ), this, SLOT( contextMenuRequested( QListViewItem*, const QPoint&, int ) ) ); + connect( _iconview, SIGNAL( rightButtonPressed( QIconViewItem*, const QPoint& ) ), this, SLOT( contextMenuRequested( QIconViewItem*, const QPoint& ) ) ); + #endif + + // + // signal forwarders + // + // unfortunately we can't short-circuit all the QListView and QIconView signals + // to OVersatileView signals, because the signal/slot mechanism doesn't allow + // type-conversion :-( + + // common signals for listview + + connect( _listview, SIGNAL( selectionChanged() ), this, SIGNAL( selectionChanged() ) ); + connect( _listview, SIGNAL( selectionChanged( QListViewItem * ) ), this, SLOT( selectionChanged( QListViewItem * ) ) ); + connect( _listview, SIGNAL( currentChanged( QListViewItem * ) ), this, SLOT( currentChanged( QListViewItem * ) ) ); + connect( _listview, SIGNAL( clicked( QListViewItem * ) ), this, SLOT( clicked( QListViewItem * ) ) ); + connect( _listview, SIGNAL( pressed( QListViewItem * ) ), this, SLOT( pressed( QListViewItem * ) ) ); + + connect( _listview, SIGNAL( doubleClicked( QListViewItem * ) ), this, SLOT( doubleClicked( QListViewItem * ) ) ); + connect( _listview, SIGNAL( returnPressed( QListViewItem * ) ), this, SLOT( returnPressed( QListViewItem * ) ) ); + + connect( _listview, SIGNAL( onItem( QListViewItem * ) ), this, SLOT( onItem( QListViewItem * ) ) ); + connect( _listview, SIGNAL( onViewport() ), this, SIGNAL( onViewport() ) ); + + // common signals for iconview + + connect( _iconview, SIGNAL( selectionChanged() ), this, SIGNAL( selectionChanged() ) ); + connect( _iconview, SIGNAL( selectionChanged( QIconViewItem * ) ), this, SLOT( selectionChanged( QIconViewItem * ) ) ); + connect( _iconview, SIGNAL( currentChanged( QIconViewItem * ) ), this, SLOT( currentChanged( QIconViewItem * ) ) ); + connect( _iconview, SIGNAL( clicked( QIconViewItem * ) ), this, SLOT( clicked( QIconViewItem * ) ) ); + connect( _iconview, SIGNAL( pressed( QIconViewItem * ) ), this, SLOT( pressed( QIconViewItem * ) ) ); + + connect( _iconview, SIGNAL( doubleClicked( QIconViewItem * ) ), this, SLOT( doubleClicked( QIconViewItem * ) ) ); + connect( _iconview, SIGNAL( returnPressed( QIconViewItem * ) ), this, SLOT( returnPressed( QIconViewItem * ) ) ); + + connect( _iconview, SIGNAL( onItem( QIconViewItem * ) ), this, SLOT( onItem( QIconViewItem * ) ) ); + connect( _iconview, SIGNAL( onViewport() ), this, SIGNAL( onViewport() ) ); + + // listview only signals + + connect( _listview, SIGNAL( expanded( QListViewItem * ) ), this, SLOT( expanded( QListViewItem * ) ) ); + connect( _listview, SIGNAL( collapsed( QListViewItem * ) ), this, SLOT( collapsed( QListViewItem * ) ) ); + + // iconview only signals + + connect( _iconview, SIGNAL( moved() ), this, SIGNAL( moved() ) ); +} + +OVersatileView::~OVersatileView() +{ +} + +QPopupMenu* OVersatileView::contextMenu() const +{ + return _contextmenu; +} + +void OVersatileView::contextMenuRequested( QListViewItem* item, const QPoint& pos, int col ) +{ + // can't use QObject::inherits here, because ListViewItems, beit Q, O or K, + // do not inherit from QObject - assuming here the programmer is + // disciplined enough to only add OVersatileViewItems to an OVersatileView + popupContextMenu( static_cast<OVersatileViewItem*>( item ), pos, col ); +} + +void OVersatileView::contextMenuRequested( QIconViewItem* item, const QPoint& pos ) +{ + // see above + popupContextMenu( static_cast<OVersatileViewItem*>( item ), pos, -1 ); +} + +void OVersatileView::popupContextMenu( OVersatileViewItem* item, const QPoint& pos, int col ) +{ + if ( not item ) + _contextmenu->exec( pos ); + else + emit( contextMenuRequested( item, pos, col ) ); +} + +void OVersatileView::setSynchronization( bool sync ) +{ + _synchronization = sync; +} + +bool OVersatileView::synchronization() +{ + return _synchronization; +} + +void OVersatileView::setDefaultPixmaps( int mode, QPixmap& leaf, QPixmap& opened, QPixmap& closed ) +{ + if ( mode == Tree ) + { + _treeleaf = leaf; + _treeopened = opened; + _treeclosed = closed; + } + else if ( mode == Icons ) + { + _iconleaf = leaf; + _iconopened = opened; + _iconclosed = closed; + } + else + { + qDebug( "OVersatileView::setDefaultPixmaps(): invalid mode" ); + } +} + +QIconView* OVersatileView::iconView() const +{ + return _iconview; +} + +OListView* OVersatileView::listView() const +{ + return _listview; +} + +void OVersatileView::setViewMode( int mode ) +{ + if ( mode == Tree ) + { + _viewmode = mode; + raiseWidget( _listview ); + } + else if ( mode == Icons ) + { + _viewmode = mode; + raiseWidget( _iconview ); + } + else + { + qDebug( "OVersatileView::setViewMode(): invalid mode" ); + } +} + +void OVersatileView::setIconViewMode() +{ + setViewMode( Icons ); +} + +void OVersatileView::setTreeViewMode() +{ + setViewMode( Tree ); +} + +bool OVersatileView::isValidViewMode( int mode ) const +{ + switch ( _warningpolicy ) + { + case OVersatileView::None: + { + return true; + } + case OVersatileView::Warn: + { + if ( _viewmode != mode ) + { + qDebug( "OVersatileView::isValidViewMode(): Requested operation not valid in current mode." ); + return true; + } + } + case OVersatileView::WarnReturn: + { + if ( _viewmode != mode ) + { + qDebug( "OVersatileView::isValidViewMode(): Requested operation not valid in current mode." ); + return false; + } + } + default: + { + qWarning( "OVersatileView::isValidViewMode(): Inconsistent object state!" ); + return true; + } + } +} +void OVersatileView::setWarningPolicy( int policy ) const +{ + _warningpolicy = policy; +} +bool OVersatileView::warningPolicy() const +{ + return _warningpolicy; +} +//==============================================================================================// +// Stupid Signal forwarders... +// Folks, this is why I like python with its dynamic typing: +// I can code the following dozens of lines C++ in four Python lines... +//==============================================================================================// + +void OVersatileView::selectionChanged( QListViewItem * item ) +{ + emit( selectionChanged( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::selectionChanged( QIconViewItem * item ) +{ + emit( selectionChanged( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::currentChanged( QListViewItem * item ) +{ + emit( currentChanged( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::currentChanged( QIconViewItem * item ) +{ + emit( currentChanged( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::clicked( QListViewItem * item ) +{ + emit( clicked( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::clicked( QIconViewItem * item ) +{ + emit( clicked( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::pressed( QListViewItem * item ) +{ + emit( pressed( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::pressed( QIconViewItem * item ) +{ + emit( pressed( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::doubleClicked( QListViewItem * item ) +{ + emit( doubleClicked( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::doubleClicked( QIconViewItem * item ) +{ + emit( doubleClicked( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::returnPressed( QListViewItem * item ) +{ + emit( returnPressed( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::returnPressed( QIconViewItem * item ) +{ + emit( returnPressed( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::onItem( QListViewItem * item ) +{ + emit( onItem( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::onItem( QIconViewItem * item ) +{ + emit( onItem( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::expanded( QListViewItem *item ) // QListView +{ + //qDebug( "OVersatileView::expanded(): opening tree..." ); + if ( not _treeopened.isNull() ) + item->setPixmap( 0, _treeopened ); + emit( expanded( static_cast<OVersatileViewItem*>( item ) ) ); +} +void OVersatileView::collapsed( QListViewItem *item ) // QListView +{ + if ( not _treeclosed.isNull() ) + item->setPixmap( 0, _treeclosed ); + emit( collapsed( static_cast<OVersatileViewItem*>( item ) ) ); +} + +//=============================================================================================// +// OVersatileView Case I - API only existing in QListView or QIconView but not in both! +//==============================================================================================// + +int OVersatileView::treeStepSize() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->treeStepSize(); +} + void OVersatileView::setTreeStepSize( int size ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setTreeStepSize( size ); +} + +QHeader * OVersatileView::header() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return 0; + } + return _listview->header(); +} + + int OVersatileView::addColumn( const QString &label, int size ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->addColumn( label, size ); +} + + int OVersatileView::addColumn( const QIconSet& iconset, const QString &label, int size ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->addColumn( iconset, label, size ); +} + +void OVersatileView::removeColumn( int index ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->removeColumn( index ); +} + void OVersatileView::setColumnText( int column, const QString &label ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setColumnText( column, label ); +} + void OVersatileView::setColumnText( int column, const QIconSet& iconset, const QString &label ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setColumnText( column, iconset, label ); +} +QString OVersatileView::columnText( int column ) const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return QString::null; + } + return _listview->columnText( column ); +} + void OVersatileView::setColumnWidth( int column, int width ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setColumnWidth( column, width ); +} +int OVersatileView::columnWidth( int column ) const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->columnWidth( column ); +} + void OVersatileView::setColumnWidthMode( int column, WidthMode mode ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setColumnWidth( column, mode ); +} +int OVersatileView::columns() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->columns(); +} + + void OVersatileView::setColumnAlignment( int column, int align ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setColumnAlignment( column, align ); +} +int OVersatileView::columnAlignment( int column ) const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->columnAlignment( column ); +} + +OVersatileViewItem * OVersatileView::itemAt( const QPoint & screenPos ) const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _listview->itemAt( screenPos ) ); +} +QRect OVersatileView::itemRect( const OVersatileViewItem * item ) const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return QRect( -1, -1, -1, -1 ); + } + return _listview->itemRect( item ); +} +int OVersatileView::itemPos( const OVersatileViewItem * item ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->itemPos( item ); +} + +bool OVersatileView::isSelected( const OVersatileViewItem * item ) const // QListView // also in QIconViewItem but !in QIconView *shrug* +{ + if ( not isValidViewMode( Tree ) ) + { + return false; + } + return _listview->isSelected( item ); +} + + void OVersatileView::setMultiSelection( bool enable ) +{ + _listview->setMultiSelection( enable ); +} +bool OVersatileView::isMultiSelection() const +{ + return _listview->isMultiSelection(); +} + +OVersatileViewItem * OVersatileView::selectedItem() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _listview->selectedItem() ); +} + void OVersatileView::setOpen( OVersatileViewItem * item, bool open ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setOpen( item, open ); +} +bool OVersatileView::isOpen( const OVersatileViewItem * item ) const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return false; + } + return _listview->isOpen( item ); +} + +OVersatileViewItem * OVersatileView::firstChild() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _listview->firstChild() ); +} +int OVersatileView::childCount() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->childCount(); +} + + void OVersatileView::setAllColumnsShowFocus( bool focus ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setAllColumnsShowFocus( focus ); +} +bool OVersatileView::allColumnsShowFocus() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return false; + } + return _listview->allColumnsShowFocus(); +} + + void OVersatileView::setItemMargin( int margin ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setItemMargin( margin ); +} +int OVersatileView::itemMargin() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->itemMargin(); +} + + void OVersatileView::setRootIsDecorated( bool decorate ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setRootIsDecorated( decorate ); +} +bool OVersatileView::rootIsDecorated() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return false; + } + return _listview->rootIsDecorated(); +} + +void OVersatileView::setShowSortIndicator( bool show ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setShowSortIndicator( show ); +} +bool OVersatileView::showSortIndicator() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return false; + } + return _listview->showSortIndicator(); +} + +void OVersatileView::triggerUpdate() // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->triggerUpdate(); +} + +// +// only in QIconView +// + +uint OVersatileView::count() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return 0; + } + return _iconview->count(); +} + +int OVersatileView::index( const OVersatileViewItem *item ) const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return -1; + } + return _iconview->index( item ); +} + +OVersatileViewItem* OVersatileView::firstItem() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _iconview->firstItem() ); +} +OVersatileViewItem* OVersatileView::lastItem() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _iconview->lastItem() ); +} + +OVersatileViewItem* OVersatileView::findItem( const QPoint &pos ) const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _iconview->findItem( pos ) ); +} +OVersatileViewItem* OVersatileView::findItem( const QString &text ) const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _iconview->findItem( text ) ); +} + +OVersatileViewItem* OVersatileView::findFirstVisibleItem( const QRect &r ) const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _iconview->findFirstVisibleItem( r ) ); +} +OVersatileViewItem* OVersatileView::findLastVisibleItem( const QRect &r ) const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _iconview->findLastVisibleItem( r ) ); +} + + void OVersatileView::setGridX( int rx ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setGridX( rx ); +} + void OVersatileView::setGridY( int ry ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setGridY( ry ); +} +int OVersatileView::gridX() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return -1; + } + return _iconview->gridX(); +} +int OVersatileView::gridY() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return -1; + } + return _iconview->gridY(); +} + void OVersatileView::setSpacing( int sp ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setSpacing( sp ); +} +int OVersatileView::spacing() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return -1; + } + return _iconview->spacing(); +} + void OVersatileView::setItemTextPos( QIconView::ItemTextPos pos ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setItemTextPos( pos ); +} +QIconView::ItemTextPos OVersatileView::itemTextPos() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return (QIconView::ItemTextPos) -1; + } + return _iconview->itemTextPos(); +} + void OVersatileView::setItemTextBackground( const QBrush &b ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setItemTextBackground( b ); +} +QBrush OVersatileView::itemTextBackground() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return QBrush(); + } + return _iconview->itemTextBackground(); +} + void OVersatileView::setArrangement( QIconView::Arrangement am ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setArrangement( am ); +} +QIconView::Arrangement OVersatileView::arrangement() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return (QIconView::Arrangement) -1; + } + return _iconview->arrangement(); +} + void OVersatileView::setResizeMode( QIconView::ResizeMode am ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setResizeMode( am ); +} +QIconView::ResizeMode OVersatileView::resizeMode() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return (QIconView::ResizeMode) -1; + } + return _iconview->resizeMode(); +} + void OVersatileView::setMaxItemWidth( int w ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setMaxItemWidth( w ); +} +int OVersatileView::maxItemWidth() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return -1; + } + return _iconview->maxItemWidth(); +} + void OVersatileView::setMaxItemTextLength( int w ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setMaxItemTextLength( w ); +} +int OVersatileView::maxItemTextLength() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return -1; + } + return _iconview->maxItemTextLength(); +} + void OVersatileView::setAutoArrange( bool b ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setAutoArrange( b ); +} +bool OVersatileView::autoArrange() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return false; + } + return _iconview->autoArrange(); +} + void OVersatileView::setShowToolTips( bool b ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setShowToolTips( b ); +} +bool OVersatileView::showToolTips() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return false; + } + return _iconview->showToolTips(); +} + +bool OVersatileView::sorting() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return false; + } + return _iconview->sorting(); +} +bool OVersatileView::sortDirection() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return false; + } + return _iconview->sortDirection(); +} + + void OVersatileView::setItemsMovable( bool b ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setItemsMovable( b ); +} +bool OVersatileView::itemsMovable() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return false; + } + return _iconview->itemsMovable(); +} +void OVersatileView::setWordWrapIconText( bool b ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setWordWrapIconText( b ); +} +bool OVersatileView::wordWrapIconText() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return false; + } + return _iconview->wordWrapIconText(); +} + +void OVersatileView::arrangeItemsInGrid( const QSize &grid, bool update ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->arrangeItemsInGrid( grid, update ); +} +void OVersatileView::arrangeItemsInGrid( bool update ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->arrangeItemsInGrid( update ); +} +void OVersatileView::updateContents() // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->updateContents(); +} + +//==============================================================================================// +// OVersatileView Case II - QListView / QIconView common API +//==============================================================================================// + +void OVersatileView::clear() +{ + _iconview->clear(); + _listview->clear(); +} + +void OVersatileView::setFont( const QFont & font ) +{ + _iconview->setFont( font ); + _listview->setFont( font ); +} +void OVersatileView::setPalette( const QPalette & palette ) +{ + _iconview->setPalette( palette ); + _listview->setPalette( palette ); +} + +void OVersatileView::takeItem( OVersatileViewItem * item ) +{ + _iconview->takeItem( item ); + _listview->takeItem( item ); +} + +void OVersatileView::setSelectionMode( SelectionMode mode ) +{ + _iconview->setSelectionMode( (QIconView::SelectionMode) mode ); + _listview->setSelectionMode( (QListView::SelectionMode) mode ); +} +OVersatileView::SelectionMode OVersatileView::selectionMode() const +{ + return (OVersatileView::SelectionMode) _iconview->selectionMode(); +} + +void OVersatileView::selectAll( bool select ) +{ + _iconview->selectAll( select ); +} +void OVersatileView::clearSelection() +{ + _iconview->clearSelection(); + _listview->clearSelection(); +} +void OVersatileView::invertSelection() +{ + _iconview->invertSelection(); + _listview->invertSelection(); +} + +void OVersatileView::ensureItemVisible( const OVersatileViewItem * item ) +{ + _iconview->ensureItemVisible( const_cast<OVersatileViewItem*>( item ) ); + _listview->ensureItemVisible( item ); +} +void OVersatileView::repaintItem( const OVersatileViewItem * item ) const +{ + _iconview->repaintItem( const_cast<OVersatileViewItem*>( item ) ); + _listview->repaintItem( item ); +} + +void OVersatileView::setCurrentItem( OVersatileViewItem * item ) +{ + _iconview->setCurrentItem( item ); + _listview->setCurrentItem( item ); +} +OVersatileViewItem * OVersatileView::currentItem() const +{ + return static_cast<OVersatileViewItem*>( _listview->currentItem() ); +} + +// bool eventFilter( QObject * o, QEvent * ) // use QWidgetStack implementation + +// QSize minimumSizeHint() const // use QWidgetStack implementation +// QSizePolicy sizePolicy() const // use QWidgetStack implementation +// QSize sizeHint() const // use QWidgetStack implementation + +//==============================================================================================// +// OVersatileView Case III - APIs which differ slightly +//==============================================================================================// + +/* + + void OVersatileView::insertItem( OVersatileViewItem * ) // QListView + void OVersatileView::insertItem( OVersatileViewItem *item, OVersatileViewItem *after = 0L ) // QIconView + + void OVersatileView::setSelected( OVersatileViewItem *, bool ) // QListView + void OVersatileView::setSelected( OVersatileViewItem *item, bool s, bool cb = FALSE ) // QIconView + + void OVersatileView::setSorting( int column, bool increasing = TRUE ) // QListView +void OVersatileView::setSorting( bool sort, bool ascending = TRUE ) // QIconView + +void OVersatileView::sort() // #### make in next major release // QListView + void OVersatileView::sort( bool ascending = TRUE ) // QIconView + +*/ + + diff --git a/libopie2/opieui/oversatileview.h b/libopie2/opieui/oversatileview.h new file mode 100644 index 0000000..1df8154 --- a/dev/null +++ b/libopie2/opieui/oversatileview.h @@ -0,0 +1,394 @@ +/* + This file is part of the Opie Project + + =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + .=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 OVERSATILEVIEW_H +#define OVERSATILEVIEW_H + +/* QT */ + +#include <qwidgetstack.h> +#include <qiconview.h> + +/* OPIE */ + +#include <qpe/qpeapplication.h> + +/* FORWARDS */ + +class QHeader; +class QIconSet; +class QIconViewItem; +class OListView; +class QListViewItem; +class QPopupMenu; +class QString; + +#ifndef QT_NO_DRAGANDDROP +class QIconDragItem; +#endif + +class OVersatileView : public QWidgetStack +{ + Q_OBJECT + + friend class OVersatileViewItem; + + //==============================================================================================// + // OVersatileView High Level API + //==============================================================================================// + + public: + OVersatileView( QWidget* parent = 0, const char* name = 0, int mode = 0 ); + ~OVersatileView(); + + QPopupMenu* contextMenu() const; + + void setSynchronization( bool sync ); + bool synchronization(); + + enum ViewMode { Tree = 0, Icons }; + int viewMode(); + + QIconView* iconView() const; + OListView* listView() const; + + enum WarningPolicy { None = 0, Warn, WarnReturn }; + + void setWarningPolicy( int ) const; // warn, if calling a method which doesn't apply to the current viewmode + bool warningPolicy() const; + + void setDefaultPixmaps( int mode, QPixmap& leaf, QPixmap& opened, QPixmap& closed ); + + public slots: + void setViewMode( int mode ); + void setIconViewMode(); + void setTreeViewMode(); + + protected: + virtual bool isValidViewMode( int mode ) const; + virtual void popupContextMenu( OVersatileViewItem* item, const QPoint& pos, int col = 0 ); + + private: + int _viewmode; + bool _synchronization; + mutable int _warningpolicy; + + OListView* _listview; + QIconView* _iconview; + + QPixmap _treeleaf; + QPixmap _treeopened; + QPixmap _treeclosed; + + QPixmap _iconleaf; + QPixmap _iconopened; + QPixmap _iconclosed; + + QPopupMenu* _contextmenu; + + int _iconstyle; + int _treestyle; + + private slots: + + void contextMenuRequested( QListViewItem*, const QPoint&, int ); + void contextMenuRequested( QIconViewItem*, const QPoint& ); + + // type converting signal forwarders + + void selectionChanged( QListViewItem * ); + void currentChanged( QListViewItem * ); + void clicked( QListViewItem * ); + void pressed( QListViewItem * ); + void doubleClicked( QListViewItem * ); + void returnPressed( QListViewItem * ); + void onItem( QListViewItem * ); + + void selectionChanged( QIconViewItem * ); + void currentChanged( QIconViewItem * ); + void clicked( QIconViewItem * ); + void pressed( QIconViewItem * ); + void doubleClicked( QIconViewItem * ); + void returnPressed( QIconViewItem * ); + void onItem( QIconViewItem * ); + + void expanded( QListViewItem * item ); // QListView + void collapsed( QListViewItem * item ); // QListView + + signals: + + void contextMenuRequested( OVersatileViewItem * item, const QPoint& pos, int col ); + + /*#ifndef QT_NO_DRAGANDDROP + void dropped( QDropEvent *e, const QValueList<QIconDragItem> &lst ); // QIconView + #endif + void itemRenamed( OVersatileViewItem *item, const QString & ); // QIconView + void itemRenamed( OVersatileViewItem *item ); // QIconView + */ + + //==============================================================================================// + // "Derived" API - Case 1: Methods existing either only in QListView or only in QIconView + //==============================================================================================// + +public: + + /* + enum Arrangement { // QIconView + LeftToRight = 0, + TopToBottom + }; + enum ResizeMode { // QIconView + Fixed = 0, + Adjust + }; + enum ItemTextPos { // QIconView + Bottom = 0, + Right + }; + */ + + // + // only in QListView + // + + int treeStepSize() const; // QListView + virtual void setTreeStepSize( int ); // QListView + + QHeader * header() const; // QListView + + virtual int addColumn( const QString &label, int size = -1); // QListView + virtual int addColumn( const QIconSet& iconset, const QString &label, int size = -1); // QListView + void removeColumn( int index ); // #### make virtual in next major release! // QListView + virtual void setColumnText( int column, const QString &label ); // QListView + virtual void setColumnText( int column, const QIconSet& iconset, const QString &label ); // QListView + QString columnText( int column ) const; // QListView + virtual void setColumnWidth( int column, int width ); // QListView + int columnWidth( int column ) const; // QListView + enum WidthMode { Manual, Maximum }; // QListView + virtual void setColumnWidthMode( int column, WidthMode ); // QListView + WidthMode columnWidthMode( int column ) const; // QListView + int columns() const; // QListView + + virtual void setColumnAlignment( int, int ); // QListView + int columnAlignment( int ) const; // QListView + + OVersatileViewItem * itemAt( const QPoint & screenPos ) const; // QListView + QRect itemRect( const OVersatileViewItem * ) const; // QListView + int itemPos( const OVersatileViewItem * ); // QListView + + bool isSelected( const OVersatileViewItem * ) const; // QListView // also in QIconViewItem but not in QIconView *shrug* + + virtual void setMultiSelection( bool enable ); // QListView + bool isMultiSelection() const; // QListView + + OVersatileViewItem * selectedItem() const; // QListView + virtual void setOpen( OVersatileViewItem *, bool ); // QListView + bool isOpen( const OVersatileViewItem * ) const; // QListView + + OVersatileViewItem * firstChild() const; // QListView + int childCount() const; // QListView + + virtual void setAllColumnsShowFocus( bool ); // QListView + bool allColumnsShowFocus() const; // QListView + + virtual void setItemMargin( int ); // QListView + int itemMargin() const; // QListView + + virtual void setRootIsDecorated( bool ); // QListView + bool rootIsDecorated() const; // QListView + + void setShowSortIndicator( bool show ); // QListView + bool showSortIndicator() const; // QListView + + int index( const OVersatileViewItem *item ) const; // QIconView + + public slots: + void triggerUpdate(); // QListView + + signals: + void expanded( OVersatileViewItem *item ); // QListView + void collapsed( OVersatileViewItem *item ); // QListView + + // + // only in QIconView + // + + public: + uint count() const; // QIconView + + OVersatileViewItem *firstItem() const; // QIconView + OVersatileViewItem *lastItem() const; // QIconView + + OVersatileViewItem *findItem( const QPoint &pos ) const; // QIconView + OVersatileViewItem *findItem( const QString &text ) const; // QIconView + + OVersatileViewItem* findFirstVisibleItem( const QRect &r ) const; // QIconView + OVersatileViewItem* findLastVisibleItem( const QRect &r ) const; // QIconView + + virtual void setGridX( int rx ); // QIconView + virtual void setGridY( int ry ); // QIconView + int gridX() const; // QIconView + int gridY() const; // QIconView + virtual void setSpacing( int sp ); // QIconView + int spacing() const; // QIconView + virtual void setItemTextPos( QIconView::ItemTextPos pos ); // QIconView + QIconView::ItemTextPos itemTextPos() const; // QIconView + virtual void setItemTextBackground( const QBrush &b ); // QIconView + QBrush itemTextBackground() const; // QIconView + virtual void setArrangement( QIconView::Arrangement am ); // QIconView + QIconView::Arrangement arrangement() const; // QIconView + virtual void setResizeMode( QIconView::ResizeMode am ); // QIconView + QIconView::ResizeMode resizeMode() const; // QIconView + virtual void setMaxItemWidth( int w ); // QIconView + int maxItemWidth() const; // QIconView + virtual void setMaxItemTextLength( int w ); // QIconView + int maxItemTextLength() const; // QIconView + virtual void setAutoArrange( bool b ); // QIconView + bool autoArrange() const; // QIconView + virtual void setShowToolTips( bool b ); // QIconView + bool showToolTips() const; // QIconView + + bool sorting() const; // QIconView + bool sortDirection() const; // QIconView + + virtual void setItemsMovable( bool b ); // QIconView + bool itemsMovable() const; // QIconView + virtual void setWordWrapIconText( bool b ); // QIconView + bool wordWrapIconText() const; // QIconView + + public slots: + virtual void arrangeItemsInGrid( const QSize &grid, bool update = TRUE ); // QIconView + virtual void arrangeItemsInGrid( bool update = TRUE ); // QIconView + virtual void updateContents(); // QIconView + + signals: + /*#ifndef QT_NO_DRAGANDDROP + void dropped( QDropEvent *e, const QValueList<QIconDragItem> &lst ); // QIconView + #endif + */ + void moved(); // QIconView + void itemRenamed( OVersatileViewItem *item, const QString & ); // QIconView + void itemRenamed( OVersatileViewItem *item ); // QIconView + + //==============================================================================================// + // "Derived" API - Case 2: Methods existing in QListView and QIconView with the same signatures + //==============================================================================================// + + public: + enum SelectionMode { + Single = 0, + Multi, + Extended, + NoSelection + }; + + virtual void clear(); + + virtual void setFont( const QFont & ); + virtual void setPalette( const QPalette & ); + + virtual void takeItem( OVersatileViewItem * ); + + void setSelectionMode( SelectionMode mode ); + SelectionMode selectionMode() const; + + virtual void selectAll( bool select ); + virtual void clearSelection(); + virtual void invertSelection(); + + void ensureItemVisible( const OVersatileViewItem * ); + virtual void repaintItem( const OVersatileViewItem * ) const; + + virtual void setCurrentItem( OVersatileViewItem * ); + OVersatileViewItem * currentItem() const; + + // bool eventFilter( QObject * o, QEvent * ); // use QWidgetStack implementation + + // QSize minimumSizeHint() const; // use QWidgetStack implementation + // QSizePolicy sizePolicy() const; // use QWidgetStack implementation + // QSize sizeHint() const; // use QWidgetStack implementation + + signals: + void selectionChanged(); + void selectionChanged( OVersatileViewItem * ); + void currentChanged( OVersatileViewItem * ); + void clicked( OVersatileViewItem * ); + void pressed( OVersatileViewItem * ); + + void doubleClicked( OVersatileViewItem * ); + void returnPressed( OVersatileViewItem * ); + + void onItem( OVersatileViewItem * ); + void onViewport(); + + //==============================================================================================// + // "Derived" API - Case 2: Methods existing in QListView and QIconView with differing signatures + //==============================================================================================// + + /* + + public: + virtual void insertItem( OVersatileViewItem * ); // QListView + virtual void insertItem( OVersatileViewItem *item, OVersatileViewItem *after = 0L ); // QIconView + + virtual void setSelected( OVersatileViewItem *, bool ); // QListView + virtual void setSelected( OVersatileViewItem *item, bool s, bool cb = FALSE ); // QIconView + + virtual void setSorting( int column, bool increasing = TRUE ); // QListView + void setSorting( bool sort, bool ascending = TRUE ); // QIconView + + void sort(); // #### make virtual in next major release // QListView + virtual void sort( bool ascending = TRUE ); // QIconView + + */ + + signals: + void clicked( OVersatileViewItem *, const QPoint &, int ); // QListView + void clicked( OVersatileViewItem *, const QPoint & ); // QIconView + + void pressed( OVersatileViewItem *, const QPoint &, int ); // QListView + void pressed( OVersatileViewItem *, const QPoint & ); // QIconView + + void rightButtonClicked( OVersatileViewItem* item, const QPoint& pos ); // QIconView + void rightButtonClicked( OVersatileViewItem *, const QPoint&, int ); // QListView + + void rightButtonPressed( OVersatileViewItem* item, const QPoint& pos ); // QIconView + void rightButtonPressed( OVersatileViewItem *, const QPoint&, int ); // QListView + + void mouseButtonPressed( int, OVersatileViewItem *, const QPoint& , int ); // QListView + void mouseButtonPressed( int button, OVersatileViewItem* item, const QPoint& pos ); // QIconView + + void mouseButtonClicked( int, OVersatileViewItem *, const QPoint&, int ); // QListView + void mouseButtonClicked( int button, OVersatileViewItem* item, const QPoint& pos ); // QIconView + +}; + +#endif + diff --git a/libopie2/opieui/oversatileviewitem.cpp b/libopie2/opieui/oversatileviewitem.cpp new file mode 100644 index 0000000..379ce24 --- a/dev/null +++ b/libopie2/opieui/oversatileviewitem.cpp @@ -0,0 +1,132 @@ +/* + This file is part of the Opie Project + + =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + .=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/oversatileviewitem.h> +#include <opie2/oversatileview.h> + +OVersatileViewItem::OVersatileViewItem( OVersatileView * parent ) + :OListViewItem( parent->_listview ), QIconViewItem( parent->_iconview ), + _versatileview( parent ) +{ + init(); +} + +OVersatileViewItem::OVersatileViewItem( OVersatileView * parent, OVersatileViewItem * after ) + :OListViewItem( parent->_listview, after ), QIconViewItem( parent->_iconview, after ), + _versatileview( parent ) +{ + init(); +} + +OVersatileViewItem::OVersatileViewItem( OVersatileView * parent, + QString a, QString b, QString c, QString d, + QString e, QString f, QString g, QString h ) + :OListViewItem( parent->_listview, a, b, c, d, e, f, g, h ), + QIconViewItem( parent->_iconview, a ), + _versatileview( parent ) +{ + init(); +} + +OVersatileViewItem::OVersatileViewItem( OVersatileView * parent, OVersatileViewItem* after, + QString a, QString b, QString c, QString d, + QString e, QString f, QString g, QString h ) + :OListViewItem( parent->_listview, after, a, b, c, d, e, f, g, h ), + QIconViewItem( parent->_iconview, after, a ), + _versatileview( parent ) +{ + init(); +} + +OVersatileViewItem::OVersatileViewItem( OVersatileViewItem * parent, + QString a, QString b, QString c, QString d, + QString e, QString f, QString g, QString h ) + :OListViewItem( parent, a, b, c, d, e, f, g, h ), + QIconViewItem( parent->_versatileview->_iconview, a ), + _versatileview( parent->_versatileview ) +{ + init(); +} + +OVersatileViewItem::OVersatileViewItem( OVersatileViewItem * parent, OVersatileViewItem* after, + QString a, QString b, QString c, QString d, + QString e, QString f, QString g, QString h ) + :OListViewItem( parent, after, a, b, c, d, e, f, g, h ), + QIconViewItem( parent->_versatileview->_iconview, after, a ), + _versatileview( parent->_versatileview ) +{ + init(); +} + +OVersatileViewItem::~OVersatileViewItem() +{ +} + +OVersatileView* OVersatileViewItem::versatileView() const +{ + return _versatileview; +} + +void OVersatileViewItem::init() +{ + if ( not firstChild() ) + { + // I'm a sweet yellow and browne autumn leaf + + OListViewItem::setPixmap( 0, _versatileview->_treeleaf ); + QIconViewItem::setPixmap( _versatileview->_iconleaf ); + } + else + { + // I'm a node and I have a little baby child + + if ( isOpen() ) + { + OListViewItem::setPixmap( 0, _versatileview->_treeopened ); + QIconViewItem::setPixmap( _versatileview->_iconopened ); + } + else + { + OListViewItem::setPixmap( 0, _versatileview->_treeclosed ); + QIconViewItem::setPixmap( _versatileview->_iconclosed ); + } + } + +} + +void OVersatileViewItem::setRenameEnabled( bool allow ) +{ + #if (QT_VERSION >= 0x030000) + OListViewItem::setRenameEnabled( 0, allow ); // TODO: Backport to Qt-Embedded 2.x? + #endif + QIconViewItem::setRenameEnabled( allow ); +} + + diff --git a/libopie2/opieui/oversatileviewitem.h b/libopie2/opieui/oversatileviewitem.h new file mode 100644 index 0000000..ee8ee20 --- a/dev/null +++ b/libopie2/opieui/oversatileviewitem.h @@ -0,0 +1,100 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=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 OVERSATILEVIEWITEM_H +#define OVERSATILEVIEWITEM_H + +/* QT */ + +#include <qiconview.h> + +/* OPIE */ + +#include <opie2/olistview.h> + +class OVersatileView; + +class OVersatileViewItem : public OListViewItem, public QIconViewItem +{ + public: + OVersatileViewItem( OVersatileView * parent ); + + OVersatileViewItem( OVersatileView * parent, OVersatileViewItem * after ); + + OVersatileViewItem( OVersatileViewItem * parent, OVersatileViewItem * after ); + + OVersatileViewItem( OVersatileView * parent, QString, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null ); + + OVersatileViewItem( OVersatileViewItem * parent, QString, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null ); + + OVersatileViewItem( OVersatileView * parent, OVersatileViewItem * after, QString, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null ); + + OVersatileViewItem( OVersatileViewItem * parent, OVersatileViewItem * after, QString, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null ); + + virtual ~OVersatileViewItem(); + + OVersatileView* versatileView() const; + + // TODO: Implement the remaining constructors from QIconView + + /* OIconViewItem( QIconView *parent, const QString &text, const QPixmap &icon ); + OIconViewItem( QIconView *parent, QIconViewItem *after, const QString &text, const QPixmap &icon ); + */ + + virtual void setRenameEnabled( bool ); + + // TODO: Implement the remaining method multiplexers + + private: + OVersatileView* _versatileview; + + private: + void init(); + +}; + +#endif diff --git a/libopie2/pics/view_icon.png b/libopie2/pics/view_icon.png Binary files differnew file mode 100644 index 0000000..4ae49f4 --- a/dev/null +++ b/libopie2/pics/view_icon.png diff --git a/libopie2/pics/view_icon.xpm b/libopie2/pics/view_icon.xpm new file mode 100644 index 0000000..70cb833 --- a/dev/null +++ b/libopie2/pics/view_icon.xpm @@ -0,0 +1,35 @@ +/* XPM */ +static char * view_icon_xpm[] = { +"16 16 16 1", +" c None", +". c #87BD88", +"+ c #8BBE8B", +"@ c #81BA81", +"# c #6DAF6D", +"$ c #87BD87", +"% c #FCFDFC", +"& c #AED0AE", +"* c #4E9C4C", +"= c #91BD91", +"- c #72B172", +"; c #448643", +"> c #519F50", +", c #499247", +"' c #356A35", +") c #686868", +" ", +" .+@# .+@# ", +" $%&* $%&* ", +" @=-; @=-; ", +" #>,' #>,' ", +" ", +" )))))) )))))) ", +" ", +" ", +" .+@# .+@# ", +" $%&* $%&* ", +" @=-; @=-; ", +" #>,' #>,' ", +" ", +" )))))) )))))) ", +" "}; diff --git a/libopie2/pics/view_tree.png b/libopie2/pics/view_tree.png Binary files differnew file mode 100644 index 0000000..192d25e --- a/dev/null +++ b/libopie2/pics/view_tree.png diff --git a/libopie2/pics/view_tree.xpm b/libopie2/pics/view_tree.xpm new file mode 100644 index 0000000..de819c0 --- a/dev/null +++ b/libopie2/pics/view_tree.xpm @@ -0,0 +1,36 @@ +/* XPM */ +static char * view_tree_xpm[] = { +"16 16 17 1", +" c None", +". c #3A3A3A", +"+ c #87BD88", +"@ c #8BBE8B", +"# c #81BA81", +"$ c #6DAF6D", +"% c #87BD87", +"& c #FCFDFC", +"* c #AED0AE", +"= c #4E9C4C", +"- c #91BD91", +"; c #72B172", +"> c #448643", +", c #686868", +"' c #519F50", +") c #499247", +"! c #356A35", +" . ", +" . ", +" . +@#$ ", +" . %&*= ", +" .. #-;> ,, ,,,", +" . $')! ", +" . ", +" . ", +" . ", +" . +@#$ ", +" . %&*= ", +" .. #-;> ,, ,,,", +" $')! ", +" ", +" ", +" "}; 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 |