diff options
Diffstat (limited to 'src/knemod')
58 files changed, 7027 insertions, 0 deletions
diff --git a/src/knemod/Makefile.am b/src/knemod/Makefile.am new file mode 100644 index 0000000..a9496bc --- /dev/null +++ b/src/knemod/Makefile.am @@ -0,0 +1,47 @@ +## Makefile.am for knemo + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/knemod.pot + +# this has all of the subdirectories that make will recurse into. if +# there are none, comment this out +SUBDIRS = pics backends + +# this is the program that gets installed. it's name is used for all +# of the other Makefile.am variables +kde_module_LTLIBRARIES = kded_knemod.la + +# set the include path for X, qt and KDE +INCLUDES = -I$(srcdir)/../common -I$(srcdir)/backends $(all_includes) + +# the library search path. +kded_knemod_la_LDFLAGS = -module -avoid-version $(all_libraries) + +# the libraries to link against. +kded_knemod_la_LIBADD = $(LIB_KIO) $(LIB_KUTILS) backends/libknemo_backends.la + +# which sources should be compiled for knemo +kded_knemod_la_SOURCES = knemodaemon.cpp knemodaemon.skel interface.cpp \ + interfaceicon.cpp interfacetray.cpp \ + interfacemonitor.cpp \ + interfacestatusdlg.ui interfacestatusdialog.cpp \ + interfacetooltip.cpp signalplotter.cpp \ + interfacestatistics.cpp interfacestatisticsdlg.ui \ + interfacestatisticsdialog.cpp + +# these are the headers for your project +noinst_HEADERS = knemodaemon.h interface.h interfaceicon.h \ + interfacemonitor.h \ + interfacestatusdialog.h interfacetray.h \ + interfacetooltip.h signalplotter.h \ + interfacestatistics.h global.h \ + interfacestatisticsdialog.h + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +services_DATA = knemod.desktop +servicesdir = $(kde_servicesdir)/kded + +mydata_DATA = eventsrc +mydatadir = $(kde_datadir)/knemo diff --git a/src/knemod/backends/Makefile.am b/src/knemod/backends/Makefile.am new file mode 100644 index 0000000..aab0fd0 --- /dev/null +++ b/src/knemod/backends/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for knemo backends + +noinst_LTLIBRARIES = libknemo_backends.la + +# set the include path for X, qt and KDE +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../../common $(all_includes) + +# the library search path. +libknemo_backends_la_LDFLAGS = -module -avoid-version $(all_libraries) + +# the libraries to link against. +libknemo_backends_la_LIBADD = $(LIB_KIO) $(LIB_KUTILS) + +# which sources should be compiled as backends +libknemo_backends_la_SOURCES = backendbase.cpp nettoolsbackend.cpp sysbackend.cpp + +# the headers of the backends +noinst_HEADERS = backendbase.h nettoolsbackend.h sysbackend.h + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + diff --git a/src/knemod/backends/backendbase.cpp b/src/knemod/backends/backendbase.cpp new file mode 100644 index 0000000..82da372 --- /dev/null +++ b/src/knemod/backends/backendbase.cpp @@ -0,0 +1,38 @@ +/* This file is part of KNemo + Copyright (C) 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "backendbase.h" + +BackendBase::BackendBase( QDict<Interface>& interfaces ) + : mInterfaces( interfaces ) +{ +} + +BackendBase::~BackendBase() +{ +} + +void BackendBase::updateComplete() +{ + QDictIterator<Interface> ifIt( mInterfaces ); + for ( ; ifIt.current(); ++ifIt ) + { + ifIt.current()->activateMonitor(); + } +} diff --git a/src/knemod/backends/backendbase.h b/src/knemod/backends/backendbase.h new file mode 100644 index 0000000..183e40a --- /dev/null +++ b/src/knemod/backends/backendbase.h @@ -0,0 +1,68 @@ +/* This file is part of KNemo + Copyright (C) 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef BACKENDBASE_H +#define BACKENDBASE_H + +#include <qdict.h> +#include <qstring.h> + +#include <klocale.h> + +#include "data.h" +#include "interface.h" + +/** + * This is the baseclass for all backends. Every backend that + * should be used for KNemo must inherit from this class. + * + * @short Baseclass for all backends + * @author Percy Leonhardt <[email protected]> + */ + +class BackendBase +{ +public: + BackendBase( QDict<Interface>& interfaces ); + virtual ~BackendBase(); + + /** + * Create an instance of this backend because KNemo + * does not know about the different types of backends. + */ + + /** + * This function is called from KNemo whenever the + * backend shall update the information of the + * interfaces in the QDict. + */ + virtual void update() = 0; + +protected: + /** + * Call this function when you have completed the + * update. It will trigger the interfaces to check + * if there state has changed. + */ + void updateComplete(); + + const QDict<Interface>& mInterfaces; +}; + +#endif // BACKENDBASE_H diff --git a/src/knemod/backends/daemonregistry.h b/src/knemod/backends/daemonregistry.h new file mode 100644 index 0000000..ba4638d --- /dev/null +++ b/src/knemod/backends/daemonregistry.h @@ -0,0 +1,54 @@ +/* This file is part of KNemo + Copyright (C) 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef DAEMONREGISTRY_H +#define DAEMONREGISTRY_H + +#include <qstring.h> + +#include <klocale.h> + +#include "backendbase.h" +#include "sysbackend.h" +#include "nettoolsbackend.h" + +/** + * This registry tells KNemo what backends are available + * and how they can be created. It is only used by the daemon + * to create the selected backend. Two registries were + * necessary to avoid linking the KCM module against all backends. + * + * @short Registry for all backends + * @author Percy Leonhardt <[email protected]> + */ + +struct DaemonRegistryEntry +{ + QString name; + BackendBase* (*function) ( QDict<Interface>& ); +}; + +DaemonRegistryEntry DaemonRegistry[] = +{ + { "Nettools", NetToolsBackend::createInstance }, + { "Sys", SysBackend::createInstance }, + { QString::null, 0 } +}; + +#endif // DAEMONREGISTRY_H diff --git a/src/knemod/backends/kcmregistry.h b/src/knemod/backends/kcmregistry.h new file mode 100644 index 0000000..23820ac --- /dev/null +++ b/src/knemod/backends/kcmregistry.h @@ -0,0 +1,61 @@ +/* This file is part of KNemo + Copyright (C) 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCMREGISTRY_H +#define KCMREGISTRY_H + +#include <qstring.h> + +#include <klocale.h> + +/** + * This registry tells the KCM module what backends are available + * and how they can be created. It also offers a short description + * for every backend that is used in the configuration dialog of KNemo. + * It should describe how a backend gathers its information. + * + * @short Registry for all backends + * @author Percy Leonhardt <[email protected]> + */ + +struct KCMRegistryEntry +{ + QString name; + QString description; +}; + +KCMRegistryEntry KCMRegistry[] = +{ + { "Nettools", + i18n( "Uses the tools from the nettool packge like ifconfig, " \ + "iwconfig and route to read the necessary information " \ + "from the ouput of these commands.\n" \ + "This backend works rather stable but causes a relativly " \ + "high CPU load." ) }, + { "Sys", + i18n( "Uses the sys filesystem available in 2.6 kernels and " \ + "direct system calls to the Linux kernel.\n" \ + "This backend is rather new, so expect minor problems. " \ + "As an advantage this backend should reduce the CPU load " \ + "and should not access the harddisc while gathering " \ + "information." ) }, + { QString::null, QString::null } +}; + +#endif // KCMREGISTRY_H diff --git a/src/knemod/backends/nettoolsbackend.cpp b/src/knemod/backends/nettoolsbackend.cpp new file mode 100644 index 0000000..dca42e1 --- /dev/null +++ b/src/knemod/backends/nettoolsbackend.cpp @@ -0,0 +1,498 @@ +/* This file is part of KNemo + Copyright (C) 2004, 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qmap.h> +#include <qregexp.h> +#include <qstringlist.h> + +#include <kdebug.h> +#include <kprocess.h> +#include <kio/global.h> + +#include "nettoolsbackend.h" + +#include "config.h" + +NetToolsBackend::NetToolsBackend( QDict<Interface>& interfaces ) + : QObject(), + BackendBase( interfaces ), + mRouteProcess(0L), + mIfconfigProcess(0L), + mIwconfigProcess(0L) +{ +} + +NetToolsBackend::~NetToolsBackend() +{ + if ( mRouteProcess ) + { + mRouteProcess->kill(); + delete mRouteProcess; + } + if ( mIfconfigProcess ) + { + mIfconfigProcess->kill(); + delete mIfconfigProcess; + } + if ( mIwconfigProcess ) + { + mIwconfigProcess->kill(); + delete mIwconfigProcess; + } +} + +BackendBase* NetToolsBackend::createInstance( QDict<Interface>& interfaces ) +{ + return new NetToolsBackend( interfaces ); +} + +void NetToolsBackend::update() +{ + if ( !mIfconfigProcess ) + { + mIfconfigStdout = QString::null; + mIfconfigProcess = new KProcess(); + mIfconfigProcess->setEnvironment( "LANG", "C" ); + mIfconfigProcess->setEnvironment( "LC_ALL", "C" ); + *mIfconfigProcess << PATH_IFCONFIG << "-a"; + connect( mIfconfigProcess, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + this, SLOT( ifconfigProcessStdout( KProcess*, char*, int ) ) ); + connect( mIfconfigProcess, SIGNAL( processExited( KProcess* ) ), + this, SLOT( ifconfigProcessExited( KProcess* ) ) ); + + if ( !mIfconfigProcess->start( KProcess::NotifyOnExit, KProcess::Stdout ) ) + { + delete mIfconfigProcess; + mIfconfigProcess = 0L; + } + } + +#ifdef PATH_IWCONFIG + if ( !mIwconfigProcess ) + { + mIwconfigStdout = QString::null; + mIwconfigProcess = new KProcess(); + mIwconfigProcess->setEnvironment( "LANG", "C" ); + mIwconfigProcess->setEnvironment( "LC_ALL", "C" ); + *mIwconfigProcess << PATH_IWCONFIG; + connect( mIwconfigProcess, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + this, SLOT( iwconfigProcessStdout( KProcess*, char*, int ) ) ); + connect( mIwconfigProcess, SIGNAL( receivedStderr( KProcess*, char*, int ) ), + this, SLOT( iwconfigProcessStdout( KProcess*, char*, int ) ) ); + connect( mIwconfigProcess, SIGNAL( processExited( KProcess* ) ), + this, SLOT( iwconfigProcessExited( KProcess* ) ) ); + + if ( !mIwconfigProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + delete mIwconfigProcess; + mIwconfigProcess = 0L; + } + } +#endif + +#ifdef PATH_ROUTE + if ( !mRouteProcess ) + { + mRouteStdout = QString::null; + mRouteProcess = new KProcess(); + mRouteProcess->setEnvironment( "LANG", "C" ); + mRouteProcess->setEnvironment( "LC_ALL", "C" ); + *mRouteProcess << PATH_ROUTE << "-n"; + connect( mRouteProcess, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + this, SLOT( routeProcessStdout( KProcess*, char*, int ) ) ); + connect( mRouteProcess, SIGNAL( receivedStderr( KProcess*, char*, int ) ), + this, SLOT( routeProcessStdout( KProcess*, char*, int ) ) ); + connect( mRouteProcess, SIGNAL( processExited( KProcess* ) ), + this, SLOT( routeProcessExited( KProcess* ) ) ); + + if ( !mRouteProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + delete mRouteProcess; + mRouteProcess = 0L; + } + } +#endif +} + +void NetToolsBackend::routeProcessExited( KProcess* process ) +{ + if ( process == mRouteProcess ) + { + mRouteProcess->deleteLater(); // we're in a slot connected to mRouteProcess + mRouteProcess = 0L; + parseRouteOutput(); + } +} + +void NetToolsBackend::routeProcessStdout( KProcess*, char* buffer, int buflen ) +{ + mRouteStdout += QString::fromLatin1( buffer, buflen ); +} + +void NetToolsBackend::ifconfigProcessExited( KProcess* process ) +{ + if ( process == mIfconfigProcess ) + { + delete mIfconfigProcess; + mIfconfigProcess = 0L; + parseIfconfigOutput(); + } +} + +void NetToolsBackend::ifconfigProcessStdout( KProcess*, char* buffer, int buflen ) +{ + mIfconfigStdout += QString::fromLatin1( buffer, buflen ); +} + +void NetToolsBackend::iwconfigProcessExited( KProcess* process ) +{ + if ( process == mIwconfigProcess ) + { + delete mIwconfigProcess; + mIwconfigProcess = 0L; + parseIwconfigOutput(); + } +} + +void NetToolsBackend::iwconfigProcessStdout( KProcess*, char* buffer, int buflen ) +{ + mIwconfigStdout += QString::fromLatin1( buffer, buflen ); +} + +void NetToolsBackend::parseIfconfigOutput() +{ + /* mIfconfigStdout contains the complete output of 'ifconfig' which we + * are going to parse here. + */ + QMap<QString, QString> configs; + QStringList ifList = QStringList::split( "\n\n", mIfconfigStdout ); + QStringList::Iterator it; + for ( it = ifList.begin(); it != ifList.end(); ++it ) + { + int index = ( *it ).find( ' ' ); + if ( index == -1 ) + continue; + QString key = ( *it ).left( index ); + configs[key] = ( *it ).mid( index ); + } + + /* We loop over the interfaces the user wishs to monitor. + * If we find the interface in the output of 'ifconfig' + * we update its data, otherwise we mark it as + * 'not existing'. + */ + QDictIterator<Interface> ifIt( mInterfaces ); + for ( ; ifIt.current(); ++ifIt ) + { + QString key = ifIt.currentKey(); + Interface* interface = ifIt.current(); + + if ( configs.find( key ) == configs.end() ) + { + // The interface does not exist. Meaning the driver + // isn't loaded and/or the interface has not been created. + interface->getData().existing = false; + interface->getData().available = false; + } + // JJ 2005-07-18: use RUNNING instead of UP to detect whether interface is connected + else if ( !configs[key].contains( "inet " ) || + !configs[key].contains( "RUNNING" ) ) + { + // The interface is up or has an IP assigned but not both + interface->getData().existing = true; + interface->getData().available = false; + } + else + { + // ...determine the type of the interface + if ( configs[key].contains( "Ethernet" ) ) + interface->setType( Interface::ETHERNET ); + else + interface->setType( Interface::PPP ); + + // Update the interface. + interface->getData().existing = true; + interface->getData().available = true; + updateInterfaceData( configs[key], interface->getData(), interface->getType() ); + } + } + updateComplete(); +} + +void NetToolsBackend::updateInterfaceData( QString& config, InterfaceData& data, int type ) +{ + QRegExp regExp( ".*RX.*:(\\d+).*:\\d+.*:\\d+.*:\\d+" ); + if ( regExp.search( config ) > -1 ) + data.rxPackets = regExp.cap( 1 ).toULong(); + + regExp.setPattern( ".*TX.*:(\\d+).*:\\d+.*:\\d+.*:\\d+" ); + if ( regExp.search( config ) > -1 ) + data.txPackets = regExp.cap( 1 ).toULong(); + + regExp.setPattern( "RX bytes:(\\d+)\\s*\\(\\d+\\.\\d+\\s*\\w+\\)" ); + if ( regExp.search( config ) > -1 ) + { + // We count the traffic on ourself to avoid an overflow after + // 4GB of traffic. + unsigned long currentRxBytes = regExp.cap( 1 ).toULong(); + if ( currentRxBytes < data.prevRxBytes ) + { + // there was an overflow + if ( type == Interface::ETHERNET ) + { + // This makes data counting more accurate but will not work + // for interfaces that reset the transfered data to zero + // when deactivated like ppp does. + data.rxBytes += 0xFFFFFFFF - data.prevRxBytes; + } + data.prevRxBytes = 0L; + } + if ( data.rxBytes == 0L ) + { + // on startup set to currently received bytes + data.rxBytes = currentRxBytes; + // this is new: KNemo only counts the traffic transfered + // while it is running. Important to not falsify statistics! + data.prevRxBytes = currentRxBytes; + } + else + // afterwards only add difference to previous number of bytes + data.rxBytes += currentRxBytes - data.prevRxBytes; + + data.incomingBytes = currentRxBytes - data.prevRxBytes; + data.prevRxBytes = currentRxBytes; + data.rxString = KIO::convertSize( data.rxBytes ); + } + + regExp.setPattern( "TX bytes:(\\d+)\\s*\\(\\d+\\.\\d+\\s*\\w+\\)" ); + if ( regExp.search( config ) > -1 ) + { + // We count the traffic on ourself to avoid an overflow after + // 4GB of traffic. + unsigned long currentTxBytes = regExp.cap( 1 ).toULong(); + if ( currentTxBytes < data.prevTxBytes ) + { + // there was an overflow + if ( type == Interface::ETHERNET ) + { + // This makes data counting more accurate but will not work + // for interfaces that reset the transfered data to zero + // when deactivated like ppp does. + data.txBytes += 0xFFFFFFFF - data.prevTxBytes; + } + data.prevTxBytes = 0L; + } + if ( data.txBytes == 0L ) + { + // on startup set to currently transmitted bytes + data.txBytes = currentTxBytes; + // this is new: KNemo only counts the traffic transfered + // while it is running. Important to not falsify statistics! + data.prevTxBytes = currentTxBytes; + } + else + // afterwards only add difference to previous number of bytes + data.txBytes += currentTxBytes - data.prevTxBytes; + + data.outgoingBytes = currentTxBytes - data.prevTxBytes; + data.prevTxBytes = currentTxBytes; + data.txString = KIO::convertSize( data.txBytes ); + } + + regExp.setPattern( "inet\\s+\\w+:(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})" ); + if ( regExp.search( config ) > -1 ) + data.ipAddress = regExp.cap( 1 ); + + regExp.setPattern( "(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}).*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}).*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})" ); + if ( regExp.search( config ) > -1 ) + { + data.broadcastAddress = regExp.cap( 2 ); + data.subnetMask = regExp.cap( 3 ); + } + + if ( type == Interface::ETHERNET ) + { + regExp.setPattern( "(.{2}:.{2}:.{2}:.{2}:.{2}:.{2})" ); + if ( regExp.search( config ) > -1 ) + data.hwAddress = regExp.cap( 1 ); + } + else if ( type == Interface::PPP ) + { + regExp.setPattern( "(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}).*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}).*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})" ); + if ( regExp.search( config ) > -1 ) + data.ptpAddress = regExp.cap( 2 ); + } +} + +void NetToolsBackend::parseIwconfigOutput() +{ + /* mIwconfigStdout contains the complete output of 'iwconfig' which we + * are going to parse here. + */ + QMap<QString, QString> configs; + QStringList ifList = QStringList::split( "\n\n", mIwconfigStdout ); + QStringList::Iterator it; + for ( it = ifList.begin(); it != ifList.end(); ++it ) + { + int index = ( *it ).find( ' ' ); + if ( index == -1 ) + continue; + QString key = ( *it ).left( index ); + configs[key] = ( *it ).mid( index ); + } + + /* We loop over the interfaces the user wishs to monitor. + * If we find the interface in the output of 'iwconfig' + * we update its data. + */ + QDictIterator<Interface> ifIt( mInterfaces ); + for ( ; ifIt.current(); ++ifIt ) + { + QString key = ifIt.currentKey(); + Interface* interface = ifIt.current(); + + if ( configs.find( key ) == configs.end() ) + { + // The interface was not found. + continue; + } + else if ( configs[key].contains( "no wireless extensions" ) ) + { + // The interface isn't a wireless device. + interface->getData().wirelessDevice = false; + } + else + { + // Update the wireless data of the interface. + interface->getData().wirelessDevice = true; + updateWirelessData( configs[key], interface->getWirelessData() ); + } + } +} + +void NetToolsBackend::updateWirelessData( QString& config, WirelessData& data ) +{ + QRegExp regExp( "ESSID:([^\"][\\S]*)" ); + if ( regExp.search( config ) > -1 ) + data.essid = regExp.cap( 1 ); + else + { + regExp.setPattern( "ESSID:\"([^\"]*)" ); + if ( regExp.search( config ) > -1 ) + data.essid = regExp.cap( 1 ); + else + data.essid = QString::null; + } + + regExp.setPattern( "Mode:(\\w*)" ); + if ( regExp.search( config ) > -1 ) + data.mode = regExp.cap( 1 ); + + regExp.setPattern( "Frequency:([\\w|\\.]*\\s*\\w*)" ); + if ( regExp.search( config ) > -1 ) + { + data.frequency = regExp.cap( 1 ); + data.channel = "-"; + } + else + { + data.frequency = "-"; + regExp.setPattern( "Channel:(\\d*)" ); + if ( regExp.search( config ) > -1 ) + data.channel = regExp.cap( 1 ); + else + data.channel = "-"; + } + + regExp.setPattern( "Bit Rate[=:](\\d*\\s*[\\w/]*)" ); + if ( regExp.search( config ) > -1 ) + data.bitRate = regExp.cap( 1 ); + + regExp.setPattern( "(.{2}:.{2}:.{2}:.{2}:.{2}:.{2})" ); + if ( regExp.search( config ) > -1 ) + data.accessPoint = regExp.cap( 1 ); + + regExp.setPattern( "Nickname:\"(\\w*)\"" ); + if ( regExp.search( config ) > -1 ) + data.nickName = regExp.cap( 1 ); + + regExp.setPattern( "Link Quality[=:]([\\d]*)" ); + if ( regExp.search( config ) > -1 ) + data.linkQuality = regExp.cap( 1 ); + + regExp.setPattern( "Encryption key:" ); + if ( regExp.search( config ) > -1 ) + { + regExp.setPattern( "Encryption key:off" ); + if ( regExp.search( config ) > -1 ) + { + data.encryption = false; + } + else + { + data.encryption = true; + } + } + else + { + data.encryption = false; + } +} + +void NetToolsBackend::parseRouteOutput() +{ + /* mRouteStdout contains the complete output of 'route' which we + * are going to parse here. + */ + QMap<QString, QStringList> configs; + QStringList routeList = QStringList::split( "\n", mRouteStdout ); + QStringList::Iterator it; + for ( it = routeList.begin(); it != routeList.end(); ++it ) + { + QStringList routeParameter = QStringList::split( " ", *it ); + if ( routeParameter.count() < 8 ) // no routing entry + continue; + if ( routeParameter[0] != "0.0.0.0" ) // no default route + continue; + configs[routeParameter[7]] = routeParameter; + } + + /* We loop over the interfaces the user wishs to monitor. + * If we find the interface in the output of 'route' we update + * the data of the interface. + */ + QDictIterator<Interface> ifIt( mInterfaces ); + for ( ; ifIt.current(); ++ifIt ) + { + QString key = ifIt.currentKey(); + Interface* interface = ifIt.current(); + + if ( configs.find( key ) != configs.end() ) + { + // Update the default gateway. + QStringList routeParameter = configs[key]; + interface->getData().defaultGateway = routeParameter[1]; + } + else + { + // Reset the default gateway. + interface->getData().defaultGateway = QString::null; + } + } +} diff --git a/src/knemod/backends/nettoolsbackend.h b/src/knemod/backends/nettoolsbackend.h new file mode 100644 index 0000000..788938c --- /dev/null +++ b/src/knemod/backends/nettoolsbackend.h @@ -0,0 +1,72 @@ +/* This file is part of KNemo + Copyright (C) 2004 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef NETTOOLSBACKEND_H +#define NETTOOLSBACKEND_H + +#include <qobject.h> + +#include "backendbase.h" + +class KProcess; + +/** + * The nettools backend runs 'ifconfig', 'iwconfig' and 'route' + * and parses their output. It then triggers the interface + * monitor to look for changes in the state of the interface. + * + * @short Update the information of the interfaces via nettools + * @author Percy Leonhardt <[email protected]> + */ + +class NetToolsBackend : public QObject, BackendBase +{ + Q_OBJECT +public: + NetToolsBackend(QDict<Interface>& interfaces ); + virtual ~NetToolsBackend(); + + static BackendBase* createInstance( QDict<Interface>& interfaces ); + + void update(); + +private slots: + void routeProcessExited( KProcess* process ); + void routeProcessStdout( KProcess* process, char* buffer, int buflen ); + void ifconfigProcessExited( KProcess* process ); + void ifconfigProcessStdout( KProcess* process, char* buffer, int buflen ); + void iwconfigProcessExited( KProcess* process ); + void iwconfigProcessStdout( KProcess* process, char* buffer, int buflen ); + +private: + void parseRouteOutput(); + void parseIfconfigOutput(); + void updateInterfaceData( QString& config, InterfaceData& data, int type ); + void parseIwconfigOutput(); + void updateWirelessData( QString& config, WirelessData& data ); + + QString mRouteStdout; + QString mIfconfigStdout; + QString mIwconfigStdout; + KProcess* mRouteProcess; + KProcess* mIfconfigProcess; + KProcess* mIwconfigProcess; +}; + +#endif // NETTOOLSBACKEND_H diff --git a/src/knemod/backends/sysbackend.cpp b/src/knemod/backends/sysbackend.cpp new file mode 100644 index 0000000..2caf325 --- /dev/null +++ b/src/knemod/backends/sysbackend.cpp @@ -0,0 +1,428 @@ +/* This file is part of KNemo + Copyright (C) 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <stdio.h> +#include <string.h> +#include <arpa/inet.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include <qmap.h> +#include <qdir.h> +#include <qregexp.h> +#include <qstringlist.h> + +#include <kdebug.h> +#include <kprocess.h> +#include <kio/global.h> + +#include "sysbackend.h" + +#include "config.h" + +#ifdef HAVE_LIBIW +#include <iwlib.h> +#else +#include <net/if.h> +#endif + +#define RTF_GATEWAY 0x0002 +#define SYSPATH "/sys/class/net/" +#define PROCROUTE "/proc/net/route" + +SysBackend::SysBackend( QDict<Interface>& interfaces ) + : BackendBase( interfaces ) +{ +} + +SysBackend::~SysBackend() +{ +} + +BackendBase* SysBackend::createInstance( QDict<Interface>& interfaces ) +{ + return new SysBackend( interfaces ); +} + +void SysBackend::update() +{ + QDir dir( SYSPATH ); + QStringList ifList = dir.entryList( QDir::Dirs ); + + QDictIterator<Interface> ifIt( mInterfaces ); + for ( ; ifIt.current(); ++ifIt ) + { + QString key = ifIt.currentKey(); + Interface* interface = ifIt.current(); + + if ( ifList.find( key ) == ifList.end() ) + { + // The interface does not exist. Meaning the driver + // isn't loaded and/or the interface has not been created. + interface->getData().existing = false; + interface->getData().available = false; + } + else + { + if ( QFile::exists( SYSPATH + key + "/wireless" ) ) + { + interface->getData().wirelessDevice = true; + } + + unsigned int carrier = 0; + if ( !readNumberFromFile( SYSPATH + key + "/carrier", carrier ) || + carrier == 0 ) + { + // The interface is there but not useable. + interface->getData().existing = true; + interface->getData().available = false; + } + else + { + // ...determine the type of the interface + unsigned int type = 0; + if ( readNumberFromFile( SYSPATH + key + "/type", type ) && + type == 512 ) + { + interface->setType( Interface::PPP ); + } + else + { + interface->setType( Interface::ETHERNET ); + } + + // Update the interface. + interface->getData().existing = true; + interface->getData().available = true; + updateInterfaceData( key, interface->getData(), interface->getType() ); + + if ( interface->getData().wirelessDevice == true ) + { + updateWirelessData( key, interface->getWirelessData() ); + } + } + } + } + updateComplete(); +} + +bool SysBackend::readNumberFromFile( const QString& fileName, unsigned int& value ) +{ + FILE* file = fopen( fileName.latin1(), "r" ); + if ( file != NULL ) + { + if ( fscanf( file, "%ul", &value ) > 0 ) + { + fclose( file ); + return true; + } + fclose( file ); + } + + return false; +} + +bool SysBackend::readStringFromFile( const QString& fileName, QString& string ) +{ + char buffer[64]; + FILE* file = fopen( fileName.latin1(), "r" ); + if ( file != NULL ) + { + if ( fscanf( file, "%s", buffer ) > 0 ) + { + fclose( file ); + string = buffer; + return true; + } + fclose( file ); + } + + return false; +} + +void SysBackend::updateInterfaceData( const QString& ifName, InterfaceData& data, int type ) +{ + QString ifFolder = SYSPATH + ifName + "/"; + + unsigned int rxPackets = 0; + if ( readNumberFromFile( ifFolder + "statistics/rx_packets", rxPackets ) ) + { + data.rxPackets = rxPackets; + } + + unsigned int txPackets = 0; + if ( readNumberFromFile( ifFolder + "statistics/tx_packets", txPackets ) ) + { + data.txPackets = txPackets; + } + + unsigned int rxBytes = 0; + if ( readNumberFromFile( ifFolder + "statistics/rx_bytes", rxBytes ) ) + { + // We count the traffic on ourself to avoid an overflow after + // 4GB of traffic. + if ( rxBytes < data.prevRxBytes ) + { + // there was an overflow + if ( type == Interface::ETHERNET ) + { + // This makes data counting more accurate but will not work + // for interfaces that reset the transfered data to zero + // when deactivated like ppp does. + data.rxBytes += 0xFFFFFFFF - data.prevRxBytes; + } + data.prevRxBytes = 0L; + } + if ( data.rxBytes == 0L ) + { + // on startup set to currently received bytes + data.rxBytes = rxBytes; + // this is new: KNemo only counts the traffic transfered + // while it is running. Important to not falsify statistics! + data.prevRxBytes = rxBytes; + } + else + // afterwards only add difference to previous number of bytes + data.rxBytes += rxBytes - data.prevRxBytes; + + data.incomingBytes = rxBytes - data.prevRxBytes; + data.prevRxBytes = rxBytes; + data.rxString = KIO::convertSize( data.rxBytes ); + } + + unsigned int txBytes = 0; + if ( readNumberFromFile( ifFolder + "statistics/tx_bytes", txBytes ) ) + { + // We count the traffic on ourself to avoid an overflow after + // 4GB of traffic. + if ( txBytes < data.prevTxBytes ) + { + // there was an overflow + if ( type == Interface::ETHERNET ) + { + // This makes data counting more accurate but will not work + // for interfaces that reset the transfered data to zero + // when deactivated like ppp does. + data.txBytes += 0xFFFFFFFF - data.prevTxBytes; + } + data.prevTxBytes = 0L; + } + if ( data.txBytes == 0L ) + { + // on startup set to currently received bytes + data.txBytes = txBytes; + // this is new: KNemo only counts the traffic transfered + // while it is running. Important to not falsify statistics! + data.prevTxBytes = txBytes; + } + else + // afterwards only add difference to previous number of bytes + data.txBytes += txBytes - data.prevTxBytes; + + data.outgoingBytes = txBytes - data.prevTxBytes; + data.prevTxBytes = txBytes; + data.txString = KIO::convertSize( data.txBytes ); + } + + if ( type == Interface::ETHERNET ) + { + QString hwAddress; + if ( readStringFromFile( ifFolder + "address", hwAddress ) ) + { + data.hwAddress = hwAddress; + } + + // for the default gateway we use the proc filesystem + QFile routeFile( PROCROUTE ); + if ( routeFile.open( IO_ReadOnly ) ) + { + QString routeData( routeFile.readAll().data() ); + QStringList routeEntries = QStringList::split( "\n", routeData ); + QStringList::Iterator it; + for ( it = routeEntries.begin(); it != routeEntries.end(); ++it ) + { + QRegExp regExp( ".*\\s+[\\w\\d]{8}\\s+([\\w\\d]{8})\\s+(\\d{4})" ); + if ( ( regExp.search( *it ) > -1 ) + && ( regExp.cap( 2 ).toUInt() & RTF_GATEWAY ) ) + { + bool ok; + struct in_addr in; + in.s_addr = regExp.cap( 1 ).toULong( &ok, 16 ); + data.defaultGateway = inet_ntoa( in ); + break; + } + } + routeFile.close(); + } + + } + + // use ioctls for the rest + int fd; + struct ifreq ifr; + if ( ( fd = socket(AF_INET, SOCK_DGRAM, 0) ) > -1 ) + { + strcpy( ifr.ifr_name, ifName.latin1() ); + ifr.ifr_addr.sa_family = AF_INET; + if ( ioctl( fd, SIOCGIFADDR, &ifr ) > -1 ) + { + data.ipAddress = inet_ntoa(((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr); + } + if ( ioctl( fd, SIOCGIFDSTADDR, &ifr) > -1 ) + { + data.ptpAddress = inet_ntoa(((struct sockaddr_in*)&ifr.ifr_dstaddr)->sin_addr); + } + + if ( ioctl( fd, SIOCGIFBRDADDR, &ifr ) > -1 ) + { + data.broadcastAddress = inet_ntoa(((struct sockaddr_in*)&ifr.ifr_broadaddr)->sin_addr); + } + + if ( ioctl( fd, SIOCGIFNETMASK, &ifr ) > -1 ) + { + data.subnetMask = inet_ntoa(((struct sockaddr_in*)&ifr.ifr_netmask)->sin_addr); + } + close( fd ); + } +} + +void SysBackend::updateWirelessData( const QString& ifName, WirelessData& data ) +{ + QString wirelessFolder = SYSPATH + ifName + "/wireless/"; + + unsigned int link = 0; + if ( readNumberFromFile( wirelessFolder + "link", link ) ) + { + data.linkQuality = QString::number( link ); + } + +#ifdef HAVE_LIBIW + // The following code was taken from iwconfig.c and iwlib.c. + int fd; + if ( ( fd = iw_sockets_open() ) > 0 ) + { + struct iwreq wrq; + char buffer[128]; + if ( iw_get_ext( fd, ifName.latin1(), SIOCGIWFREQ, &wrq ) >= 0 ) + { + int channel = -1; + double freq = iw_freq2float( &( wrq.u.freq ) ); + struct iw_range range; + if( iw_get_range_info( fd, ifName.latin1(), &range ) >= 0 ) + { + if ( freq < KILO ) + { + channel = iw_channel_to_freq( (int) freq, &freq, &range ); + } + else + { + channel = iw_freq_to_channel( freq, &range ); + } + iw_print_freq_value( buffer, sizeof( buffer ), freq ); + data.frequency = buffer; + data.channel = QString::number( channel ); + } + } + + char essid[IW_ESSID_MAX_SIZE + 1]; + memset( essid, 0, IW_ESSID_MAX_SIZE + 1 ); + wrq.u.essid.pointer = (caddr_t) essid; + wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1; + wrq.u.essid.flags = 0; + if ( iw_get_ext( fd, ifName.latin1(), SIOCGIWESSID, &wrq ) >= 0 ) + { + if ( wrq.u.data.flags > 0 ) + { + data.essid = essid; + } + else + { + data.essid = "any"; + } + } + + if ( iw_get_ext( fd, ifName.latin1(), SIOCGIWAP, &wrq ) >= 0 ) + { + char ap_addr[128]; + iw_ether_ntop( (const ether_addr*) wrq.u.ap_addr.sa_data, ap_addr); + data.accessPoint = ap_addr; + } + + memset( essid, 0, IW_ESSID_MAX_SIZE + 1 ); + wrq.u.essid.pointer = (caddr_t) essid; + wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1; + wrq.u.essid.flags = 0; + if ( iw_get_ext( fd, ifName.latin1(), SIOCGIWNICKN, &wrq ) >= 0 ) + { + if ( wrq.u.data.length > 1 ) + { + data.nickName = essid; + } + else + { + data.nickName = QString::null; + } + } + + if ( iw_get_ext( fd, ifName.latin1(), SIOCGIWRATE, &wrq ) >= 0 ) + { + iwparam bitrate; + memcpy (&(bitrate), &(wrq.u.bitrate), sizeof (iwparam)); + iw_print_bitrate( buffer, sizeof( buffer ), wrq.u.bitrate.value ); + data.bitRate = buffer; + } + + if ( iw_get_ext( fd, ifName.latin1(), SIOCGIWMODE, &wrq ) >= 0 ) + { + int mode = wrq.u.mode; + if ( mode < IW_NUM_OPER_MODE && mode >= 0 ) + { + data.mode = iw_operation_mode[mode]; + } + else + { + data.mode = QString::null; + } + } + + unsigned char key[IW_ENCODING_TOKEN_MAX]; + wrq.u.data.pointer = (caddr_t) key; + wrq.u.data.length = IW_ENCODING_TOKEN_MAX; + wrq.u.data.flags = 0; + if ( iw_get_ext( fd, ifName.latin1(), SIOCGIWENCODE, &wrq ) >= 0 ) + { + if ( ( wrq.u.data.flags & IW_ENCODE_DISABLED ) || ( wrq.u.data.length == 0 ) ) + { + data.encryption = false; + } + else + { + data.encryption = true; + } + } + else + { + data.encryption = false; + } + close( fd ); + } +#endif +} + diff --git a/src/knemod/backends/sysbackend.h b/src/knemod/backends/sysbackend.h new file mode 100644 index 0000000..10650b6 --- /dev/null +++ b/src/knemod/backends/sysbackend.h @@ -0,0 +1,54 @@ +/* This file is part of KNemo + Copyright (C) 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef SYSBACKEND_H +#define SYSBACKEND_H + +#include "backendbase.h" + +/** + * The sys backend uses the sys filesystem available in 2.6 + * kernels. It reads all necessary information from the files + * and folders located at /sys and parses their output. + * It then triggers the interface monitor to look for changes + * in the state of the interface. + * + * @short Update the information of the interfaces via sys filesystem + * @author Percy Leonhardt <[email protected]> + */ + +class SysBackend : public BackendBase +{ +public: + SysBackend(QDict<Interface>& interfaces ); + virtual ~SysBackend(); + + static BackendBase* createInstance( QDict<Interface>& interfaces ); + + void update(); + +private: + bool readNumberFromFile( const QString& fileName, unsigned int& value ); + bool readStringFromFile( const QString& fileName, QString& string ); + void updateWirelessData( const QString& ifName, WirelessData& data ); + void updateInterfaceData( const QString& ifName, InterfaceData& data, int type ); + +}; + +#endif // SYSBACKEND_H diff --git a/src/knemod/eventsrc b/src/knemod/eventsrc new file mode 100644 index 0000000..13f8aff --- /dev/null +++ b/src/knemod/eventsrc @@ -0,0 +1,220 @@ +[!Global!] +IconName=knemo +Comment=KDE Network Monitor +Comment[bg]=Монитор на мрежата +Comment[br]=Eveshaer ar rouedad evit KDE +Comment[cs]=KDE monitor sítě +Comment[da]=KDE's netværksovervågning +Comment[de]=KDE-Netzwerkmonitor +Comment[el]=Επίβλεψη δικτύου του KDE +Comment[es]=Monitor de red de KDE +Comment[et]=KDE võrgumonitor +Comment[ga]=Monatóir Líonra KDE +Comment[gl]=Un Monitor de Rede para KDE +Comment[it]=Monitor di rete di KDE +Comment[ja]=KDE ネットワークモニタ +Comment[ka]=KDE-ის ქსელის მონიტორი +Comment[lt]=Tinklo įrenginių stebėjimo KDE programa +Comment[nl]=KDE networkmonitor +Comment[pa]=KDE ਨੈਟਵਰਕ ਨਿਗਰਾਨ +Comment[pl]=Monitor sieci dla KDE +Comment[pt]=Monitor da Rede do KDE +Comment[pt_BR]=Monitor de Rede do KDE +Comment[ru]=Сетевой монитор KDE +Comment[sr]=Надгледање мреже за KDE +Comment[sr@Latn]=Nadgledanje mreže za KDE +Comment[sv]=KDE-nätverksövervakning +Comment[tr]=KDE Ağ İzleyici +Comment[uk]=Монітор мережі для KDE +Comment[xx]=xxKDE Network Monitorxx +Comment[zh_CN]=KDE 网络监视器 + +[knemo_connected] +Name=Connected +Name[bg]=Активно +Name[br]=Kevreet +Name[ca]=Connectat +Name[cs]=Připojen +Name[cy]=Wedi cysylltu +Name[da]=Forbundet +Name[de]=Verbunden +Name[el]=Συνδέθηκε +Name[es]=Conectado +Name[et]=Ühendatud +Name[fr]=Connecté +Name[ga]=Nasctha +Name[gl]=Conectado +Name[hi]=कनेक्टेड +Name[it]=Connesso +Name[ja]=接続 +Name[ka]=დაკავშირებულია +Name[lt]=Prijungta +Name[nl]=Verbonden +Name[pa]=ਜੁੜਿਆ +Name[pl]=Podłączony +Name[pt]=Ligado +Name[pt_BR]=Conectado +Name[ru]=Соединено +Name[sr]=Повезан +Name[sr@Latn]=Povezan +Name[sv]=Uppkopplat +Name[ta]=இணைக்கப்பட்டது +Name[tr]=Bağlı +Name[uk]=З'єднано +Name[xx]=xxConnectedxx +Name[zh_CN]=已连接 +Comment=Interface is connected +Comment[bg]=Интерфейсът е активен +Comment[br]=Kevreet eo an etrefas +Comment[cs]=Rozhraní je připojeno +Comment[da]=Grænseflade er forbundet +Comment[de]=Die Schnittstelle ist verbunden +Comment[el]=Η διασύνδεση είναι συνδεδεμένη +Comment[es]=La interfaz está conectada +Comment[et]=Liides on ühendatud +Comment[ga]=Tá an comhéadan nasctha +Comment[gl]=A interface está conectada +Comment[it]=L'interfaccia è connessa +Comment[ja]=インターフェースが接続されました +Comment[ka]=ინტერფეისი დაკავშირებულია +Comment[lt]=Įrenginys prijungtas +Comment[nl]=Interface is verbonden +Comment[pa]=ਇੰਟਰਫੇਸ ਜੁੜਿਆ ਹੈ +Comment[pl]=Interfejs jest podłączony +Comment[pt]=A interface foi ligada +Comment[pt_BR]=A interface está conectada +Comment[ru]=Интерфейс подключен +Comment[sr]=Интерфејс је повезан +Comment[sr@Latn]=Interfejs je povezan +Comment[sv]=Gränssnittet är uppkopplat +Comment[tr]=Arayüz bağlandı +Comment[uk]=Інтерфейс з'єднано +Comment[xx]=xxInterface is connectedxx +Comment[zh_CN]=接口已连接 +default_sound=KDE_Dialog_Appear.wav +default_presentation=17 + +[knemo_disconnected] +Name=Disconnected +Name[bg]=Неактивен +Name[br]=Digevreet +Name[ca]=Desconnectat +Name[cs]=Odpojen +Name[cy]=Datgysylltwyd +Name[da]=Afbrudt +Name[de]=Getrennt +Name[el]=Αποσυνδέθηκε +Name[es]=Desconectado +Name[et]=Lahutatud +Name[fr]=Déconnecté +Name[ga]=Dínasctha +Name[gl]=Desconectada +Name[hi]=डिस्कनेक्टेड +Name[it]=Disconnesso +Name[ja]=切断 +Name[ka]=კავშირი გაწყვეტილია +Name[lt]=Atjungta +Name[nl]=Niet verbonden +Name[pa]=ਜੁੜਿਆ ਨਹੀਂ +Name[pl]=Rozłączony +Name[pt]=Desligado +Name[pt_BR]=Desconectado +Name[ru]=Отключено +Name[sr]=Неповезан +Name[sr@Latn]=Nepovezan +Name[sv]=Nerkopplat +Name[ta]=துண்டிக்கப்பட்டது +Name[tr]=Bağlantı kesildi +Name[uk]=Роз'єднано +Name[xx]=xxDisconnectedxx +Name[zh_CN]=已断开 +Comment=Interface is disconnected +Comment[bg]=Интерфейсът е неактивен +Comment[br]=Digevreet eo an etrefas +Comment[cs]=Rozhraní je odpojeno +Comment[da]=Grænseflade er afbrudt +Comment[de]=Die Schnittstelle ist nicht verbunden +Comment[el]=Η διασύνδεση αποσυνδέθηκε +Comment[es]=La interfaz está desconectada +Comment[et]=Liides on lahutatud +Comment[ga]=Tá an comhéadan dínasctha +Comment[gl]=A interface está desconectada +Comment[it]=L'interfaccia è disconnessa +Comment[ja]=インターフェースが切断されました +Comment[ka]=ინტერფეისის კავშირი გაწყვეტილია +Comment[lt]=Įrenginys atjungtas +Comment[nl]=Interface is niet verbonden +Comment[pa]=ਇੰਟਰਫੇਸ ਜੁੜਿਆ ਨਹੀਂ ਹੈ +Comment[pl]=Interfejs jest rozłączony +Comment[pt]=A interface foi desligada +Comment[pt_BR]=A interface está desconectada +Comment[ru]=Интерфейс не подключен +Comment[sr]=Интерфејс је неповезан +Comment[sr@Latn]=Interfejs je nepovezan +Comment[sv]=Gränssnittet är nerkopplat +Comment[tr]=Arayüz bağlantısı kesildi +Comment[uk]=Інтерфейс роз'єднано +Comment[xx]=xxInterface is disconnectedxx +Comment[zh_CN]=接口已断开 +default_sound=KDE_Dialog_Disappear.wav +default_presentation=17 + +[knemo_notexisting] +Name=Not existing +Name[bg]=Несъществуващ +Name[br]=N'eo ket endeo +Name[cs]=Neexistuje +Name[da]=Eksisterer ikke +Name[de]=Existiert nicht +Name[el]=Δεν υπάρχει +Name[es]=Inexistente +Name[et]=Pole olemas +Name[ga]=Níl sé ann +Name[gl]=Non existe +Name[it]=Inesistente +Name[ja]=存在しません +Name[ka]=არ არსებობს +Name[lt]=Nėra +Name[nl]=Niet-bestaand +Name[pa]=ਮੌਜੂਦ ਨਹੀਂ +Name[pl]=Nie istnieje +Name[pt]=Não existente +Name[pt_BR]=Inexistente +Name[ru]=Не существует +Name[sr]=Не постоји +Name[sr@Latn]=Ne postoji +Name[sv]=Existerar inte +Name[tr]=Mevcut değil +Name[uk]=Не існує +Name[xx]=xxNot existingxx +Name[zh_CN]=不存在 +Comment=Interface does not exist +Comment[bg]=Интерфейсът не съществува +Comment[br]=N'eo ket endeo an etrefas +Comment[cs]=Rozhraní neexistuje +Comment[da]=Grænsefladen eksisterer ikke +Comment[de]=Die Schnittstelle existiert nicht +Comment[el]=Η διασύνδεση δεν υπάρχει +Comment[es]=La interfaz no existe +Comment[et]=Liidest pole olemas +Comment[ga]=Níl an comhéadan ann +Comment[gl]=A interface non existe +Comment[it]=L'interfaccia non esiste +Comment[ja]=インターフェースが存在しません +Comment[ka]=ინტერფეისი არ არსებობს +Comment[lt]=Įrenginio nėra +Comment[nl]=De interface bestaat niet +Comment[pa]=ਇੰਟਰਫੇਸ ਮੌਜੂਦ ਨਹੀਂ ਹੈ +Comment[pl]=Interfejs nie istnieje +Comment[pt]=A interface não existe +Comment[pt_BR]=A interface não existe +Comment[ru]=Интерфейс не существует +Comment[sr]=Интерфејс не постоји +Comment[sr@Latn]=Interfejs ne postoji +Comment[sv]=Gränssnittet finns inte +Comment[tr]=Arayüz mevcut değil +Comment[uk]=Інтерфейсу не існує +Comment[xx]=xxInterface does not existxx +Comment[zh_CN]=接口不存在 +default_sound=KDE_Notify.wav +default_presentation=0 diff --git a/src/knemod/global.h b/src/knemod/global.h new file mode 100644 index 0000000..d00a54e --- /dev/null +++ b/src/knemod/global.h @@ -0,0 +1,130 @@ +/* This file is part of KNemo + Copyright (C) 2005 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef GLOBAL_H +#define GLOBAL_H + +#include <qpair.h> +#include <qcolor.h> +#include <qstring.h> + +/** + * This file contains data structures and enums used in the knemo daemon. + * + * @short Daemon wide structures and enums + * @author Percy Leonhardt <[email protected]> + */ + +struct GeneralData +{ + int toolTipContent; + int pollInterval; + int saveInterval; + QString statisticsDir; +}; + +struct InterfaceData +{ + InterfaceData() + : existing( false ), + available( false ), + wirelessDevice( false ), + prevRxPackets( 0L ), + prevTxPackets( 0L ), + rxPackets( 0L ), + txPackets( 0L ), + prevRxBytes( 0L ), + prevTxBytes( 0L ), + incomingBytes( 0L ), + outgoingBytes( 0L ), + rxBytes( 0L ), + txBytes( 0L ) + {} + + bool existing; + bool available; + bool wirelessDevice; + unsigned long prevRxPackets; + unsigned long prevTxPackets; + unsigned long rxPackets; + unsigned long txPackets; + unsigned long prevRxBytes; + unsigned long prevTxBytes; + unsigned long incomingBytes; + unsigned long outgoingBytes; + QString ipAddress; + QString subnetMask; + QString hwAddress; + QString ptpAddress; + QString broadcastAddress; + QString defaultGateway; + QString rxString; + QString txString; + Q_UINT64 rxBytes; + Q_UINT64 txBytes; +}; + +struct WirelessData +{ + QString essid; + QString mode; + QString frequency; + QString channel; + QString bitRate; + QString linkQuality; + QString accessPoint; + QString nickName; + bool encryption; +}; + +struct PlotterSettings +{ + int pixel; + int count; + int distance; + int fontSize; + int minimumValue; + int maximumValue; + bool labels; + bool topBar; + bool showIncoming; + bool showOutgoing; + bool verticalLines; + bool horizontalLines; + bool automaticDetection; + bool verticalLinesScroll; + QColor colorVLines; + QColor colorHLines; + QColor colorIncoming; + QColor colorOutgoing; + QColor colorBackground; +}; + +struct StatisticEntry +{ + int day; + int month; + int year; + Q_UINT64 rxBytes; + Q_UINT64 txBytes; +}; + +extern QPair<QString, int> ToolTips[]; + +#endif // GLOBAL_H diff --git a/src/knemod/interface.cpp b/src/knemod/interface.cpp new file mode 100644 index 0000000..2378662 --- /dev/null +++ b/src/knemod/interface.cpp @@ -0,0 +1,487 @@ +/* This file is part of KNemo + Copyright (C) 2004, 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qtimer.h> +#include <qpixmap.h> + +#include <kwin.h> +#include <kdebug.h> +#include <klocale.h> +#include <kwinmodule.h> +#include <kiconloader.h> + +#include "interface.h" +#include "signalplotter.h" +#include "interfacestatistics.h" +#include "interfacestatusdialog.h" +#include "interfacestatisticsdialog.h" + +Interface::Interface( QString ifname, + const GeneralData& generalData, + const PlotterSettings& plotterSettings ) + : QObject(), + mType( UNKNOWN_TYPE ), + mState( UNKNOWN_STATE ), + mOutgoingPos( 0 ), + mIncomingPos( 0 ), + mName( ifname ), + mPlotterTimer( 0 ), + mIcon( this ), + mStatistics( 0 ), + mStatusDialog( 0 ), + mStatisticsDialog( 0 ), + mPlotter( 0 ), + mVisibleBeams( NONE ), + mGeneralData( generalData ), + mPlotterSettings( plotterSettings ) +{ + connect( &mMonitor, SIGNAL( statusChanged( int ) ), + &mIcon, SLOT( updateStatus( int ) ) ); + connect( &mMonitor, SIGNAL( available( int ) ), + &mIcon, SLOT( updateTrayStatus( int ) ) ); + connect( &mMonitor, SIGNAL( notAvailable( int ) ), + &mIcon, SLOT( updateTrayStatus( int ) ) ); + connect( &mMonitor, SIGNAL( notExisting( int ) ), + &mIcon, SLOT( updateTrayStatus( int ) ) ); + connect( &mMonitor, SIGNAL( available( int ) ), + this, SLOT( setStartTime( int ) ) ); + connect( &mMonitor, SIGNAL( statusChanged( int ) ), + this, SLOT( resetData( int ) ) ); + connect( &mIcon, SIGNAL( statisticsSelected() ), + this, SLOT( showStatisticsDialog() ) ); +} + +Interface::~Interface() +{ + if ( mStatusDialog != 0 ) + { + delete mStatusDialog; + } + if ( mPlotter != 0 ) + { + delete mPlotter; + } + if ( mPlotterTimer != 0 ) + { + mPlotterTimer->stop(); + delete mPlotterTimer; + } + if ( mStatistics != 0 ) + { + // this will also delete a possibly open statistics dialog + stopStatistics(); + } +} + +void Interface::configChanged() +{ + // UNKNOWN_STATE to avoid notification + mIcon.updateTrayStatus( UNKNOWN_STATE ); + // handle changed iconset by user + mIcon.updateStatus( mState ); + mIcon.updateToolTip(); + mIcon.updateMenu(); + + if ( mPlotter != 0L ) + { + configurePlotter(); + } + + if ( mStatistics != 0 ) + { + mStatistics->configChanged(); + } + + if ( mSettings.activateStatistics && mStatistics == 0 ) + { + // user turned on statistics + startStatistics(); + } + else if ( !mSettings.activateStatistics && mStatistics != 0 ) + { + // user turned off statistics + stopStatistics(); + } + + if ( mStatusDialog ) + { + mStatusDialog->setStatisticsGroupEnabled( mSettings.activateStatistics ); + } +} + +void Interface::activateMonitor() +{ + mMonitor.checkStatus( this ); +} + +void Interface::setStartTime( int ) +{ + mStartTime.setDate( QDate::currentDate() ); + mStartTime.setTime( QTime::currentTime() ); +} + +void Interface::showStatusDialog() +{ + // Toggle the status dialog. + // First click will show the status dialog, second will hide it. + if ( mStatusDialog == 0L ) + { + mStatusDialog = new InterfaceStatusDialog( this ); + connect( &mMonitor, SIGNAL( available( int ) ), + mStatusDialog, SLOT( enableNetworkGroups( int ) ) ); + connect( &mMonitor, SIGNAL( notAvailable( int ) ), + mStatusDialog, SLOT( disableNetworkGroups( int ) ) ); + connect( &mMonitor, SIGNAL( notExisting( int ) ), + mStatusDialog, SLOT( disableNetworkGroups( int ) ) ); + if ( mStatistics != 0 ) + { + connect( mStatistics, SIGNAL( currentEntryChanged() ), + mStatusDialog, SLOT( statisticsChanged() ) ); + mStatusDialog->statisticsChanged(); + } + activateOrHide( mStatusDialog, true ); + } + else + { + // Toggle the status dialog. + activateOrHide( mStatusDialog ); + } +} + +void Interface::showSignalPlotter( bool wasMiddleButton ) +{ + // No plotter, create it. + if ( mPlotter == 0L ) + { + mPlotter = new SignalPlotter( 0L, mName.local8Bit() ); + mPlotter->setIcon( SmallIcon( "knemo" ) ); + mPlotter->setCaption( mName + " " + i18n( "Traffic" ) ); + mPlotter->setTitle( mName ); + configurePlotter(); + activateOrHide( mPlotter, true ); + + mPlotterTimer = new QTimer(); + connect( mPlotterTimer, SIGNAL( timeout() ), + this, SLOT( updatePlotter() ) ); + mPlotterTimer->start( 1000 ); + } + else + { + if ( wasMiddleButton ) + { + // Toggle the signal plotter. + activateOrHide( mPlotter ); + } + else + { + // Called from the context menu, show the dialog. + activateOrHide( mPlotter, true ); + } + } +} + +void Interface::showStatisticsDialog() +{ + if ( mStatisticsDialog == 0 ) + { + mStatisticsDialog = new InterfaceStatisticsDialog( this ); + if ( mStatistics == 0 ) + { + // should never happen but you never know... + startStatistics(); + } + connect( mStatistics, SIGNAL( dayStatisticsChanged() ), + mStatisticsDialog, SLOT( updateDays() ) ); + connect( mStatistics, SIGNAL( monthStatisticsChanged() ), + mStatisticsDialog, SLOT( updateMonths() ) ); + connect( mStatistics, SIGNAL( yearStatisticsChanged() ), + mStatisticsDialog, SLOT( updateYears() ) ); + connect( mStatistics, SIGNAL( currentEntryChanged() ), + mStatisticsDialog, SLOT( updateCurrentEntry() ) ); + connect( mStatisticsDialog, SIGNAL( clearDailyStatisticsClicked() ), + mStatistics, SLOT( clearDayStatistics() ) ); + connect( mStatisticsDialog, SIGNAL( clearMonthlyStatisticsClicked() ), + mStatistics, SLOT( clearMonthStatistics() ) ); + connect( mStatisticsDialog, SIGNAL( clearYearlyStatisticsClicked() ), + mStatistics, SLOT( clearYearStatistics() ) ); + + mStatisticsDialog->updateDays(); + mStatisticsDialog->updateMonths(); + mStatisticsDialog->updateYears(); + } + mStatisticsDialog->show(); +} + +void Interface::resetData( int state ) +{ + // For PPP interfaces we will reset all data to zero when the + // interface gets disconnected. If the driver also resets its data + // (like PPP seems to do) we will start from zero for every new + // connection. + if ( mType == PPP && + ( state == NOT_AVAILABLE || + state == NOT_EXISTING ) ) + { + mData.prevTxBytes = mData.txBytes = 0; + mData.prevRxBytes = mData.rxBytes = 0; + mData.prevTxPackets = mData.txPackets = 0; + mData.prevRxPackets = mData.rxPackets = 0; + } +} + +void Interface::updatePlotter() +{ + if ( mPlotter ) + { + double outgoingBytes = mData.outgoingBytes / 1024.0 / (double) mGeneralData.pollInterval; + double incomingBytes = mData.incomingBytes / 1024.0 / (double) mGeneralData.pollInterval; + + QValueList<double> trafficList; + switch ( mVisibleBeams ) + { + case BOTH: + if ( mIncomingPos == 1 ) + { + trafficList.append( outgoingBytes ); + trafficList.append( incomingBytes ); + } + else + { + trafficList.append( incomingBytes ); + trafficList.append( outgoingBytes ); + } + mPlotter->addSample( trafficList ); + break; + case INCOMING_TRAFFIC: + trafficList.append( incomingBytes ); + mPlotter->addSample( trafficList ); + break; + case OUTGOING_TRAFFIC: + trafficList.append( outgoingBytes ); + mPlotter->addSample( trafficList ); + break; + case NONE: + break; + } + } +} + +void Interface::configurePlotter() +{ + mPlotter->setFontSize( mPlotterSettings.fontSize ); + if ( !mPlotterSettings.automaticDetection ) + { + mPlotter->setMinValue( mPlotterSettings.minimumValue ); + mPlotter->setMaxValue( mPlotterSettings.maximumValue ); + } + mPlotter->setHorizontalScale( mPlotterSettings.pixel ); + mPlotter->setHorizontalLinesCount( mPlotterSettings.count ); + mPlotter->setVerticalLinesDistance( mPlotterSettings.distance ); + mPlotter->setShowLabels( mPlotterSettings.labels ); + mPlotter->setShowTopBar( mPlotterSettings.topBar ); + mPlotter->setShowVerticalLines( mPlotterSettings.verticalLines ); + mPlotter->setShowHorizontalLines( mPlotterSettings.horizontalLines ); + mPlotter->setUseAutoRange( mPlotterSettings.automaticDetection ); + mPlotter->setVerticalLinesScroll( mPlotterSettings.verticalLinesScroll ); + mPlotter->setVerticalLinesColor( mPlotterSettings.colorVLines ); + mPlotter->setHorizontalLinesColor( mPlotterSettings.colorHLines ); + mPlotter->setBackgroundColor( mPlotterSettings.colorBackground ); + + // add or remove beams according to user settings + VisibleBeams nextVisibleBeams = NONE; + if ( mPlotterSettings.showOutgoing ) + nextVisibleBeams = (VisibleBeams) ( nextVisibleBeams | OUTGOING_TRAFFIC ); + if ( mPlotterSettings.showIncoming ) + nextVisibleBeams = (VisibleBeams) ( nextVisibleBeams | INCOMING_TRAFFIC ); + + QValueList<QColor>& colors = mPlotter->beamColors(); + switch( mVisibleBeams ) + { + case NONE: + if ( nextVisibleBeams == BOTH ) + { + mOutgoingPos = 0; + mPlotter->addBeam( mPlotterSettings.colorOutgoing ); + mIncomingPos = 1; + mPlotter->addBeam( mPlotterSettings.colorIncoming ); + } + else if ( nextVisibleBeams == OUTGOING_TRAFFIC ) + { + mOutgoingPos = 0; + mPlotter->addBeam( mPlotterSettings.colorOutgoing ); + } + else if ( nextVisibleBeams == INCOMING_TRAFFIC ) + { + mIncomingPos = 0; + mPlotter->addBeam( mPlotterSettings.colorIncoming ); + } + break; + case INCOMING_TRAFFIC: + if ( nextVisibleBeams == BOTH ) + { + mOutgoingPos = 1; + mPlotter->addBeam( mPlotterSettings.colorOutgoing ); + } + else if ( nextVisibleBeams == OUTGOING_TRAFFIC ) + { + mPlotter->removeBeam( mIncomingPos ); + mOutgoingPos = 0; + mPlotter->addBeam( mPlotterSettings.colorOutgoing ); + } + else if ( nextVisibleBeams == INCOMING_TRAFFIC ) + { + colors[mIncomingPos] = ( mPlotterSettings.colorIncoming ); + } + else if ( nextVisibleBeams == NONE ) + { + mPlotter->removeBeam( mIncomingPos ); + } + break; + case OUTGOING_TRAFFIC: + if ( nextVisibleBeams == BOTH ) + { + mIncomingPos = 1; + mPlotter->addBeam( mPlotterSettings.colorIncoming ); + } + else if ( nextVisibleBeams == INCOMING_TRAFFIC ) + { + mPlotter->removeBeam( mOutgoingPos ); + mIncomingPos = 0; + mPlotter->addBeam( mPlotterSettings.colorIncoming ); + } + else if ( nextVisibleBeams == OUTGOING_TRAFFIC ) + { + colors[mOutgoingPos] = ( mPlotterSettings.colorOutgoing ); + } + else if ( nextVisibleBeams == NONE ) + { + mPlotter->removeBeam( mOutgoingPos ); + } + break; + case BOTH: + if ( nextVisibleBeams == BOTH ) + { + colors[mIncomingPos] = ( mPlotterSettings.colorIncoming ); + colors[mOutgoingPos] = ( mPlotterSettings.colorOutgoing ); + } + else if ( nextVisibleBeams == OUTGOING_TRAFFIC ) + { + mOutgoingPos = 0; + mPlotter->removeBeam( mIncomingPos ); + } + else if ( nextVisibleBeams == INCOMING_TRAFFIC ) + { + mIncomingPos = 0; + mPlotter->removeBeam( mOutgoingPos ); + } + else if ( nextVisibleBeams == NONE ) + { + mPlotter->removeBeam( 0 ); + mPlotter->removeBeam( 0 ); + } + break; + } + mVisibleBeams = nextVisibleBeams; + mPlotter->repaint(); +} + +void Interface::startStatistics() +{ + mStatistics = new InterfaceStatistics( this ); + connect( &mMonitor, SIGNAL( incomingData( unsigned long ) ), + mStatistics, SLOT( addIncomingData( unsigned long ) ) ); + connect( &mMonitor, SIGNAL( outgoingData( unsigned long ) ), + mStatistics, SLOT( addOutgoingData( unsigned long ) ) ); + if ( mStatusDialog != 0 ) + { + connect( mStatistics, SIGNAL( currentEntryChanged() ), + mStatusDialog, SLOT( statisticsChanged() ) ); + mStatusDialog->statisticsChanged(); + } + + mStatistics->loadStatistics(); +} + +void Interface::stopStatistics() +{ + if ( mStatisticsDialog != 0 ) + { + // this will close an open statistics dialog + delete mStatisticsDialog; + mStatisticsDialog = 0; + } + + mStatistics->saveStatistics(); + + delete mStatistics; + mStatistics = 0; +} + +// taken from ksystemtray.cpp +void Interface::activateOrHide( QWidget* widget, bool onlyActivate ) +{ + if ( !widget ) + return; + + KWin::WindowInfo info1 = KWin::windowInfo( widget->winId(), NET::XAWMState | NET::WMState ); + // mapped = visible (but possibly obscured) + bool mapped = (info1.mappingState() == NET::Visible) && !info1.isMinimized(); + // - not mapped -> show, raise, focus + // - mapped + // - obscured -> raise, focus + // - not obscured -> hide + if( !mapped ) + { + KWin::setOnDesktop( widget->winId(), KWin::currentDesktop() ); + widget->show(); + widget->raise(); + KWin::activateWindow( widget->winId() ); + } + else + { + KWinModule module; + for( QValueList< WId >::ConstIterator it = module.stackingOrder().fromLast(); + it != module.stackingOrder().end() && (*it) != widget->winId(); + --it ) + { + KWin::WindowInfo info2 = KWin::windowInfo( *it, (unsigned long) + NET::WMGeometry | NET::XAWMState | NET::WMState | NET::WMWindowType ); + if( info2.mappingState() != NET::Visible ) + continue; // not visible on current desktop -> ignore + if( !info2.geometry().intersects( widget->geometry())) + continue; // not obscuring the window -> ignore + if( !info1.hasState( NET::KeepAbove ) && info2.hasState( NET::KeepAbove )) + continue; // obscured by window kept above -> ignore + NET::WindowType type = info2.windowType( NET::NormalMask | NET::DesktopMask + | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask + | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask ); + if( type == NET::Dock || type == NET::TopMenu ) + continue; // obscured by dock or topmenu -> ignore + widget->raise(); + KWin::activateWindow( widget->winId()); + return; + } + if ( !onlyActivate ) + { + widget->hide(); + } + } +} + +#include "interface.moc" diff --git a/src/knemod/interface.h b/src/knemod/interface.h new file mode 100644 index 0000000..06bea0a --- /dev/null +++ b/src/knemod/interface.h @@ -0,0 +1,243 @@ +/* This file is part of KNemo + Copyright (C) 2004, 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef INTERFACE_H +#define INTERFACE_H + +#include <qobject.h> +#include <qstring.h> +#include <qdatetime.h> + +#include "data.h" +#include "global.h" +#include "interfaceicon.h" +#include "interfacemonitor.h" + +class QTimer; +class SignalPlotter; +class InterfaceStatistics; +class InterfaceStatusDialog; +class InterfaceStatisticsDialog; + +/** + * This class is the central place for all things that belong to an + * interface. It stores some information and knows about the interface + * data, icon, monitor and settings. + * + * @short Central class for every interface + * @author Percy Leonhardt <[email protected]> + */ +class Interface : public QObject +{ + Q_OBJECT +public: + /** + * Default Constructor + */ + Interface(QString ifname, + const GeneralData& generalData, + const PlotterSettings& plotterSettings ); + + /** + * Default Destructor + */ + virtual ~Interface(); + + void setType( int type ) + { + mType = type; + } + + int getType() + { + return mType; + } + + void setState( int state ) + { + mState = state; + } + + int getState() + { + return mState; + } + + const QDateTime& getStartTime() const + { + return mStartTime; + } + + const QString& getName() const + { + return mName; + } + + InterfaceData& getData() + { + return mData; + } + + InterfaceSettings& getSettings() + { + return mSettings; + } + + WirelessData& getWirelessData() + { + return mWirelessData; + } + + const GeneralData& getGeneralData() const + { + return mGeneralData; + } + + InterfaceStatistics* getStatistics() + { + return mStatistics; + } + + /** + * Called from reparseConfiguration() when the user changed + * the settings. + */ + void configChanged(); + + /** + * Called from the interface updater class after new data from + * 'ifconfig' has been read. This will trigger the monitor to + * to look for changes in interface data or interface state. + */ + void activateMonitor(); + + enum InterfaceState + { + UNKNOWN_STATE = -1, + NOT_EXISTING = 0, + NOT_AVAILABLE = 1, + AVAILABLE = 2, + RX_TRAFFIC = 4, + TX_TRAFFIC = 8 + }; + + enum InterfaceType + { + UNKNOWN_TYPE, + ETHERNET, + PPP + }; + + enum IconSet + { + MONITOR = 0, + MODEM, + NETWORK, + WIRELESS + }; + +public slots: + /* + * Called when the user left-clicks on the tray icon + * Toggles the status dialog by showing it on the first click and + * hiding it on the second click. + */ + void showStatusDialog(); + + /* + * Called when the user middle-clicks on the tray icon + * Toggles the signal plotter that displays the incoming and + * outgoing traffic. + */ + void showSignalPlotter( bool wasMiddleButton ); + + /* + * Called when the user selects the appropriate entry in the context menu. + */ + void showStatisticsDialog(); + + /* + * Reset data when PPP interface is disconnected + */ + void resetData( int state ); + +private slots: + /** + * Start the uptimer when the interface is connected + */ + void setStartTime( int ); + + /** + * Update the signal plotter with new data + */ + void updatePlotter(); + + /** + * Configure the signal plotter with user settings + */ + void configurePlotter(); + +private: + /** + * Start the statistics and load previously saved ones + */ + void startStatistics(); + + /** + * Store the statistics and stop collecting any further data + */ + void stopStatistics(); + + /** + * The following function is taken from ksystemtray.cpp for + * correct show, raise, focus and hide of status dialog and + * signal plotter. + */ + void activateOrHide( QWidget* widget, bool onlyActivate = false ); + + enum VisibleBeams + { + NONE = 0, + INCOMING_TRAFFIC = 1, + OUTGOING_TRAFFIC = 2, + BOTH = 3 + }; + + int mType; + int mState; + int mOutgoingPos; + int mIncomingPos; + QString mName; + QTimer* mPlotterTimer; + QDateTime mStartTime; + InterfaceIcon mIcon; + InterfaceData mData; + InterfaceMonitor mMonitor; + InterfaceSettings mSettings; + InterfaceStatistics* mStatistics; + WirelessData mWirelessData; + InterfaceStatusDialog* mStatusDialog; + InterfaceStatisticsDialog* mStatisticsDialog; + SignalPlotter* mPlotter; + VisibleBeams mVisibleBeams; + const GeneralData& mGeneralData; + const PlotterSettings& mPlotterSettings; +}; + +#endif // INTERFACE_H diff --git a/src/knemod/interfaceicon.cpp b/src/knemod/interfaceicon.cpp new file mode 100644 index 0000000..4bda3df --- /dev/null +++ b/src/knemod/interfaceicon.cpp @@ -0,0 +1,309 @@ +/* This file is part of KNemo + Copyright (C) 2004, 2005 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <unistd.h> + +#include <qpixmap.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kprocess.h> +#include <kpopupmenu.h> +#include <kiconloader.h> +#include <knotifyclient.h> + +#include "data.h" +#include "interface.h" +#include "knemodaemon.h" +#include "interfaceicon.h" +#include "interfacetray.h" +#include "interfacemonitor.h" +#include "interfacetooltip.h" + +const QString InterfaceIcon::ICON_DISCONNECTED = "network_disconnected"; +const QString InterfaceIcon::ICON_CONNECTED = "network_connected"; +const QString InterfaceIcon::ICON_INCOMING = "network_incoming"; +const QString InterfaceIcon::ICON_OUTGOING = "network_outgoing"; +const QString InterfaceIcon::ICON_TRAFFIC = "network_traffic"; +const QString InterfaceIcon::SUFFIX_PPP = "_ppp"; +const QString InterfaceIcon::SUFFIX_LAN = "_lan"; +const QString InterfaceIcon::SUFFIX_WLAN = "_wlan"; + +InterfaceIcon::InterfaceIcon( Interface* interface ) + : QObject(), + mInterface( interface ), + mTray( 0L ) +{ +} + +InterfaceIcon::~InterfaceIcon() +{ + if ( mTray != 0L ) + delete mTray; +} + +void InterfaceIcon::updateStatus( int status ) +{ + if ( mTray == 0L ) + return; + + // If the user wants something different than the default icons + // append the correct suffix to the filename. + QString suffix; + if ( mInterface->getSettings().iconSet == Interface::NETWORK ) + { + suffix = SUFFIX_LAN; + } + else if ( mInterface->getSettings().iconSet == Interface::WIRELESS ) + { + suffix = SUFFIX_WLAN; + } + else if ( mInterface->getSettings().iconSet == Interface::MODEM ) + { + suffix = SUFFIX_PPP; + } + else + { + suffix = ""; // use standard icons + } + + // Now set the correct icon depending on the status of the interface. + if ( status == Interface::NOT_AVAILABLE || + status == Interface::NOT_EXISTING ) + { + mTray->setPixmap( mTray->loadIcon( ICON_DISCONNECTED + suffix ) ); + } + else if ( ( status & Interface::RX_TRAFFIC ) && + ( status & Interface::TX_TRAFFIC ) ) + { + mTray->setPixmap( mTray->loadIcon( ICON_TRAFFIC + suffix ) ); + } + else if ( status & Interface::RX_TRAFFIC ) + { + mTray->setPixmap( mTray->loadIcon( ICON_INCOMING + suffix ) ); + } + else if ( status & Interface::TX_TRAFFIC ) + { + mTray->setPixmap( mTray->loadIcon( ICON_OUTGOING + suffix ) ); + } + else + { + mTray->setPixmap( mTray->loadIcon( ICON_CONNECTED + suffix ) ); + } +} + +void InterfaceIcon::updateToolTip() +{ + if ( mTray == 0L ) + return; + + QString toolTip = mInterface->getSettings().alias; + if ( toolTip == QString::null ) + toolTip = mInterface->getName(); + new InterfaceToolTip( mInterface, mTray ); +} + +void InterfaceIcon::updateMenu() +{ + if ( mTray == 0L ) + return; + + // Remove all old entries. + KPopupMenu* menu = mTray->contextMenu(); + int count = menu->count(); + for ( int i = 0; i < count - 6; i++ ) + menu->removeItemAt( 6 ); + + InterfaceSettings& settings = mInterface->getSettings(); + + // If the user wants statistics, add an entry to show them. + if ( settings.activateStatistics ) + { + menu->insertItem( i18n( "Open &Statistics" ), this, + SIGNAL( statisticsSelected() ) ); + } + + // If the user wants custom commands, add them. + if ( settings.customCommands ) + { + menu->insertSeparator(); + QValueVector<InterfaceCommand>::iterator it; + for ( it = settings.commands.begin(); it != settings.commands.end(); it++ ) + (*it).id = menu->insertItem( (*it).menuText ); + } +} + +void InterfaceIcon::updateTrayStatus( int previousState ) +{ + bool interfaceExists = mInterface->getData().existing; + bool interfaceAvailable = mInterface->getData().available; + bool hideWhenNotExisting = mInterface->getSettings().hideWhenNotExisting; + bool hideWhenNotAvailable = mInterface->getSettings().hideWhenNotAvailable; + + // notification 'interface not available' + if ( !interfaceAvailable && mTray != 0L && + previousState == Interface::AVAILABLE ) + { + /* When KNemo is starting we don't show the change in connection + * status as this would be annoying when KDE starts. + */ + QString title; + if ( mInterface->getSettings().alias != QString::null ) + title = mInterface->getSettings().alias; + else + title = mInterface->getName(); + + KNotifyClient::event( mTray->winId(), "knemo_disconnected", + title + ":\n" + i18n( "Not connected." ) ); + /* Wait half a second before deleting the tray so that the call + * to the notification daemon has a chance to run before the + * winId gets invalid. + */ + usleep( 500000 ); + } + + // notification 'interface not existing' + if ( !interfaceExists && mTray != 0L && + previousState != Interface::UNKNOWN_STATE ) + { + /* When KNemo is starting we don't show the change in connection + * status as this would be annoying when KDE starts. + */ + QString title; + if ( mInterface->getSettings().alias != QString::null ) + title = mInterface->getSettings().alias; + else + title = mInterface->getName(); + + KNotifyClient::event( mTray->winId(), "knemo_notexisting", + title + ":\n" + i18n( "Not existing." ) ); + /* Wait half a second before deleting the tray so that the call + * to the notification daemon has a chance to run before the + * winId gets invalid. + */ + usleep( 500000 ); + } + + /* Remove the icon if + * - the interface is not available and the option to hide it is selected + * - the interface does not exist, the option to hide it is selected + * and the other option is not selected + */ + if ( mTray != 0L && + ( ( !interfaceAvailable && hideWhenNotAvailable ) || + ( !interfaceExists && hideWhenNotExisting && !hideWhenNotAvailable ) ) ) + { + delete mTray; + mTray = 0L; + } + /* Create the icon if + * - the interface is available + * - the interface is not available and the option to hide it is not + * selected and the interface does exist + * - the interface does not exist and the option to hide it is not selected + * and the other option is not selected + */ + else if ( mTray == 0L && + ( interfaceAvailable || + ( !interfaceAvailable && !hideWhenNotAvailable && interfaceExists ) || + ( !interfaceExists && !hideWhenNotExisting && !hideWhenNotAvailable ) ) ) + { + mTray = new InterfaceTray( mInterface->getName() ); + QToolTip::add( mTray, mInterface->getName() ); + KPopupMenu* menu = mTray->contextMenu(); + connect( menu, SIGNAL( activated( int ) ), + this, SLOT( menuActivated( int ) ) ); + connect( mTray, SIGNAL( leftClicked() ), + mInterface, SLOT( showStatusDialog() ) ); + connect( mTray, SIGNAL( graphSelected( bool ) ), + mInterface, SLOT( showSignalPlotter( bool ) ) ); + connect( mTray, SIGNAL( configSelected() ), + this, SLOT( showConfigDialog() ) ); + + updateStatus( mInterface->getState() ); + updateToolTip(); + updateMenu(); + mTray->show(); + } + + // notification 'interface available' + if ( interfaceAvailable && mTray != 0L && + previousState != Interface::UNKNOWN_STATE ) + { + /* When KNemo is starting we don't show the change in connection + * status as this would be annoying when KDE starts. + */ + QString title; + if ( mInterface->getSettings().alias != QString::null ) + title = mInterface->getSettings().alias; + else + title = mInterface->getName(); + + /* Wait half a second before calling the notification daemon + * so that the winId of the tray is valid when used below. + */ + usleep( 500000 ); + if ( mInterface->getData().wirelessDevice ) + { + KNotifyClient::event( mTray->winId(), "knemo_connected", + title + ":\n" + i18n( "Connection established to\n" ) + + mInterface->getWirelessData().essid ); + } + else + { + KNotifyClient::event( mTray->winId(), "knemo_connected", + title + ":\n" + i18n( "Connection established." ) ); + } + } +} + +void InterfaceIcon::showConfigDialog() +{ + KNemoDaemon::sSelectedInterface = mInterface->getName(); + + KProcess process; + process << "kcmshell" << "kcm_knemo"; + process.start( KProcess::DontCare ); +} + +void InterfaceIcon::menuActivated( int id ) +{ + InterfaceSettings& settings = mInterface->getSettings(); + QValueVector<InterfaceCommand>::iterator it; + for ( it = settings.commands.begin(); it != settings.commands.end(); it++ ) + { + if ( (*it).id == id ) + { + KProcess process; + if ( (*it).runAsRoot ) + { + process << "kdesu"; + process << (*it).command; + } + else + process << QStringList::split( ' ', (*it).command ); + + process.start( KProcess::DontCare ); + break; + } + } +} + +#include "interfaceicon.moc" diff --git a/src/knemod/interfaceicon.h b/src/knemod/interfaceicon.h new file mode 100644 index 0000000..96d320b --- /dev/null +++ b/src/knemod/interfaceicon.h @@ -0,0 +1,105 @@ +/* This file is part of KNemo + Copyright (C) 2004, 2005 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef INTERFACEICON_H +#define INTERFACEICON_H + +#include <qobject.h> +#include <qstring.h> + +class Interface; +class InterfaceTray; + +/** + * This is the logical representation of the systemtray icon. It handles + * creation and deletion of the real icon, setting the tooltip, setting + * the correct icon image and displaying of the settings dialog. + * + * @short Logical representation of the systemtray icon + * @author Percy Leonhardt <[email protected]> + */ + +class InterfaceIcon : public QObject +{ + Q_OBJECT +public: + /** + * Default Constructor + */ + InterfaceIcon( Interface* interface ); + + /** + * Default Destructor + */ + virtual ~InterfaceIcon(); + + /* + * Change the tooltip according to the alias of the interface + */ + void updateToolTip(); + + /* + * Fill the context menu with entries if the user configured + * start and stop command + */ + void updateMenu(); + +signals: + void statisticsSelected(); + +public slots: + /* + * Changes the icon image displayed in the tray + */ + void updateStatus( int status ); + + /* + * Creates or deletes the tray icon + */ + void updateTrayStatus( int previousState ); + +private slots: + /* + * Called when the user selects 'Configure KNemo' from the context menu + */ + void showConfigDialog(); + + /* + * Called when the user setup custom commands and selects one + * in the context menu + */ + void menuActivated( int id ); + +private: + // the interface this icon belongs to + Interface* mInterface; + // the real tray icon + InterfaceTray* mTray; + + static const QString ICON_DISCONNECTED; + static const QString ICON_CONNECTED; + static const QString ICON_INCOMING; + static const QString ICON_OUTGOING; + static const QString ICON_TRAFFIC; + static const QString SUFFIX_PPP; + static const QString SUFFIX_LAN; + static const QString SUFFIX_WLAN; +}; + +#endif // INTERFACEICON_H diff --git a/src/knemod/interfacemonitor.cpp b/src/knemod/interfacemonitor.cpp new file mode 100644 index 0000000..b75d35e --- /dev/null +++ b/src/knemod/interfacemonitor.cpp @@ -0,0 +1,100 @@ +/* This file is part of KNemo + Copyright (C) 2004, 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <kdebug.h> + +#include "interface.h" +#include "interfacemonitor.h" + +InterfaceMonitor::InterfaceMonitor( QObject* parent, const char* name ) + : QObject( parent, name ) +{ +} + +InterfaceMonitor::~InterfaceMonitor() +{ +} + +void InterfaceMonitor::checkStatus( Interface* interface ) +{ + int currentState; + int previousState = interface->getState(); + InterfaceData& data = interface->getData(); + int trafficThreshold = interface->getSettings().trafficThreshold; + + if ( !data.existing ) + // the interface does not exist + currentState = Interface::NOT_EXISTING; + else if ( !data.available ) + // the interface exists but is not connected + currentState = Interface::NOT_AVAILABLE; + else + { + // the interface is connected, look for traffic + currentState = Interface::AVAILABLE; + if ( ( data.rxPackets - data.prevRxPackets ) > (unsigned int) trafficThreshold ) + currentState |= Interface::RX_TRAFFIC; + if ( ( data.txPackets - data.prevTxPackets ) > (unsigned int) trafficThreshold ) + currentState |= Interface::TX_TRAFFIC; + } + + // update the statistics + if ( data.incomingBytes > 0 ) + { + emit incomingData( data.incomingBytes ); + } + if ( data.outgoingBytes > 0 ) + { + emit outgoingData( data.outgoingBytes ); + } + + data.prevRxPackets = data.rxPackets; + data.prevTxPackets = data.txPackets; + + if ( ( previousState == Interface::NOT_EXISTING || + previousState == Interface::NOT_AVAILABLE || + previousState == Interface::UNKNOWN_STATE ) && + currentState & Interface::AVAILABLE ) + { + emit available( previousState ); + } + else if ( ( previousState == Interface::NOT_EXISTING || + previousState & Interface::AVAILABLE || + previousState == Interface::UNKNOWN_STATE ) && + currentState == Interface::NOT_AVAILABLE ) + { + emit notAvailable( previousState ); + } + else if ( ( previousState == Interface::NOT_AVAILABLE || + previousState & Interface::AVAILABLE || + previousState == Interface::UNKNOWN_STATE ) && + currentState == Interface::NOT_EXISTING ) + { + emit notExisting( previousState ); + } + + // make sure the icon fits the current state + if ( previousState != currentState ) + { + emit statusChanged( currentState ); + interface->setState( currentState ); + } +} + +#include "interfacemonitor.moc" diff --git a/src/knemod/interfacemonitor.h b/src/knemod/interfacemonitor.h new file mode 100644 index 0000000..eacc1ea --- /dev/null +++ b/src/knemod/interfacemonitor.h @@ -0,0 +1,72 @@ +/* This file is part of KNemo + Copyright (C) 2004, 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef INTERFACEMONITOR_H +#define INTERFACEMONITOR_H + +#include <qobject.h> + +#include "data.h" + +class Interface; + +/** + * This class monitors the interface for possible state changes and + * for incoming and outgong traffic. If the state changed or traffic + * was transmitted it sends an according signal. + * + * @short Monitor changes of the interface + * @author Percy Leonhardt <[email protected]> + */ + +class InterfaceMonitor : public QObject +{ + Q_OBJECT +public: + /** + * Default Constructor + */ + InterfaceMonitor(QObject* parent = 0L, const char* name = 0L); + + /** + * Default Destructor + */ + virtual ~InterfaceMonitor(); + + /** + * Tell the monitor to check the status of the interface + */ + void checkStatus( Interface* interface ); + +signals: + // the interface is now connected + void available( int ); + // the interface is now disconnected + void notAvailable( int ); + // the interface no longer exists + void notExisting( int ); + // there was incoming and/or outgoing traffic + void statusChanged( int ); + // the amount of incoming traffic (for statistics) + void incomingData( unsigned long ); + // the amount of outgoing traffic (for statistics) + void outgoingData( unsigned long ); +}; + +#endif // INTERFACEMONITOR_H diff --git a/src/knemod/interfacestatistics.cpp b/src/knemod/interfacestatistics.cpp new file mode 100644 index 0000000..a73d04b --- /dev/null +++ b/src/knemod/interfacestatistics.cpp @@ -0,0 +1,384 @@ +/* This file is part of KNemo + Copyright (C) 2005, 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qdom.h> +#include <qfile.h> +#include <qtimer.h> +#include <qstring.h> +#include <qdatetime.h> + +#include <kdebug.h> + +#include "interface.h" +#include "interfacestatistics.h" + +InterfaceStatistics::InterfaceStatistics( Interface* interface ) + : QObject(), + mInterface( interface ) +{ + mDayStatistics.setAutoDelete( true ); + mMonthStatistics.setAutoDelete( true ); + mYearStatistics.setAutoDelete( true ); + initStatistics(); + + mSaveTimer = new QTimer(); + connect( mSaveTimer, SIGNAL( timeout() ), this, SLOT( saveStatistics() ) ); + mSaveTimer->start( mInterface->getGeneralData().saveInterval * 1000 ); +} + +InterfaceStatistics::~InterfaceStatistics() +{ + mSaveTimer->stop(); + delete mSaveTimer; + + mDayStatistics.clear(); + mMonthStatistics.clear(); + mYearStatistics.clear(); +} + +void InterfaceStatistics::loadStatistics() +{ + QDomDocument doc( "statistics" ); + QString dir = mInterface->getGeneralData().statisticsDir; + QFile file( dir + "/statistics_" + mInterface->getName() ); + + if ( !file.open( IO_ReadOnly ) ) + return; + if ( !doc.setContent( &file ) ) + { + file.close(); + return; + } + file.close(); + + mDayStatistics.clear(); + mMonthStatistics.clear(); + mYearStatistics.clear(); + + QDomElement root = doc.documentElement(); + QDomNode n = root.namedItem( "days" ); + if ( !n.isNull() ) + { + QDomNode dayNode = n.firstChild(); + while ( !dayNode.isNull() ) + { + QDomElement day = dayNode.toElement(); + if ( !day.isNull() ) + { + StatisticEntry* entry = new StatisticEntry(); + entry->day = day.attribute( "day" ).toInt(); + entry->month = day.attribute( "month" ).toInt(); + entry->year = day.attribute( "year" ).toInt(); + entry->rxBytes = (Q_UINT64) day.attribute( "rxBytes" ).toDouble(); + entry->txBytes = (Q_UINT64) day.attribute( "txBytes" ).toDouble(); + mDayStatistics.append( entry ); + } + dayNode = dayNode.nextSibling(); + } + mDayStatistics.sort(); + } + + n = root.namedItem( "months" ); + if ( !n.isNull() ) + { + QDomNode monthNode = n.firstChild(); + while ( !monthNode.isNull() ) + { + QDomElement month = monthNode.toElement(); + if ( !month.isNull() ) + { + StatisticEntry* entry = new StatisticEntry(); + entry->day = 0; + entry->month = month.attribute( "month" ).toInt(); + entry->year = month.attribute( "year" ).toInt(); + entry->rxBytes = (Q_UINT64) month.attribute( "rxBytes" ).toDouble(); + entry->txBytes = (Q_UINT64) month.attribute( "txBytes" ).toDouble(); + mMonthStatistics.append( entry ); + } + monthNode = monthNode.nextSibling(); + } + mMonthStatistics.sort(); + } + + n = root.namedItem( "years" ); + if ( !n.isNull() ) + { + QDomNode yearNode = n.firstChild(); + while ( !yearNode.isNull() ) + { + QDomElement year = yearNode.toElement(); + if ( !year.isNull() ) + { + StatisticEntry* entry = new StatisticEntry(); + entry->day = 0; + entry->month = 0; + entry->year = year.attribute( "year" ).toInt(); + entry->rxBytes = (Q_UINT64) year.attribute( "rxBytes" ).toDouble(); + entry->txBytes = (Q_UINT64) year.attribute( "txBytes" ).toDouble(); + mYearStatistics.append( entry ); + } + yearNode = yearNode.nextSibling(); + } + mYearStatistics.sort(); + } + initStatistics(); +} + +void InterfaceStatistics::saveStatistics() +{ + QDomDocument doc( "statistics" ); + QDomElement root = doc.createElement( "statistics" ); + doc.appendChild( root ); + + QDomElement days = doc.createElement( "days" ); + StatisticEntry* iterator = mDayStatistics.first(); + while ( iterator ) + { + QDomElement day = doc.createElement( "day" ); + day.setAttribute( "day", iterator->day ); + day.setAttribute( "month", iterator->month ); + day.setAttribute( "year", iterator->year ); + day.setAttribute( "rxBytes", (double) iterator->rxBytes ); + day.setAttribute( "txBytes", (double) iterator->txBytes ); + days.appendChild( day ); + iterator = mDayStatistics.next(); + } + root.appendChild( days ); + + QDomElement months = doc.createElement( "months" ); + iterator = mMonthStatistics.first(); + while ( iterator ) + { + QDomElement month = doc.createElement( "month" ); + month.setAttribute( "month", iterator->month ); + month.setAttribute( "year", iterator->year ); + month.setAttribute( "rxBytes", (double) iterator->rxBytes ); + month.setAttribute( "txBytes", (double) iterator->txBytes ); + months.appendChild( month ); + iterator = mMonthStatistics.next(); + } + root.appendChild( months ); + + QDomElement years = doc.createElement( "years" ); + iterator = mYearStatistics.first(); + while ( iterator ) + { + QDomElement year = doc.createElement( "year" ); + year.setAttribute( "year", iterator->year ); + year.setAttribute( "rxBytes", (double) iterator->rxBytes ); + year.setAttribute( "txBytes", (double) iterator->txBytes ); + years.appendChild( year ); + iterator = mYearStatistics.next(); + } + root.appendChild( years ); + + QString dir = mInterface->getGeneralData().statisticsDir; + QFile file( dir + "/statistics_" + mInterface->getName() ); + if ( !file.open( IO_WriteOnly ) ) + return; + + QTextStream stream( &file ); + stream << doc.toString(); + file.close(); +} + +void InterfaceStatistics::configChanged() +{ + // restart the timer with the new value + mSaveTimer->changeInterval( mInterface->getGeneralData().saveInterval * 1000 ); +} + +const StatisticEntry* InterfaceStatistics::getCurrentDay() const +{ + return mCurrentDay; +} + +const StatisticEntry* InterfaceStatistics::getCurrentMonth() const +{ + return mCurrentMonth; +} + +const StatisticEntry* InterfaceStatistics::getCurrentYear() const +{ + return mCurrentYear; +} + +const StatisticsPtrList<StatisticEntry>& InterfaceStatistics::getDayStatistics() const +{ + return mDayStatistics; +} + +const StatisticsPtrList<StatisticEntry>& InterfaceStatistics::getMonthStatistics() const +{ + return mMonthStatistics; +} + +const StatisticsPtrList<StatisticEntry>& InterfaceStatistics::getYearStatistics() const +{ + return mYearStatistics; +} + +void InterfaceStatistics::addIncomingData( unsigned long data ) +{ + checkCurrentEntry(); + + mCurrentDay->rxBytes += data; + mCurrentMonth->rxBytes += data; + mCurrentYear->rxBytes += data; + + emit currentEntryChanged(); +} + +void InterfaceStatistics::addOutgoingData( unsigned long data ) +{ + checkCurrentEntry(); + + mCurrentDay->txBytes += data; + mCurrentMonth->txBytes += data; + mCurrentYear->txBytes += data; + + emit currentEntryChanged(); +} + +void InterfaceStatistics::clearDayStatistics() +{ + mDayStatistics.clear(); + updateCurrentDay(); +} + +void InterfaceStatistics::clearMonthStatistics() +{ + mMonthStatistics.clear(); + updateCurrentMonth(); +} + +void InterfaceStatistics::clearYearStatistics() +{ + mYearStatistics.clear(); + updateCurrentYear(); +} + +void InterfaceStatistics::checkCurrentEntry() +{ + if ( mCurrentDay->day != QDate::currentDate().day() || + mCurrentDay->month != QDate::currentDate().month() || + mCurrentDay->year != QDate::currentDate().year() ) + { + // current day has changed + updateCurrentDay(); + + if ( mCurrentMonth->month != QDate::currentDate().month() || + mCurrentMonth->year != QDate::currentDate().year() ) + { + // current month has also changed + updateCurrentMonth(); + } + + if ( mCurrentYear->year != QDate::currentDate().year() ) + { + // current year has also changed + updateCurrentYear(); + } + } +} + +void InterfaceStatistics::initStatistics() +{ + updateCurrentDay(); + updateCurrentMonth(); + updateCurrentYear(); + + emit currentEntryChanged(); +} + +void InterfaceStatistics::updateCurrentDay() +{ + mCurrentDay = mDayStatistics.first(); + while ( mCurrentDay ) + { + if ( mCurrentDay->day == QDate::currentDate().day() && + mCurrentDay->month == QDate::currentDate().month() && + mCurrentDay->year == QDate::currentDate().year() ) + { + // found current day in list + return; + } + mCurrentDay = mDayStatistics.next(); + } + + // the current day is not in the list + mCurrentDay = new StatisticEntry(); + mCurrentDay->day = QDate::currentDate().day(); + mCurrentDay->month = QDate::currentDate().month(); + mCurrentDay->year = QDate::currentDate().year(); + mCurrentDay->rxBytes = 0; + mCurrentDay->txBytes = 0; + mDayStatistics.append( mCurrentDay ); // TODO: insert at correct position + emit dayStatisticsChanged(); +} + +void InterfaceStatistics::updateCurrentMonth() +{ + mCurrentMonth = mMonthStatistics.first(); + while ( mCurrentMonth ) + { + if ( mCurrentMonth->month == QDate::currentDate().month() && + mCurrentMonth->year == QDate::currentDate().year() ) + { + // found current month in list + return; + } + mCurrentMonth = mMonthStatistics.next(); + } + + // the current month is not in the list + mCurrentMonth = new StatisticEntry(); + mCurrentMonth->day = 0; + mCurrentMonth->month = QDate::currentDate().month(); + mCurrentMonth->year = QDate::currentDate().year(); + mCurrentMonth->rxBytes = 0; + mCurrentMonth->txBytes = 0; + mMonthStatistics.append( mCurrentMonth ); // TODO: insert at correct position + emit monthStatisticsChanged(); +} + +void InterfaceStatistics::updateCurrentYear() +{ + mCurrentYear = mYearStatistics.first(); + while ( mCurrentYear ) + { + if ( mCurrentYear->year == QDate::currentDate().year() ) + { + // found current year in list + return; + } + mCurrentYear = mYearStatistics.next(); + } + + // the current year is not in the list + mCurrentYear = new StatisticEntry(); + mCurrentYear->day = 0; + mCurrentYear->month = 0; + mCurrentYear->year = QDate::currentDate().year(); + mCurrentYear->rxBytes = 0; + mCurrentYear->txBytes = 0; + mYearStatistics.append( mCurrentYear ); // TODO: insert at correct position + emit yearStatisticsChanged(); +} + diff --git a/src/knemod/interfacestatistics.h b/src/knemod/interfacestatistics.h new file mode 100644 index 0000000..a4e3246 --- /dev/null +++ b/src/knemod/interfacestatistics.h @@ -0,0 +1,191 @@ +/* This file is part of KNemo + Copyright (C) 2005, 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef INTERFACESTATISTICS_H +#define INTERFACESTATISTICS_H + +#include <qobject.h> +#include <qptrlist.h> + +#include "global.h" + +class QTimer; +class Interface; + +template<class type> +class StatisticsPtrList : public QPtrList<type> +{ +protected: + virtual int compareItems ( QPtrCollection::Item item1, QPtrCollection::Item item2 ) + { + StatisticEntry* entry1 = static_cast<StatisticEntry*>( item1 ); + StatisticEntry* entry2 = static_cast<StatisticEntry*>( item2 ); + + if ( entry1->year > entry2->year ) + { + return 1; + } + else if ( entry2->year > entry1->year ) + { + return -1; + } // ...here we know that years are the same... + else if ( entry1->month > entry2->month ) + { + return 1; + } + else if ( entry2->month > entry1->month ) + { + return -1; + } // ...here we know that months are the same... + else if ( entry1->day > entry2->day ) + { + return 1; + } + else if ( entry2->day > entry1->day ) + { + return -1; + } // ...here we know that dates are equal. + + return 0; + }; +}; + +/** + * This class is able to collect transfered data for an interface, + * store it in a file and deliver it on request. + * + * @short Statistics of transfered data for an interface + * @author Percy Leonhardt <[email protected]> + */ + +class InterfaceStatistics : public QObject +{ + Q_OBJECT +public: + /** + * Default Constructor + */ + InterfaceStatistics( Interface* interface ); + + /** + * Default Destructor + */ + virtual ~InterfaceStatistics(); + + /** + * Load the statistics from a xml file + */ + void loadStatistics(); + + /** + * Called from Interface::configChanged() when the user + * changed the settings. + */ + void configChanged(); + + const StatisticEntry* getCurrentDay() const; + const StatisticEntry* getCurrentMonth() const; + const StatisticEntry* getCurrentYear() const; + const StatisticsPtrList<StatisticEntry>& getDayStatistics() const; + const StatisticsPtrList<StatisticEntry>& getMonthStatistics() const; + const StatisticsPtrList<StatisticEntry>& getYearStatistics() const; + +signals: + /** + * The current entry has changed. There is only one signal + * for day, month and year because if the day changes, + * month and year also change. + */ + void currentEntryChanged(); + /** + * The list has changed i.e. there is a new day entry or the list was cleared + */ + void dayStatisticsChanged(); + /** + * The list has changed i.e. there is a new month entry or the list was cleared + */ + void monthStatisticsChanged(); + /** + * The list has changed i.e. there is a new year entry or the list was cleared + */ + void yearStatisticsChanged(); + +public slots: + /** + * Save the statistics to a xml file + * (slot so it can be triggered by a timer signal) + */ + void saveStatistics(); + /** + * Add incoming data to the current day, month and year + */ + void addIncomingData( unsigned long data ); + /** + * Add outgoing data to the current day, month and year + */ + void addOutgoingData( unsigned long data ); + /** + * Clear all entries of the day statistics + */ + void clearDayStatistics(); + /** + * Clear all entries of the month statistics + */ + void clearMonthStatistics(); + /** + * Clear all entries of the year statistics + */ + void clearYearStatistics(); + +private: + /** + * Make sure the current entry corresponds with the current date + */ + void checkCurrentEntry(); + /** + * Fill the statistics with a current entry + */ + void initStatistics(); + /** + * Check if the current day is in the day statistics. If found set + * mCurrentDay to the found entry else create a new one. + */ + void updateCurrentDay(); + /** + * Check if the current month is in the month statistics. If found set + * mCurrentMonth to the found entry else create a new one. + */ + void updateCurrentMonth(); + /** + * Check if the current year is in the year statistics. If found set + * mCurrentYear to the found entry else create a new one. + */ + void updateCurrentYear(); + + QTimer* mSaveTimer; + Interface* mInterface; + StatisticEntry* mCurrentDay; + StatisticEntry* mCurrentMonth; + StatisticEntry* mCurrentYear; + StatisticsPtrList<StatisticEntry> mDayStatistics; + StatisticsPtrList<StatisticEntry> mMonthStatistics; + StatisticsPtrList<StatisticEntry> mYearStatistics; +}; + +#endif // INTERFACESTATISTICS_H diff --git a/src/knemod/interfacestatisticsdialog.cpp b/src/knemod/interfacestatisticsdialog.cpp new file mode 100644 index 0000000..55ee49a --- /dev/null +++ b/src/knemod/interfacestatisticsdialog.cpp @@ -0,0 +1,139 @@ +/* This file is part of KNemo + Copyright (C) 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qtable.h> +#include <qdatetime.h> +#include <qpushbutton.h> + +#include <klocale.h> +#include <kio/global.h> +#include <kiconloader.h> +#include <kcalendarsystem.h> + +#include "data.h" +#include "interface.h" +#include "interfacestatistics.h" +#include "interfacestatisticsdialog.h" + +/* + * I assume that the last entry in each table is also the current. This will fail + * if we walk back in time, so better not play with the system date... + */ + +InterfaceStatisticsDialog::InterfaceStatisticsDialog( Interface* interface, QWidget* parent, const char* name ) + : InterfaceStatisticsDlg( parent, name ), + mInterface( interface ) +{ + setIcon( SmallIcon( "knemo" ) ); + setCaption( interface->getName() + " " + i18n( "Statistics" ) ); + + connect( buttonClearDaily, SIGNAL( clicked() ), SIGNAL( clearDailyStatisticsClicked() ) ); + connect( buttonClearMonthly, SIGNAL( clicked() ), SIGNAL( clearMonthlyStatisticsClicked() ) ); + connect( buttonClearYearly, SIGNAL( clicked() ), SIGNAL( clearYearlyStatisticsClicked() ) ); +} + +InterfaceStatisticsDialog::~InterfaceStatisticsDialog() +{ +} + +void InterfaceStatisticsDialog::updateDays() +{ + QPtrList<StatisticEntry> dayStatistics = mInterface->getStatistics()->getDayStatistics(); + StatisticEntry* iterator = dayStatistics.first(); + tableDaily->setNumRows( dayStatistics.count() ); + int row = 0; + while ( iterator ) + { + QDate date( iterator->year, iterator->month, iterator->day ); + tableDaily->verticalHeader()->setLabel( row, KGlobal::locale()->formatDate( date, true ) ); + tableDaily->setText( row, 0, KIO::convertSize( iterator->txBytes ) ); + tableDaily->setText( row, 1, KIO::convertSize( iterator->rxBytes ) ); + tableDaily->setText( row, 2, KIO::convertSize( iterator->rxBytes + iterator->txBytes ) ); + row++; + iterator = dayStatistics.next(); + } + + tableDaily->setCurrentCell( row - 1, 2 ); + tableDaily->ensureCellVisible( row - 1, 2 ); +} + +void InterfaceStatisticsDialog::updateMonths() +{ + QPtrList<StatisticEntry> monthStatistics = mInterface->getStatistics()->getMonthStatistics(); + StatisticEntry* iterator = monthStatistics.first(); + tableMonthly->setNumRows( monthStatistics.count() ); + int row = 0; + while ( iterator ) + { + const KCalendarSystem* calendar = KGlobal::locale()->calendar(); + QString monthName = calendar->monthName( iterator->month, iterator->year ) + " " + QString::number( iterator->year ); + tableMonthly->verticalHeader()->setLabel( row, monthName ); + tableMonthly->setText( row, 0, KIO::convertSize( iterator->txBytes ) ); + tableMonthly->setText( row, 1, KIO::convertSize( iterator->rxBytes ) ); + tableMonthly->setText( row, 2, KIO::convertSize( iterator->rxBytes + iterator->txBytes ) ); + row++; + iterator = monthStatistics.next(); + } + + tableMonthly->setCurrentCell( row - 1, 2 ); + tableMonthly->ensureCellVisible( row - 1, 2 ); +} + +void InterfaceStatisticsDialog::updateYears() +{ + QPtrList<StatisticEntry> yearStatistics = mInterface->getStatistics()->getYearStatistics(); + StatisticEntry* iterator = yearStatistics.first(); + tableYearly->setNumRows( yearStatistics.count() ); + int row = 0; + while ( iterator ) + { + tableYearly->verticalHeader()->setLabel( row, QString::number( iterator->year ) ); + tableYearly->setText( row, 0, KIO::convertSize( iterator->txBytes ) ); + tableYearly->setText( row, 1, KIO::convertSize( iterator->rxBytes ) ); + tableYearly->setText( row, 2, KIO::convertSize( iterator->rxBytes + iterator->txBytes ) ); + row++; + iterator = yearStatistics.next(); + } + + tableYearly->setCurrentCell( row - 1, 2 ); + tableYearly->ensureCellVisible( row - 1, 2 ); +} + +void InterfaceStatisticsDialog::updateCurrentEntry() +{ + int lastRow = tableDaily->numRows() - 1; + const StatisticEntry* currentEntry = mInterface->getStatistics()->getCurrentDay(); + tableDaily->setText( lastRow, 0, KIO::convertSize( currentEntry->txBytes ) ); + tableDaily->setText( lastRow, 1, KIO::convertSize( currentEntry->rxBytes ) ); + tableDaily->setText( lastRow, 2, KIO::convertSize( currentEntry->rxBytes + currentEntry->txBytes ) ); + + lastRow = tableMonthly->numRows() - 1; + currentEntry = mInterface->getStatistics()->getCurrentMonth(); + tableMonthly->setText( lastRow, 0, KIO::convertSize( currentEntry->txBytes ) ); + tableMonthly->setText( lastRow, 1, KIO::convertSize( currentEntry->rxBytes ) ); + tableMonthly->setText( lastRow, 2, KIO::convertSize( currentEntry->rxBytes + currentEntry->txBytes ) ); + + lastRow = tableYearly->numRows() - 1; + currentEntry = mInterface->getStatistics()->getCurrentYear(); + tableYearly->setText( lastRow, 0, KIO::convertSize( currentEntry->txBytes ) ); + tableYearly->setText( lastRow, 1, KIO::convertSize( currentEntry->rxBytes ) ); + tableYearly->setText( lastRow, 2, KIO::convertSize( currentEntry->rxBytes + currentEntry->txBytes ) ); +} + +#include "interfacestatisticsdialog.moc" diff --git a/src/knemod/interfacestatisticsdialog.h b/src/knemod/interfacestatisticsdialog.h new file mode 100644 index 0000000..ce5e0e3 --- /dev/null +++ b/src/knemod/interfacestatisticsdialog.h @@ -0,0 +1,68 @@ +/* This file is part of KNemo + Copyright (C) 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef INTERFACESTATISTICSDIALOG_H +#define INTERFACESTATISTICSDIALOG_H + +#include <qwidget.h> + +#include "interfacestatisticsdlg.h" + +class QTimer; +class Interface; + +/** + * This class shows the statistics dialog. It contains the tables for the + * different statistics. + * + * @short Statistics dialog + * @author Percy Leonhardt <[email protected]> + */ + +class InterfaceStatisticsDialog : public InterfaceStatisticsDlg +{ + Q_OBJECT +public: + /** + * Default Constructor + */ + InterfaceStatisticsDialog( Interface* interface, + QWidget* parent = 0L, const char* name = 0L ); + + /** + * Default Destructor + */ + virtual ~InterfaceStatisticsDialog(); + +signals: + void clearDailyStatisticsClicked(); + void clearMonthlyStatisticsClicked(); + void clearYearlyStatisticsClicked(); + +public slots: + void updateDays(); + void updateMonths(); + void updateYears(); + void updateCurrentEntry(); + +private: + Interface* mInterface; +}; + +#endif // INTERFACESTATISTICSDIALOG_H diff --git a/src/knemod/interfacestatisticsdlg.ui b/src/knemod/interfacestatisticsdlg.ui new file mode 100644 index 0000000..b028832 --- /dev/null +++ b/src/knemod/interfacestatisticsdlg.ui @@ -0,0 +1,230 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>InterfaceStatisticsDlg</class> +<widget class="QDialog"> + <property name="name"> + <cstring>InterfaceStatisticsDlg</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>490</width> + <height>502</height> + </rect> + </property> + <property name="caption"> + <string>Statistics</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>buttonClose</cstring> + </property> + <property name="text"> + <string>&Close</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QTabWidget" row="0" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>tabWidget</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>daily</cstring> + </property> + <attribute name="title"> + <string>Daily</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QTable"> + <column> + <property name="text"> + <string>Sent</string> + </property> + </column> + <column> + <property name="text"> + <string>Received</string> + </property> + </column> + <column> + <property name="text"> + <string>Total</string> + </property> + </column> + <property name="name"> + <cstring>tableDaily</cstring> + </property> + <property name="numRows"> + <number>1</number> + </property> + <property name="numCols"> + <number>3</number> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonClearDaily</cstring> + </property> + <property name="text"> + <string>Clear daily statistics</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>monthy</cstring> + </property> + <attribute name="title"> + <string>Monthly</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QTable"> + <column> + <property name="text"> + <string>Sent</string> + </property> + </column> + <column> + <property name="text"> + <string>Received</string> + </property> + </column> + <column> + <property name="text"> + <string>Total</string> + </property> + </column> + <property name="name"> + <cstring>tableMonthly</cstring> + </property> + <property name="numRows"> + <number>1</number> + </property> + <property name="numCols"> + <number>3</number> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonClearMonthly</cstring> + </property> + <property name="text"> + <string>Clear monthly statistics</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>yearly</cstring> + </property> + <attribute name="title"> + <string>Yearly</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QTable"> + <column> + <property name="text"> + <string>Sent</string> + </property> + </column> + <column> + <property name="text"> + <string>Received</string> + </property> + </column> + <column> + <property name="text"> + <string>Total</string> + </property> + </column> + <property name="name"> + <cstring>tableYearly</cstring> + </property> + <property name="numRows"> + <number>1</number> + </property> + <property name="numCols"> + <number>3</number> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonClearYearly</cstring> + </property> + <property name="text"> + <string>Clear yearly statistics</string> + </property> + </widget> + </vbox> + </widget> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer28</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>211</width> + <height>31</height> + </size> + </property> + </spacer> + <spacer row="1" column="2"> + <property name="name"> + <cstring>spacer29</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>201</width> + <height>31</height> + </size> + </property> + </spacer> + </grid> +</widget> +<connections> + <connection> + <sender>buttonClose</sender> + <signal>clicked()</signal> + <receiver>InterfaceStatisticsDlg</receiver> + <slot>close()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/knemod/interfacestatusdialog.cpp b/src/knemod/interfacestatusdialog.cpp new file mode 100644 index 0000000..87260af --- /dev/null +++ b/src/knemod/interfacestatusdialog.cpp @@ -0,0 +1,308 @@ +/* This file is part of KNemo + Copyright (C) 2004, 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qtimer.h> +#include <qlabel.h> +#include <qstring.h> +#include <qgroupbox.h> +#include <qdatetime.h> +#include <qtabwidget.h> + +#include <kdebug.h> +#include <kconfig.h> +#include <klocale.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <kactivelabel.h> +#include <kio/global.h> + +#include "data.h" +#include "interface.h" +#include "interfacestatistics.h" +#include "interfacestatusdialog.h" + +InterfaceStatusDialog::InterfaceStatusDialog( Interface* interface, QWidget* parent, const char* name ) + : InterfaceStatusDlg( parent, name ), + mPosInitialized( false ), + mInterface( interface ) +{ + setIcon( SmallIcon( "knemo" ) ); + setCaption( interface->getName() + " " + i18n( "Interface Status" ) ); + updateDialog(); + if ( interface->getData().available ) + { + enableNetworkGroups( 0 ); + } + else + { + disableNetworkGroups( 0 ); + } + if ( !interface->getData().wirelessDevice ) + { + QWidget* wirelessTab = tabWidget->page( 2 ); + tabWidget->removePage( wirelessTab ); + delete wirelessTab; + } + + if ( !interface->getSettings().activateStatistics ) + { + setStatisticsGroupEnabled( false ); + } + + // Restore window size and position. + KConfig* config = new KConfig( "knemorc", false ); + if ( config->hasGroup( "Interface_" + mInterface->getName() ) ) + { + config->setGroup( "Interface_" + mInterface->getName() ); + if ( config->hasKey( "StatusX" ) && config->hasKey( "StatusY" ) ) + { + mPos.setX( config->readNumEntry( "StatusX" ) ); + mPos.setY( config->readNumEntry( "StatusY" ) ); + mPosInitialized = true; + } + if ( config->hasKey( "StatusWidth" ) && config->hasKey( "StatusHeight" ) ) + resize( config->readNumEntry( "StatusWidth" ), + config->readNumEntry( "StatusHeight" ) ); + } + delete config; + + statisticsChanged(); + + mTimer = new QTimer(); + connect( mTimer, SIGNAL( timeout() ), this, SLOT( updateDialog() ) ); + mTimer->start( 1000 ); +} + +InterfaceStatusDialog::~InterfaceStatusDialog() +{ + mTimer->stop(); + delete mTimer; + + // Store window size and position. + KConfig* config = new KConfig( "knemorc", false ); + if ( config->hasGroup( "Interface_" + mInterface->getName() ) ) + { + config->setGroup( "Interface_" + mInterface->getName() ); + config->writeEntry( "StatusX", x() ); + config->writeEntry( "StatusY", y() ); + config->writeEntry( "StatusWidth", width() ); + config->writeEntry( "StatusHeight", height() ); + config->sync(); + } + delete config; +} + +void InterfaceStatusDialog::hide() +{ + mPos = pos(); + mPosInitialized = true; + QDialog::hide(); +} + +void InterfaceStatusDialog::show() +{ + QDialog::show(); + /** + * mPosInitialized should always be true, except when + * starting KNemo for the very first time. + */ + if ( mPosInitialized ) + move( mPos ); +} + +void InterfaceStatusDialog::setStatisticsGroupEnabled( bool enabled ) +{ + groupBoxStatistics->setEnabled( enabled ); +} + +void InterfaceStatusDialog::updateDialog() +{ + InterfaceData& data = mInterface->getData(); + InterfaceSettings& settings = mInterface->getSettings(); + + // connection tab + textLabelInterface->setText( mInterface->getName() ); + textLabelAlias->setText( settings.alias ); + if ( data.available ) + { + textLabelStatus->setText( i18n( "Connection established." ) ); + int upsecs = mInterface->getStartTime().secsTo( QDateTime::currentDateTime() ); + int updays = upsecs / 86400; // don't use QDateTime::daysTo() because + // we only want complete days + + QString uptime; + if ( updays == 1 ) + uptime = "1 day, "; + else if ( updays > 1 ) + uptime = QString( "%1 days, " ).arg( updays ); + + upsecs -= 86400 * updays; // we only want the seconds of today + int hrs = upsecs / 3600; + int mins = ( upsecs - hrs * 3600 ) / 60; + int secs = upsecs - hrs * 3600 - mins * 60; + QString time; + time.sprintf( "%02d:%02d:%02d", hrs, mins, secs ); + uptime += time; + textLabelUptime->setText( uptime ); + } + else if ( data.existing ) + { + textLabelStatus->setText( i18n( "Not connected." ) ); + textLabelUptime->setText( "00:00:00" ); + } + else + { + textLabelStatus->setText( i18n( "Not existing." ) ); + textLabelUptime->setText( "00:00:00" ); + } + + if ( data.available ) + { + // ip tab + textLabelIP->setText( data.ipAddress ); + textLabelSubnet->setText( data.subnetMask ); + if ( mInterface->getType() == Interface::ETHERNET ) + { + variableLabel1->setText( i18n( "Broadcast Address:" ) ); + variableText1->setText( data.broadcastAddress ); + variableLabel2->setText( i18n( "Default Gateway:" ) ); + variableText2->setText( data.defaultGateway ); + variableLabel3->setText( i18n( "HW-Address:" ) ); + variableText3->setText( data.hwAddress ); + } + else if ( mInterface->getType() == Interface::PPP ) + { + variableLabel1->setText( i18n( "PtP-Address:" ) ); + variableText1->setText( data.ptpAddress ); + variableLabel2->setText( QString::null ); + variableText2->setText( QString::null ); + variableLabel3->setText( QString::null ); + variableText3->setText( QString::null ); + } + else + { + // shouldn't happen + variableLabel1->setText( QString::null ); + variableText1->setText( QString::null ); + variableLabel2->setText( QString::null ); + variableText2->setText( QString::null ); + variableLabel3->setText( QString::null ); + variableText3->setText( QString::null ); + } + + // traffic tab + textLabelPacketsSend->setText( QString::number( data.txPackets ) ); + textLabelPacketsReceived->setText( QString::number( data.rxPackets ) ); + textLabelBytesSend->setText( data.txString ); + textLabelBytesReceived->setText( data.rxString ); + unsigned long bytesPerSecond = data.outgoingBytes / mInterface->getGeneralData().pollInterval; + textLabelSpeedSend->setText( KIO::convertSize( bytesPerSecond ) + i18n( "/s" ) ); + bytesPerSecond = data.incomingBytes / mInterface->getGeneralData().pollInterval; + textLabelSpeedReceived->setText( KIO::convertSize( bytesPerSecond ) + i18n( "/s" ) ); + + if ( data.wirelessDevice ) + { + WirelessData& wdata = mInterface->getWirelessData(); + + // wireless tab + textLabelESSID->setText( wdata.essid ); + textLabelAccessPoint->setText( wdata.accessPoint ); + textLabelNickName->setText( wdata.nickName ); + textLabelMode->setText( wdata.mode ); + textLabelFreqChannel->setText( wdata.frequency + " [" + wdata.channel + "]" ); + textLabelBitRate->setText( wdata.bitRate ); + textLabelLinkQuality->setText( wdata.linkQuality + "%" ); + if ( wdata.encryption == true ) + { + textLabelEncryption->setText( i18n( "active" ) ); + } + else + { + textLabelEncryption->setText( i18n( "off" ) ); + } + } + } +} + +void InterfaceStatusDialog::enableNetworkGroups( int ) +{ + groupBoxIP->setEnabled( true ); + groupBoxCurrentConnection->setEnabled( true ); +} + +void InterfaceStatusDialog::disableNetworkGroups( int ) +{ + groupBoxIP->setEnabled( false ); + groupBoxCurrentConnection->setEnabled( false ); + + // clear IP group + textLabelIP->setText( QString::null ); + textLabelSubnet->setText( QString::null ); + variableText1->setText( QString::null ); + variableText2->setText( QString::null ); + variableText3->setText( QString::null ); + + // clear current connection group + textLabelPacketsSend->setText( QString::null ); + textLabelPacketsReceived->setText( QString::null ); + textLabelBytesSend->setText( QString::null ); + textLabelBytesReceived->setText( QString::null ); + textLabelSpeedSend->setText( QString::null ); + textLabelSpeedReceived->setText( QString::null ); + + // clear wireless tab + if ( mInterface->getData().wirelessDevice ) + { + textLabelESSID->setText( QString::null ); + textLabelAccessPoint->setText( QString::null ); + textLabelNickName->setText( QString::null ); + textLabelMode->setText( QString::null ); + textLabelFreqChannel->setText( QString::null ); + textLabelBitRate->setText( QString::null ); + textLabelLinkQuality->setText( QString::null ); + textLabelEncryption->setText( QString::null ); + } +} + +void InterfaceStatusDialog::statisticsChanged() +{ + InterfaceStatistics* statistics = mInterface->getStatistics(); + + if ( statistics == 0 ) + { + return; + } + + const StatisticEntry* entry = statistics->getCurrentDay(); + textLabelTodaySent->setText( KIO::convertSize( entry->txBytes ) ); + textLabelTodayReceived->setText( KIO::convertSize( entry->rxBytes ) ); + textLabelTodayTotal->setText( KIO::convertSize( entry->txBytes + entry->rxBytes ) ); + + entry = statistics->getCurrentMonth(); + textLabelMonthSent->setText( KIO::convertSize( entry->txBytes ) ); + textLabelMonthReceived->setText( KIO::convertSize( entry->rxBytes ) ); + textLabelMonthTotal->setText( KIO::convertSize( entry->txBytes + entry->rxBytes ) ); + + entry = statistics->getCurrentYear(); + textLabelYearSent->setText( KIO::convertSize( entry->txBytes ) ); + textLabelYearReceived->setText( KIO::convertSize( entry->rxBytes ) ); + textLabelYearTotal->setText( KIO::convertSize( entry->txBytes + entry->rxBytes ) ); +} + +#include "interfacestatusdialog.moc" diff --git a/src/knemod/interfacestatusdialog.h b/src/knemod/interfacestatusdialog.h new file mode 100644 index 0000000..3b15362 --- /dev/null +++ b/src/knemod/interfacestatusdialog.h @@ -0,0 +1,89 @@ +/* This file is part of KNemo + Copyright (C) 2004, 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef INTERFACESTATUSDIALOG_H +#define INTERFACESTATUSDIALOG_H + +#include <qwidget.h> + +#include "interfacestatusdlg.h" + +class QTimer; +class Interface; + +/** + * This class serves as the main window for KNemo. It handles the + * menus, toolbars, and status bars. + * + * @short Main window class + * @author Percy Leonhardt <[email protected]> + */ + +class InterfaceStatusDialog : public InterfaceStatusDlg +{ + Q_OBJECT +public: + /** + * Default Constructor + */ + InterfaceStatusDialog( Interface* interface, + QWidget* parent = 0L, const char* name = 0L ); + + /** + * Default Destructor + */ + virtual ~InterfaceStatusDialog(); + + /** + * Implemented to store position. + */ + void hide(); + void show(); + + /** + * Enable or disable the statistics group when the user turned statistics on or off. + */ + void setStatisticsGroupEnabled( bool enabled ); + +public slots: + /** + * Enable the network groups when the interface is connected + */ + void enableNetworkGroups( int ); + /** + * Disable the network groups when the interface is not connected + */ + void disableNetworkGroups( int ); + /** + * Update the statistics tab when data changed + */ + void statisticsChanged(); + +private slots: + void updateDialog(); + +private: + QPoint mPos; + bool mPosInitialized; + + QTimer* mTimer; + Interface* mInterface; +}; + +#endif // INTERFACESTATUSDIALOG_H diff --git a/src/knemod/interfacestatusdlg.ui b/src/knemod/interfacestatusdlg.ui new file mode 100644 index 0000000..f707ef3 --- /dev/null +++ b/src/knemod/interfacestatusdlg.ui @@ -0,0 +1,759 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>InterfaceStatusDlg</class> +<widget class="QDialog"> + <property name="name"> + <cstring>InterfaceStatusDlg</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>292</width> + <height>328</height> + </rect> + </property> + <property name="caption"> + <string>Interface Status</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QTabWidget"> + <property name="name"> + <cstring>tabWidget</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>connection</cstring> + </property> + <attribute name="title"> + <string>Connection</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="5" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>81</width> + <height>30</height> + </size> + </property> + </spacer> + <widget class="QGroupBox" row="4" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>groupBoxIP</cstring> + </property> + <property name="title"> + <string>IP</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>textLabelIP</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>textLabelSubnet</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>variableText1</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="3" column="1"> + <property name="name"> + <cstring>variableText2</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="4" column="1"> + <property name="name"> + <cstring>variableText3</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel4_2</cstring> + </property> + <property name="text"> + <string>IP-Address:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel5_2</cstring> + </property> + <property name="text"> + <string>Subnet Mask:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>variableLabel1</cstring> + </property> + <property name="text"> + <string>Broadcast Address:</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>variableLabel2</cstring> + </property> + <property name="text"> + <string>Default Gateway:</string> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>variableLabel3</cstring> + </property> + <property name="text"> + <string>HW-Address:</string> + </property> + </widget> + </grid> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>textLabelAlias</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>textLabelInterface</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>textLabelStatus</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="3" column="1"> + <property name="name"> + <cstring>textLabelUptime</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel24</cstring> + </property> + <property name="text"> + <string>Interface:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel14</cstring> + </property> + <property name="text"> + <string>Alias:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Status:</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Uptime:</string> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>traffic</cstring> + </property> + <attribute name="title"> + <string>Traffic</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBoxCurrentConnection</cstring> + </property> + <property name="title"> + <string>Current connection</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>textLabel8</cstring> + </property> + <property name="text"> + <string>Received</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>textLabel7</cstring> + </property> + <property name="text"> + <string>Sent</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>textLabelPacketsSend</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="1" column="2"> + <property name="name"> + <cstring>textLabelPacketsReceived</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel9</cstring> + </property> + <property name="text"> + <string>Packets:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel10</cstring> + </property> + <property name="text"> + <string>Bytes:</string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel10_2</cstring> + </property> + <property name="text"> + <string>Speed:</string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>textLabelBytesSend</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="2" column="2"> + <property name="name"> + <cstring>textLabelBytesReceived</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="3" column="1"> + <property name="name"> + <cstring>textLabelSpeedSend</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="3" column="2"> + <property name="name"> + <cstring>textLabelSpeedReceived</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBoxStatistics</cstring> + </property> + <property name="title"> + <string>Statistics</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel9_2_2</cstring> + </property> + <property name="text"> + <string>Today:</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel10_2_2_2</cstring> + </property> + <property name="text"> + <string>This year:</string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>textLabel8_2_3</cstring> + </property> + <property name="text"> + <string>Received</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="0" column="3"> + <property name="name"> + <cstring>textLabel8_2_2_2</cstring> + </property> + <property name="text"> + <string>Total</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel10_3_2</cstring> + </property> + <property name="text"> + <string>This month:</string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + <widget class="QLabel" row="1" column="2"> + <property name="name"> + <cstring>textLabelTodayReceived</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="2" column="2"> + <property name="name"> + <cstring>textLabelMonthReceived</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="3" column="2"> + <property name="name"> + <cstring>textLabelYearReceived</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="1" column="3"> + <property name="name"> + <cstring>textLabelTodayTotal</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="2" column="3"> + <property name="name"> + <cstring>textLabelMonthTotal</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="3" column="3"> + <property name="name"> + <cstring>textLabelYearTotal</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>textLabel7_2_2</cstring> + </property> + <property name="text"> + <string>Sent</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>textLabelMonthSent</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="3" column="1"> + <property name="name"> + <cstring>textLabelYearSent</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>textLabelTodaySent</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer4_3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>81</width> + <height>16</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>wireless</cstring> + </property> + <attribute name="title"> + <string>Wireless</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel3_2</cstring> + </property> + <property name="text"> + <string>Connected to:</string> + </property> + </widget> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>textLabelESSID</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel3_2_2_2</cstring> + </property> + <property name="text"> + <string>Access point:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>textLabelAccessPoint</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="5" column="0"> + <property name="name"> + <cstring>textLabel3_2_4</cstring> + </property> + <property name="text"> + <string>Bit Rate:</string> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>textLabelFC</cstring> + </property> + <property name="text"> + <string>Frequency [Channel]:</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel3_2_2</cstring> + </property> + <property name="text"> + <string>Mode:</string> + </property> + </widget> + <widget class="QLabel" row="5" column="1"> + <property name="name"> + <cstring>textLabelBitRate</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="4" column="1"> + <property name="name"> + <cstring>textLabelFreqChannel</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="3" column="1"> + <property name="name"> + <cstring>textLabelMode</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>textLabelNickName</cstring> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel3_2_5</cstring> + </property> + <property name="text"> + <string>Nickname:</string> + </property> + </widget> + <spacer row="8" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>spacer4_4</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>81</width> + <height>50</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="6" column="0"> + <property name="name"> + <cstring>textLabel3_2_6</cstring> + </property> + <property name="text"> + <string>Link Quality:</string> + </property> + </widget> + <widget class="QLabel" row="7" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Encryption:</string> + </property> + </widget> + <widget class="QLabel" row="6" column="1"> + <property name="name"> + <cstring>textLabelLinkQuality</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="7" column="1"> + <property name="name"> + <cstring>textLabelEncryption</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + </grid> + </widget> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>0</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonClose</cstring> + </property> + <property name="text"> + <string>&Close</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>0</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>buttonClose</sender> + <signal>clicked()</signal> + <receiver>InterfaceStatusDlg</receiver> + <slot>accept()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/knemod/interfacetooltip.cpp b/src/knemod/interfacetooltip.cpp new file mode 100644 index 0000000..77d6505 --- /dev/null +++ b/src/knemod/interfacetooltip.cpp @@ -0,0 +1,204 @@ +/* This file is part of KNemo + Copyright (C) 2004 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qrect.h> +#include <qstring.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kio/global.h> + +#include "data.h" +#include "interface.h" +#include "interfacetooltip.h" + +InterfaceToolTip::InterfaceToolTip( Interface* interface, + QWidget* parent ) + : QToolTip( parent ), + mInterface( interface ) +{ + setupToolTipArray(); +} + +InterfaceToolTip::~InterfaceToolTip() +{ +} + +void InterfaceToolTip::maybeTip( const QPoint& ) +{ + QRect rect( parentWidget()->rect() ); + if ( !rect.isValid() ) + return; + + QString tooltip; + setupText( tooltip ); + tip( rect, tooltip ); +} + +void InterfaceToolTip::setupText( QString& text ) +{ + int toolTipContent = mInterface->getGeneralData().toolTipContent; + InterfaceData& data = mInterface->getData(); + + text += "<table cellspacing=0 cellpadding=0 border=0>"; + if ( ( toolTipContent & ALIAS ) && + mInterface->getSettings().alias != QString::null ) + text += "<tr><th colspan=2 align=center>" + mInterface->getSettings().alias + "</th></tr>"; + if ( toolTipContent & INTERFACE ) + text += "<tr><td>" + mToolTips[0].first + "</td><td>" + mInterface->getName() + "</td></tr>"; + if ( data.available ) + { + if ( toolTipContent & STATUS ) + text += "<tr><td>" + mToolTips[2].first + "</td><td>" + i18n( "Connection established." ) + "</td></tr>"; + if ( toolTipContent & UPTIME ) + { + int upsecs = mInterface->getStartTime().secsTo( QDateTime::currentDateTime() ); + int updays = upsecs / 86400; // don't use QDateTime::daysTo() because + // we only want complete days + + QString uptime; + if ( updays == 1 ) + uptime = "1 day, "; + else if ( updays > 1 ) + uptime = QString( "%1 days, " ).arg( updays ); + + upsecs -= 86400 * updays; // we only want the seconds of today + int hrs = upsecs / 3600; + int mins = ( upsecs - hrs * 3600 ) / 60; + int secs = upsecs - hrs * 3600 - mins * 60; + QString time; + time.sprintf( "%02d:%02d:%02d", hrs, mins, secs ); + uptime += time; + text += "<tr><td>" + mToolTips[3].first + "</td><td>" + uptime + "</td></tr>"; + } + } + else if ( data.existing ) + { + if ( toolTipContent & STATUS ) + text += "<tr><td>" + mToolTips[2].first + "</td><td>" + i18n( "Not connected." ) + "</td></tr>"; + } + else + { + if ( toolTipContent & STATUS ) + text += "<tr><td>" + mToolTips[2].first + "</td><td>" + i18n( "Not existing." ) + "</td></tr>"; + } + + if ( data.available ) + { + if ( toolTipContent & IP_ADDRESS ) + text += "<tr><td>" + mToolTips[4].first + "</td><td>" + data.ipAddress + "</td></tr>"; + if ( toolTipContent & SUBNET_MASK ) + text += "<tr><td>" + mToolTips[5].first + "</td><td>" + data.subnetMask + "</td></tr>"; + if ( mInterface->getType() == Interface::ETHERNET ) + { + if ( toolTipContent & BCAST_ADDRESS ) + text += "<tr><td>" + mToolTips[18].first + "</td><td>" + data.broadcastAddress + "</td></tr>"; + if ( toolTipContent & GATEWAY ) + text += "<tr><td>" + mToolTips[19].first + "</td><td>" + data.defaultGateway + "</td></tr>"; + if ( toolTipContent & HW_ADDRESS ) + text += "<tr><td>" + mToolTips[6].first + "</td><td>" + data.hwAddress + "</td></tr>"; + } + if ( mInterface->getType() == Interface::PPP ) + { + if ( toolTipContent & PTP_ADDRESS ) + text += "<tr><td>" + mToolTips[7].first + "</td><td>" + data.ptpAddress + "</td></tr>"; + } + if ( toolTipContent & RX_PACKETS ) + text += "<tr><td>" + mToolTips[8].first + "</td><td>" + QString::number( data.rxPackets ) + "</td></tr>"; + if ( toolTipContent & TX_PACKETS ) + text += "<tr><td>" + mToolTips[9].first + "</td><td>" + QString::number( data.txPackets ) + "</td></tr>"; + if ( toolTipContent & RX_BYTES ) + text += "<tr><td>" + mToolTips[10].first + "</td><td>" + data.rxString + "</td></tr>"; + if ( toolTipContent & TX_BYTES ) + text += "<tr><td>" + mToolTips[11].first + "</td><td>" + data.txString + "</td></tr>"; + if ( toolTipContent & DOWNLOAD_SPEED ) + { + unsigned long bytesPerSecond = data.incomingBytes / mInterface->getGeneralData().pollInterval; + text += "<tr><td>" + mToolTips[20].first + "</td><td>" + KIO::convertSize( bytesPerSecond ) + i18n( "/s" ) + "</td></tr>"; + } + if ( toolTipContent & UPLOAD_SPEED ) + { + unsigned long bytesPerSecond = data.outgoingBytes / mInterface->getGeneralData().pollInterval; + text += "<tr><td>" + mToolTips[21].first + "</td><td>" + KIO::convertSize( bytesPerSecond ) + i18n( "/s" ) + "</td></tr>"; + } + } + + if ( data.available && data.wirelessDevice ) + { + WirelessData& wdata = mInterface->getWirelessData(); + if ( toolTipContent & ESSID ) + text += "<tr><td>" + mToolTips[12].first + "</td><td>" + wdata.essid + "</td></tr>"; + if ( toolTipContent & MODE ) + text += "<tr><td>" + mToolTips[13].first + "</td><td>" + wdata.mode + "</td></tr>"; + if ( toolTipContent & FREQUENCY ) + text += "<tr><td>" + mToolTips[14].first + "</td><td>" + wdata.frequency + "</td></tr>"; + if ( toolTipContent & BIT_RATE ) + text += "<tr><td>" + mToolTips[15].first + "</td><td>" + wdata.bitRate + "</td></tr>"; + if ( toolTipContent & ACCESS_POINT ) + text += "<tr><td>" + mToolTips[16].first + "</td><td>" + wdata.accessPoint + "</td></tr>"; + if ( toolTipContent & LINK_QUALITY ) + text += "<tr><td>" + mToolTips[17].first + "</td><td>" + wdata.linkQuality + "</td></tr>"; + if ( toolTipContent & NICK_NAME ) + text += "<tr><td>" + mToolTips[22].first + "</td><td>" + wdata.nickName + "</td></tr>"; + if ( toolTipContent & ENCRYPTION ) + { + if ( wdata.encryption == true ) + { + text += "<tr><td>" + mToolTips[23].first + "</td><td>" + i18n( "active" ) + "</td></tr>"; + } + else + { + text += "<tr><td>" + mToolTips[23].first + "</td><td>" + i18n( "off" ) + "</td></tr>"; + } + } + } + text += "</table>"; +} + +void InterfaceToolTip::setupToolTipArray() +{ + // Cannot make this data static as the i18n macro doesn't seem + // to work when called to early i.e. before setting the catalogue. + mToolTips[0] = QPair<QString, int>( i18n( "Interface" ), INTERFACE ); + mToolTips[1] = QPair<QString, int>( i18n( "Alias" ), ALIAS ); + mToolTips[2] = QPair<QString, int>( i18n( "Status" ), STATUS ); + mToolTips[3] = QPair<QString, int>( i18n( "Uptime" ), UPTIME ); + mToolTips[4] = QPair<QString, int>( i18n( "IP-Address" ), IP_ADDRESS ); + mToolTips[5] = QPair<QString, int>( i18n( "Subnet Mask" ), SUBNET_MASK ); + mToolTips[6] = QPair<QString, int>( i18n( "HW-Address" ), HW_ADDRESS ); + mToolTips[7] = QPair<QString, int>( i18n( "PtP-Address" ), PTP_ADDRESS ); + mToolTips[8] = QPair<QString, int>( i18n( "Packets Received" ), RX_PACKETS ); + mToolTips[9] = QPair<QString, int>( i18n( "Packets Sent" ), TX_PACKETS ); + mToolTips[10] = QPair<QString, int>( i18n( "Bytes Received" ), RX_BYTES ); + mToolTips[11] = QPair<QString, int>( i18n( "Bytes Sent" ), TX_BYTES ); + mToolTips[12] = QPair<QString, int>( i18n( "ESSID" ), ESSID ); + mToolTips[13] = QPair<QString, int>( i18n( "Mode" ), MODE ); + mToolTips[14] = QPair<QString, int>( i18n( "Frequency" ), FREQUENCY ); + mToolTips[15] = QPair<QString, int>( i18n( "Bit Rate" ), BIT_RATE ); + mToolTips[16] = QPair<QString, int>( i18n( "Access Point" ), ACCESS_POINT ); + mToolTips[17] = QPair<QString, int>( i18n( "Link Quality" ), LINK_QUALITY ); + mToolTips[18] = QPair<QString, int>( i18n( "Broadcast Address" ), BCAST_ADDRESS ); + mToolTips[19] = QPair<QString, int>( i18n( "Default Gateway" ), LINK_QUALITY ); + mToolTips[20] = QPair<QString, int>( i18n( "Download Speed" ), DOWNLOAD_SPEED ); + mToolTips[21] = QPair<QString, int>( i18n( "Upload Speed" ), UPLOAD_SPEED ); + mToolTips[22] = QPair<QString, int>( i18n( "Nickname" ), NICK_NAME ); + mToolTips[23] = QPair<QString, int>( i18n( "Encryption" ), ENCRYPTION ); + mToolTips[24] = QPair<QString, int>(); +} + diff --git a/src/knemod/interfacetooltip.h b/src/knemod/interfacetooltip.h new file mode 100644 index 0000000..7c4dbd9 --- /dev/null +++ b/src/knemod/interfacetooltip.h @@ -0,0 +1,72 @@ +/* This file is part of KNemo + Copyright (C) 2004 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef INTERFACETOOLTIP_H +#define INTERFACETOOLTIP_H + +#include <qpair.h> +#include <qtooltip.h> + +class Interface; + +/** + * This call is responsible for displaying the tooltip of an + * interface icon. It is derived from QToolTip and overwrites + * the function maybeTip(const QPoint & p) to update the tooltip + * text just before it is going to be displayed. + * + * @short Display tooltip according to user settings + * @author Percy Leonhardt <[email protected]> + */ + +class InterfaceToolTip : public QToolTip +{ +public: + /** + * Default Constructor + */ + InterfaceToolTip( Interface* interface, QWidget* parent = 0L ); + + /** + * Default Destructor + */ + virtual ~InterfaceToolTip(); + + /** + * From the Qt documentation: + * It is called when there is a possibility that a tool tip should + * be shown and must decide whether there is a tool tip for the point p + * in the widget that this QToolTip object relates to. If so, maybeTip() + * must call tip() with the rectangle the tip applies to, the tip's text + * and optionally the QToolTipGroup details and the geometry in screen + * coordinates. + */ + void maybeTip( const QPoint& ); + +private: + void setupText( QString& text ); + void setupToolTipArray(); + + // the interface this tooltip belongs to + Interface* mInterface; + // the tooltip text for each information + QPair<QString, int> mToolTips[25]; +}; + +#endif // INTERFACETOOLTIP_H diff --git a/src/knemod/interfacetray.cpp b/src/knemod/interfacetray.cpp new file mode 100644 index 0000000..5e2e154 --- /dev/null +++ b/src/knemod/interfacetray.cpp @@ -0,0 +1,121 @@ +/* This file is part of KNemo + Copyright (C) 2004, 2005 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qwidget.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kbugreport.h> +#include <kaboutdata.h> +#include <kpopupmenu.h> +#include <kiconloader.h> +#include <kapplication.h> +#include <kaboutapplication.h> +#include <kactioncollection.h> + +#include "interfacetray.h" + +static const char description[] = + I18N_NOOP( "KNemo - the KDE Network Monitor" ); + +static const char version[] = "0.4.8"; + +InterfaceTray::InterfaceTray( const QString& ifname, + QWidget* parent, const char* name ) + : KSystemTray( parent, name ) +{ + actionCollection()->clear(); // remove the quit entry + + KPopupMenu* popup = contextMenu(); + int id = popup->idAt( 0 ); + popup->changeTitle( id, SmallIcon( "knemo" ), + "KNemo - " + ifname ); + popup->insertItem( SmallIcon( "knemo" ), + i18n( "&About KNemo" ), this, + SLOT( showAboutDialog() ) ); + popup->insertItem( i18n( "&Report Bug..." ), this, + SLOT( showReportBugDialog() ) ); + popup->insertSeparator(); + popup->insertItem( SmallIcon( "configure" ), + i18n( "&Configure KNemo..." ), this, + SIGNAL( configSelected() ) ); + popup->insertItem( SmallIcon( "ksysguard" ), + i18n( "&Open Traffic Plotter" ), this, + SLOT( showGraph() ) ); +} + +InterfaceTray::~InterfaceTray() +{ +} + +void InterfaceTray::mousePressEvent( QMouseEvent* e ) +{ + if ( !rect().contains( e->pos() ) ) + return; + + switch( e->button() ) + { + case LeftButton: + emit leftClicked(); + break; + case MidButton: + emit graphSelected( true ); + break; + case RightButton: + KSystemTray::mousePressEvent( e ); + break; + default: + break; + } +} + +void InterfaceTray::showAboutDialog() +{ + KAboutData data ( "knemo", I18N_NOOP( "KNemo" ), version, + description, KAboutData::License_GPL, + "(c) 2004, 2005, 2006 Percy Leonhardt\n\nSignal plotter taken from KSysGuard\n(c) 1999 - 2002, Chris Schlaeger", + 0, + "http://extragear.kde.org/apps/knemo/" + ); + data.addAuthor( "Percy Leonhardt", I18N_NOOP( "Author" ), + "[email protected]" ); + data.addCredit( "Michael Olbrich", I18N_NOOP( "Threshold support" ), + "[email protected]" ); + data.addCredit( "Chris Schlaeger", I18N_NOOP( "Signal plotter" ), + "[email protected]" ); + + KAboutApplication about( &data ); + about.setProgramLogo( DesktopIcon( "knemo" ) ); + about.exec(); +} + +void InterfaceTray::showReportBugDialog() +{ + KAboutData data ( "knemo", I18N_NOOP( "KNemo" ), version ); + KBugReport bugReport( 0, true, &data ); + bugReport.exec(); +} + +void InterfaceTray::showGraph() +{ + emit graphSelected( false ); +} + +#include "interfacetray.moc" diff --git a/src/knemod/interfacetray.h b/src/knemod/interfacetray.h new file mode 100644 index 0000000..b783c45 --- /dev/null +++ b/src/knemod/interfacetray.h @@ -0,0 +1,81 @@ +/* This file is part of KNemo + Copyright (C) 2004 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef INTERFACETRAY_H +#define INTERFACETRAY_H + +#include <ksystemtray.h> + +class QWidget; + +/** + * This class is the graphical representation of and interface + * in the system tray. It has a customized context menu and will + * emit a signal when the user left clicks the icon. + * + * @short Graphical representation of the tray icon + * @author Percy Leonhardt <[email protected]> + */ + +class InterfaceTray : public KSystemTray +{ + Q_OBJECT +public: + /** + * Default Constructor + */ + InterfaceTray( const QString& ifname, + QWidget* parent = 0L, const char* name = 0L ); + + /** + * Default Destructor + */ + virtual ~InterfaceTray(); + +signals: + void leftClicked(); + void graphSelected( bool ); + void configSelected(); + void startCommandSelected(); + void stopCommandSelected(); + +protected: + void mousePressEvent( QMouseEvent* e ); + +protected slots: + /** + * Will display the about dialog if the user selected + * the corresponding entry in the context menu. + */ + void showAboutDialog(); + + /** + * Will display the report bug dialog that allows the user + * to send a bug report by mail. + */ + void showReportBugDialog(); + + /** + * Opens the traffic plotter or brings it to the front if it + * is hidden. + */ + void showGraph(); +}; + +#endif // INTERFACETRAY_H diff --git a/src/knemod/knemod.desktop b/src/knemod/knemod.desktop new file mode 100644 index 0000000..d4f41e6 --- /dev/null +++ b/src/knemod/knemod.desktop @@ -0,0 +1,41 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Service +ServiceTypes=KDEDModule +X-KDE-ModuleType=Library +X-KDE-Library=knemod +X-KDE-FactoryName=knemod +X-KDE-Kded-autoload=true +X-KDE-Kded-load-on-demand=false +Name=KNemo +Name[de]=Netzwerküberwachung KNemo +Name[sv]=Knemo +Name[xx]=xxKNemoxx +Comment=KDE Network Monitor +Comment[bg]=Монитор на мрежата +Comment[br]=Eveshaer ar rouedad evit KDE +Comment[cs]=KDE monitor sítě +Comment[da]=KDE's netværksovervågning +Comment[de]=KDE-Netzwerkmonitor +Comment[el]=Επίβλεψη δικτύου του KDE +Comment[es]=Monitor de red de KDE +Comment[et]=KDE võrgumonitor +Comment[ga]=Monatóir Líonra KDE +Comment[gl]=Un Monitor de Rede para KDE +Comment[it]=Monitor di rete di KDE +Comment[ja]=KDE ネットワークモニタ +Comment[ka]=KDE-ის ქსელის მონიტორი +Comment[lt]=Tinklo įrenginių stebėjimo KDE programa +Comment[nl]=KDE networkmonitor +Comment[pa]=KDE ਨੈਟਵਰਕ ਨਿਗਰਾਨ +Comment[pl]=Monitor sieci dla KDE +Comment[pt]=Monitor da Rede do KDE +Comment[pt_BR]=Monitor de Rede do KDE +Comment[ru]=Сетевой монитор KDE +Comment[sr]=Надгледање мреже за KDE +Comment[sr@Latn]=Nadgledanje mreže za KDE +Comment[sv]=KDE-nätverksövervakning +Comment[tr]=KDE Ağ İzleyici +Comment[uk]=Монітор мережі для KDE +Comment[xx]=xxKDE Network Monitorxx +Comment[zh_CN]=KDE 网络监视器 diff --git a/src/knemod/knemodaemon.cpp b/src/knemod/knemodaemon.cpp new file mode 100644 index 0000000..e5a7f88 --- /dev/null +++ b/src/knemod/knemodaemon.cpp @@ -0,0 +1,344 @@ +/* This file is part of KNemo + Copyright (C) 2004, 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qtimer.h> +#include <qstrlist.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kconfig.h> +#include <kprocess.h> +#include <kinstance.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> + +#include "knemodaemon.h" +#include "interface.h" +#include "backendbase.h" +#include "daemonregistry.h" + +QString KNemoDaemon::sSelectedInterface = QString::null; + +extern "C" { + KDE_EXPORT KDEDModule *create_knemod(const QCString &name) { + return new KNemoDaemon(name); + } +} + +KNemoDaemon::KNemoDaemon( const QCString& name ) + : KDEDModule( name ), + mColorVLines( 0x04FB1D ), + mColorHLines( 0x04FB1D ), + mColorIncoming( 0x1889FF ), + mColorOutgoing( 0xFF7F08 ), + mColorBackground( 0x313031 ), + mInstance( new KInstance( "knemo" ) ), + mNotifyInstance( new KNotifyClient::Instance( mInstance ) ) +{ + KGlobal::locale()->insertCatalogue( "knemod" ); + readConfig(); + + // select the backend from the config file + KConfig* config = new KConfig( "knemorc", true ); + config->setGroup( "General" ); + mBackendName = config->readEntry( "Backend", "Nettools" ); + delete config; + + bool foundBackend = false; + int i; + for ( i = 0; DaemonRegistry[i].name != QString::null; i++ ) + { + if ( DaemonRegistry[i].name == mBackendName ) + { + foundBackend = true; + break; + } + } + + if ( !foundBackend ) + { + i = 0; // use the first backend (Nettools) + } + mBackend = ( *DaemonRegistry[i].function )( mInterfaceDict ); + + mInterfaceDict.setAutoDelete( true ); + + mPollTimer = new QTimer(); + connect( mPollTimer, SIGNAL( timeout() ), this, SLOT( updateInterfaces() ) ); + mPollTimer->start( mGeneralData.pollInterval * 1000 ); +} + +KNemoDaemon::~KNemoDaemon() +{ + mPollTimer->stop(); + delete mPollTimer; + delete mBackend; + delete mNotifyInstance; + delete mInstance; + + QDictIterator<Interface> it( mInterfaceDict ); + for ( ; it.current(); ) + { + mInterfaceDict.remove( it.currentKey() ); + // 'remove' already advanced the iterator to the next item + } +} + +void KNemoDaemon::readConfig() +{ + KConfig* config = new KConfig( "knemorc", true ); + + config->setGroup( "General" ); + mGeneralData.pollInterval = config->readNumEntry( "PollInterval", 1 ); + mGeneralData.saveInterval = config->readNumEntry( "SaveInterval", 60 ); + mGeneralData.statisticsDir = config->readEntry( "StatisticsDir", KGlobal::dirs()->saveLocation( "data", "knemo/" ) ); + mGeneralData.toolTipContent = config->readNumEntry( "ToolTipContent", 2 ); + QStrList list; + int numEntries = config->readListEntry( "Interfaces", list ); + + if ( numEntries == 0 ) + return; + + char* interface; + for ( interface = list.first(); interface; interface = list.next() ) + { + Interface* iface = new Interface( interface, mGeneralData, mPlotterSettings ); + QString group( "Interface_" ); + group += interface; + if ( config->hasGroup( group ) ) + { + config->setGroup( group ); + InterfaceSettings& settings = iface->getSettings(); + settings.alias = config->readEntry( "Alias" ); + settings.iconSet = config->readNumEntry( "IconSet", 0 ); + settings.customCommands = config->readBoolEntry( "CustomCommands" ); + settings.hideWhenNotAvailable = config->readBoolEntry( "HideWhenNotAvailable" ); + settings.hideWhenNotExisting = config->readBoolEntry( "HideWhenNotExisting" ); + settings.activateStatistics = config->readBoolEntry( "ActivateStatistics" ); + settings.trafficThreshold = config->readNumEntry( "TrafficThreshold", 0 ); + if ( settings.customCommands ) + { + int numCommands = config->readNumEntry( "NumCommands" ); + for ( int i = 0; i < numCommands; i++ ) + { + QString entry; + InterfaceCommand cmd; + entry = QString( "RunAsRoot%1" ).arg( i + 1 ); + cmd.runAsRoot = config->readBoolEntry( entry ); + entry = QString( "Command%1" ).arg( i + 1 ); + cmd.command = config->readEntry( entry ); + entry = QString( "MenuText%1" ).arg( i + 1 ); + cmd.menuText = config->readEntry( entry ); + settings.commands.append( cmd ); + } + } + iface->configChanged(); // important to activate the statistics + } + mInterfaceDict.insert( interface, iface ); + } + + // load the settings for the plotter + config->setGroup( "PlotterSettings" ); + mPlotterSettings.pixel = config->readNumEntry( "Pixel", 1 ); + mPlotterSettings.count = config->readNumEntry( "Count", 5 ); + mPlotterSettings.distance = config->readNumEntry( "Distance", 30 ); + mPlotterSettings.fontSize = config->readNumEntry( "FontSize", 8 ); + mPlotterSettings.minimumValue = config->readNumEntry( "MinimumValue", 0 ); + mPlotterSettings.maximumValue = config->readNumEntry( "MaximumValue", 1 ); + mPlotterSettings.labels = config->readBoolEntry( "Labels", true ); + mPlotterSettings.topBar = config->readBoolEntry( "TopBar", false ); + mPlotterSettings.showIncoming = config->readBoolEntry( "ShowIncoming", true ); + mPlotterSettings.showOutgoing = config->readBoolEntry( "ShowOutgoing", true ); + mPlotterSettings.verticalLines = config->readBoolEntry( "VerticalLines", true ); + mPlotterSettings.horizontalLines = config->readBoolEntry( "HorizontalLines", true ); + mPlotterSettings.automaticDetection = config->readBoolEntry( "AutomaticDetection", true ); + mPlotterSettings.verticalLinesScroll = config->readBoolEntry( "VerticalLinesScroll", true ); + mPlotterSettings.colorVLines = config->readColorEntry( "ColorVLines", &mColorVLines ); + mPlotterSettings.colorHLines = config->readColorEntry( "ColorHLines", &mColorHLines ); + mPlotterSettings.colorIncoming = config->readColorEntry( "ColorIncoming", &mColorIncoming ); + mPlotterSettings.colorOutgoing = config->readColorEntry( "ColorOutgoing", &mColorOutgoing ); + mPlotterSettings.colorBackground = config->readColorEntry( "ColorBackground", &mColorBackground ); + + delete config; +} + +void KNemoDaemon::reparseConfiguration() +{ + // Read the settings from the config file. + QDict<InterfaceSettings> settingsDict; + KConfig* config = new KConfig( "knemorc", false ); + + config->setGroup( "General" ); + mGeneralData.pollInterval = config->readNumEntry( "PollInterval", 1 ); + mGeneralData.saveInterval = config->readNumEntry( "SaveInterval", 60 ); + mGeneralData.statisticsDir = config->readEntry( "StatisticsDir", KGlobal::dirs()->saveLocation( "data", "knemo/" ) ); + mGeneralData.toolTipContent = config->readNumEntry( "ToolTipContent", 2 ); + + // restart the timer with the new interval + mPollTimer->changeInterval( mGeneralData.pollInterval * 1000 ); + + // select the backend from the config file + QString backend = config->readEntry( "Backend", "Nettools" ); + + if ( mBackendName != backend ) + { + bool foundBackend = false; + mBackendName = backend; + int i; + for ( i = 0; DaemonRegistry[i].name != QString::null; i++ ) + { + if ( DaemonRegistry[i].name == backend ) + { + foundBackend = true; + break; + } + } + + if ( foundBackend ) + { + delete mBackend; + mBackend = ( *DaemonRegistry[i].function )( mInterfaceDict ); + } + } + + QStrList list; + int numEntries = config->readListEntry( "Interfaces", list ); + + if ( numEntries == 0 ) + return; + + char* interface; + for ( interface = list.first(); interface; interface = list.next() ) + { + QString group( "Interface_" ); + group += interface; + InterfaceSettings* settings = new InterfaceSettings(); + if ( config->hasGroup( group ) ) + { + config->setGroup( group ); + settings->alias = config->readEntry( "Alias" ); + settings->iconSet = config->readNumEntry( "IconSet", 0 ); + settings->customCommands = config->readBoolEntry( "CustomCommands" ); + settings->hideWhenNotAvailable = config->readBoolEntry( "HideWhenNotAvailable" ); + settings->hideWhenNotExisting = config->readBoolEntry( "HideWhenNotExisting" ); + settings->activateStatistics = config->readBoolEntry( "ActivateStatistics" ); + settings->trafficThreshold = config->readNumEntry( "TrafficThreshold", 0 ); + if ( settings->customCommands ) + { + int numCommands = config->readNumEntry( "NumCommands" ); + for ( int i = 0; i < numCommands; i++ ) + { + QString entry; + InterfaceCommand cmd; + entry = QString( "RunAsRoot%1" ).arg( i + 1 ); + cmd.runAsRoot = config->readBoolEntry( entry ); + entry = QString( "Command%1" ).arg( i + 1 ); + cmd.command = config->readEntry( entry ); + entry = QString( "MenuText%1" ).arg( i + 1 ); + cmd.menuText = config->readEntry( entry ); + settings->commands.append( cmd ); + } + } + } + settingsDict.insert( interface, settings ); + } + + // load the settings for the plotter + config->setGroup( "PlotterSettings" ); + mPlotterSettings.pixel = config->readNumEntry( "Pixel", 1 ); + mPlotterSettings.count = config->readNumEntry( "Count", 5 ); + mPlotterSettings.distance = config->readNumEntry( "Distance", 30 ); + mPlotterSettings.fontSize = config->readNumEntry( "FontSize", 8 ); + mPlotterSettings.minimumValue = config->readNumEntry( "MinimumValue", 0 ); + mPlotterSettings.maximumValue = config->readNumEntry( "MaximumValue", 1 ); + mPlotterSettings.labels = config->readBoolEntry( "Labels", true ); + mPlotterSettings.topBar = config->readBoolEntry( "TopBar", false ); + mPlotterSettings.showIncoming = config->readBoolEntry( "ShowIncoming", true ); + mPlotterSettings.showOutgoing = config->readBoolEntry( "ShowOutgoing", true ); + mPlotterSettings.verticalLines = config->readBoolEntry( "VerticalLines", true ); + mPlotterSettings.horizontalLines = config->readBoolEntry( "HorizontalLines", true ); + mPlotterSettings.automaticDetection = config->readBoolEntry( "AutomaticDetection", true ); + mPlotterSettings.verticalLinesScroll = config->readBoolEntry( "VerticalLinesScroll", true ); + mPlotterSettings.colorVLines = config->readColorEntry( "ColorVLines", &mColorVLines ); + mPlotterSettings.colorHLines = config->readColorEntry( "ColorHLines", &mColorHLines ); + mPlotterSettings.colorIncoming = config->readColorEntry( "ColorIncoming", &mColorIncoming ); + mPlotterSettings.colorOutgoing = config->readColorEntry( "ColorOutgoing", &mColorOutgoing ); + mPlotterSettings.colorBackground = config->readColorEntry( "ColorBackground", &mColorBackground ); + + // Remove all interfaces that the user deleted from + // the internal list. + QDictIterator<Interface> it( mInterfaceDict ); + for ( ; it.current(); ) + { + if ( settingsDict.find( it.currentKey() ) == 0 ) + { + config->deleteGroup( "Interface_" + it.currentKey() ); + mInterfaceDict.remove( it.currentKey() ); + // 'remove' already advanced the iterator to the next item + } + else + ++it; + } + config->sync(); + delete config; + + // Update all other interfaces and add new ones. + QDictIterator<InterfaceSettings> setIt( settingsDict ); + for ( ; setIt.current(); ++setIt ) + { + Interface* iface; + if ( mInterfaceDict.find( setIt.currentKey() ) == 0 ) + { + iface = new Interface( setIt.currentKey(), mGeneralData, mPlotterSettings ); + mInterfaceDict.insert( setIt.currentKey(), iface ); + } + else + iface = mInterfaceDict[setIt.currentKey()]; + + InterfaceSettings& settings = iface->getSettings(); + settings.alias = setIt.current()->alias; + settings.iconSet = setIt.current()->iconSet; + settings.customCommands = setIt.current()->customCommands; + settings.hideWhenNotAvailable = setIt.current()->hideWhenNotAvailable; + settings.hideWhenNotExisting = setIt.current()->hideWhenNotExisting; + settings.activateStatistics = setIt.current()->activateStatistics; + settings.trafficThreshold = setIt.current()->trafficThreshold; + settings.commands = setIt.current()->commands; + iface->configChanged(); + } +} + +QString KNemoDaemon::getSelectedInterface() +{ + // Reset the variable to avoid preselecting an interface when + // the user opens the control center module from the control + // center afterwards. + QString tmp = sSelectedInterface; + sSelectedInterface = QString::null; + + return tmp; +} + +void KNemoDaemon::updateInterfaces() +{ + mBackend->update(); +} + +#include "knemodaemon.moc" diff --git a/src/knemod/knemodaemon.h b/src/knemod/knemodaemon.h new file mode 100644 index 0000000..d62c288 --- /dev/null +++ b/src/knemod/knemodaemon.h @@ -0,0 +1,120 @@ +/* This file is part of KNemo + Copyright (C) 2004, 2006 Percy Leonhardt <[email protected]> + + KNemo 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. + + KNemo 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KNEMODAEMON_H +#define KNEMODAEMON_H + +#include <qdict.h> +#include <qcolor.h> +#include <qcstring.h> +#include <qdatetime.h> + +#include <kdedmodule.h> +#include <knotifyclient.h> + +#include "data.h" +#include "global.h" + +class QTimer; +class KInstance; +class Interface; +class BackendBase; +class KNotifyClient::Instance; + +/** + * This class is the main entry point of KNemo. It reads the configuration, + * creates the logical interfaces and starts an interface updater. It also + * takes care of configuration changes by the user. + * + * @short KNemos main entry point + * @author Percy Leonhardt <[email protected]> + */ +class KNemoDaemon : public KDEDModule +{ + K_DCOP + Q_OBJECT +public: + /** + * Default Constructor + */ + KNemoDaemon( const QCString& name ); + + /** + * Default Destructor + */ + virtual ~KNemoDaemon(); + + // tell the control center module which interface the user selected + static QString sSelectedInterface; + +k_dcop: + /* + * Called from the control center module when the user changed + * the settings. It updates the internal list of interfaces + * that should be monitored. + */ + virtual void reparseConfiguration(); + + /* When the user selects 'Configure KNemo...' from the context + * menus this functions gets called from the control center + * module. This way the module knows for which interface the + * user opened the dialog and can preselect the appropriate + * interface in the list. + */ + virtual QString getSelectedInterface(); + +private: + /* + * Read the configuration on startup + */ + void readConfig(); + +private slots: + /** + * trigger the backend to update the interface informations + */ + void updateInterfaces(); + +private: + QColor mColorVLines; + QColor mColorHLines; + QColor mColorIncoming; + QColor mColorOutgoing; + QColor mColorBackground; + + // every time this timer expires we will + // gather new informations from the backend + QTimer* mPollTimer; + // our own instance + KInstance* mInstance; + // needed so that KNotifyClient::event will work + KNotifyClient::Instance* mNotifyInstance; + // application wide settings are stored here + GeneralData mGeneralData; + // settings for the traffic plotter are stored here + PlotterSettings mPlotterSettings; + // the name of backend we currently use + QString mBackendName; + // the backend used to update the interface informations + BackendBase* mBackend; + // a list of all interfaces the user wants to monitor + QDict<Interface> mInterfaceDict; +}; + +#endif // KNEMODAEMON_H diff --git a/src/knemod/pics/Makefile.am b/src/knemod/pics/Makefile.am new file mode 100644 index 0000000..d085bb3 --- /dev/null +++ b/src/knemod/pics/Makefile.am @@ -0,0 +1,2 @@ +# Install the icons into the global KDE directories +KDE_ICON = AUTO diff --git a/src/knemod/pics/cr16-app-knemo.png b/src/knemod/pics/cr16-app-knemo.png Binary files differnew file mode 100644 index 0000000..1989704 --- /dev/null +++ b/src/knemod/pics/cr16-app-knemo.png diff --git a/src/knemod/pics/cr22-action-network_connected.png b/src/knemod/pics/cr22-action-network_connected.png Binary files differnew file mode 100644 index 0000000..86a0872 --- /dev/null +++ b/src/knemod/pics/cr22-action-network_connected.png diff --git a/src/knemod/pics/cr22-action-network_connected_lan.png b/src/knemod/pics/cr22-action-network_connected_lan.png Binary files differnew file mode 100644 index 0000000..a72c89f --- /dev/null +++ b/src/knemod/pics/cr22-action-network_connected_lan.png diff --git a/src/knemod/pics/cr22-action-network_connected_ppp.png b/src/knemod/pics/cr22-action-network_connected_ppp.png Binary files differnew file mode 100644 index 0000000..6abcd43 --- /dev/null +++ b/src/knemod/pics/cr22-action-network_connected_ppp.png diff --git a/src/knemod/pics/cr22-action-network_connected_wlan.png b/src/knemod/pics/cr22-action-network_connected_wlan.png Binary files differnew file mode 100644 index 0000000..b7395aa --- /dev/null +++ b/src/knemod/pics/cr22-action-network_connected_wlan.png diff --git a/src/knemod/pics/cr22-action-network_disconnected.png b/src/knemod/pics/cr22-action-network_disconnected.png Binary files differnew file mode 100644 index 0000000..d6ff91a --- /dev/null +++ b/src/knemod/pics/cr22-action-network_disconnected.png diff --git a/src/knemod/pics/cr22-action-network_disconnected_lan.png b/src/knemod/pics/cr22-action-network_disconnected_lan.png Binary files differnew file mode 100644 index 0000000..5aad370 --- /dev/null +++ b/src/knemod/pics/cr22-action-network_disconnected_lan.png diff --git a/src/knemod/pics/cr22-action-network_disconnected_ppp.png b/src/knemod/pics/cr22-action-network_disconnected_ppp.png Binary files differnew file mode 100644 index 0000000..729f1f9 --- /dev/null +++ b/src/knemod/pics/cr22-action-network_disconnected_ppp.png diff --git a/src/knemod/pics/cr22-action-network_disconnected_wlan.png b/src/knemod/pics/cr22-action-network_disconnected_wlan.png Binary files differnew file mode 100644 index 0000000..b1da123 --- /dev/null +++ b/src/knemod/pics/cr22-action-network_disconnected_wlan.png diff --git a/src/knemod/pics/cr22-action-network_incoming.png b/src/knemod/pics/cr22-action-network_incoming.png Binary files differnew file mode 100644 index 0000000..ea4b71d --- /dev/null +++ b/src/knemod/pics/cr22-action-network_incoming.png diff --git a/src/knemod/pics/cr22-action-network_incoming_lan.png b/src/knemod/pics/cr22-action-network_incoming_lan.png Binary files differnew file mode 100644 index 0000000..222d38d --- /dev/null +++ b/src/knemod/pics/cr22-action-network_incoming_lan.png diff --git a/src/knemod/pics/cr22-action-network_incoming_ppp.png b/src/knemod/pics/cr22-action-network_incoming_ppp.png Binary files differnew file mode 100644 index 0000000..51d144d --- /dev/null +++ b/src/knemod/pics/cr22-action-network_incoming_ppp.png diff --git a/src/knemod/pics/cr22-action-network_incoming_wlan.png b/src/knemod/pics/cr22-action-network_incoming_wlan.png Binary files differnew file mode 100644 index 0000000..b471965 --- /dev/null +++ b/src/knemod/pics/cr22-action-network_incoming_wlan.png diff --git a/src/knemod/pics/cr22-action-network_outgoing.png b/src/knemod/pics/cr22-action-network_outgoing.png Binary files differnew file mode 100644 index 0000000..e813f93 --- /dev/null +++ b/src/knemod/pics/cr22-action-network_outgoing.png diff --git a/src/knemod/pics/cr22-action-network_outgoing_lan.png b/src/knemod/pics/cr22-action-network_outgoing_lan.png Binary files differnew file mode 100644 index 0000000..fa3b0c5 --- /dev/null +++ b/src/knemod/pics/cr22-action-network_outgoing_lan.png diff --git a/src/knemod/pics/cr22-action-network_outgoing_ppp.png b/src/knemod/pics/cr22-action-network_outgoing_ppp.png Binary files differnew file mode 100644 index 0000000..751b788 --- /dev/null +++ b/src/knemod/pics/cr22-action-network_outgoing_ppp.png diff --git a/src/knemod/pics/cr22-action-network_outgoing_wlan.png b/src/knemod/pics/cr22-action-network_outgoing_wlan.png Binary files differnew file mode 100644 index 0000000..7cd6ef5 --- /dev/null +++ b/src/knemod/pics/cr22-action-network_outgoing_wlan.png diff --git a/src/knemod/pics/cr22-action-network_traffic.png b/src/knemod/pics/cr22-action-network_traffic.png Binary files differnew file mode 100644 index 0000000..0d2a4b2 --- /dev/null +++ b/src/knemod/pics/cr22-action-network_traffic.png diff --git a/src/knemod/pics/cr22-action-network_traffic_lan.png b/src/knemod/pics/cr22-action-network_traffic_lan.png Binary files differnew file mode 100644 index 0000000..f41a05a --- /dev/null +++ b/src/knemod/pics/cr22-action-network_traffic_lan.png diff --git a/src/knemod/pics/cr22-action-network_traffic_ppp.png b/src/knemod/pics/cr22-action-network_traffic_ppp.png Binary files differnew file mode 100644 index 0000000..0dce305 --- /dev/null +++ b/src/knemod/pics/cr22-action-network_traffic_ppp.png diff --git a/src/knemod/pics/cr22-action-network_traffic_wlan.png b/src/knemod/pics/cr22-action-network_traffic_wlan.png Binary files differnew file mode 100644 index 0000000..634b2d3 --- /dev/null +++ b/src/knemod/pics/cr22-action-network_traffic_wlan.png diff --git a/src/knemod/pics/cr32-app-knemo.png b/src/knemod/pics/cr32-app-knemo.png Binary files differnew file mode 100644 index 0000000..ac2d6dd --- /dev/null +++ b/src/knemod/pics/cr32-app-knemo.png diff --git a/src/knemod/signalplotter.cpp b/src/knemod/signalplotter.cpp new file mode 100644 index 0000000..4945a2d --- /dev/null +++ b/src/knemod/signalplotter.cpp @@ -0,0 +1,706 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + + $Id: SignalPlotter.cc,v 1.7 2004/01/04 13:43:48 waba Exp $ +*/ + +#include <math.h> +#include <string.h> + +#include <qpainter.h> +#include <qpixmap.h> + +#include <kdebug.h> +#include <kconfig.h> + +#include "signalplotter.h" + +static inline int min( int a, int b ) +{ + return ( a < b ? a : b ); +} + +SignalPlotter::SignalPlotter( QWidget *parent, const char *name ) + : QDialog( parent, name ), + mPosInitialized( false ), + mName( name ) +{ + // Auto deletion does not work for pointer to arrays. + mBeamData.setAutoDelete( false ); + + setBackgroundMode( NoBackground ); + + mSamples = 0; + mMinValue = mMaxValue = 0.0; + mUseAutoRange = true; + + mGraphStyle = GRAPH_POLYGON; + + // Anything smaller than this does not make sense. + setMinimumSize( 16, 16 ); + setSizePolicy( QSizePolicy( QSizePolicy::Expanding, + QSizePolicy::Expanding, false ) ); + + mShowVerticalLines = true; + mVerticalLinesColor = QColor( 0x04FB1D ); + mVerticalLinesDistance = 30; + mVerticalLinesScroll = true; + mVerticalLinesOffset = 0; + mHorizontalScale = 1; + + mShowHorizontalLines = true; + mHorizontalLinesColor = QColor( 0x04FB1D ); + mHorizontalLinesCount = 5; + + mShowLabels = true; + mShowTopBar = false; + mFontSize = 8; + + mBackgroundColor = QColor( 0x313031 ); + + // Restore window size and position. + KConfig* config = new KConfig( "knemorc", false ); + if ( config->hasGroup( "Interface_" + mName ) ) + { + config->setGroup( "Interface_" + mName ); + if ( config->hasKey( "PlotterX" ) && config->hasKey( "PlotterY" ) ) + { + mPos.setX( config->readNumEntry( "PlotterX" ) ); + mPos.setY( config->readNumEntry( "PlotterY" ) ); + mPosInitialized = true; + } + if ( config->hasKey( "PlotterWidth" ) && config->hasKey( "PlotterHeight" ) ) + resize( config->readNumEntry( "PlotterWidth" ), + config->readNumEntry( "PlotterHeight" ) ); + } + delete config; +} + +SignalPlotter::~SignalPlotter() +{ + for ( double* p = mBeamData.first(); p; p = mBeamData.next() ) + delete [] p; + + // Store window size and position. + KConfig* config = new KConfig( "knemorc", false ); + if ( config->hasGroup( "Interface_" + mName ) ) + { + config->setGroup( "Interface_" + mName ); + config->writeEntry( "PlotterX", x() ); + config->writeEntry( "PlotterY", y() ); + config->writeEntry( "PlotterWidth", width() ); + config->writeEntry( "PlotterHeight", height() ); + config->sync(); + } + delete config; +} + +void SignalPlotter::hide() +{ + mPos = pos(); + mPosInitialized = true; + QDialog::hide(); +} + +void SignalPlotter::show() +{ + QDialog::show(); + /** + * mPosInitialized should always be true, except when + * starting KNemo for the very first time. + */ + if ( mPosInitialized ) + move( mPos ); +} + +bool SignalPlotter::addBeam( const QColor &color ) +{ + double* d = new double[ mSamples ]; + memset( d, 0, sizeof(double) * mSamples ); + mBeamData.append( d ); + mBeamColor.append( color ); + + return true; +} + +void SignalPlotter::addSample( const QValueList<double>& sampleBuf ) +{ + if ( mBeamData.count() != sampleBuf.count() ) + return; + + double* d; + if ( mUseAutoRange ) { + double sum = 0; + for ( d = mBeamData.first(); d; d = mBeamData.next() ) { + sum += d[ 0 ]; + if ( sum < mMinValue ) + mMinValue = sum; + if ( sum > mMaxValue ) + mMaxValue = sum; + } + } + + /* If the vertical lines are scrolling, increment the offset + * so they move with the data. The vOffset / hScale confusion + * is because v refers to Vertical Lines, and h to the horizontal + * distance between the vertical lines. */ + if ( mVerticalLinesScroll ) { + mVerticalLinesOffset = ( mVerticalLinesOffset + mHorizontalScale) + % mVerticalLinesDistance; + } + + // Shift data buffers one sample down and insert new samples. + QValueList<double>::ConstIterator s; + for ( d = mBeamData.first(), s = sampleBuf.begin(); d; d = mBeamData.next(), ++s ) { + memmove( d, d + 1, ( mSamples - 1 ) * sizeof( double ) ); + d[ mSamples - 1 ] = *s; + } + + update(); +} + +void SignalPlotter::changeRange( int beam, double min, double max ) +{ + // Only the first beam affects range calculation. + if ( beam > 1 ) + return; + + mMinValue = min; + mMaxValue = max; +} + +QValueList<QColor> &SignalPlotter::beamColors() +{ + return mBeamColor; +} + +void SignalPlotter::removeBeam( uint pos ) +{ + mBeamColor.remove( mBeamColor.at( pos ) ); + mBeamData.remove( pos ); +} + +void SignalPlotter::setTitle( const QString &title ) +{ + mTitle = title; +} + +QString SignalPlotter::title() const +{ + return mTitle; +} + +void SignalPlotter::setUseAutoRange( bool value ) +{ + mUseAutoRange = value; +} + +bool SignalPlotter::useAutoRange() const +{ + return mUseAutoRange; +} + +void SignalPlotter::setMinValue( double min ) +{ + mMinValue = min; +} + +double SignalPlotter::minValue() const +{ + return ( mUseAutoRange ? 0 : mMinValue ); +} + +void SignalPlotter::setMaxValue( double max ) +{ + mMaxValue = max; +} + +double SignalPlotter::maxValue() const +{ + return ( mUseAutoRange ? 0 : mMaxValue ); +} + +void SignalPlotter::setGraphStyle( uint style ) +{ + mGraphStyle = style; +} + +uint SignalPlotter::graphStyle() const +{ + return mGraphStyle; +} + +void SignalPlotter::setHorizontalScale( uint scale ) +{ + if (scale == mHorizontalScale) + return; + + mHorizontalScale = scale; + if (isVisible()) + updateDataBuffers(); +} + +uint SignalPlotter::horizontalScale() const +{ + return mHorizontalScale; +} + +void SignalPlotter::setShowVerticalLines( bool value ) +{ + mShowVerticalLines = value; +} + +bool SignalPlotter::showVerticalLines() const +{ + return mShowVerticalLines; +} + +void SignalPlotter::setVerticalLinesColor( const QColor &color ) +{ + mVerticalLinesColor = color; +} + +QColor SignalPlotter::verticalLinesColor() const +{ + return mVerticalLinesColor; +} + +void SignalPlotter::setVerticalLinesDistance( int distance ) +{ + mVerticalLinesDistance = distance; +} + +int SignalPlotter::verticalLinesDistance() const +{ + return mVerticalLinesDistance; +} + +void SignalPlotter::setVerticalLinesScroll( bool value ) +{ + mVerticalLinesScroll = value; +} + +bool SignalPlotter::verticalLinesScroll() const +{ + return mVerticalLinesScroll; +} + +void SignalPlotter::setShowHorizontalLines( bool value ) +{ + mShowHorizontalLines = value; +} + +bool SignalPlotter::showHorizontalLines() const +{ + return mShowHorizontalLines; +} + +void SignalPlotter::setHorizontalLinesColor( const QColor &color ) +{ + mHorizontalLinesColor = color; +} + +QColor SignalPlotter::horizontalLinesColor() const +{ + return mHorizontalLinesColor; +} + +void SignalPlotter::setHorizontalLinesCount( int count ) +{ + mHorizontalLinesCount = count; +} + +int SignalPlotter::horizontalLinesCount() const +{ + return mHorizontalLinesCount; +} + +void SignalPlotter::setShowLabels( bool value ) +{ + mShowLabels = value; +} + +bool SignalPlotter::showLabels() const +{ + return mShowLabels; +} + +void SignalPlotter::setShowTopBar( bool value ) +{ + mShowTopBar = value; +} + +bool SignalPlotter::showTopBar() const +{ + return mShowTopBar; +} + +void SignalPlotter::setFontSize( int size ) +{ + mFontSize = size; +} + +int SignalPlotter::fontSize() const +{ + return mFontSize; +} + +void SignalPlotter::setBackgroundColor( const QColor &color ) +{ + mBackgroundColor = color; +} + +QColor SignalPlotter::backgroundColor() const +{ + return mBackgroundColor; +} + +void SignalPlotter::resizeEvent( QResizeEvent* ) +{ + Q_ASSERT( width() > 2 ); + + updateDataBuffers(); +} + +void SignalPlotter::updateDataBuffers() +{ + /* Since the data buffers for the beams are equal in size to the + * width of the widget minus 2 we have to enlarge or shrink the + * buffers accordingly when a resize occures. To have a nicer + * display we try to keep as much data as possible. Data that is + * lost due to shrinking the buffers cannot be recovered on + * enlarging though. */ + + /* Determine new number of samples first. + * +0.5 to ensure rounding up + * +2 for extra data points so there is + * 1) no wasted space and + * 2) no loss of precision when drawing the first data point. */ + uint newSampleNum = static_cast<uint>( ( ( width() - 2 ) / + mHorizontalScale ) + 2.5 ); + + // overlap between the old and the new buffers. + int overlap = min( mSamples, newSampleNum ); + + for ( uint i = 0; i < mBeamData.count(); ++i ) { + double* nd = new double[ newSampleNum ]; + + // initialize new part of the new buffer + if ( newSampleNum > (uint)overlap ) + memset( nd, 0, sizeof( double ) * ( newSampleNum - overlap ) ); + + // copy overlap from old buffer to new buffer + memcpy( nd + ( newSampleNum - overlap ), mBeamData.at( i ) + + ( mSamples - overlap ), overlap * sizeof( double ) ); + + mBeamData.remove( i ); + mBeamData.insert( i, nd ); + } + + mSamples = newSampleNum; +} + +void SignalPlotter::paintEvent( QPaintEvent* ) +{ + uint w = width(); + uint h = height(); + + /* Do not do repaints when the widget is not yet setup properly. */ + if ( w <= 2 ) + return; + + QPixmap pm( w, h ); + QPainter p; + p.begin( &pm, this ); + + pm.fill( mBackgroundColor ); + /* Draw white line along the bottom and the right side of the + * widget to create a 3D like look. */ + p.setPen( QColor( colorGroup().light() ) ); + p.drawLine( 0, h - 1, w - 1, h - 1 ); + p.drawLine( w - 1, 0, w - 1, h - 1 ); + + p.setClipRect( 1, 1, w - 2, h - 2 ); + double range = mMaxValue - mMinValue; + + /* If the range is too small we will force it to 1.0 since it + * looks a lot nicer. */ + if ( range < 0.000001 ) + range = 1.0; + + double minValue = mMinValue; + if ( mUseAutoRange ) { + if ( mMinValue != 0.0 ) { + double dim = pow( 10, floor( log10( fabs( mMinValue ) ) ) ) / 2; + if ( mMinValue < 0.0 ) + minValue = dim * floor( mMinValue / dim ); + else + minValue = dim * ceil( mMinValue / dim ); + range = mMaxValue - minValue; + if ( range < 0.000001 ) + range = 1.0; + } + // Massage the range so that the grid shows some nice values. + double step = range / mHorizontalLinesCount; + double dim = pow( 10, floor( log10( step ) ) ) / 2; + range = dim * ceil( step / dim ) * mHorizontalLinesCount; + } + double maxValue = minValue + range; + + int top = 0; + if ( mShowTopBar && h > ( mFontSize + 2 + mHorizontalLinesCount * 10 ) ) { + /* Draw horizontal bar with current sensor values at top of display. */ + p.setPen( mHorizontalLinesColor ); + int x0 = w / 2; + p.setFont( QFont( p.font().family(), mFontSize ) ); + top = p.fontMetrics().height(); + h -= top; + int h0 = top - 2; + + // JJ 2005-07-18: show numerical in/out values in the top bar ---> + double *d1 = mBeamData.first(); + double UploadSpeed = 0; + if(d1) + UploadSpeed = d1[ w - 3 ]; // read value from graph data + + double *d2 = mBeamData.next(); + double DownloadSpeed = 0; + if(d2) + DownloadSpeed = d2[ w - 3 ]; // read value from graph data + + // The left side of the top bar is now divided into three sections: + // - name of interface (original title) + // - download speed (numerically, from the value shown by the bar on the right) + // - upload speed (numerically, from the value shown by the bar on the right) + + // title + p.drawText(0, 0, x0/3, top - 2, Qt::AlignCenter, mTitle ); + + QValueList<QColor>::Iterator col_speeds; + col_speeds = mBeamColor.begin(); + QColor UploadColor = *(col_speeds++); + QColor DownloadColor = *(col_speeds); + + // download speed + QString DownloadSpeedText; + DownloadSpeedText.sprintf("in: %0.2f KB/s", DownloadSpeed); + p.setPen( DownloadColor ); + p.drawText(x0/3, 0, x0/3, top - 2, Qt::AlignCenter, DownloadSpeedText ); + + // upload speed + QString UploadSpeedText; + UploadSpeedText.sprintf("out: %0.2f KB/s", UploadSpeed); + p.setPen( UploadColor ); + p.drawText(2*x0/3, 0, x0/3, top - 2, Qt::AlignCenter, UploadSpeedText ); + + // restore correct pen color for the separator lines + p.setPen( mHorizontalLinesColor ); + // <--- JJ 2005-07-18 + + p.drawLine( x0 - 1, 1, x0 - 1, h0 ); + p.drawLine( 0, top - 1, w - 2, top - 1 ); + + double bias = -minValue; + double scaleFac = ( w - x0 - 2 ) / range; + QValueList<QColor>::Iterator col; + col = mBeamColor.begin(); + for ( double* d = mBeamData.first(); d; d = mBeamData.next(), ++col ) { + int start = x0 + (int)( bias * scaleFac ); + int end = x0 + (int)( ( bias += d[ w - 3 ] ) * scaleFac ); + /* If the rect is wider than 2 pixels we draw only the last + * pixels with the bright color. The rest is painted with + * a 50% darker color. */ + if ( end - start > 1 ) { + p.setPen( (*col).dark( 150 ) ); + p.setBrush( (*col).dark( 150 ) ); + p.drawRect( start, 1, end - start, h0 ); + p.setPen( *col ); + p.drawLine( end, 1, end, h0 ); + } else if ( start - end > 1 ) { + p.setPen( (*col).dark( 150 ) ); + p.setBrush( (*col).dark( 150 ) ); + p.drawRect( end, 1, start - end, h0 ); + p.setPen( *col ); + p.drawLine( end, 1, end, h0 ); + } else { + p.setPen( *col ); + p.drawLine( start, 1, start, h0 ); + } + } + } + + /* Draw scope-like grid vertical lines */ + if ( mShowVerticalLines && w > 60 ) { + p.setPen( mVerticalLinesColor ); + for ( uint x = mVerticalLinesOffset; x < ( w - 2 ); x += mVerticalLinesDistance ) + p.drawLine( w - x, top, w - x, h + top - 2 ); + } + + /* In autoRange mode we determine the range and plot the values in + * one go. This is more efficiently than running through the + * buffers twice but we do react on recently discarded samples as + * well as new samples one plot too late. So the range is not + * correct if the recently discarded samples are larger or smaller + * than the current extreme values. But we can probably live with + * this. */ + if ( mUseAutoRange ) + mMinValue = mMaxValue = 0.0; + + /* Plot stacked values */ + double scaleFac = ( h - 2 ) / range; + if ( mGraphStyle == GRAPH_ORIGINAL ) { + int xPos = 0; + for ( int i = 0; i < mSamples; i++, xPos += mHorizontalScale ) { + double bias = -minValue; + QValueList<QColor>::Iterator col; + col = mBeamColor.begin(); + double sum = 0.0; + for ( double* d = mBeamData.first(); d; d = mBeamData.next(), ++col ) { + if ( mUseAutoRange ) { + sum += d[ i ]; + if ( sum < mMinValue ) + mMinValue = sum; + if ( sum > mMaxValue ) + mMaxValue = sum; + } + int start = top + h - 2 - (int)( bias * scaleFac ); + int end = top + h - 2 - (int)( ( bias + d[ i ] ) * scaleFac ); + bias += d[ i ]; + /* If the line is longer than 2 pixels we draw only the last + * 2 pixels with the bright color. The rest is painted with + * a 50% darker color. */ + if ( end - start > 2 ) { + p.fillRect( xPos, start, mHorizontalScale, end - start - 1, (*col).dark( 150 ) ); + p.fillRect( xPos, end - 1, mHorizontalScale, 2, *col ); + } else if ( start - end > 2 ) { + p.fillRect( xPos, start, mHorizontalScale, end - start + 1, (*col).dark( 150 ) ); + p.fillRect( xPos, end + 1, mHorizontalScale, 2, *col ); + } else + p.fillRect( xPos, start, mHorizontalScale, end - start, *col ); + + } + } + } else if ( mGraphStyle == GRAPH_POLYGON ) { + int *prevVals = new int[ mBeamData.count() ]; + int hack[ 4 ] = { 0, 0, 0, 0 }; + int x1 = w - ( ( mSamples + 1 ) * mHorizontalScale ); + + for ( int i = 0; i < mSamples; i++ ) { + QValueList<QColor>::Iterator col; + col = mBeamColor.begin(); + double sum = 0.0; + int y = top + h - 2; + int oldY = top + h; + int oldPrevY = oldY; + int height = 0; + int j = 0; + int jMax = mBeamData.count() - 1; + x1 += mHorizontalScale; + int x2 = x1 + mHorizontalScale; + + for ( double* d = mBeamData.first(); d; d = mBeamData.next(), ++col, j++ ) { + if ( mUseAutoRange ) { + sum += d[ i ]; + if ( sum < mMinValue ) + mMinValue = sum; + if ( sum > mMaxValue ) + mMaxValue = sum; + } + height = (int)( ( d[ i ] - minValue ) * scaleFac ); + y -= height; + + /* If the line is longer than 2 pixels we draw only the last + * 2 pixels with the bright color. The rest is painted with + * a 50% darker color. */ + QPen lastPen = QPen( p.pen() ); + p.setPen( (*col).dark( 150 ) ); + p.setBrush( (*col).dark( 150 ) ); + QPointArray pa( 4 ); + int prevY = ( i == 0 ) ? y : prevVals[ j ]; + pa.putPoints( 0, 1, x1, prevY ); + pa.putPoints( 1, 1, x2, y ); + pa.putPoints( 2, 1, x2, oldY ); + pa.putPoints( 3, 1, x1, oldPrevY ); + p.drawPolygon( pa ); + p.setPen( lastPen ); + if ( jMax == 0 ) { + // draw as normal, no deferred drawing req'd. + p.setPen( *col ); + p.drawLine( x1, prevY, x2, y ); + } else if ( j == jMax ) { + // draw previous values and current values + p.drawLine( hack[ 0 ], hack[ 1 ], hack[ 2 ], hack[ 3 ] ); + p.setPen( *col ); + p.drawLine( x1, prevY, x2, y ); + } else if ( j == 0 ) { + // save values only + hack[ 0 ] = x1; + hack[ 1 ] = prevY; + hack[ 2 ] = x2; + hack[ 3 ] = y; + p.setPen( *col ); + } else { + p.drawLine( hack[ 0 ], hack[ 1 ], hack[ 2 ], hack[ 3 ] ); + hack[ 0 ] = x1; + hack[ 1 ] = prevY; + hack[ 2 ] = x2; + hack[ 3 ] = y; + p.setPen( *col ); + } + + prevVals[ j ] = y; + oldY = y; + oldPrevY = prevY; + } + } + + delete[] prevVals; + } + + /* Draw horizontal lines and values. Lines are drawn when the + * height is greater than 10 times hCount + 1, values are shown + * when width is greater than 60 */ + if ( mShowHorizontalLines && h > ( 10 * ( mHorizontalLinesCount + 1 ) ) ) { + p.setPen( mHorizontalLinesColor ); + p.setFont( QFont( p.font().family(), mFontSize ) ); + QString val; + for ( uint y = 1; y < mHorizontalLinesCount; y++ ) { + p.drawLine( 0, top + y * ( h / mHorizontalLinesCount ), w - 2, + top + y * ( h / mHorizontalLinesCount ) ); + if ( mShowLabels && h > ( mFontSize + 1 ) * ( mHorizontalLinesCount + 1 ) + && w > 60 ) { + val = QString( "%1" ).arg( maxValue - y * ( range / mHorizontalLinesCount ) ); + p.drawText( 6, top + y * ( h / mHorizontalLinesCount ) - 1, val ); + } + } + + if ( mShowLabels && h > ( mFontSize + 1 ) * ( mHorizontalLinesCount + 1 ) + && w > 60 ) { + val = QString( "%1" ).arg( minValue ); + p.drawText( 6, top + h - 2, val ); + } + } + + p.end(); + bitBlt( this, 0, 0, &pm ); +} + +#include "signalplotter.moc" diff --git a/src/knemod/signalplotter.h b/src/knemod/signalplotter.h new file mode 100644 index 0000000..f0dabfb --- /dev/null +++ b/src/knemod/signalplotter.h @@ -0,0 +1,160 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + + $Id: SignalPlotter.h,v 1.5 2004/01/04 13:43:48 waba Exp $ +*/ + +#ifndef KSG_SIGNALPLOTTER_H +#define KSG_SIGNALPLOTTER_H + +#include <qpoint.h> +#include <qdialog.h> +#include <qptrlist.h> +#include <qstring.h> +#include <qvaluelist.h> + +#define GRAPH_POLYGON 0 +#define GRAPH_ORIGINAL 1 + +class QColor; + +class SignalPlotter : public QDialog +{ + Q_OBJECT + + public: + SignalPlotter( QWidget *parent = 0, const char *name = 0 ); + ~SignalPlotter(); + + /** + * Implemented to store position. + */ + void hide(); + void show(); + + bool addBeam( const QColor &color ); + void addSample( const QValueList<double> &samples ); + + void removeBeam( uint pos ); + + void changeRange( int beam, double min, double max ); + + QValueList<QColor> &beamColors(); + + void setTitle( const QString &title ); + QString title() const; + + void setUseAutoRange( bool value ); + bool useAutoRange() const; + + void setMinValue( double min ); + double minValue() const; + + void setMaxValue( double max ); + double maxValue() const; + + void setGraphStyle( uint style ); + uint graphStyle() const; + + void setHorizontalScale( uint scale ); + uint horizontalScale() const; + + void setShowVerticalLines( bool value ); + bool showVerticalLines() const; + + void setVerticalLinesColor( const QColor &color ); + QColor verticalLinesColor() const; + + void setVerticalLinesDistance( int distance ); + int verticalLinesDistance() const; + + void setVerticalLinesScroll( bool value ); + bool verticalLinesScroll() const; + + void setShowHorizontalLines( bool value ); + bool showHorizontalLines() const; + + void setHorizontalLinesColor( const QColor &color ); + QColor horizontalLinesColor() const; + + void setHorizontalLinesCount( int count ); + int horizontalLinesCount() const; + + void setShowLabels( bool value ); + bool showLabels() const; + + void setShowTopBar( bool value ); + bool showTopBar() const; + + void setFontSize( int size ); + int fontSize() const; + + void setBackgroundColor( const QColor &color ); + QColor backgroundColor() const; + + protected: + void updateDataBuffers(); + + virtual void resizeEvent( QResizeEvent* ); + virtual void paintEvent( QPaintEvent* ); + + private: + QPoint mPos; + bool mPosInitialized; + + double mMinValue; + double mMaxValue; + bool mUseAutoRange; + + uint mGraphStyle; + + bool mShowVerticalLines; + QColor mVerticalLinesColor; + uint mVerticalLinesDistance; + bool mVerticalLinesScroll; + uint mVerticalLinesOffset; + uint mHorizontalScale; + + bool mShowHorizontalLines; + QColor mHorizontalLinesColor; + uint mHorizontalLinesCount; + + bool mShowLabels; + bool mShowTopBar; + uint mFontSize; + + QColor mBackgroundColor; + + QPtrList<double> mBeamData; + QValueList<QColor> mBeamColor; + + int mSamples; + + /** + * The name of the interface. + * Needed to store the geometry of the plotter in the right + * group of the config file. + */ + QString mName; + QString mTitle; +}; + +#endif |