diff options
Diffstat (limited to 'ksysguard/gui')
91 files changed, 17469 insertions, 0 deletions
diff --git a/ksysguard/gui/KSGAppletSettings.cc b/ksysguard/gui/KSGAppletSettings.cc new file mode 100644 index 000000000..df4748cb8 --- /dev/null +++ b/ksysguard/gui/KSGAppletSettings.cc @@ -0,0 +1,106 @@ +/* + This file is part of KSysGuard. + Copyright ( C ) 2002 Nadeem Hasan ( nhasan@kde.org ) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or ( at your option ) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qlabel.h> +#include <qlayout.h> +#include <qspinbox.h> + +#include <kaccelmanager.h> +#include <klocale.h> + +#include "KSGAppletSettings.h" + +KSGAppletSettings::KSGAppletSettings( QWidget *parent, const char *name ) + : KDialogBase( parent, name, false, QString::null, Ok|Apply|Cancel, + Ok, true ) +{ + setCaption( i18n( "System Guard Settings" ) ); + + QWidget *page = new QWidget( this ); + setMainWidget( page ); + + QGridLayout *topLayout = new QGridLayout( page, 3, 2, KDialog::marginHint(), + KDialog::spacingHint() ); + + QLabel *label = new QLabel( i18n( "Number of displays:" ), page ); + topLayout->addWidget( label, 0, 0 ); + + mNumDisplay = new QSpinBox( 1, 32, 1, page ); + mNumDisplay->setValue(2); + topLayout->addWidget( mNumDisplay, 0, 1 ); + label->setBuddy( mNumDisplay ); + + label = new QLabel( i18n( "Size ratio:" ), page ); + topLayout->addWidget( label, 1, 0 ); + + mSizeRatio = new QSpinBox( 50, 500, 50, page ); + mSizeRatio->setSuffix( i18n( "%" ) ); + mSizeRatio->setValue(100); + topLayout->addWidget( mSizeRatio, 1, 1 ); + label->setBuddy( mSizeRatio ); + + label = new QLabel( i18n( "Update interval:" ), page ); + topLayout->addWidget( label, 2, 0 ); + + mInterval = new QSpinBox( 1, 300, 1, page ); + mInterval->setValue(2); + mInterval->setSuffix( i18n( " sec" ) ); + topLayout->addWidget( mInterval, 2, 1 ); + label->setBuddy( mInterval ); + + resize( QSize( 250, 130 ).expandedTo( minimumSizeHint() ) ); + + KAcceleratorManager::manage( page ); +} + +KSGAppletSettings::~KSGAppletSettings() +{ +} + +int KSGAppletSettings::numDisplay() const +{ + return mNumDisplay->value(); +} + +void KSGAppletSettings::setNumDisplay( int value ) +{ + mNumDisplay->setValue( value ); +} + +int KSGAppletSettings::sizeRatio() const +{ + return mSizeRatio->value(); +} + +void KSGAppletSettings::setSizeRatio( int value ) +{ + mSizeRatio->setValue( value ); +} + +int KSGAppletSettings::updateInterval() const +{ + return mInterval->value(); +} + +void KSGAppletSettings::setUpdateInterval( int value ) +{ + mInterval->setValue( value ); +} + diff --git a/ksysguard/gui/KSGAppletSettings.h b/ksysguard/gui/KSGAppletSettings.h new file mode 100644 index 000000000..a825e2841 --- /dev/null +++ b/ksysguard/gui/KSGAppletSettings.h @@ -0,0 +1,49 @@ +/* + This file is part of KSysGuard. + Copyright ( C ) 2002 Nadeem Hasan ( nhasan@kde.org ) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or ( at your option ) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KSG_APPLETSETTINGS_H +#define KSG_APPLETSETTINGS_H + +#include <kdialogbase.h> + +class QSpinBox; + +class KSGAppletSettings : public KDialogBase +{ + public: + KSGAppletSettings( QWidget *parent = 0, const char *name = 0 ); + ~KSGAppletSettings(); + + void setNumDisplay( int ); + int numDisplay() const; + + void setSizeRatio( int ); + int sizeRatio() const; + + void setUpdateInterval( int ); + int updateInterval() const; + + private: + QSpinBox *mInterval; + QSpinBox *mNumDisplay; + QSpinBox *mSizeRatio; +}; + +#endif diff --git a/ksysguard/gui/KSysGuardApplet.cc b/ksysguard/gui/KSysGuardApplet.cc new file mode 100644 index 000000000..5240a068b --- /dev/null +++ b/ksysguard/gui/KSysGuardApplet.cc @@ -0,0 +1,495 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 + <cs@kde.org>. Please do not commit any changes without consulting + me first. Thanks! + +*/ + +#include <qcursor.h> +#include <qdom.h> +#include <qdragobject.h> +#include <qfile.h> +#include <qpushbutton.h> +#include <qspinbox.h> +#include <qtooltip.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <ksavefile.h> +#include <kstandarddirs.h> +#include <kpopupmenu.h> + +#include <ksgrd/SensorClient.h> +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include "DancingBars.h" +#include "FancyPlotter.h" +#include "KSGAppletSettings.h" +#include "MultiMeter.h" + +#include "KSysGuardApplet.h" + +extern "C" +{ + KDE_EXPORT KPanelApplet* init( QWidget *parent, const QString& configFile ) + { + KGlobal::locale()->insertCatalogue( "ksysguard" ); + return new KSysGuardApplet( configFile, KPanelApplet::Normal, + KPanelApplet::Preferences, parent, + "ksysguardapplet" ); + } +} + +KSysGuardApplet::KSysGuardApplet( const QString& configFile, Type type, + int actions, QWidget *parent, + const char *name ) + : KPanelApplet( configFile, type, actions, parent, name) +{ + mSettingsDlg = 0; + + KSGRD::SensorMgr = new KSGRD::SensorManager(); + + KSGRD::Style = new KSGRD::StyleEngine(); + + mDockCount = 1; + mDockList = new QWidget*[ mDockCount ]; + + mSizeRatio = 1.0; + addEmptyDisplay( mDockList, 0 ); + + updateInterval( 2 ); + + load(); + + setAcceptDrops( true ); +} + +KSysGuardApplet::~KSysGuardApplet() +{ + save(); + + delete [] mDockList; + mDockList = 0; + + delete mSettingsDlg; + mSettingsDlg = 0; + + delete KSGRD::Style; + delete KSGRD::SensorMgr; + KSGRD::SensorMgr = 0; +} + +int KSysGuardApplet::widthForHeight( int height ) const +{ + return ( (int) ( height * mSizeRatio + 0.5 ) * mDockCount ); +} + +int KSysGuardApplet::heightForWidth( int width ) const +{ + return ( (int) ( width * mSizeRatio + 0.5 ) * mDockCount ); +} + +void KSysGuardApplet::resizeEvent( QResizeEvent* ) +{ + layout(); +} + +void KSysGuardApplet::preferences() +{ + if(mSettingsDlg) { + return; + } + mSettingsDlg = new KSGAppletSettings( this ); + + connect( mSettingsDlg, SIGNAL( applyClicked() ), SLOT( applySettings() ) ); + connect( mSettingsDlg, SIGNAL( okClicked() ), SLOT( applySettings() ) ); + connect( mSettingsDlg, SIGNAL( finished() ), SLOT( preferencesFinished() ) ); + + mSettingsDlg->setNumDisplay( mDockCount ); + mSettingsDlg->setSizeRatio( (int) ( mSizeRatio * 100.0 + 0.5 ) ); + mSettingsDlg->setUpdateInterval( updateInterval() ); + + mSettingsDlg->show(); +} +void KSysGuardApplet::preferencesFinished() +{ + mSettingsDlg->delayedDestruct(); + mSettingsDlg = 0; +} +void KSysGuardApplet::applySettings() +{ + updateInterval( mSettingsDlg->updateInterval() ); + mSizeRatio = mSettingsDlg->sizeRatio() / 100.0; + resizeDocks( mSettingsDlg->numDisplay() ); + + for ( uint i = 0; i < mDockCount; ++i ) + if ( !mDockList[ i ]->isA( "QFrame" ) ) + ((KSGRD::SensorDisplay*)mDockList[ i ])->setUpdateInterval( updateInterval() ); + + save(); +} + +void KSysGuardApplet::sensorDisplayModified( bool modified ) +{ + if ( modified ) + save(); +} + +void KSysGuardApplet::layout() +{ + if ( orientation() == Horizontal ) { + int h = height(); + int w = (int) ( h * mSizeRatio + 0.5 ); + for ( uint i = 0; i < mDockCount; ++i ) + if ( mDockList[ i ] ) + mDockList[ i ]->setGeometry( i * w, 0, w, h ); + } else { + int w = width(); + int h = (int) ( w * mSizeRatio + 0.5 ); + for ( uint i = 0; i < mDockCount; ++i ) + if ( mDockList[ i ] ) + mDockList[ i ]->setGeometry( 0, i * h, w, h ); + } +} + +int KSysGuardApplet::findDock( const QPoint& point ) +{ + if ( orientation() == Horizontal ) + return ( point.x() / (int) ( height() * mSizeRatio + 0.5 ) ); + else + return ( point.y() / (int) ( width() * mSizeRatio + 0.5 ) ); +} + +void KSysGuardApplet::dragEnterEvent( QDragEnterEvent *e ) +{ + e->accept( QTextDrag::canDecode( e ) ); +} + +void KSysGuardApplet::dropEvent( QDropEvent *e ) +{ + QString dragObject; + + if ( QTextDrag::decode( e, dragObject ) ) { + // The host name, sensor name and type are seperated by a ' '. + QStringList parts = QStringList::split( ' ', dragObject ); + + QString hostName = parts[ 0 ]; + QString sensorName = parts[ 1 ]; + QString sensorType = parts[ 2 ]; + QString sensorDescr = parts[ 3 ]; + + if ( hostName.isEmpty() || sensorName.isEmpty() || sensorType.isEmpty() ) + return; + + int dock = findDock( e->pos() ); + if ( mDockList[ dock ]->isA( "QFrame" ) ) { + if ( sensorType == "integer" || sensorType == "float" ) { + KPopupMenu popup; + QWidget *wdg = 0; + + popup.insertTitle( i18n( "Select Display Type" ) ); + popup.insertItem( i18n( "&Signal Plotter" ), 1 ); + popup.insertItem( i18n( "&Multimeter" ), 2 ); + popup.insertItem( i18n( "&Dancing Bars" ), 3 ); + switch ( popup.exec( QCursor::pos() ) ) { + case 1: + wdg = new FancyPlotter( this, "FancyPlotter", sensorDescr, + 100.0, 100.0, true ); + break; + + case 2: + wdg = new MultiMeter( this, "MultiMeter", sensorDescr, + 100.0, 100.0, true ); + break; + + case 3: + wdg = new DancingBars( this, "DancingBars", sensorDescr, + 100, 100, true ); + break; + } + + if ( wdg ) { + delete mDockList[ dock ]; + mDockList[ dock ] = wdg; + layout(); + + connect( wdg, SIGNAL( modified( bool ) ), + SLOT( sensorDisplayModified( bool ) ) ); + + mDockList[ dock ]->show(); + } + } else { + KMessageBox::sorry( this, + i18n( "The KSysGuard applet does not support displaying of " + "this type of sensor. Please choose another sensor." ) ); + + layout(); + } + } + + if ( !mDockList[ dock ]->isA( "QFrame" ) ) + ((KSGRD::SensorDisplay*)mDockList[ dock ])-> + addSensor( hostName, sensorName, sensorType, sensorDescr ); + } + + save(); +} + +void KSysGuardApplet::customEvent( QCustomEvent *e ) +{ + if ( e->type() == QEvent::User ) { + // SensorDisplays send out this event if they want to be removed. + removeDisplay( (KSGRD::SensorDisplay*)e->data() ); + save(); + } +} + +void KSysGuardApplet::removeDisplay( KSGRD::SensorDisplay *display ) +{ + for ( uint i = 0; i < mDockCount; ++i ) + if ( display == mDockList[i] ) { + delete mDockList[ i ]; + + addEmptyDisplay( mDockList, i ); + return; + } +} + +void KSysGuardApplet::resizeDocks( uint newDockCount ) +{ + /* This function alters the number of available docks. The number of + * docks can be increased or decreased. We try to preserve existing + * docks if possible. */ + + if ( newDockCount == mDockCount ) { + emit updateLayout(); + return; + } + + // Create and initialize new dock array. + QWidget** tmp = new QWidget*[ newDockCount ]; + + uint i; + for ( i = 0; ( i < newDockCount ) && ( i < mDockCount ); ++i ) + tmp[ i ] = mDockList[ i ]; + + for ( i = newDockCount; i < mDockCount; ++i ) + if ( mDockList[ i ] ) + delete mDockList[ i ]; + + for ( i = mDockCount; i < newDockCount; ++i ) + addEmptyDisplay( tmp, i ); + + delete [] mDockList; + + mDockList = tmp; + mDockCount = newDockCount; + + emit updateLayout(); +} + +bool KSysGuardApplet::load() +{ + KStandardDirs* kstd = KGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + QString fileName = kstd->findResource( "data", "KSysGuardApplet.xml" ); + + QFile file( fileName ); + if ( !file.open( IO_ReadOnly ) ) { + KMessageBox::sorry( this, i18n( "Cannot open the file %1." ).arg( fileName ) ); + return false; + } + + // Parse the XML file. + QDomDocument doc; + + // Read in file and check for a valid XML header. + if ( !doc.setContent( &file ) ) { + KMessageBox::sorry( this, i18n( "The file %1 does not contain valid XML." ) + .arg( fileName ) ); + return false; + } + + // Check for proper document type. + if ( doc.doctype().name() != "KSysGuardApplet" ) { + KMessageBox::sorry( this, i18n( "The file %1 does not contain a valid applet " + "definition, which must have a document type 'KSysGuardApplet'." ) + .arg( fileName ) ); + return false; + } + + QDomElement element = doc.documentElement(); + bool ok; + uint count = element.attribute( "dockCnt" ).toUInt( &ok ); + if ( !ok ) + count = 1; + + mSizeRatio = element.attribute( "sizeRatio" ).toDouble( &ok ); + if ( !ok ) + mSizeRatio = 1.0; + + updateInterval( element.attribute( "interval" ).toUInt( &ok ) ); + if ( !ok ) + updateInterval( 2 ); + + resizeDocks( count ); + + /* Load lists of hosts that are needed for the work sheet and try + * to establish a connection. */ + QDomNodeList dnList = element.elementsByTagName( "host" ); + uint i; + for ( i = 0; i < dnList.count(); ++i ) { + QDomElement element = dnList.item( i ).toElement(); + int port = element.attribute( "port" ).toInt( &ok ); + if ( !ok ) + port = -1; + + KSGRD::SensorMgr->engage( element.attribute( "name" ), + element.attribute( "shell" ), + element.attribute( "command" ), port ); + } + //if no hosts are specified, at least connect to localhost + if(dnList.count() == 0) + KSGRD::SensorMgr->engage( "localhost", "", "ksysguardd", -1); + + // Load the displays and place them into the work sheet. + dnList = element.elementsByTagName( "display" ); + for ( i = 0; i < dnList.count(); ++i ) { + QDomElement element = dnList.item( i ).toElement(); + uint dock = element.attribute( "dock" ).toUInt(); + if ( i >= mDockCount ) { + kdDebug (1215) << "Dock number " << i << " out of range " + << mDockCount << endl; + return false; + } + + QString classType = element.attribute( "class" ); + KSGRD::SensorDisplay* newDisplay; + if ( classType == "FancyPlotter" ) + newDisplay = new FancyPlotter( this, "FancyPlotter", "Dummy", 100.0, 100.0, true /*no frame*/, true /*run ksysguard menu*/); + else if ( classType == "MultiMeter" ) + newDisplay = new MultiMeter( this, "MultiMeter", "Dummy", 100.0, 100.0, true /*no frame*/, true /*run ksysguard menu*/ ); + else if ( classType == "DancingBars" ) + newDisplay = new DancingBars( this, "DancingBars", "Dummy", 100, 100, true /*no frame*/, true /*run ksysguard menu*/); + else { + KMessageBox::sorry( this, i18n( "The KSysGuard applet does not support displaying of " + "this type of sensor. Please choose another sensor." ) ); + return false; + } + + newDisplay->setUpdateInterval( updateInterval() ); + + // load display specific settings + if ( !newDisplay->restoreSettings( element ) ) + return false; + + delete mDockList[ dock ]; + mDockList[ dock ] = newDisplay; + + connect( newDisplay, SIGNAL( modified( bool ) ), + SLOT( sensorDisplayModified( bool ) ) ); + } + + return true; +} + +bool KSysGuardApplet::save() +{ + // Parse the XML file. + QDomDocument doc( "KSysGuardApplet" ); + doc.appendChild( doc.createProcessingInstruction( + "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); + + // save work sheet information + QDomElement ws = doc.createElement( "WorkSheet" ); + doc.appendChild( ws ); + ws.setAttribute( "dockCnt", mDockCount ); + ws.setAttribute( "sizeRatio", mSizeRatio ); + ws.setAttribute( "interval", updateInterval() ); + + QStringList hosts; + uint i; + for ( i = 0; i < mDockCount; ++i ) + if ( !mDockList[ i ]->isA( "QFrame" ) ) + ((KSGRD::SensorDisplay*)mDockList[ i ])->hosts( hosts ); + + // save host information (name, shell, etc.) + QStringList::Iterator it; + for ( it = hosts.begin(); it != hosts.end(); ++it ) { + QString shell, command; + int port; + + if ( KSGRD::SensorMgr->hostInfo( *it, shell, command, port ) ) { + QDomElement host = doc.createElement( "host" ); + ws.appendChild( host ); + host.setAttribute( "name", *it ); + host.setAttribute( "shell", shell ); + host.setAttribute( "command", command ); + host.setAttribute( "port", port ); + } + } + + for ( i = 0; i < mDockCount; ++i ) + if ( !mDockList[ i ]->isA( "QFrame" ) ) { + QDomElement element = doc.createElement( "display" ); + ws.appendChild( element ); + element.setAttribute( "dock", i ); + element.setAttribute( "class", mDockList[ i ]->className() ); + + ((KSGRD::SensorDisplay*)mDockList[ i ])->saveSettings( doc, element ); + } + + KStandardDirs* kstd = KGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + QString fileName = kstd->saveLocation( "data", "ksysguard" ); + fileName += "/KSysGuardApplet.xml"; + + KSaveFile file( fileName, 0644 ); + + if ( file.status() == 0 ) + { + file.textStream()->setEncoding( QTextStream::UnicodeUTF8 ); + *(file.textStream()) << doc; + file.close(); + } + else + { + KMessageBox::sorry( this, i18n( "Cannot save file %1" ).arg( fileName ) ); + return false; + } + + return true; +} + +void KSysGuardApplet::addEmptyDisplay( QWidget **dock, uint pos ) +{ + dock[ pos ] = new QFrame( this ); + ((QFrame*)dock[ pos ])->setFrameStyle( QFrame::WinPanel | QFrame::Sunken ); + QToolTip::add( dock[ pos ], + i18n( "Drag sensors from the KDE System Guard into this cell." ) ); + + layout(); + if ( isVisible() ) + dock[ pos ]->show(); +} + +#include "KSysGuardApplet.moc" diff --git a/ksysguard/gui/KSysGuardApplet.h b/ksysguard/gui/KSysGuardApplet.h new file mode 100644 index 000000000..b9d91091e --- /dev/null +++ b/ksysguard/gui/KSysGuardApplet.h @@ -0,0 +1,85 @@ +/* + KKSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 + <cs@kde.org>. Please do not commit any changes without consulting + me first. Thanks! + +*/ + +#ifndef KSG_KSYSGUARDAPPLET_H +#define KSG_KSYSGUARDAPPLET_H + +#include <kpanelapplet.h> + +namespace KSGRD +{ +class SensorBoard; +class SensorDisplay; +} + +class QDragEnterEvent; +class QDropEvent; +class QPoint; +class KSGAppletSettings; + +class KSysGuardApplet : public KPanelApplet, public KSGRD::SensorBoard +{ + Q_OBJECT + + public: + KSysGuardApplet( const QString& configFile, Type type = Normal, + int actions = 0, QWidget *parent = 0, + const char *name = 0 ); + virtual ~KSysGuardApplet(); + + virtual int heightForWidth( int width ) const; + virtual int widthForHeight( int height ) const; + + virtual void preferences(); + + protected: + void resizeEvent( QResizeEvent* ); + void dragEnterEvent( QDragEnterEvent* ); + void dropEvent( QDropEvent* ); + void customEvent( QCustomEvent* ); + + + private slots: + void applySettings(); + void sensorDisplayModified( bool ); + void preferencesFinished(); + + private: + void layout(); + void resizeDocks( uint newDockCount ); + void addEmptyDisplay( QWidget **dock, uint pos ); + + bool load(); + bool save(); + + int findDock( const QPoint& ); + void removeDisplay( KSGRD::SensorDisplay* ); + + double mSizeRatio; + uint mDockCount; + KSGAppletSettings* mSettingsDlg; + QWidget** mDockList; +}; + +#endif diff --git a/ksysguard/gui/KSysGuardApplet.xml b/ksysguard/gui/KSysGuardApplet.xml new file mode 100644 index 000000000..2f115f61e --- /dev/null +++ b/ksysguard/gui/KSysGuardApplet.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE KSysGuardApplet> +<WorkSheet sizeRatio="1.2" dockCnt="2" interval="4" > + <host port="-1" shell="" name="localhost" command="ksysguardd" /> + <display topBar="1" vColor="326429" title="CPU" dock="0" bColor="3223601" graphStyle="0" class="FancyPlotter" unit="" hScale="1" showUnit="0" hLines="1" hCount="2" vLines="1" autoRange="1" min="0" max="0" hColor="14606046" globalUpdate="1" pause="0" fontSize="8" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="cpu/user" hostName="localhost" color="1608191" sensorType="integer" /> + <beam sensorName="cpu/sys" hostName="localhost" color="16743688" sensorType="integer" /> + <beam sensorName="cpu/nice" hostName="localhost" color="16771600" sensorType="integer" /> + </display> + <display topBar="1" vColor="4605510" title="Mem" dock="1" bColor="3223601" graphStyle="0" class="FancyPlotter" unit="" hScale="5" showUnit="0" hLines="1" hCount="2" vLines="0" autoRange="1" min="0" max="0" hColor="14606046" globalUpdate="1" pause="0" fontSize="8" labels="0" vScroll="1" vDistance="30" > + <beam sensorName="mem/physical/application" hostName="localhost" color="1608191" sensorType="integer" /> + <beam sensorName="mem/physical/buf" hostName="localhost" color="16743688" sensorType="integer" /> + <beam sensorName="mem/physical/cached" hostName="localhost" color="16771600" sensorType="integer" /> + </display> +</WorkSheet> diff --git a/ksysguard/gui/Makefile.am b/ksysguard/gui/Makefile.am new file mode 100644 index 000000000..c0b9d12b3 --- /dev/null +++ b/ksysguard/gui/Makefile.am @@ -0,0 +1,63 @@ + +kdemimedir = $(kde_mimedir)/application +kdemime_DATA = x-ksysguard.desktop + +rcdir = $(kde_datadir)/ksysguard +rc_DATA = ksysguardui.rc + +xdg_apps_DATA = ksysguard.desktop + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = ksysguardapplet.desktop + +# claim, which subdirectories you want to install +SUBDIRS = ksgrd SensorDisplayLib + +# set the include path for X, qt and KDE +INCLUDES = -I$(srcdir)/ksgrd -I$(srcdir)/SensorDisplayLib -I$(top_builddir)/ksysguard/gui/SensorDisplayLib $(all_includes) + +####### This part is very ksysguard specific +# you can add here more. This one gets installed +bin_PROGRAMS = ksysguard kpm + +# Which sources should be compiled for ksysguard. +ksysguard_SOURCES = \ + SensorBrowser.cc \ + WorkSheet.cc \ + WorkSheetSettings.cc \ + Workspace.cc \ + ksysguard.cc ksysguard.skel + +ksysguard_LDADD = \ + ksgrd/libksgrd.la \ + SensorDisplayLib/libsensordisplays.la \ + $(LIB_KDEUI) $(LIB_KIO) $(LIB_KDNSSD) +ksysguard_LDFLAGS = $(all_libraries) $(KDE_RPATH) + +kpm_SOURCES = kpm.c + +appdatadir = $(kde_datadir)/ksysguard +appdata_DATA = ProcessTable.sgrd SystemLoad.sgrd KSysGuardApplet.xml + +# This stuff is now for the kicker applet +kde_module_LTLIBRARIES = sysguard_panelapplet.la + +sysguard_panelapplet_la_SOURCES = \ + KSysGuardApplet.cc \ + KSGAppletSettings.cc + +sysguard_panelapplet_la_LIBADD = \ + ksgrd/libksgrd.la \ + SensorDisplayLib/libsensordisplays.la \ + $(LIB_KDEUI) $(LIB_KIO) +sysguard_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) + +EXTRA_DIST = $(lnk_DATA) + +# just to make sure, automake makes them +METASOURCES = AUTO + +messages: rc.cpp + $(EXTRACTRC) `find . -name "*.ui"` >> rc.cpp + $(EXTRACTATTR) --attr=display,title SystemLoad.sgrd KSysGuardApplet.xml >> rc.cpp + $(XGETTEXT) `find . -name "*.cpp" -o -name "*.cc"` -o $(podir)/ksysguard.pot diff --git a/ksysguard/gui/ProcessTable.sgrd b/ksysguard/gui/ProcessTable.sgrd new file mode 100644 index 000000000..2717a2b9d --- /dev/null +++ b/ksysguard/gui/ProcessTable.sgrd @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE KSysGuardWorkSheet> +<WorkSheet rows="1" interval="2" columns="1" > + <host port="-1" shell="" name="localhost" command="ksysguardd" /> + <display title="" class="ProcessController" row="0" unit="" sensorName="ps" column="0" filter="0" showUnit="0" sortColumn="0" hostName="localhost" globalUpdate="1" incrOrder="1" tree="0" sensorType="table" pause="0" > + <column currentWidth="127" savedWidth="126" index="0" /> + <column currentWidth="42" savedWidth="46" index="1" /> + <column currentWidth="0" savedWidth="42" index="2" /> + <column currentWidth="0" savedWidth="33" index="3" /> + <column currentWidth="0" savedWidth="42" index="4" /> + <column currentWidth="0" savedWidth="66" index="5" /> + <column currentWidth="52" savedWidth="45" index="6" /> + <column currentWidth="72" savedWidth="48" index="7" /> + <column currentWidth="38" savedWidth="36" index="8" /> + <column currentWidth="57" savedWidth="65" index="9" /> + <column currentWidth="52" savedWidth="30" index="10" /> + <column currentWidth="56" savedWidth="150" index="11" /> + <column currentWidth="402" savedWidth="150" index="12" /> + </display> +</WorkSheet> diff --git a/ksysguard/gui/SensorBrowser.cc b/ksysguard/gui/SensorBrowser.cc new file mode 100644 index 000000000..969978947 --- /dev/null +++ b/ksysguard/gui/SensorBrowser.cc @@ -0,0 +1,412 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#include <qdragobject.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +#include <kdebug.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <ksgrd/SensorManager.h> + +#include "SensorBrowser.h" + +class HostItem : public QListViewItem +{ + public: + HostItem( SensorBrowser *parent, const QString &text, int id, + KSGRD::SensorAgent *host) + : QListViewItem( parent, text ), mInited( false ), mId( id ), + mHost( host ), mParent( parent ) + { + setExpandable( true ); + } + + void setOpen( bool open ) + { + if ( open && !mInited ) { + mInited = true; + // request sensor list from host + mHost->sendRequest( "monitors", mParent, mId ); + } + + QListViewItem::setOpen( open ); + } + + private: + bool mInited; + int mId; + KSGRD::SensorAgent* mHost; + SensorBrowser* mParent; +}; + +SensorBrowser::SensorBrowser( QWidget* parent, KSGRD::SensorManager* sm, + const char* name) + : KListView( parent, name ), mSensorManager( sm ) +{ + mHostInfoList.setAutoDelete(true); + + connect( mSensorManager, SIGNAL( update() ), SLOT( update() ) ); + connect( this, SIGNAL( clicked( QListViewItem* ) ), + SLOT( newItemSelected( QListViewItem* ) ) ); + connect( this, SIGNAL( returnPressed( QListViewItem* ) ), + SLOT( newItemSelected( QListViewItem* ) ) ); + + addColumn( i18n( "Sensor Browser" ) ); + addColumn( i18n( "Sensor Type" ) ); + setFullWidth( true ); + + QToolTip::add( this, i18n( "Drag sensors to empty cells of a worksheet " + "or the panel applet." ) ); + setRootIsDecorated( true ); + + // The sensor browser can be completely hidden. + setMinimumWidth( 1 ); + + QWhatsThis::add( this, i18n( "The sensor browser lists the connected hosts and the sensors " + "that they provide. Click and drag sensors into drop zones " + "of a worksheet or the panel applet. A display will appear " + "that visualizes the " + "values provided by the sensor. Some sensor displays can " + "display values of multiple sensors. Simply drag other " + "sensors on to the display to add more sensors." ) ); +} + +SensorBrowser::~SensorBrowser() +{ +} + +void SensorBrowser::disconnect() +{ + QPtrListIterator<HostInfo> it( mHostInfoList ); + + for ( ; it.current(); ++it ) + if ( (*it)->listViewItem()->isSelected() ) { + kdDebug(1215) << "Disconnecting " << (*it)->hostName() << endl; + KSGRD::SensorMgr->requestDisengage( (*it)->sensorAgent() ); + } +} + +void SensorBrowser::hostReconfigured( const QString& ) +{ + // TODO: not yet implemented. +} + +void SensorBrowser::update() +{ + static int id = 0; + + KSGRD::SensorManagerIterator it( mSensorManager ); + + mHostInfoList.clear(); + clear(); + + KSGRD::SensorAgent* host; + for ( int i = 0 ; ( host = it.current() ); ++it, ++i ) { + QString hostName = mSensorManager->hostName( host ); + HostItem* lvi = new HostItem( this, hostName, id, host ); + + QPixmap pix = KGlobal::iconLoader()->loadIcon( "computer", KIcon::Desktop, KIcon::SizeSmall ); + lvi->setPixmap( 0, pix ); + + HostInfo* hostInfo = new HostInfo( id, host, hostName, lvi ); + mHostInfoList.append( hostInfo ); + ++id; + } + + setMouseTracking( false ); +} + +void SensorBrowser::newItemSelected( QListViewItem *item ) +{ + static bool showAnnoyingPopup = true; + if ( item && item->pixmap( 0 ) && showAnnoyingPopup) + { + showAnnoyingPopup = false; + KMessageBox::information( this, i18n( "Drag sensors to empty fields in a worksheet." ), + QString::null, "ShowSBUseInfo" ); + } +} + +void SensorBrowser::answerReceived( int id, const QString &answer ) +{ + /* An answer has the following format: + + cpu/idle integer + cpu/sys integer + cpu/nice integer + cpu/user integer + ps table + */ + + QPtrListIterator<HostInfo> it( mHostInfoList ); + + /* Check if id is still valid. It can get obsolete by rapid calls + * of update() or when the sensor died. */ + for ( ; it.current(); ++it ) + if ( (*it)->id() == id ) + break; + + if ( !it.current() ) + return; + + KSGRD::SensorTokenizer lines( answer, '\n' ); + + for ( uint i = 0; i < lines.count(); ++i ) { + if ( lines[ i ].isEmpty() ) + break; + + KSGRD::SensorTokenizer words( lines[ i ], '\t' ); + QString sensorName = words[ 0 ]; + QString sensorType = words[ 1 ]; + + /* Calling update() a rapid sequence will create pending + * requests that do not get erased by calling + * clear(). Subsequent updates will receive the old pending + * answers so we need to make sure that we register each + * sensor only once. */ + if ( (*it)->isRegistered( sensorName ) ) + return; + + /* The sensor browser can display sensors in a hierachical order. + * Sensors can be grouped into nodes by seperating the hierachical + * nodes through slashes in the sensor name. E. g. cpu/user is + * the sensor user in the cpu node. There is no limit for the + * depth of nodes. */ + KSGRD::SensorTokenizer absolutePath( sensorName, '/' ); + + QListViewItem* parent = (*it)->listViewItem(); + for ( uint j = 0; j < absolutePath.count(); ++j ) { + // Localize the sensor name part by part. + QString name = KSGRD::SensorMgr->translateSensorPath( absolutePath[ j ] ); + + bool found = false; + QListViewItem* sibling = parent->firstChild(); + while ( sibling && !found ) { + if (sibling->text( 0 ) == name ) { + // The node or sensor is already known. + found = true; + } else + sibling = sibling->nextSibling(); + } + if ( !found ) { + QListViewItem* lvi = new QListViewItem( parent, name ); + if ( j == absolutePath.count() - 1 ) { + QPixmap pix = KGlobal::iconLoader()->loadIcon( "ksysguardd", KIcon::Desktop, + KIcon::SizeSmall ); + lvi->setPixmap( 0, pix ); + lvi->setText( 1, KSGRD::SensorMgr->translateSensorType( sensorType ) ); + + // add sensor info to internal data structure + (*it)->addSensor( lvi, sensorName, name, sensorType ); + } else + parent = lvi; + + // The child indicator might need to be updated. + repaintItem( parent ); + } else + parent = sibling; + } + } + + repaintItem( (*it)->listViewItem() ); +} + +void SensorBrowser::viewportMouseMoveEvent( QMouseEvent *e ) +{ + /* setMouseTracking(false) seems to be broken. With current Qt + * mouse tracking cannot be turned off. So we have to check each event + * whether the LMB is really pressed. */ + + if ( !( e->state() & LeftButton ) ) + return; + + QListViewItem* item = itemAt( e->pos() ); + if ( !item ) // no item under cursor + return; + + // Make sure that a sensor and not a node or hostname has been picked. + QPtrListIterator<HostInfo> it( mHostInfoList ); + for ( ; it.current() && !(*it)->isRegistered( item ); ++it ); + if ( !it.current() ) + return; + + // Create text drag object as + // "<hostname> <sensorname> <sensortype> <sensordescription>". + // Only the description may contain blanks. + mDragText = (*it)->hostName() + " " + + (*it)->sensorName( item ) + " " + + (*it)->sensorType( item ) + " " + + (*it)->sensorDescription( item ); + + QDragObject* dragObject = new QTextDrag( mDragText, this ); + dragObject->dragCopy(); +} + +QStringList SensorBrowser::listHosts() +{ + QStringList hostList; + + QPtrListIterator<HostInfo> it( mHostInfoList ); + for ( ; it.current(); ++it ) + hostList.append( (*it)->hostName() ); + + return hostList; +} + +QStringList SensorBrowser::listSensors( const QString &hostName ) +{ + QPtrListIterator<HostInfo> it( mHostInfoList ); + for ( ; it.current(); ++it ) { + if ( (*it)->hostName() == hostName ) { + return (*it)->allSensorNames(); + } + } + + return QStringList(); +} + +/** + Helper classes + */ +SensorInfo::SensorInfo( QListViewItem *lvi, const QString &name, + const QString &desc, const QString &type ) + : mLvi( lvi ), mName( name ), mDesc( desc ), mType( type ) +{ +} + +QListViewItem* SensorInfo::listViewItem() const +{ + return mLvi; +} + +const QString& SensorInfo::name() const +{ + return mName; +} + +const QString& SensorInfo::type() const +{ + return mType; +} + +const QString& SensorInfo::description() const +{ + return mDesc; +} + +HostInfo::HostInfo( int id, const KSGRD::SensorAgent *agent, + const QString &name, QListViewItem *lvi ) + : mId( id ), mSensorAgent( agent ), mHostName( name ), mLvi( lvi ) +{ + mSensorList.setAutoDelete( true ); +} + +int HostInfo::id() const +{ + return ( mId ); +} + +const KSGRD::SensorAgent* HostInfo::sensorAgent() const +{ + return mSensorAgent; +} + +const QString& HostInfo::hostName() const +{ + return mHostName; +} + +QListViewItem* HostInfo::listViewItem() const +{ + return mLvi; +} + +const QString& HostInfo::sensorName( const QListViewItem *lvi ) const +{ + QPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current() && (*it)->listViewItem() != lvi; ++it ); + + Q_ASSERT( it.current() ); + return ( (*it)->name() ); +} + +QStringList HostInfo::allSensorNames() const +{ + QStringList list; + + QPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current(); ++it ) + list.append( it.current()->name() ); + + return list; +} + +const QString& HostInfo::sensorType( const QListViewItem *lvi ) const +{ + QPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current() && (*it)->listViewItem() != lvi; ++it ); + + Q_ASSERT( it.current() ); + return ( (*it)->type() ); +} + +const QString& HostInfo::sensorDescription( const QListViewItem *lvi ) const +{ + QPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current() && (*it)->listViewItem() != lvi; ++it ); + + Q_ASSERT( it.current() ); + return ( (*it)->description() ); +} + +void HostInfo::addSensor( QListViewItem *lvi, const QString& name, + const QString& desc, const QString& type ) +{ + SensorInfo* info = new SensorInfo( lvi, name, desc, type ); + mSensorList.append( info ); +} + +bool HostInfo::isRegistered( const QString& name ) const +{ + QPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current(); ++it ) + if ( (*it)->name() == name ) + return true; + + return false; +} + +bool HostInfo::isRegistered( QListViewItem *lvi ) const +{ + QPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current(); ++it ) + if ( (*it)->listViewItem() == lvi ) + return true; + + return false; +} + +#include "SensorBrowser.moc" diff --git a/ksysguard/gui/SensorBrowser.h b/ksysguard/gui/SensorBrowser.h new file mode 100644 index 000000000..9021166d9 --- /dev/null +++ b/ksysguard/gui/SensorBrowser.h @@ -0,0 +1,193 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SENSORBROWSER_H +#define KSG_SENSORBROWSER_H + +#include <qdict.h> + +#include <klistview.h> +#include <ksgrd/SensorClient.h> + +class QMouseEvent; + +namespace KSGRD { +class SensorManager; +class SensorAgent; +} + +class SensorInfo; +class HostInfo; + +/** + * The SensorBrowser is the graphical front-end of the SensorManager. It + * displays the currently available hosts and their sensors. + */ +class SensorBrowser : public KListView, public KSGRD::SensorClient +{ + Q_OBJECT + + public: + SensorBrowser( QWidget* parent, KSGRD::SensorManager* sm, const char* name = 0 ); + ~SensorBrowser(); + + QStringList listHosts(); + QStringList listSensors( const QString &hostName ); + + public slots: + void disconnect(); + void hostReconfigured( const QString &hostName ); + void update(); + void newItemSelected( QListViewItem *item ); + + protected: + virtual void viewportMouseMoveEvent( QMouseEvent* ); + + private: + void answerReceived( int id, const QString& ); + + KSGRD::SensorManager* mSensorManager; + + QPtrList<HostInfo> mHostInfoList; + QString mDragText; + +}; + +/** + Helper classes + */ +class SensorInfo +{ + public: + SensorInfo( QListViewItem *lvi, const QString &name, const QString &desc, + const QString &type ); + ~SensorInfo() {} + + /** + Returns a pointer to the list view item of the sensor. + */ + QListViewItem* listViewItem() const; + + /** + Returns the name of the sensor. + */ + const QString& name() const; + + /** + Returns the description of the sensor. + */ + const QString& description() const; + + /** + Returns the type of the sensor. + */ + const QString& type() const; + + private: + QListViewItem* mLvi; + QString mName; + QString mDesc; + QString mType; +}; + +class HostInfo +{ + public: + HostInfo( int id, const KSGRD::SensorAgent *agent, const QString &name, + QListViewItem *lvi ); + ~HostInfo() { } + + /** + Returns the unique id of the host. + */ + int id() const; + + /** + Returns a pointer to the sensor agent of the host. + */ + const KSGRD::SensorAgent* sensorAgent() const; + + /** + Returns the name of the host. + */ + const QString& hostName() const; + + /** + Returns the a pointer to the list view item of the host. + */ + QListViewItem* listViewItem() const; + + /** + Returns the sensor name of a special list view item. + */ + const QString& sensorName( const QListViewItem *lvi ) const; + + /** + Returns all sensor names of the host. + */ + QStringList allSensorNames() const; + + /** + Returns the type of a special list view item. + */ + const QString& sensorType( const QListViewItem *lvi ) const; + + /** + Returns the description of a special list view item. + */ + const QString& sensorDescription( const QListViewItem *lvi ) const; + + /** + Adds a new Sensor to the host. + + @param lvi The list view item. + @param name The sensor name. + @param desc A description. + @param type The type of the sensor. + */ + void addSensor( QListViewItem *lvi, const QString& name, + const QString& desc, const QString& type ); + + /** + Returns whether the sensor with @ref name + is registered at the host. + */ + bool isRegistered( const QString& name ) const; + + /** + Returns whether the sensor with @ref lvi + is registered at the host. + */ + bool isRegistered( QListViewItem *lvi ) const; + + private: + int mId; + + const KSGRD::SensorAgent* mSensorAgent; + const QString mHostName; + QListViewItem* mLvi; + + QPtrList<SensorInfo> mSensorList; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/BarGraph.cc b/ksysguard/gui/SensorDisplayLib/BarGraph.cc new file mode 100644 index 000000000..f6dc741cb --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/BarGraph.cc @@ -0,0 +1,177 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <assert.h> +#include <string.h> + +#include <qpainter.h> + +#include <kdebug.h> +#include <kiconloader.h> + +#include <ksgrd/StyleEngine.h> + +#include "BarGraph.h" + +BarGraph::BarGraph( QWidget *parent, const char *name ) + : QWidget( parent, name ) +{ + // paintEvent covers whole widget so we use no background to avoid flicker + setBackgroundMode( NoBackground ); + + bars = 0; + minValue = 0.0; + maxValue = 100.0; + lowerLimit = upperLimit = 0.0; + lowerLimitActive = upperLimitActive = false; + + normalColor = KSGRD::Style->firstForegroundColor(); + alarmColor = KSGRD::Style->alarmColor(); + backgroundColor = KSGRD::Style->backgroundColor(); + fontSize = KSGRD::Style->fontSize(); + + // Anything smaller than this does not make sense. + setMinimumSize( 16, 16 ); + setSizePolicy( QSizePolicy( QSizePolicy::Expanding, + QSizePolicy::Expanding, false ) ); +} + +BarGraph::~BarGraph() +{ +} + +bool BarGraph::addBar( const QString &footer ) +{ + samples.resize( bars + 1 ); + samples[ bars++ ] = 0.0; + footers.append( footer ); + + return true; +} + +bool BarGraph::removeBar( uint idx ) +{ + if ( idx >= bars ) { + kdDebug(1215) << "BarGraph::removeBar: idx " << idx << " out of range " + << bars << endl; + return false; + } + + samples.resize( --bars ); + footers.remove( footers.at( idx ) ); + update(); + + return true; +} + +void BarGraph::updateSamples( const QMemArray<double> &newSamples ) +{ + samples = newSamples; + update(); +} + +void BarGraph::changeRange( double min, double max ) +{ + minValue = min; + maxValue = max; +} + +void BarGraph::paintEvent( QPaintEvent* ) +{ + int w = width(); + int h = height(); + + QPixmap pm( w, h ); + QPainter p; + p.begin( &pm, this ); + p.setFont( QFont( p.font().family(), fontSize ) ); + QFontMetrics fm( p.font() ); + + pm.fill( backgroundColor ); + + /* 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 ); + + if ( bars > 0 ) { + int barWidth = ( w - 2 ) / bars; + uint b; + /* Labels are only printed underneath the bars if the labels + * for all bars are smaller than the bar width. If a single + * label does not fit no label is shown. */ + bool showLabels = true; + for ( b = 0; b < bars; b++ ) + if ( fm.width( footers[ b ] ) > barWidth ) + showLabels = false; + + int barHeight; + if ( showLabels ) + barHeight = h - 2 - ( 2 * fm.lineSpacing() ) - 2; + else + barHeight = h - 2; + + for ( uint b = 0; b < bars; b++ ) { + int topVal = (int) ( (float)barHeight / maxValue * + ( samples[ b ] - minValue ) ); + /* TODO: This widget does not handle negative values properly. */ + if ( topVal < 0 ) + topVal = 0; + + for ( int i = 0; i < barHeight && i < topVal; i += 2 ) { + if ( ( upperLimitActive && samples[ b ] > upperLimit ) || + ( lowerLimitActive && samples[ b ] < lowerLimit ) ) + p.setPen( alarmColor.light( static_cast<int>( 30 + ( 70.0 / + ( barHeight + 1 ) * i ) ) ) ); + else + p.setPen( normalColor.light( static_cast<int>( 30 + ( 70.0 / + ( barHeight + 1 ) * i ) ) ) ); + p.drawLine( b * barWidth + 3, barHeight - i, ( b + 1 ) * barWidth - 3, + barHeight - i ); + } + + if ( ( upperLimitActive && samples[ b ] > upperLimit ) || + ( lowerLimitActive && samples[ b ] < lowerLimit ) ) + p.setPen( alarmColor ); + else + p.setPen( normalColor ); + + if ( showLabels ) { + p.drawText( b * barWidth + 3, h - ( 2 * fm.lineSpacing() ) - 2, + barWidth - 2 * 3, fm.lineSpacing(), Qt::AlignCenter, + footers[ b ] ); + p.drawText( b * barWidth + 3, h - fm.lineSpacing() - 2, + barWidth - 2 * 3, fm.lineSpacing(), Qt::AlignCenter, + QString( "%1" ).arg( samples[ b ] ) ); + } + } + } + + p.end(); + bitBlt( this, 0, 0, &pm ); +} + +#include "BarGraph.moc" diff --git a/ksysguard/gui/SensorDisplayLib/BarGraph.h b/ksysguard/gui/SensorDisplayLib/BarGraph.h new file mode 100644 index 000000000..aca20c629 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/BarGraph.h @@ -0,0 +1,94 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_BARGRAPH_H +#define KSG_BARGRAPH_H + +#include <qmemarray.h> +#include <qptrvector.h> +#include <qwidget.h> + +class BarGraph : public QWidget +{ + Q_OBJECT + + friend class DancingBars; + + public: + BarGraph( QWidget *parent, const char *name = 0 ); + ~BarGraph(); + + bool addBar( const QString &footer ); + bool removeBar( uint idx ); + + void updateSamples( const QMemArray<double> &newSamples ); + + double getMin() const + { + return minValue; + } + + double getMax() const + { + return maxValue; + } + + void getLimits( double &l, bool &la, double &u, bool &ua ) const + { + l = lowerLimit; + la = lowerLimitActive; + u = upperLimit; + ua = upperLimitActive; + } + + void setLimits( double l, bool la, double u, bool ua ) + { + lowerLimit = l; + lowerLimitActive = la; + upperLimit = u; + upperLimitActive = ua; + } + + void changeRange( double min, double max ); + + protected: + virtual void paintEvent( QPaintEvent* ); + + private: + double minValue; + double maxValue; + double lowerLimit; + double lowerLimitActive; + double upperLimit; + bool upperLimitActive; + bool autoRange; + QMemArray<double> samples; + QStringList footers; + uint bars; + QColor normalColor; + QColor alarmColor; + QColor backgroundColor; + int fontSize; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/DancingBars.cc b/ksysguard/gui/SensorDisplayLib/DancingBars.cc new file mode 100644 index 000000000..48c360713 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DancingBars.cc @@ -0,0 +1,353 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000, 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qcheckbox.h> +#include <qdom.h> +#include <qlineedit.h> +#include <qlistview.h> +#include <qpushbutton.h> +#include <qspinbox.h> +#include <qtooltip.h> + +#include <kdebug.h> +#include <klocale.h> +#include <knumvalidator.h> +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include "BarGraph.h" +#include "DancingBarsSettings.h" + +#include "DancingBars.h" + +DancingBars::DancingBars( QWidget *parent, const char *name, const QString &title, + int, int, bool noFrame_, bool isApplet ) + : KSGRD::SensorDisplay( parent, name, title, noFrame_, isApplet ) +{ + mBars = 0; + mFlags = QBitArray(100); + mFlags.fill( false ); + + if ( noFrame() ) + mPlotter = new BarGraph( this ); + else + mPlotter = new BarGraph( frame() ); + + setMinimumSize( sizeHint() ); + + /* All RMB clicks to the mPlotter widget will be handled by + * SensorDisplay::eventFilter. */ + mPlotter->installEventFilter( this ); + + setPlotterWidget( mPlotter ); + + setModified( false ); +} + +DancingBars::~DancingBars() +{ +} + +void DancingBars::configureSettings() +{ + mSettingsDialog = new DancingBarsSettings( this ); + + mSettingsDialog->setTitle( title() ); + mSettingsDialog->setMinValue( mPlotter->getMin() ); + mSettingsDialog->setMaxValue( mPlotter->getMax() ); + + double l, u; + bool la, ua; + mPlotter->getLimits( l, la, u, ua ); + + mSettingsDialog->setUseUpperLimit( ua ); + mSettingsDialog->setUpperLimit( u ); + + mSettingsDialog->setUseLowerLimit( la ); + mSettingsDialog->setLowerLimit( l ); + + mSettingsDialog->setForegroundColor( mPlotter->normalColor ); + mSettingsDialog->setAlarmColor( mPlotter->alarmColor ); + mSettingsDialog->setBackgroundColor( mPlotter->backgroundColor ); + mSettingsDialog->setFontSize( mPlotter->fontSize ); + + QValueList< QStringList > list; + for ( uint i = mBars - 1; i < mBars; i-- ) { + QStringList entry; + entry << sensors().at( i )->hostName(); + entry << KSGRD::SensorMgr->translateSensor( sensors().at( i )->name() ); + entry << mPlotter->footers[ i ]; + entry << KSGRD::SensorMgr->translateUnit( sensors().at( i )->unit() ); + entry << ( sensors().at( i )->isOk() ? i18n( "OK" ) : i18n( "Error" ) ); + + list.append( entry ); + } + mSettingsDialog->setSensors( list ); + + connect( mSettingsDialog, SIGNAL( applyClicked() ), SLOT( applySettings() ) ); + + if ( mSettingsDialog->exec() ) + applySettings(); + + delete mSettingsDialog; + mSettingsDialog = 0; +} + +void DancingBars::applySettings() +{ + setTitle( mSettingsDialog->title() ); + mPlotter->changeRange( mSettingsDialog->minValue(), mSettingsDialog->maxValue() ); + mPlotter->setLimits( mSettingsDialog->useLowerLimit() ? + mSettingsDialog->lowerLimit() : 0, + mSettingsDialog->useLowerLimit(), + mSettingsDialog->useUpperLimit() ? + mSettingsDialog->upperLimit() : 0, + mSettingsDialog->useUpperLimit() ); + + mPlotter->normalColor = mSettingsDialog->foregroundColor(); + mPlotter->alarmColor = mSettingsDialog->alarmColor(); + mPlotter->backgroundColor = mSettingsDialog->backgroundColor(); + mPlotter->fontSize = mSettingsDialog->fontSize(); + + QValueList< QStringList > list = mSettingsDialog->sensors(); + QValueList< QStringList >::Iterator it; + + for ( uint i = 0; i < sensors().count(); i++ ) { + bool found = false; + for ( it = list.begin(); it != list.end(); ++it ) { + if ( (*it)[ 0 ] == sensors().at( i )->hostName() && + (*it)[ 1 ] == KSGRD::SensorMgr->translateSensor( sensors().at( i )->name() ) ) { + mPlotter->footers[ i ] = (*it)[ 2 ]; + found = true; + break; + } + } + + if ( !found ) + removeSensor( i ); + } + + repaint(); + setModified( true ); +} + +void DancingBars::applyStyle() +{ + mPlotter->normalColor = KSGRD::Style->firstForegroundColor(); + mPlotter->alarmColor = KSGRD::Style->alarmColor(); + mPlotter->backgroundColor = KSGRD::Style->backgroundColor(); + mPlotter->fontSize = KSGRD::Style->fontSize(); + + repaint(); + setModified( true ); +} + +bool DancingBars::addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &title ) +{ + if ( type != "integer" && type != "float" ) + return false; + + if ( mBars >= 32 ) + return false; + + if ( !mPlotter->addBar( title ) ) + return false; + + registerSensor( new KSGRD::SensorProperties( hostName, name, type, title ) ); + + /* To differentiate between answers from value requests and info + * requests we add 100 to the beam index for info requests. */ + sendRequest( hostName, name + "?", mBars + 100 ); + ++mBars; + mSampleBuffer.resize( mBars ); + + QString tooltip; + for ( uint i = 0; i < mBars; ++i ) { + tooltip += QString( "%1%2:%3" ).arg( i != 0 ? "\n" : "" ) + .arg( sensors().at( i )->hostName() ) + .arg( sensors().at( i )->name() ); + } + QToolTip::remove( mPlotter ); + QToolTip::add( mPlotter, tooltip ); + + return true; +} + +bool DancingBars::removeSensor( uint pos ) +{ + if ( pos >= mBars ) { + kdDebug(1215) << "DancingBars::removeSensor: idx out of range (" + << pos << ")" << endl; + return false; + } + + mPlotter->removeBar( pos ); + mBars--; + KSGRD::SensorDisplay::removeSensor( pos ); + + QString tooltip; + for ( uint i = 0; i < mBars; ++i ) { + tooltip += QString( "%1%2:%3" ).arg( i != 0 ? "\n" : "" ) + .arg( sensors().at( i )->hostName() ) + .arg( sensors().at( i )->name() ); + } + QToolTip::remove( mPlotter ); + QToolTip::add( mPlotter, tooltip ); + + return true; +} + +void DancingBars::updateSamples( const QMemArray<double> &samples ) +{ + mPlotter->updateSamples( samples ); +} + +void DancingBars::resizeEvent( QResizeEvent* ) +{ + if ( noFrame() ) + mPlotter->setGeometry( 0, 0, width(), height() ); + else + frame()->setGeometry( 0, 0, width(), height() ); +} + +QSize DancingBars::sizeHint() +{ + if ( noFrame() ) + return ( mPlotter->sizeHint() ); + else + return ( frame()->sizeHint() ); +} + +void DancingBars::answerReceived( int id, const QString &answer ) +{ + /* We received something, so the sensor is probably ok. */ + sensorError( id, false ); + + if ( id < 100 ) { + mSampleBuffer[ id ] = answer.toDouble(); + if ( mFlags.testBit( id ) == true ) { + kdDebug(1215) << "ERROR: DancingBars lost sample (" << mFlags + << ", " << mBars << ")" << endl; + sensorError( id, true ); + } + mFlags.setBit( id, true ); + + bool allBitsAvailable = true; + for ( uint i = 0; i < mBars; ++i ) + allBitsAvailable &= mFlags.testBit( i ); + + if ( allBitsAvailable ) { + mPlotter->updateSamples( mSampleBuffer ); + mFlags.fill( false ); + } + } else if ( id >= 100 ) { + KSGRD::SensorIntegerInfo info( answer ); + if ( id == 100 ) + if ( mPlotter->getMin() == 0.0 && mPlotter->getMax() == 0.0 ) { + /* We only use this information from the sensor when the + * display is still using the default values. If the + * sensor has been restored we don't touch the already set + * values. */ + mPlotter->changeRange( info.min(), info.max() ); + } + + sensors().at( id - 100 )->setUnit( info.unit() ); + } +} + +bool DancingBars::restoreSettings( QDomElement &element ) +{ + SensorDisplay::restoreSettings( element ); + + mPlotter->changeRange( element.attribute( "min", "0" ).toDouble(), + element.attribute( "max", "0" ).toDouble() ); + + mPlotter->setLimits( element.attribute( "lowlimit", "0" ).toDouble(), + element.attribute( "lowlimitactive", "0" ).toInt(), + element.attribute( "uplimit", "0" ).toDouble(), + element.attribute( "uplimitactive", "0" ).toInt() ); + + mPlotter->normalColor = restoreColor( element, "normalColor", + KSGRD::Style->firstForegroundColor() ); + mPlotter->alarmColor = restoreColor( element, "alarmColor", + KSGRD::Style->alarmColor() ); + mPlotter->backgroundColor = restoreColor( element, "backgroundColor", + KSGRD::Style->backgroundColor() ); + mPlotter->fontSize = element.attribute( "fontSize", QString( "%1" ).arg( + KSGRD::Style->fontSize() ) ).toInt(); + + QDomNodeList dnList = element.elementsByTagName( "beam" ); + for ( uint i = 0; i < dnList.count(); ++i ) { + QDomElement el = dnList.item( i ).toElement(); + addSensor( el.attribute( "hostName" ), el.attribute( "sensorName" ), + ( el.attribute( "sensorType" ).isEmpty() ? "integer" : + el.attribute( "sensorType" ) ), el.attribute( "sensorDescr" ) ); + } + + setModified( false ); + + return true; +} + +bool DancingBars::saveSettings( QDomDocument &doc, QDomElement &element, + bool save ) +{ + element.setAttribute( "min", mPlotter->getMin() ); + element.setAttribute( "max", mPlotter->getMax() ); + double l, u; + bool la, ua; + mPlotter->getLimits( l, la, u, ua ); + element.setAttribute( "lowlimit", l ); + element.setAttribute( "lowlimitactive", la ); + element.setAttribute( "uplimit", u ); + element.setAttribute( "uplimitactive", ua ); + + saveColor( element, "normalColor", mPlotter->normalColor ); + saveColor( element, "alarmColor", mPlotter->alarmColor ); + saveColor( element, "backgroundColor", mPlotter->backgroundColor ); + element.setAttribute( "fontSize", mPlotter->fontSize ); + + for ( uint i = 0; i < mBars; ++i ) { + QDomElement beam = doc.createElement( "beam" ); + element.appendChild( beam ); + beam.setAttribute( "hostName", sensors().at( i )->hostName() ); + beam.setAttribute( "sensorName", sensors().at( i )->name() ); + beam.setAttribute( "sensorType", sensors().at( i )->type() ); + beam.setAttribute( "sensorDescr", mPlotter->footers[ i ] ); + } + + SensorDisplay::saveSettings( doc, element ); + + if ( save ) + setModified( false ); + + return true; +} + +bool DancingBars::hasSettingsDialog() const +{ + return true; +} + +#include "DancingBars.moc" diff --git a/ksysguard/gui/SensorDisplayLib/DancingBars.h b/ksysguard/gui/SensorDisplayLib/DancingBars.h new file mode 100644 index 000000000..ad671dfe7 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DancingBars.h @@ -0,0 +1,90 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_DANCINGBARS_H +#define KSG_DANCINGBARS_H + +#include <SensorDisplay.h> +#include <qbitarray.h> + +class KIntNumInput; + +class QGroupBox; +class QLineEdit; +class QListViewItem; + +class BarGraph; +class DancingBarsSettings; + +class DancingBars : public KSGRD::SensorDisplay +{ + Q_OBJECT + + public: + DancingBars( QWidget *parent = 0, const char *name = 0, + const QString &title = QString::null, int min = 0, + int max = 100, bool noFrame = false, bool isApplet = false ); + virtual ~DancingBars(); + + void configureSettings(); + + bool addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &title ); + bool removeSensor( uint pos ); + + void updateSamples( const QMemArray<double> &samples ); + + virtual QSize sizeHint(); + + virtual void answerReceived( int id, const QString &answer ); + + bool restoreSettings( QDomElement& ); + bool saveSettings( QDomDocument&, QDomElement&, bool save = true ); + + virtual bool hasSettingsDialog() const; + + public slots: + void applySettings(); + virtual void applyStyle(); + + protected: + virtual void resizeEvent( QResizeEvent* ); + + private: + uint mBars; + + BarGraph* mPlotter; + + DancingBarsSettings* mSettingsDialog; + + /** + The sample buffer and the flags are needed to store the incoming + samples for each beam until all samples of the period have been + received. The flags variable is used to ensure that all samples have + been received. + */ + QMemArray<double> mSampleBuffer; + QBitArray mFlags; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.cc b/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.cc new file mode 100644 index 000000000..15e6b6ec3 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.cc @@ -0,0 +1,398 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <kaccelmanager.h> +#include <kcolorbutton.h> +#include <klineedit.h> +#include <kinputdialog.h> +#include <klistview.h> +#include <klocale.h> +#include <knuminput.h> + +#include <qcheckbox.h> +#include <qframe.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qwhatsthis.h> + +#include "DancingBarsSettings.h" + +DancingBarsSettings::DancingBarsSettings( QWidget* parent, const char* name ) + : KDialogBase( Tabbed, i18n( "Edit BarGraph Preferences" ), + Ok | Apply | Cancel, Ok, parent, name, true, true ) +{ + // Range page + QFrame *page = addPage( i18n( "Range" ) ); + QGridLayout *pageLayout = new QGridLayout( page, 3, 1, 0, spacingHint() ); + + QGroupBox *groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Title" ), page ); + QGridLayout *boxLayout = new QGridLayout( groupBox->layout(), 1, 1 ); + + mTitle = new KLineEdit( groupBox ); + QWhatsThis::add( mTitle, i18n( "Enter the title of the display here." ) ); + boxLayout->addWidget( mTitle, 0, 0 ); + + pageLayout->addWidget( groupBox, 0, 0 ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Display Range" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 1, 5 ); + boxLayout->setColStretch( 2, 1 ); + + QLabel *label = new QLabel( i18n( "Minimum value:" ), groupBox ); + boxLayout->addWidget( label, 0, 0 ); + + mMinValue = new KDoubleSpinBox( 0, 100, 0.5, 0, 2, groupBox ); + QWhatsThis::add( mMinValue, i18n( "Enter the minimum value for the display here. If both values are 0, automatic range detection is enabled." ) ); + boxLayout->addWidget( mMinValue, 0, 1 ); + label->setBuddy( mMinValue ); + + label = new QLabel( i18n( "Maximum value:" ), groupBox ); + boxLayout->addWidget( label, 0, 3 ); + + mMaxValue = new KDoubleSpinBox( 0, 10000, 0.5, 100, 2, groupBox ); + QWhatsThis::add( mMaxValue, i18n( "Enter the maximum value for the display here. If both values are 0, automatic range detection is enabled." ) ); + boxLayout->addWidget( mMaxValue, 0, 4 ); + label->setBuddy( mMaxValue ); + + pageLayout->addWidget( groupBox, 1, 0 ); + + pageLayout->setRowStretch( 2, 1 ); + + // Alarm page + page = addPage( i18n( "Alarms" ) ); + pageLayout = new QGridLayout( page, 3, 1, 0, spacingHint() ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Alarm for Minimum Value" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 1, 4 ); + boxLayout->setColStretch( 1, 1 ); + + mUseLowerLimit = new QCheckBox( i18n( "Enable alarm" ), groupBox ); + QWhatsThis::add( mUseLowerLimit, i18n( "Enable the minimum value alarm." ) ); + boxLayout->addWidget( mUseLowerLimit, 0, 0 ); + + label = new QLabel( i18n( "Lower limit:" ), groupBox ); + boxLayout->addWidget( label, 0, 2 ); + + mLowerLimit = new KDoubleSpinBox( 0, 100, 0.5, 0, 2, groupBox ); + mLowerLimit->setEnabled( false ); + boxLayout->addWidget( mLowerLimit, 0, 3 ); + label->setBuddy( mLowerLimit ); + + pageLayout->addWidget( groupBox, 0, 0 ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Alarm for Maximum Value" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 1, 4 ); + boxLayout->setColStretch( 1, 1 ); + + mUseUpperLimit = new QCheckBox( i18n( "Enable alarm" ), groupBox ); + QWhatsThis::add( mUseUpperLimit, i18n( "Enable the maximum value alarm." ) ); + boxLayout->addWidget( mUseUpperLimit, 0, 0 ); + + label = new QLabel( i18n( "Upper limit:" ), groupBox ); + boxLayout->addWidget( label, 0, 2 ); + + mUpperLimit = new KDoubleSpinBox( 0, 100, 0.5, 0, 2, groupBox ); + mUpperLimit->setEnabled( false ); + boxLayout->addWidget( mUpperLimit, 0, 3 ); + label->setBuddy( mUpperLimit ); + + pageLayout->addWidget( groupBox, 1, 0 ); + + pageLayout->setRowStretch( 2, 1 ); + + // Look page + page = addPage( i18n( "Look" ) ); + pageLayout = new QGridLayout( page, 5, 2, 0, spacingHint() ); + + label = new QLabel( i18n( "Normal bar color:" ), page ); + pageLayout->addWidget( label, 0, 0 ); + + mForegroundColor = new KColorButton( page ); + pageLayout->addWidget( mForegroundColor, 0, 1 ); + label->setBuddy( mForegroundColor ); + + label = new QLabel( i18n( "Out-of-range color:" ), page ); + pageLayout->addWidget( label, 1, 0 ); + + mAlarmColor = new KColorButton( page ); + pageLayout->addWidget( mAlarmColor, 1, 1 ); + label->setBuddy( mAlarmColor ); + + label = new QLabel( i18n( "Background color:" ), page ); + pageLayout->addWidget( label, 2, 0 ); + + mBackgroundColor = new KColorButton( page ); + pageLayout->addWidget( mBackgroundColor, 2, 1 ); + label->setBuddy( mBackgroundColor ); + + label = new QLabel( i18n( "Font size:" ), page ); + pageLayout->addWidget( label, 3, 0 ); + + mFontSize = new KIntNumInput( 9, page ); + QWhatsThis::add( mFontSize, i18n( "This determines the size of the font used to print a label underneath the bars. Bars are automatically suppressed if text becomes too large, so it is advisable to use a small font size here." ) ); + pageLayout->addWidget( mFontSize, 3, 1 ); + label->setBuddy( mFontSize ); + + pageLayout->setRowStretch( 4, 1 ); + + // Sensor page + page = addPage( i18n( "Sensors" ) ); + pageLayout = new QGridLayout( page, 3, 2, 0, spacingHint() ); + pageLayout->setRowStretch( 2, 1 ); + + mSensorView = new KListView( page ); + mSensorView->addColumn( i18n( "Host" ) ); + mSensorView->addColumn( i18n( "Sensor" ) ); + mSensorView->addColumn( i18n( "Label" ) ); + mSensorView->addColumn( i18n( "Unit" ) ); + mSensorView->addColumn( i18n( "Status" ) ); + mSensorView->setAllColumnsShowFocus( true ); + pageLayout->addMultiCellWidget( mSensorView, 0, 2, 0, 0 ); + + mEditButton = new QPushButton( i18n( "Edit..." ), page ); + mEditButton->setEnabled( false ); + QWhatsThis::add( mEditButton, i18n( "Push this button to configure the label." ) ); + pageLayout->addWidget( mEditButton, 0, 1 ); + + mRemoveButton = new QPushButton( i18n( "Delete" ), page ); + mRemoveButton->setEnabled( false ); + QWhatsThis::add( mRemoveButton, i18n( "Push this button to delete the sensor." ) ); + pageLayout->addWidget( mRemoveButton, 1, 1 ); + + connect( mUseLowerLimit, SIGNAL( toggled( bool ) ), + mLowerLimit, SLOT( setEnabled( bool ) ) ); + connect( mUseUpperLimit, SIGNAL( toggled( bool ) ), + mUpperLimit, SLOT( setEnabled( bool ) ) ); + + connect( mSensorView, SIGNAL( selectionChanged( QListViewItem* ) ), + SLOT( selectionChanged( QListViewItem* ) ) ); + connect( mEditButton, SIGNAL( clicked() ), SLOT( editSensor() ) ); + connect( mRemoveButton, SIGNAL( clicked() ), SLOT( removeSensor() ) ); + + KAcceleratorManager::manage( this ); + + mTitle->setFocus(); +} + +DancingBarsSettings::~DancingBarsSettings() +{ +} + +void DancingBarsSettings::setTitle( const QString& title ) +{ + mTitle->setText( title ); +} + +QString DancingBarsSettings::title() const +{ + return mTitle->text(); +} + +void DancingBarsSettings::setMinValue( double min ) +{ + mMinValue->setValue( min ); +} + +double DancingBarsSettings::minValue() const +{ + return mMinValue->value(); +} + +void DancingBarsSettings::setMaxValue( double max ) +{ + mMaxValue->setValue( max ); +} + +double DancingBarsSettings::maxValue() const +{ + return mMaxValue->value(); +} + +void DancingBarsSettings::setUseLowerLimit( bool value ) +{ + mUseLowerLimit->setChecked( value ); +} + +bool DancingBarsSettings::useLowerLimit() const +{ + return mUseLowerLimit->isChecked(); +} + +void DancingBarsSettings::setLowerLimit( double limit ) +{ + mLowerLimit->setValue( limit ); +} + +double DancingBarsSettings::lowerLimit() const +{ + return mLowerLimit->value(); +} + +void DancingBarsSettings::setUseUpperLimit( bool value ) +{ + mUseUpperLimit->setChecked( value ); +} + +bool DancingBarsSettings::useUpperLimit() const +{ + return mUseUpperLimit->isChecked(); +} + +void DancingBarsSettings::setUpperLimit( double limit ) +{ + mUpperLimit->setValue( limit ); +} + +double DancingBarsSettings::upperLimit() const +{ + return mUpperLimit->value(); +} + +void DancingBarsSettings::setForegroundColor( const QColor &color ) +{ + mForegroundColor->setColor( color ); +} + +QColor DancingBarsSettings::foregroundColor() const +{ + return mForegroundColor->color(); +} + +void DancingBarsSettings::setAlarmColor( const QColor &color ) +{ + mAlarmColor->setColor( color ); +} + +QColor DancingBarsSettings::alarmColor() const +{ + return mAlarmColor->color(); +} + +void DancingBarsSettings::setBackgroundColor( const QColor &color ) +{ + mBackgroundColor->setColor( color ); +} + +QColor DancingBarsSettings::backgroundColor() const +{ + return mBackgroundColor->color(); +} + +void DancingBarsSettings::setFontSize( int size ) +{ + mFontSize->setValue( size ); +} + +int DancingBarsSettings::fontSize() const +{ + return mFontSize->value(); +} + +void DancingBarsSettings::setSensors( const QValueList< QStringList > &list ) +{ + mSensorView->clear(); + + QValueList< QStringList >::ConstIterator it; + for ( it = list.begin(); it != list.end(); ++it ) { + new QListViewItem( mSensorView, + (*it)[ 0 ], // host name + (*it)[ 1 ], // sensor name + (*it)[ 2 ], // footer title + (*it)[ 3 ], // unit + (*it)[ 4 ] ); // status + } +} + +QValueList< QStringList > DancingBarsSettings::sensors() const +{ + QValueList< QStringList > list; + + QListViewItemIterator it( mSensorView ); + while ( it.current() && !it.current()->text( 0 ).isEmpty() ) { + QStringList entry; + entry << it.current()->text( 0 ); + entry << it.current()->text( 1 ); + entry << it.current()->text( 2 ); + entry << it.current()->text( 3 ); + entry << it.current()->text( 4 ); + + list.append( entry ); + ++it; + } + + return list; +} + +void DancingBarsSettings::editSensor() +{ + QListViewItem *lvi = mSensorView->currentItem(); + + if ( !lvi ) + return; + + bool ok; + QString str = KInputDialog::getText( i18n( "Label of Bar Graph" ), + i18n( "Enter new label:" ), lvi->text( 2 ), &ok, this ); + if ( ok ) + lvi->setText( 2, str ); +} + +void DancingBarsSettings::removeSensor() +{ + QListViewItem *lvi = mSensorView->currentItem(); + + if ( lvi ) { + /* Before we delete the currently selected item, we determine a + * new item to be selected. That way we can ensure that multiple + * items can be deleted without forcing the user to select a new + * item between the deletes. If all items are deleted, the buttons + * are disabled again. */ + QListViewItem* newSelected = 0; + if ( lvi->itemBelow() ) { + lvi->itemBelow()->setSelected( true ); + newSelected = lvi->itemBelow(); + } else if ( lvi->itemAbove() ) { + lvi->itemAbove()->setSelected( true ); + newSelected = lvi->itemAbove(); + } else + selectionChanged( 0 ); + + delete lvi; + + if ( newSelected ) + mSensorView->ensureItemVisible( newSelected ); + } +} + +void DancingBarsSettings::selectionChanged( QListViewItem* lvi ) +{ + bool state = ( lvi != 0 ); + + mEditButton->setEnabled( state ); + mRemoveButton->setEnabled( state ); +} + + +#include "DancingBarsSettings.moc" diff --git a/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.h b/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.h new file mode 100644 index 000000000..12e559dc0 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.h @@ -0,0 +1,106 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_DANCINGBARSSETTINGS_H +#define KSG_DANCINGBARSSETTINGS_H + +#include <kdialogbase.h> + +class KColorButton; +class KDoubleSpinBox; +class KIntNumInput; +class KLineEdit; +class KListView; + +class QCheckBox; +class QListViewItem; +class QPushButton; + +class DancingBarsSettings : public KDialogBase +{ + Q_OBJECT + + public: + DancingBarsSettings( QWidget* parent = 0, const char* name = 0 ); + ~DancingBarsSettings(); + + void setTitle( const QString& title ); + QString title() const; + + void setMinValue( double min ); + double minValue() const; + + void setMaxValue( double max ); + double maxValue() const; + + void setUseLowerLimit( bool value ); + bool useLowerLimit() const; + + void setLowerLimit( double limit ); + double lowerLimit() const; + + void setUseUpperLimit( bool value ); + bool useUpperLimit() const; + + void setUpperLimit( double limit ); + double upperLimit() const; + + void setForegroundColor( const QColor &color ); + QColor foregroundColor() const; + + void setAlarmColor( const QColor &color ); + QColor alarmColor() const; + + void setBackgroundColor( const QColor &color ); + QColor backgroundColor() const; + + void setFontSize( int size ); + int fontSize() const; + + void setSensors( const QValueList< QStringList > &list ); + QValueList< QStringList > sensors() const; + + private slots: + void editSensor(); + void removeSensor(); + void selectionChanged( QListViewItem* ); + + private: + KColorButton *mForegroundColor; + KColorButton *mAlarmColor; + KColorButton *mBackgroundColor; + KDoubleSpinBox *mMinValue; + KDoubleSpinBox *mMaxValue; + KDoubleSpinBox *mLowerLimit; + KDoubleSpinBox *mUpperLimit; + KLineEdit *mTitle; + KListView *mSensorView; + KIntNumInput *mFontSize; + + QCheckBox *mUseLowerLimit; + QCheckBox *mUseUpperLimit; + QPushButton *mEditButton; + QPushButton *mRemoveButton; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/DummyDisplay.cc b/ksysguard/gui/SensorDisplayLib/DummyDisplay.cc new file mode 100644 index 000000000..a4ea6afb4 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DummyDisplay.cc @@ -0,0 +1,58 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000, 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <klocale.h> +#include <ksgrd/SensorManager.h> + +#include <qwhatsthis.h> + +#include "DummyDisplay.h" + +DummyDisplay::DummyDisplay( QWidget* parent, const char* name, + const QString&, double, double ) + : KSGRD::SensorDisplay( parent, name, i18n( "Drop Sensor Here" ) ) +{ + setMinimumSize( 16, 16 ); + + QWhatsThis::add( this, i18n( + "This is an empty space in a worksheet. Drag a sensor from " + "the Sensor Browser and drop it here. A sensor display will " + "appear that allows you to monitor the values of the sensor " + "over time." ) ); +} + +void DummyDisplay::resizeEvent( QResizeEvent* ) +{ + frame()->setGeometry( 0, 0, width(), height() ); +} + +bool DummyDisplay::eventFilter( QObject* object, QEvent* event ) +{ + if ( event->type() == QEvent::MouseButtonRelease && + ( (QMouseEvent*)event)->button() == LeftButton ) + setFocus(); + + return QWidget::eventFilter( object, event ); +} + +#include "DummyDisplay.moc" diff --git a/ksysguard/gui/SensorDisplayLib/DummyDisplay.h b/ksysguard/gui/SensorDisplayLib/DummyDisplay.h new file mode 100644 index 000000000..53098fa0c --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DummyDisplay.h @@ -0,0 +1,44 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_DUMMYDISPLAY_H +#define KSG_DUMMYDISPLAY_H + +#include <SensorDisplay.h> + +class DummyDisplay : public KSGRD::SensorDisplay +{ + Q_OBJECT + + public: + DummyDisplay( QWidget* parent = 0, const char* name = 0, + const QString& = QString::null, double min = 0, + double max = 0 ); + virtual ~DummyDisplay() {} + + void resizeEvent( QResizeEvent* ); + + virtual bool eventFilter( QObject*, QEvent* ); +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/FancyPlotter.cc b/ksysguard/gui/SensorDisplayLib/FancyPlotter.cc new file mode 100644 index 000000000..361ce16e7 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/FancyPlotter.cc @@ -0,0 +1,457 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qdom.h> +#include <qimage.h> +#include <qtooltip.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> +#include "SensorDisplay.h" +#include "FancyPlotterSettings.h" + +#include "FancyPlotter.h" + +FancyPlotter::FancyPlotter( QWidget* parent, const char* name, + const QString &title, double, double, + bool nf, bool isApplet) + : KSGRD::SensorDisplay( parent, name, title, nf, isApplet ) +{ + mBeams = 0; + mSettingsDialog = 0; + + if ( noFrame() ) { + mPlotter = new SignalPlotter( this ); + mPlotter->setShowTopBar( true ); + } else + mPlotter = new SignalPlotter( frame() ); + mPlotter->setTitle( title ); + mPlotter->setThinFrame(!isApplet); //if we aren't an applet, draw a thin white frame on the left and bottom, for a 3d effect + + setMinimumSize( sizeHint() ); + + /* All RMB clicks to the mPlotter widget will be handled by + * SensorDisplay::eventFilter. */ + mPlotter->installEventFilter( this ); + + setPlotterWidget( mPlotter ); + + setModified( false ); +} + +FancyPlotter::~FancyPlotter() +{ +} + +void FancyPlotter::configureSettings() +{ + if(mSettingsDialog) { + return; + } + mSettingsDialog = new FancyPlotterSettings( this ); + + mSettingsDialog->setTitle( title() ); + mSettingsDialog->setUseAutoRange( mPlotter->useAutoRange() ); + mSettingsDialog->setMinValue( mPlotter->minValue() ); + mSettingsDialog->setMaxValue( mPlotter->maxValue() ); + + mSettingsDialog->setUsePolygonStyle( mPlotter->graphStyle() == GRAPH_POLYGON ); + mSettingsDialog->setHorizontalScale( mPlotter->horizontalScale() ); + + mSettingsDialog->setShowVerticalLines( mPlotter->showVerticalLines() ); + mSettingsDialog->setVerticalLinesColor( mPlotter->verticalLinesColor() ); + mSettingsDialog->setVerticalLinesDistance( mPlotter->verticalLinesDistance() ); + mSettingsDialog->setVerticalLinesScroll( mPlotter->verticalLinesScroll() ); + + mSettingsDialog->setShowHorizontalLines( mPlotter->showHorizontalLines() ); + mSettingsDialog->setHorizontalLinesColor( mPlotter->horizontalLinesColor() ); + mSettingsDialog->setHorizontalLinesCount( mPlotter->horizontalLinesCount() ); + + mSettingsDialog->setShowLabels( mPlotter->showLabels() ); + mSettingsDialog->setShowTopBar( mPlotter->showTopBar() ); + mSettingsDialog->setFontSize( mPlotter->fontSize() ); + + mSettingsDialog->setBackgroundColor( mPlotter->backgroundColor() ); + + QValueList< QStringList > list; + for ( uint i = 0; i < mBeams; ++i ) { + QStringList entry; + entry << QString::number(i); + entry << sensors().at( i )->hostName(); + entry << KSGRD::SensorMgr->translateSensor( sensors().at( i )->name() ); + entry << KSGRD::SensorMgr->translateUnit( sensors().at( i )->unit() ); + entry << ( sensors().at( i )->isOk() ? i18n( "OK" ) : i18n( "Error" ) ); + entry << ( mPlotter->beamColors()[ i ].name() ); + + list.append( entry ); + } + mSettingsDialog->setSensors( list ); + + connect( mSettingsDialog, SIGNAL( applyClicked() ), SLOT( applySettings() ) ); + connect( mSettingsDialog, SIGNAL( okClicked() ), SLOT( applySettings() ) ); + connect( mSettingsDialog, SIGNAL( finished() ), SLOT( killDialog() ) ); + + mSettingsDialog->show(); +} + +void FancyPlotter::killDialog() { + mSettingsDialog->delayedDestruct(); + mSettingsDialog = 0; +} + +void FancyPlotter::applySettings() +{ + setTitle( mSettingsDialog->title() ); + mPlotter->setTitle( title() ); + + if ( mSettingsDialog->useAutoRange() ) + mPlotter->setUseAutoRange( true ); + else { + mPlotter->setUseAutoRange( false ); + mPlotter->changeRange( 0, mSettingsDialog->minValue(), + mSettingsDialog->maxValue() ); + } + + if ( mSettingsDialog->usePolygonStyle() ) + mPlotter->setGraphStyle( GRAPH_POLYGON ); + else + mPlotter->setGraphStyle( GRAPH_ORIGINAL ); + + if ( mPlotter->horizontalScale() != mSettingsDialog->horizontalScale() ) { + mPlotter->setHorizontalScale( mSettingsDialog->horizontalScale() ); + // Can someone think of a useful QResizeEvent to pass? + // It doesn't really matter anyway because it's not used. + emit resizeEvent( 0 ); + } + + mPlotter->setShowVerticalLines( mSettingsDialog->showVerticalLines() ); + mPlotter->setVerticalLinesColor( mSettingsDialog->verticalLinesColor() ); + mPlotter->setVerticalLinesDistance( mSettingsDialog->verticalLinesDistance() ); + mPlotter->setVerticalLinesScroll( mSettingsDialog->verticalLinesScroll() ); + + mPlotter->setShowHorizontalLines( mSettingsDialog->showHorizontalLines() ); + mPlotter->setHorizontalLinesColor( mSettingsDialog->horizontalLinesColor() ); + mPlotter->setHorizontalLinesCount( mSettingsDialog->horizontalLinesCount() ); + + mPlotter->setShowLabels( mSettingsDialog->showLabels() ); + mPlotter->setShowTopBar( mSettingsDialog->showTopBar() ); + mPlotter->setFontSize( mSettingsDialog->fontSize() ); + + mPlotter->setBackgroundColor( mSettingsDialog->backgroundColor() ); + + + QValueList<int> orderOfSensors = mSettingsDialog->order(); + QValueList<int> deletedSensors = mSettingsDialog->deleted(); + mSettingsDialog->clearDeleted(); + mSettingsDialog->resetOrder(); + QValueList< int >::Iterator itDelete; + for ( itDelete = deletedSensors.begin(); itDelete != deletedSensors.end(); ++itDelete ) + removeSensor(*itDelete); + + QValueList< int >::Iterator itOrder; + mPlotter->reorderBeams(orderOfSensors); + reorderSensors(orderOfSensors); + + QValueList< QStringList > list = mSettingsDialog->sensors(); + QValueList< QStringList >::Iterator it; + + for ( uint i = 0; i < sensors().count(); ++i ) + mPlotter->beamColors()[ i ] = QColor( list[i][ 5 ] ); + + mPlotter->repaint(); + setModified( true ); +} + +void FancyPlotter::applyStyle() +{ + mPlotter->setVerticalLinesColor( KSGRD::Style->firstForegroundColor() ); + mPlotter->setHorizontalLinesColor( KSGRD::Style->secondForegroundColor() ); + mPlotter->setBackgroundColor( KSGRD::Style->backgroundColor() ); + mPlotter->setFontSize( KSGRD::Style->fontSize() ); + for ( uint i = 0; i < mPlotter->beamColors().count() && + i < KSGRD::Style->numSensorColors(); ++i ) + mPlotter->beamColors()[ i ] = KSGRD::Style->sensorColor( i ); + + mPlotter->update(); + setModified( true ); +} + +bool FancyPlotter::addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &title ) +{ + return addSensor( hostName, name, type, title, + KSGRD::Style->sensorColor( mBeams ) ); +} + +bool FancyPlotter::addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &title, + const QColor &color ) +{ + if ( type != "integer" && type != "float" ) + return false; + + if ( mBeams > 0 && hostName != sensors().at( 0 )->hostName() ) { + KMessageBox::sorry( this, QString( "All sensors of this display need " + "to be from the host %1!" ) + .arg( sensors().at( 0 )->hostName() ) ); + + /* We have to enforce this since the answers to value requests + * need to be received in order. */ + return false; + } + + if ( !mPlotter->addBeam( color ) ) + return false; + + registerSensor( new FPSensorProperties( hostName, name, type, title, color ) ); + + /* To differentiate between answers from value requests and info + * requests we add 100 to the beam index for info requests. */ + sendRequest( hostName, name + "?", mBeams + 100 ); + + ++mBeams; + + QString tooltip; + for ( uint i = 0; i < mBeams; ++i ) { + tooltip += QString( "%1%2:%3" ).arg( i != 0 ? "\n" : "" ) + .arg( sensors().at( mBeams - i - 1 )->hostName() ) + .arg( sensors().at( mBeams - i - 1 )->name() ); + } + + QToolTip::remove( mPlotter ); + QToolTip::add( mPlotter, tooltip ); + + return true; +} + +bool FancyPlotter::removeSensor( uint pos ) +{ + if ( pos >= mBeams ) { + kdDebug(1215) << "FancyPlotter::removeSensor: idx out of range (" + << pos << ")" << endl; + return false; + } + + mPlotter->removeBeam( pos ); + mBeams--; + KSGRD::SensorDisplay::removeSensor( pos ); + + QString tooltip; + for ( uint i = 0; i < mBeams; ++i ) { + tooltip += QString( "%1%2:%3" ).arg( i != 0 ? "\n" : "" ) + .arg( sensors().at( mBeams - i - 1 )->hostName() ) + .arg( sensors().at( mBeams - i - 1 )->name() ); + } + + QToolTip::remove( mPlotter ); + QToolTip::add( mPlotter, tooltip ); + + return true; +} + +void FancyPlotter::resizeEvent( QResizeEvent* ) +{ + if ( noFrame() ) + mPlotter->setGeometry( 0, 0, width(), height() ); + else + frame()->setGeometry( 0, 0, width(), height() ); +} + +QSize FancyPlotter::sizeHint() +{ + if ( noFrame() ) + return mPlotter->sizeHint(); + else + return frame()->sizeHint(); +} + +void FancyPlotter::answerReceived( int id, const QString &answer ) +{ + if ( (uint)id < mBeams ) { + if ( id != (int)mSampleBuf.count() ) { + if ( id == 0 ) + sensorError( mBeams - 1, true ); + else + sensorError( id - 1, true ); + } + mSampleBuf.append( answer.toDouble() ); + + /* We received something, so the sensor is probably ok. */ + sensorError( id, false ); + + if ( id == (int)mBeams - 1 ) { + mPlotter->addSample( mSampleBuf ); + mSampleBuf.clear(); + } + } else if ( id >= 100 ) { + KSGRD::SensorFloatInfo info( answer ); + if ( !mPlotter->useAutoRange() && mPlotter->minValue() == 0.0 && + mPlotter->maxValue() == 0.0 ) { + /* We only use this information from the sensor when the + * display is still using the default values. If the + * sensor has been restored we don't touch the already set + * values. */ + mPlotter->changeRange( id - 100, info.min(), info.max() ); + if ( info.min() == 0.0 && info.max() == 0.0 ) + mPlotter->setUseAutoRange( true ); + } + sensors().at( id - 100 )->setUnit( info.unit() ); + } +} + +bool FancyPlotter::restoreSettings( QDomElement &element ) +{ + /* autoRage was added after KDE 2.x and was brokenly emulated by + * min == 0.0 and max == 0.0. Since we have to be able to read old + * files as well we have to emulate the old behaviour as well. */ + double min = element.attribute( "min", "0.0" ).toDouble(); + double max = element.attribute( "max", "0.0" ).toDouble(); + if ( element.attribute( "autoRange", min == 0.0 && max == 0.0 ? "1" : "0" ).toInt() ) + mPlotter->setUseAutoRange( true ); + else { + mPlotter->setUseAutoRange( false ); + mPlotter->changeRange( 0, element.attribute( "min" ).toDouble(), + element.attribute( "max" ).toDouble() ); + } + + mPlotter->setShowVerticalLines( element.attribute( "vLines", "1" ).toUInt() ); + mPlotter->setVerticalLinesColor( restoreColor( element, "vColor", + KSGRD::Style->firstForegroundColor() ) ); + mPlotter->setVerticalLinesDistance( element.attribute( "vDistance", "30" ).toUInt() ); + mPlotter->setVerticalLinesScroll( element.attribute( "vScroll", "1" ).toUInt() ); + mPlotter->setGraphStyle( element.attribute( "graphStyle", "0" ).toUInt() ); + mPlotter->setHorizontalScale( element.attribute( "hScale", "1" ).toUInt() ); + + mPlotter->setShowHorizontalLines( element.attribute( "hLines", "1" ).toUInt() ); + mPlotter->setHorizontalLinesColor( restoreColor( element, "hColor", + KSGRD::Style->secondForegroundColor() ) ); + mPlotter->setHorizontalLinesCount( element.attribute( "hCount", "5" ).toUInt() ); + + mPlotter->setShowLabels( element.attribute( "labels", "1" ).toUInt() ); + mPlotter->setShowTopBar( element.attribute( "topBar", "0" ).toUInt() ); + mPlotter->setFontSize( element.attribute( "fontSize", + QString( "%1" ).arg( KSGRD::Style->fontSize() ) ).toUInt() ); + + mPlotter->setBackgroundColor( restoreColor( element, "bColor", + KSGRD::Style->backgroundColor() ) ); + + QDomNodeList dnList = element.elementsByTagName( "beam" ); + for ( uint i = 0; i < dnList.count(); ++i ) { + QDomElement el = dnList.item( i ).toElement(); + addSensor( el.attribute( "hostName" ), el.attribute( "sensorName" ), + ( el.attribute( "sensorType" ).isEmpty() ? "integer" : + el.attribute( "sensorType" ) ), "", restoreColor( el, "color", + KSGRD::Style->sensorColor( i ) ) ); + } + + SensorDisplay::restoreSettings( element ); + + if ( !title().isEmpty() ) + mPlotter->setTitle( title() ); + + setModified( false ); + + return true; +} + +bool FancyPlotter::saveSettings( QDomDocument &doc, QDomElement &element, + bool save ) +{ + element.setAttribute( "min", mPlotter->minValue() ); + element.setAttribute( "max", mPlotter->maxValue() ); + element.setAttribute( "autoRange", mPlotter->useAutoRange() ); + element.setAttribute( "vLines", mPlotter->showVerticalLines() ); + saveColor( element, "vColor", mPlotter->verticalLinesColor() ); + element.setAttribute( "vDistance", mPlotter->verticalLinesDistance() ); + element.setAttribute( "vScroll", mPlotter->verticalLinesScroll() ); + + element.setAttribute( "graphStyle", mPlotter->graphStyle() ); + element.setAttribute( "hScale", mPlotter->horizontalScale() ); + + element.setAttribute( "hLines", mPlotter->showHorizontalLines() ); + saveColor( element, "hColor", mPlotter->horizontalLinesColor() ); + element.setAttribute( "hCount", mPlotter->horizontalLinesCount() ); + + element.setAttribute( "labels", mPlotter->showLabels() ); + element.setAttribute( "topBar", mPlotter->showTopBar() ); + element.setAttribute( "fontSize", mPlotter->fontSize() ); + + saveColor( element, "bColor", mPlotter->backgroundColor() ); + + for ( uint i = 0; i < mBeams; ++i ) { + QDomElement beam = doc.createElement( "beam" ); + element.appendChild( beam ); + beam.setAttribute( "hostName", sensors().at( i )->hostName() ); + beam.setAttribute( "sensorName", sensors().at( i )->name() ); + beam.setAttribute( "sensorType", sensors().at( i )->type() ); + saveColor( beam, "color", mPlotter->beamColors()[ i ] ); + } + + SensorDisplay::saveSettings( doc, element ); + + if ( save ) + setModified( false ); + + return true; +} + +bool FancyPlotter::hasSettingsDialog() const +{ + return true; +} + + + +FPSensorProperties::FPSensorProperties() +{ +} + +FPSensorProperties::FPSensorProperties( const QString &hostName, + const QString &name, + const QString &type, + const QString &description, + const QColor &color ) + : KSGRD::SensorProperties( hostName, name, type, description ), + mColor( color ) +{ +} + +FPSensorProperties::~FPSensorProperties() +{ +} + +void FPSensorProperties::setColor( const QColor &color ) +{ + mColor = color; +} + +QColor FPSensorProperties::color() const +{ + return mColor; +} + +#include "FancyPlotter.moc" diff --git a/ksysguard/gui/SensorDisplayLib/FancyPlotter.h b/ksysguard/gui/SensorDisplayLib/FancyPlotter.h new file mode 100644 index 000000000..d19c28760 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/FancyPlotter.h @@ -0,0 +1,103 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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. + +*/ + +#ifndef KSG_FANCYPLOTTER_H +#define KSG_FANCYPLOTTER_H + +#include <kdialogbase.h> + +#include <SensorDisplay.h> + +#include "SignalPlotter.h" + +class QListViewItem; +class FancyPlotterSettings; + +class FPSensorProperties : public KSGRD::SensorProperties +{ + public: + FPSensorProperties(); + FPSensorProperties( const QString &hostName, const QString &name, + const QString &type, const QString &description, + const QColor &color ); + ~FPSensorProperties(); + + void setColor( const QColor &color ); + QColor color() const; + + private: + QColor mColor; +}; + +class FancyPlotter : public KSGRD::SensorDisplay +{ + Q_OBJECT + + public: + FancyPlotter( QWidget* parent = 0, const char* name = 0, + const QString& title = QString::null, double min = 0, + double max = 100, bool noFrame = false, bool isApplet = false ); + virtual ~FancyPlotter(); + + void configureSettings(); + + bool addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &title ); + bool addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &title, + const QColor &color ); + + bool removeSensor( uint pos ); + + virtual QSize sizeHint(void); + + virtual void answerReceived( int id, const QString &answer ); + + virtual bool restoreSettings( QDomElement &element ); + virtual bool saveSettings( QDomDocument &doc, QDomElement &element, + bool save = true ); + + virtual bool hasSettingsDialog() const; + + public slots: + void applySettings(); + virtual void applyStyle(); + void killDialog(); + + protected: + virtual void resizeEvent( QResizeEvent* ); + + private: + uint mBeams; + + SignalPlotter* mPlotter; + + FancyPlotterSettings* mSettingsDialog; + + /** + The sample buffer and the flags are needed to store the incoming + samples for each beam until all samples of the period have been + received. The flags variable is used to ensure that all samples have + been received. + */ + QValueList<double> mSampleBuf; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.cc b/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.cc new file mode 100644 index 000000000..9d4114bd3 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.cc @@ -0,0 +1,637 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <kaccelmanager.h> +#include <kcolorbutton.h> +#include <kcolordialog.h> +#include <klineedit.h> +#include <klistview.h> +#include <klocale.h> +#include <knuminput.h> + +#include <qcheckbox.h> +#include <qbuttongroup.h> +#include <qgroupbox.h> +#include <qimage.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpixmap.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qwhatsthis.h> +#include <qheader.h> + +#include "FancyPlotterSettings.h" + +FancyPlotterSettings::FancyPlotterSettings( QWidget* parent, const char* name ) + : KDialogBase( Tabbed, i18n( "Signal Plotter Settings" ), Ok | Apply | Cancel, + Ok, parent, name, false, true ) +{ + QFrame *page = 0; + QGridLayout *pageLayout = 0; + QGridLayout *boxLayout = 0; + QGroupBox *groupBox = 0; + QLabel *label = 0; + + // Style page + page = addPage( i18n( "Style" ) ); + pageLayout = new QGridLayout( page, 3, 2, 0, spacingHint() ); + + label = new QLabel( i18n( "Title:" ), page ); + pageLayout->addWidget( label, 0, 0 ); + + mTitle = new KLineEdit( page ); + QWhatsThis::add( mTitle, i18n( "Enter the title of the display here." ) ); + pageLayout->addWidget( mTitle, 0, 1 ); + label->setBuddy( mTitle ); + + QButtonGroup *buttonBox = new QButtonGroup( 2, Qt::Vertical, + i18n( "Graph Drawing Style" ), page ); + + mUsePolygonStyle = new QRadioButton( i18n( "Basic polygons" ), buttonBox ); + mUsePolygonStyle->setChecked( true ); + mUseOriginalStyle = new QRadioButton( i18n( "Original - single line per data point" ), buttonBox ); + + pageLayout->addMultiCellWidget( buttonBox, 1, 1, 0, 1 ); + + // Scales page + page = addPage( i18n( "Scales" ) ); + pageLayout = new QGridLayout( page, 2, 1, 0, spacingHint() ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Vertical Scale" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 2, 5, spacingHint() ); + boxLayout->setColStretch( 2, 1 ); + + mUseAutoRange = new QCheckBox( i18n( "Automatic range detection" ), groupBox ); + QWhatsThis::add( mUseAutoRange, i18n( "Check this box if you want the display range to adapt dynamically to the currently displayed values; if you do not check this, you have to specify the range you want in the fields below." ) ); + boxLayout->addMultiCellWidget( mUseAutoRange, 0, 0, 0, 4 ); + + label = new QLabel( i18n( "Minimum value:" ), groupBox ); + boxLayout->addWidget( label, 1, 0 ); + + mMinValue = new KLineEdit( groupBox ); + mMinValue->setAlignment( AlignRight ); + mMinValue->setEnabled( false ); + QWhatsThis::add( mMinValue, i18n( "Enter the minimum value for the display here. If both values are 0, automatic range detection is enabled." ) ); + boxLayout->addWidget( mMinValue, 1, 1 ); + label->setBuddy( mMinValue ); + + label = new QLabel( i18n( "Maximum value:" ), groupBox ); + boxLayout->addWidget( label, 1, 3 ); + + mMaxValue = new KLineEdit( groupBox ); + mMaxValue->setAlignment( AlignRight ); + mMaxValue->setEnabled( false ); + QWhatsThis::add( mMaxValue, i18n( "Enter the maximum value for the display here. If both values are 0, automatic range detection is enabled." ) ); + boxLayout->addWidget( mMaxValue, 1, 4 ); + label->setBuddy( mMaxValue ); + + pageLayout->addWidget( groupBox, 0, 0 ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Horizontal Scale" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 2, 2, spacingHint() ); + boxLayout->setRowStretch( 1, 1 ); + + mHorizontalScale = new KIntNumInput( 1, groupBox ); + mHorizontalScale->setMinValue( 1 ); + mHorizontalScale->setMaxValue( 50 ); + boxLayout->addWidget( mHorizontalScale, 0, 0 ); + + label = new QLabel( i18n( "pixel(s) per time period" ), groupBox ); + boxLayout->addWidget( label, 0, 1 ); + + pageLayout->addWidget( groupBox, 1, 0 ); + + // Grid page + page = addPage( i18n( "Grid" ) ); + pageLayout = new QGridLayout( page, 3, 2, 0, spacingHint() ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Lines" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 2, 5, spacingHint() ); + boxLayout->setColStretch( 1, 1 ); + + mShowVerticalLines = new QCheckBox( i18n( "Vertical lines" ), groupBox ); + QWhatsThis::add( mShowVerticalLines, i18n( "Check this to activate the vertical lines if display is large enough." ) ); + boxLayout->addWidget( mShowVerticalLines, 0, 0 ); + + label = new QLabel( i18n( "Distance:" ), groupBox ); + boxLayout->addWidget( label, 0, 2 ); + + mVerticalLinesDistance = new KIntNumInput( 0, groupBox ); + mVerticalLinesDistance->setMinValue( 10 ); + mVerticalLinesDistance->setMaxValue( 120 ); + QWhatsThis::add( mVerticalLinesDistance, i18n( "Enter the distance between two vertical lines here." ) ); + boxLayout->addWidget( mVerticalLinesDistance , 0, 3 ); + label->setBuddy( mVerticalLinesDistance ); + + mVerticalLinesScroll = new QCheckBox( i18n( "Vertical lines scroll" ), groupBox ); + boxLayout->addWidget( mVerticalLinesScroll, 0, 4 ); + + mShowHorizontalLines = new QCheckBox( i18n( "Horizontal lines" ), groupBox ); + QWhatsThis::add( mShowHorizontalLines, i18n( "Check this to enable horizontal lines if display is large enough." ) ); + boxLayout->addWidget( mShowHorizontalLines, 1, 0 ); + + label = new QLabel( i18n( "Count:" ), groupBox ); + boxLayout->addWidget( label, 1, 2 ); + + mHorizontalLinesCount = new KIntNumInput( 0, groupBox ); + mHorizontalLinesCount->setMinValue( 1 ); + mHorizontalLinesCount->setMaxValue( 100 ); + QWhatsThis::add( mHorizontalLinesCount, i18n( "Enter the number of horizontal lines here." ) ); + boxLayout->addWidget( mHorizontalLinesCount , 1, 3 ); + label->setBuddy( mHorizontalLinesCount ); + + boxLayout->setRowStretch( 2, 1 ); + + pageLayout->addMultiCellWidget( groupBox, 0, 0, 0, 1 ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Text" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 3, 4, spacingHint() ); + boxLayout->setColStretch( 1, 1 ); + + mShowLabels = new QCheckBox( i18n( "Labels" ), groupBox ); + QWhatsThis::add( mShowLabels, i18n( "Check this box if horizontal lines should be decorated with the values they mark." ) ); + boxLayout->addWidget( mShowLabels, 0, 0 ); + + label = new QLabel( i18n( "Font size:" ), groupBox ); + boxLayout->addWidget( label, 0, 2 ); + + mFontSize = new KIntNumInput( 9, groupBox ); + mFontSize->setMinValue( 5 ); + mFontSize->setMaxValue( 24 ); + boxLayout->addWidget( mFontSize, 0, 3 ); + label->setBuddy( mFontSize ); + + mShowTopBar = new QCheckBox( i18n( "Top bar" ), groupBox ); + QWhatsThis::add( mShowTopBar, i18n( "Check this to active the display title bar. This is probably only useful for applet displays. The bar is only visible if the display is large enough." ) ); + boxLayout->addWidget( mShowTopBar, 1, 0 ); + + boxLayout->setRowStretch( 2, 1 ); + + pageLayout->addWidget( groupBox, 1, 0 ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Colors" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 4, 2, spacingHint() ); + + label = new QLabel( i18n( "Vertical lines:" ), groupBox ); + boxLayout->addWidget( label, 0, 0 ); + + mVerticalLinesColor = new KColorButton( groupBox ); + boxLayout->addWidget( mVerticalLinesColor, 0, 1 ); + label->setBuddy( mVerticalLinesColor ); + + label = new QLabel( i18n( "Horizontal lines:" ), groupBox ); + boxLayout->addWidget( label, 1, 0 ); + + mHorizontalLinesColor = new KColorButton( groupBox ); + boxLayout->addWidget( mHorizontalLinesColor, 1, 1 ); + label->setBuddy( mHorizontalLinesColor ); + + label = new QLabel( i18n( "Background:" ), groupBox ); + boxLayout->addWidget( label, 2, 0 ); + + mBackgroundColor = new KColorButton( groupBox ); + boxLayout->addWidget( mBackgroundColor, 2, 1 ); + label->setBuddy( mBackgroundColor ); + + boxLayout->setRowStretch( 3, 1 ); + + pageLayout->addWidget( groupBox, 1, 1 ); + + pageLayout->setRowStretch( 2, 1 ); + + // Sensors page + page = addPage( i18n( "Sensors" ) ); + pageLayout = new QGridLayout( page, 6, 2, 0, spacingHint() ); + pageLayout->setRowStretch( 2, 1 ); + pageLayout->setRowStretch( 5, 1 ); + + mSensorView = new KListView( page ); + mSensorView->addColumn("" , 0); + mSensorView->addColumn( i18n( "Host" ) ); + mSensorView->addColumn( i18n( "Sensor" ) ); + mSensorView->addColumn( i18n( "Unit" ) ); + mSensorView->addColumn( i18n( "Status" ) ); + mSensorView->setResizeMode(QListView::LastColumn); + mSensorView->header()->setResizeEnabled(false, 0); + mSensorView->hideColumn(0); + mSensorView->header()->resizeSection(0, 0); + mSensorView->setAllColumnsShowFocus( true ); + pageLayout->addMultiCellWidget( mSensorView, 0, 5, 0, 0 ); + mSensorView->setSortColumn ( -1 ); + mEditButton = new QPushButton( i18n( "Set Color..." ), page ); + mEditButton->setEnabled( false ); + QWhatsThis::add( mEditButton, i18n( "Push this button to configure the color of the sensor in the diagram." ) ); + pageLayout->addWidget( mEditButton, 0, 1 ); + + mRemoveButton = new QPushButton( i18n( "Delete" ), page ); + mRemoveButton->setEnabled( false ); + QWhatsThis::add( mRemoveButton, i18n( "Push this button to delete the sensor." ) ); + pageLayout->addWidget( mRemoveButton, 1, 1 ); + + mMoveUpButton = new QPushButton( i18n( "Move Up" ), page ); + mMoveUpButton->setEnabled( false ); + pageLayout->addWidget( mMoveUpButton, 3, 1 ); + + mMoveDownButton = new QPushButton( i18n( "Move Down" ), page ); + mMoveDownButton->setEnabled( false ); + pageLayout->addWidget( mMoveDownButton, 4, 1 ); + + connect( mUseAutoRange, SIGNAL( toggled( bool ) ), mMinValue, + SLOT( setDisabled( bool ) ) ); + connect( mUseAutoRange, SIGNAL( toggled( bool ) ), mMaxValue, + SLOT( setDisabled( bool ) ) ); + connect( mShowVerticalLines, SIGNAL( toggled( bool ) ), mVerticalLinesDistance, + SLOT( setEnabled( bool ) ) ); + connect( mShowVerticalLines, SIGNAL( toggled( bool ) ), mVerticalLinesScroll, + SLOT( setEnabled( bool ) ) ); + connect( mShowVerticalLines, SIGNAL( toggled( bool ) ), mVerticalLinesColor, + SLOT( setEnabled( bool ) ) ); + connect( mShowHorizontalLines, SIGNAL( toggled( bool ) ), mHorizontalLinesCount, + SLOT( setEnabled( bool ) ) ); + connect( mShowHorizontalLines, SIGNAL( toggled( bool ) ), mHorizontalLinesColor, + SLOT( setEnabled( bool ) ) ); + connect( mShowHorizontalLines, SIGNAL( toggled( bool ) ), mShowLabels, + SLOT( setEnabled( bool ) ) ); + connect( mSensorView, SIGNAL( selectionChanged( QListViewItem* ) ), + SLOT( selectionChanged( QListViewItem* ) ) ); + + connect( mEditButton, SIGNAL( clicked() ), SLOT( editSensor() ) ); + connect( mRemoveButton, SIGNAL( clicked() ), SLOT( removeSensor() ) ); + connect( mMoveUpButton, SIGNAL( clicked() ), SLOT( moveUpSensor() ) ); + connect( mMoveDownButton, SIGNAL( clicked() ), SLOT( moveDownSensor() ) ); + connect ( mSensorView, SIGNAL( doubleClicked( QListViewItem *, const QPoint &, int )), SLOT(editSensor())); + + KAcceleratorManager::manage( this ); +} + +FancyPlotterSettings::~FancyPlotterSettings() +{ +} + +void FancyPlotterSettings::setTitle( const QString &title ) +{ + mTitle->setText( title ); +} + +QString FancyPlotterSettings::title() const +{ + return mTitle->text(); +} + +void FancyPlotterSettings::setUseAutoRange( bool value ) +{ + mUseAutoRange->setChecked( value ); + mMinValue->setEnabled( !value ); + mMaxValue->setEnabled( !value ); +} + +bool FancyPlotterSettings::useAutoRange() const +{ + return mUseAutoRange->isChecked(); +} + +void FancyPlotterSettings::setMinValue( double min ) +{ + mMinValue->setText( QString::number( min ) ); +} + +double FancyPlotterSettings::minValue() const +{ + return mMinValue->text().toDouble(); +} + +void FancyPlotterSettings::setMaxValue( double max ) +{ + mMaxValue->setText( QString::number( max ) ); +} + +double FancyPlotterSettings::maxValue() const +{ + return mMaxValue->text().toDouble(); +} + +void FancyPlotterSettings::setUsePolygonStyle( bool value ) +{ + if ( value ) + mUsePolygonStyle->setChecked( true ); + else + mUseOriginalStyle->setChecked( true ); +} + +bool FancyPlotterSettings::usePolygonStyle() const +{ + return mUsePolygonStyle->isChecked(); +} + +void FancyPlotterSettings::setHorizontalScale( int scale ) +{ + mHorizontalScale->setValue( scale ); +} + +int FancyPlotterSettings::horizontalScale() const +{ + return mHorizontalScale->value(); +} + +void FancyPlotterSettings::setShowVerticalLines( bool value ) +{ + mShowVerticalLines->setChecked( value ); + mVerticalLinesDistance->setEnabled( value ); + mVerticalLinesScroll->setEnabled( value ); + mVerticalLinesColor->setEnabled( value ); +} + +bool FancyPlotterSettings::showVerticalLines() const +{ + return mShowVerticalLines->isChecked(); +} + +void FancyPlotterSettings::setVerticalLinesColor( const QColor &color ) +{ + mVerticalLinesColor->setColor( color ); +} + +QColor FancyPlotterSettings::verticalLinesColor() const +{ + return mVerticalLinesColor->color(); +} + +void FancyPlotterSettings::setVerticalLinesDistance( int distance ) +{ + mVerticalLinesDistance->setValue( distance ); +} + +int FancyPlotterSettings::verticalLinesDistance() const +{ + return mVerticalLinesDistance->value(); +} + +void FancyPlotterSettings::setVerticalLinesScroll( bool value ) +{ + mVerticalLinesScroll->setChecked( value ); +} + +bool FancyPlotterSettings::verticalLinesScroll() const +{ + return mVerticalLinesScroll->isChecked(); +} + +void FancyPlotterSettings::setShowHorizontalLines( bool value ) +{ + mShowHorizontalLines->setChecked( value ); + mHorizontalLinesCount->setEnabled( value ); + mHorizontalLinesColor->setEnabled( value ); + mShowLabels->setEnabled( value ); + +} + +bool FancyPlotterSettings::showHorizontalLines() const +{ + return mShowHorizontalLines->isChecked(); +} + +void FancyPlotterSettings::setHorizontalLinesColor( const QColor &color ) +{ + mHorizontalLinesColor->setColor( color ); +} + +QColor FancyPlotterSettings::horizontalLinesColor() const +{ + return mHorizontalLinesColor->color(); +} + +void FancyPlotterSettings::setHorizontalLinesCount( int count ) +{ + mHorizontalLinesCount->setValue( count ); +} + +int FancyPlotterSettings::horizontalLinesCount() const +{ + return mHorizontalLinesCount->value(); +} + +void FancyPlotterSettings::setShowLabels( bool value ) +{ + mShowLabels->setChecked( value ); +} + +bool FancyPlotterSettings::showLabels() const +{ + return mShowLabels->isChecked(); +} + +void FancyPlotterSettings::setShowTopBar( bool value ) +{ + mShowTopBar->setChecked( value ); +} + +bool FancyPlotterSettings::showTopBar() const +{ + return mShowTopBar->isChecked(); +} + +void FancyPlotterSettings::setFontSize( int size ) +{ + mFontSize->setValue( size ); +} + +int FancyPlotterSettings::fontSize() const +{ + return mFontSize->value(); +} + +void FancyPlotterSettings::setBackgroundColor( const QColor &color ) +{ + mBackgroundColor->setColor( color ); +} + +QColor FancyPlotterSettings::backgroundColor() const +{ + return mBackgroundColor->color(); +} +void FancyPlotterSettings::clearDeleted() +{ + mDeleted.clear(); +} +QValueList<int> FancyPlotterSettings::deleted() const +{ + return mDeleted; +} + +QValueList<int> FancyPlotterSettings::order() const +{ + QValueList<int> newOrder; + + QListViewItemIterator it( mSensorView ); + for ( ; it.current(); ++it ) { + newOrder.prepend(it.current()->text(0).toInt()); + } + return newOrder; +} + +void FancyPlotterSettings::resetOrder() +{ + int i = mSensorView->childCount()-1; + QListViewItemIterator it( mSensorView ); + for ( ; it.current(); ++it, --i) { + it.current()->setText(0, QString::number(i)); + } +} + +void FancyPlotterSettings::setSensors( const QValueList< QStringList > &list ) +{ + mSensorView->clear(); + + QValueList< QStringList >::ConstIterator it; + for ( it = list.begin(); it != list.end(); ++it ) { + QListViewItem* lvi = new QListViewItem( mSensorView, + (*it)[ 0 ], // id + (*it)[ 1 ], // host name + (*it)[ 2 ], // sensor name + (*it)[ 3 ], // unit + (*it)[ 4 ] ); // status + QPixmap pm( 12, 12 ); + pm.fill( QColor( (*it)[ 5 ] ) ); + lvi->setPixmap( 2, pm ); + mSensorView->insertItem( lvi ); + } +} + +QValueList< QStringList > FancyPlotterSettings::sensors() const +{ + QValueList< QStringList > list; + + QListViewItemIterator it( mSensorView ); + + for ( ; it.current(); ++it ) { + QStringList entry; + entry << it.current()->text( 0 ); + entry << it.current()->text( 1 ); + entry << it.current()->text( 2 ); + entry << it.current()->text( 3 ); + entry << it.current()->text( 4 ); + QRgb rgb = it.current()->pixmap( 2 )->convertToImage().pixel( 1, 1 ); + QColor color( qRed( rgb ), qGreen( rgb ), qBlue( rgb ) ); + entry << ( color.name() ); + + list.prepend( entry ); + } + + return list; +} + +void FancyPlotterSettings::editSensor() +{ + QListViewItem* lvi = mSensorView->currentItem(); + + if ( !lvi ) + return; + + QColor color = lvi->pixmap( 2 )->convertToImage().pixel( 1, 1 ); + int result = KColorDialog::getColor( color, parentWidget() ); + if ( result == KColorDialog::Accepted ) { + QPixmap newPm( 12, 12 ); + newPm.fill( color ); + lvi->setPixmap( 2, newPm ); + } +} + +void FancyPlotterSettings::removeSensor() +{ + QListViewItem* lvi = mSensorView->currentItem(); + + if ( lvi ) { + //Note down the id of the one we are deleting + int id = lvi->text(0).toInt(); + mDeleted.append(id); + + /* Before we delete the currently selected item, we determine a + * new item to be selected. That way we can ensure that multiple + * items can be deleted without forcing the user to select a new + * item between the deletes. If all items are deleted, the buttons + * are disabled again. */ + QListViewItem* newSelected = 0; + if ( lvi->itemBelow() ) { + lvi->itemBelow()->setSelected( true ); + newSelected = lvi->itemBelow(); + } else if ( lvi->itemAbove() ) { + lvi->itemAbove()->setSelected( true ); + newSelected = lvi->itemAbove(); + } else + selectionChanged( 0 ); + + delete lvi; + + QListViewItemIterator it( mSensorView ); + for ( ; it.current(); ++it ) { + if(it.current()->text(0).toInt() > id) + it.current()->setText(0, QString::number(it.current()->text(0).toInt() -1)); + } + + + if ( newSelected ) + mSensorView->ensureItemVisible( newSelected ); + } +} + +void FancyPlotterSettings::moveUpSensor() +{ + if ( mSensorView->currentItem() != 0 ) { + QListViewItem* item = mSensorView->currentItem()->itemAbove(); + if ( item ) { + if ( item->itemAbove() ) + { + mSensorView->currentItem()->moveItem( item->itemAbove() ); + } + else + { + item->moveItem( mSensorView->currentItem() ); + } + } + + selectionChanged( mSensorView->currentItem() ); + } +} + +void FancyPlotterSettings::moveDownSensor() +{ + if ( mSensorView->currentItem() != 0 ) { + if ( mSensorView->currentItem()->itemBelow() ) + mSensorView->currentItem()->moveItem( mSensorView->currentItem()->itemBelow() ); + + selectionChanged( mSensorView->currentItem() ); + } +} + +void FancyPlotterSettings::selectionChanged( QListViewItem *item ) +{ + bool state = ( item != 0 ); + + mEditButton->setEnabled( state ); + mRemoveButton->setEnabled( state ); + mMoveUpButton->setEnabled( state && item->itemAbove() ); + mMoveDownButton->setEnabled( state && item->itemBelow() ); +} + +#include "FancyPlotterSettings.moc" diff --git a/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.h b/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.h new file mode 100644 index 000000000..b813bee34 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.h @@ -0,0 +1,143 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef FANCYPLOTTERSETTINGS_H +#define FANCYPLOTTERSETTINGS_H + +#include <kdialogbase.h> + +class KColorButton; +class KIntNumInput; +class KLineEdit; +class KListView; + +class QCheckBox; +class QListViewItem; +class QPushButton; +class QRadioButton; + +class FancyPlotterSettings : public KDialogBase +{ + Q_OBJECT + + public: + FancyPlotterSettings( QWidget* parent = 0, const char* name = 0 ); + ~FancyPlotterSettings(); + + 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 setUsePolygonStyle( bool value ); + bool usePolygonStyle() const; + + void setHorizontalScale( int scale ); + int 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; + + void setSensors( const QValueList< QStringList > &list ); + QValueList< QStringList > sensors() const; + QValueList<int> order() const; + QValueList<int> deleted() const; + void clearDeleted(); + void resetOrder(); + + private slots: + void editSensor(); + void removeSensor(); + void moveUpSensor(); + void moveDownSensor(); + void selectionChanged( QListViewItem* ); + + private: + + KColorButton *mVerticalLinesColor; + KColorButton *mHorizontalLinesColor; + KColorButton *mBackgroundColor; + KLineEdit *mMinValue; + KLineEdit *mMaxValue; + KLineEdit *mTitle; + KIntNumInput *mHorizontalScale; + KIntNumInput *mVerticalLinesDistance; + KIntNumInput *mHorizontalLinesCount; + KIntNumInput *mFontSize; + KListView *mSensorView; + + QCheckBox *mShowVerticalLines; + QCheckBox *mShowHorizontalLines; + QCheckBox *mVerticalLinesScroll; + QCheckBox *mUseAutoRange; + QCheckBox *mShowLabels; + QCheckBox *mShowTopBar; + QPushButton *mEditButton; + QPushButton *mRemoveButton; + QPushButton *mMoveUpButton; + QPushButton *mMoveDownButton; + QRadioButton *mUsePolygonStyle; + QRadioButton *mUseOriginalStyle; + + /** The numbers of the sensors to be delete.*/ + QValueList<int> mDeleted; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/ListView.cc b/ksysguard/gui/SensorDisplayLib/ListView.cc new file mode 100644 index 000000000..885daded6 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ListView.cc @@ -0,0 +1,371 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> + +#include <config.h> +#include <qdom.h> + +#include <kcolorbutton.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include "ListView.h" +#include "ListView.moc" +#include "ListViewSettings.h" + +PrivateListViewItem::PrivateListViewItem(PrivateListView *parent) + : QListViewItem(parent) +{ + _parent = parent; +} + +int PrivateListViewItem::compare( QListViewItem *item, int col, bool ascending ) const +{ + int type = ((PrivateListView*)listView())->columnType( col ); + + if ( type == PrivateListView::Int ) { + int prev = (int)KGlobal::locale()->readNumber( key( col, ascending ) ); + int next = (int)KGlobal::locale()->readNumber( item->key( col, ascending ) ); + if ( prev < next ) + return -1; + else if ( prev == next ) + return 0; + else + return 1; + } else if ( type == PrivateListView::Float ) { + double prev = KGlobal::locale()->readNumber( key( col, ascending ) ); + double next = KGlobal::locale()->readNumber( item->key( col, ascending ) ); + if ( prev < next ) + return -1; + else + return 1; + } else if ( type == PrivateListView::Time ) { + int hourPrev, hourNext, minutesPrev, minutesNext; + sscanf( key( col, ascending ).latin1(), "%d:%d", &hourPrev, &minutesPrev ); + sscanf( item->key( col, ascending ).latin1(), "%d:%d", &hourNext, &minutesNext ); + int prev = hourPrev * 60 + minutesPrev; + int next = hourNext * 60 + minutesNext; + if ( prev < next ) + return -1; + else if ( prev == next ) + return 0; + else + return 1; + } else if ( type == PrivateListView::DiskStat ) { + QString prev = key( col, ascending ); + QString next = item->key( col, ascending ); + QString prevKey, nextKey; + + uint counter = prev.length(); + for ( uint i = 0; i < counter; ++i ) + if ( prev[ i ].isDigit() ) { + prevKey.sprintf( "%s%016d", prev.left( i ).latin1(), prev.mid( i ).toInt() ); + break; + } + + counter = next.length(); + for ( uint i = 0; i < counter; ++i ) + if ( next[ i ].isDigit() ) { + nextKey.sprintf( "%s%016d", next.left( i ).latin1(), next.mid( i ).toInt() ); + break; + } + + return prevKey.compare( nextKey ); + } else + return key( col, ascending ).localeAwareCompare( item->key( col, ascending ) ); +} + +PrivateListView::PrivateListView(QWidget *parent, const char *name) + : QListView(parent, name) +{ + QColorGroup cg = colorGroup(); + + cg.setColor(QColorGroup::Link, KSGRD::Style->firstForegroundColor()); + cg.setColor(QColorGroup::Text, KSGRD::Style->secondForegroundColor()); + cg.setColor(QColorGroup::Base, KSGRD::Style->backgroundColor()); + + setPalette(QPalette(cg, cg, cg)); +} + +void PrivateListView::update(const QString& answer) +{ + setUpdatesEnabled(false); + viewport()->setUpdatesEnabled(false); + + int vpos = verticalScrollBar()->value(); + int hpos = horizontalScrollBar()->value(); + + clear(); + + KSGRD::SensorTokenizer lines(answer, '\n'); + for (uint i = 0; i < lines.count(); i++) { + PrivateListViewItem *item = new PrivateListViewItem(this); + KSGRD::SensorTokenizer records(lines[i], '\t'); + for (uint j = 0; j < records.count(); j++) { + if ( mColumnTypes[ j ] == "f" ) + item->setText(j, KGlobal::locale()->formatNumber( records[j].toFloat() ) ); + else if ( mColumnTypes[ j ] == "D" ) + item->setText(j, KGlobal::locale()->formatNumber( records[j].toDouble(), 0 ) ); + else + item->setText(j, records[j]); + } + + insertItem(item); + } + + verticalScrollBar()->setValue(vpos); + horizontalScrollBar()->setValue(hpos); + + viewport()->setUpdatesEnabled(true); + setUpdatesEnabled(true); + + triggerUpdate(); +} + +int PrivateListView::columnType( uint pos ) const +{ + if ( pos >= mColumnTypes.count() ) + return 0; + + if ( mColumnTypes[ pos ] == "d" || mColumnTypes[ pos ] == "D" ) + return Int; + else if ( mColumnTypes[ pos ] == "f" || mColumnTypes[ pos ] == "F" ) + return Float; + else if ( mColumnTypes[ pos ] == "t" ) + return Time; + else if ( mColumnTypes[ pos ] == "M" ) + return DiskStat; + else + return Text; +} + +void PrivateListView::removeColumns(void) +{ + for (int i = columns() - 1; i >= 0; --i) + removeColumn(i); +} + +void PrivateListView::addColumn(const QString& label, const QString& type) +{ + QListView::addColumn( label ); + int col = columns() - 1; + + if (type == "s" || type == "S") + setColumnAlignment(col, AlignLeft); + else if (type == "d" || type == "D") + setColumnAlignment(col, AlignRight); + else if (type == "t") + setColumnAlignment(col, AlignRight); + else if (type == "f") + setColumnAlignment(col, AlignRight); + else if (type == "M") + setColumnAlignment(col, AlignLeft); + else + { + kdDebug(1215) << "Unknown type " << type << " of column " << label + << " in ListView!" << endl; + return; + } + + mColumnTypes.append( type ); + + /* Just use some sensible default values as initial setting. */ + QFontMetrics fm = fontMetrics(); + setColumnWidth(col, fm.width(label) + 10); +} + +ListView::ListView(QWidget* parent, const char* name, const QString& title, int, int) + : KSGRD::SensorDisplay(parent, name, title) +{ + setBackgroundColor(KSGRD::Style->backgroundColor()); + + monitor = new PrivateListView( frame() ); + Q_CHECK_PTR(monitor); + monitor->setSelectionMode(QListView::NoSelection); + monitor->setItemMargin(2); + + setMinimumSize(50, 25); + + setPlotterWidget(monitor); + + setModified(false); +} + +bool +ListView::addSensor(const QString& hostName, const QString& sensorName, const QString& sensorType, const QString& title) +{ + if (sensorType != "listview") + return (false); + + registerSensor(new KSGRD::SensorProperties(hostName, sensorName, sensorType, title)); + + setTitle(title); + + /* To differentiate between answers from value requests and info + * requests we use 100 for info requests. */ + sendRequest(hostName, sensorName + "?", 100); + sendRequest(hostName, sensorName, 19); + setModified(true); + return (true); +} + +void +ListView::updateList() +{ + sendRequest(sensors().at(0)->hostName(), sensors().at(0)->name(), 19); +} + +void +ListView::answerReceived(int id, const QString& answer) +{ + /* We received something, so the sensor is probably ok. */ + sensorError(id, false); + + switch (id) + { + case 100: { + /* We have received the answer to a '?' command that contains + * the information about the table headers. */ + KSGRD::SensorTokenizer lines(answer, '\n'); + if (lines.count() != 2) + { + kdDebug(1215) << "wrong number of lines" << endl; + return; + } + KSGRD::SensorTokenizer headers(lines[0], '\t'); + KSGRD::SensorTokenizer colTypes(lines[1], '\t'); + + /* remove all columns from list */ + monitor->removeColumns(); + + /* add the new columns */ + for (unsigned int i = 0; i < headers.count(); i++) + /* TODO: Implement translation support for header texts */ + monitor->addColumn(headers[i], colTypes[i]); + break; + } + case 19: { + monitor->update(answer); + break; + } + } +} + +void +ListView::resizeEvent(QResizeEvent*) +{ + frame()->setGeometry(0, 0, width(), height()); + monitor->setGeometry(10, 20, width() - 20, height() - 30); +} + +bool +ListView::restoreSettings(QDomElement& element) +{ + addSensor(element.attribute("hostName"), element.attribute("sensorName"), (element.attribute("sensorType").isEmpty() ? "listview" : element.attribute("sensorType")), element.attribute("title")); + + QColorGroup colorGroup = monitor->colorGroup(); + colorGroup.setColor(QColorGroup::Link, restoreColor(element, "gridColor", KSGRD::Style->firstForegroundColor())); + colorGroup.setColor(QColorGroup::Text, restoreColor(element, "textColor", KSGRD::Style->secondForegroundColor())); + colorGroup.setColor(QColorGroup::Base, restoreColor(element, "backgroundColor", KSGRD::Style->backgroundColor())); + + monitor->setPalette(QPalette(colorGroup, colorGroup, colorGroup)); + + SensorDisplay::restoreSettings(element); + + setModified(false); + + return (true); +} + +bool +ListView::saveSettings(QDomDocument& doc, QDomElement& element, bool save) +{ + element.setAttribute("hostName", sensors().at(0)->hostName()); + element.setAttribute("sensorName", sensors().at(0)->name()); + element.setAttribute("sensorType", sensors().at(0)->type()); + + QColorGroup colorGroup = monitor->colorGroup(); + saveColor(element, "gridColor", colorGroup.color(QColorGroup::Link)); + saveColor(element, "textColor", colorGroup.color(QColorGroup::Text)); + saveColor(element, "backgroundColor", colorGroup.color(QColorGroup::Base)); + + SensorDisplay::saveSettings(doc, element); + + if (save) + setModified(false); + + return (true); +} + +void +ListView::configureSettings() +{ + lvs = new ListViewSettings(this, "ListViewSettings"); + Q_CHECK_PTR(lvs); + connect(lvs, SIGNAL(applyClicked()), SLOT(applySettings())); + + QColorGroup colorGroup = monitor->colorGroup(); + lvs->setGridColor(colorGroup.color(QColorGroup::Link)); + lvs->setTextColor(colorGroup.color(QColorGroup::Text)); + lvs->setBackgroundColor(colorGroup.color(QColorGroup::Base)); + lvs->setTitle(title()); + + if (lvs->exec()) + applySettings(); + + delete lvs; + lvs = 0; +} + +void +ListView::applySettings() +{ + QColorGroup colorGroup = monitor->colorGroup(); + colorGroup.setColor(QColorGroup::Link, lvs->gridColor()); + colorGroup.setColor(QColorGroup::Text, lvs->textColor()); + colorGroup.setColor(QColorGroup::Base, lvs->backgroundColor()); + monitor->setPalette(QPalette(colorGroup, colorGroup, colorGroup)); + + setTitle(lvs->title()); + + setModified(true); +} + +void +ListView::applyStyle() +{ + QColorGroup colorGroup = monitor->colorGroup(); + colorGroup.setColor(QColorGroup::Link, KSGRD::Style->firstForegroundColor()); + colorGroup.setColor(QColorGroup::Text, KSGRD::Style->secondForegroundColor()); + colorGroup.setColor(QColorGroup::Base, KSGRD::Style->backgroundColor()); + monitor->setPalette(QPalette(colorGroup, colorGroup, colorGroup)); + + setModified(true); +} diff --git a/ksysguard/gui/SensorDisplayLib/ListView.h b/ksysguard/gui/SensorDisplayLib/ListView.h new file mode 100644 index 000000000..4b96329c0 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ListView.h @@ -0,0 +1,112 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef _ListView_h_ +#define _ListView_h_ + +#include <qlistview.h> +#include <qpainter.h> + +#include <SensorDisplay.h> + +typedef const char* (*KeyFunc)(const char*); + +class QLabel; +class QBoxGroup; +class ListViewSettings; + +class PrivateListView : public QListView +{ + Q_OBJECT +public: + enum ColumnType { Text, Int, Float, Time, DiskStat }; + + PrivateListView(QWidget *parent = 0, const char *name = 0); + + void addColumn(const QString& label, const QString& type); + void removeColumns(void); + void update(const QString& answer); + int columnType( uint pos ) const; + +private: + QStringList mColumnTypes; +}; + +class PrivateListViewItem : public QListViewItem +{ +public: + PrivateListViewItem(PrivateListView *parent = 0); + + void paintCell(QPainter *p, const QColorGroup &, int column, int width, int alignment) { + QColorGroup cgroup = _parent->colorGroup(); + QListViewItem::paintCell(p, cgroup, column, width, alignment); + p->setPen(cgroup.color(QColorGroup::Link)); + p->drawLine(0, height() - 1, width - 1, height() - 1); + } + + void paintFocus(QPainter *, const QColorGroup, const QRect) {} + + virtual int compare( QListViewItem*, int column, bool ascending ) const; + +private: + QWidget *_parent; +}; + +class ListView : public KSGRD::SensorDisplay +{ + Q_OBJECT +public: + ListView(QWidget* parent = 0, const char* name = 0, + const QString& = QString::null, int min = 0, int max = 0); + ~ListView() {} + + bool addSensor(const QString& hostName, const QString& sensorName, const QString& sensorType, const QString& sensorDescr); + void answerReceived(int id, const QString& answer); + void resizeEvent(QResizeEvent*); + void updateList(); + + bool restoreSettings(QDomElement& element); + bool saveSettings(QDomDocument& doc, QDomElement& element, bool save = true); + + virtual bool hasSettingsDialog() const + { + return (true); + } + + virtual void timerEvent(QTimerEvent*) + { + updateList(); + } + + void configureSettings(); + +public slots: + void applySettings(); + void applyStyle(); + +private: + PrivateListView* monitor; + ListViewSettings* lvs; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/ListViewSettings.cc b/ksysguard/gui/SensorDisplayLib/ListViewSettings.cc new file mode 100644 index 000000000..15822206e --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ListViewSettings.cc @@ -0,0 +1,77 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "ListViewSettings.h" +#include "ListViewSettingsWidget.h" + +#include <klocale.h> + +ListViewSettings::ListViewSettings( QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n( "List View Settings" ), + Ok|Apply|Cancel, Ok, true ) +{ + m_settingsWidget = new ListViewSettingsWidget( this, "m_settingsWidget" ); + setMainWidget( m_settingsWidget ); +} + +QString ListViewSettings::title() const +{ + return m_settingsWidget->title(); +} + +QColor ListViewSettings::textColor() const +{ + return m_settingsWidget->textColor(); +} + +QColor ListViewSettings::backgroundColor() const +{ + return m_settingsWidget->backgroundColor(); +} + +QColor ListViewSettings::gridColor() const +{ + return m_settingsWidget->gridColor(); +} + +void ListViewSettings::setTitle( const QString &title ) +{ + m_settingsWidget->setTitle( title ); +} + +void ListViewSettings::setBackgroundColor( const QColor &c ) +{ + m_settingsWidget->setBackgroundColor( c ); +} + +void ListViewSettings::setTextColor( const QColor &c ) +{ + m_settingsWidget->setTextColor( c ); +} + +void ListViewSettings::setGridColor( const QColor &c ) +{ + m_settingsWidget->setGridColor( c ); +} + +#include "ListViewSettings.moc" + +/* vim: et sw=2 ts=2 +*/ + diff --git a/ksysguard/gui/SensorDisplayLib/ListViewSettings.h b/ksysguard/gui/SensorDisplayLib/ListViewSettings.h new file mode 100644 index 000000000..9a9790791 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ListViewSettings.h @@ -0,0 +1,57 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or ( at your option ) any later version. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#ifndef LISTVIEWSETTINGS_H +#define LISTVIEWSETTINGS_H + +#include <kdialogbase.h> + +#include <qstring.h> +#include <qcolor.h> + +class ListViewSettingsWidget; + +class ListViewSettings : public KDialogBase +{ + Q_OBJECT + + public: + + ListViewSettings( QWidget *parent=0, const char *name=0 ); + + QString title() const; + QColor textColor() const; + QColor backgroundColor() const; + QColor gridColor() const; + + void setTitle( const QString & ); + void setTextColor( const QColor & ); + void setBackgroundColor( const QColor & ); + void setGridColor( const QColor & ); + + private: + + ListViewSettingsWidget *m_settingsWidget; +}; + +#endif // LISTVIEWSETTINGS_H + +/* vim: et sw=2 ts=2 +*/ diff --git a/ksysguard/gui/SensorDisplayLib/ListViewSettingsWidget.ui b/ksysguard/gui/SensorDisplayLib/ListViewSettingsWidget.ui new file mode 100644 index 000000000..f61f30dd7 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ListViewSettingsWidget.ui @@ -0,0 +1,178 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>ListViewSettingsWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>ListViewSettingsWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>399</width> + <height>202</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>titleFrame</cstring> + </property> + <property name="title"> + <string>Title</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_title</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>colorFrame</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>Box</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="title"> + <string>Colors</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter|AlignLeft</set> + </property> + <property name="vAlign" stdset="0"> + </property> + <property name="wordwrap" stdset="0"> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Text color:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Grid color:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="0" column="1"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_textColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>0</red> + <green>255</green> + <blue>0</blue> + </color> + </property> + </widget> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_gridColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>0</red> + <green>0</green> + <blue>0</blue> + </color> + </property> + </widget> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_backgroundColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </property> + </widget> + </vbox> + </widget> + </grid> + </widget> + </vbox> +</widget> +<includes> + <include location="global" impldecl="in implementation">kdialog.h</include> + <include location="local" impldecl="in implementation">ListViewSettingsWidget.ui.h</include> +</includes> +<functions> + <function specifier="non virtual" returnType="QString">title()</function> + <function specifier="non virtual" returnType="QColor">gridColor()</function> + <function specifier="non virtual" returnType="QColor">backgroundColor()</function> + <function specifier="non virtual" returnType="QColor">textColor()</function> + <function specifier="non virtual">setTitle( const QString & t )</function> + <function specifier="non virtual">setBackgroundColor( const QColor & c )</function> + <function specifier="non virtual">setTextColor( const QColor & c )</function> + <function specifier="non virtual">setGridColor( const QColor & c )</function> +</functions> +<layoutdefaults spacing="6" margin="11"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +</UI> diff --git a/ksysguard/gui/SensorDisplayLib/ListViewSettingsWidget.ui.h b/ksysguard/gui/SensorDisplayLib/ListViewSettingsWidget.ui.h new file mode 100644 index 000000000..14ff5990d --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ListViewSettingsWidget.ui.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + + +QString ListViewSettingsWidget::title() +{ + return m_title->text(); +} + + +QColor ListViewSettingsWidget::gridColor() +{ + return m_gridColor->color(); +} + + +QColor ListViewSettingsWidget::backgroundColor() +{ + return m_backgroundColor->color(); +} + + +QColor ListViewSettingsWidget::textColor() +{ + return m_textColor->color(); +} + + +void ListViewSettingsWidget::setTitle( const QString &t ) +{ + m_title->setText(t); +} + + +void ListViewSettingsWidget::setBackgroundColor( const QColor &c ) +{ + m_backgroundColor->setColor(c); +} + + +void ListViewSettingsWidget::setTextColor( const QColor &c ) +{ + m_textColor->setColor(c); +} + + +void ListViewSettingsWidget::setGridColor( const QColor &c ) +{ + m_gridColor->setColor(c); +} diff --git a/ksysguard/gui/SensorDisplayLib/LogFile.cc b/ksysguard/gui/SensorDisplayLib/LogFile.cc new file mode 100644 index 000000000..9db4c7116 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/LogFile.cc @@ -0,0 +1,285 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + 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. + +*/ + +#include <stdio.h> +#include <sys/types.h> + +#include <qpushbutton.h> +#include <qregexp.h> + +#include <qfile.h> +#include <qlistbox.h> + +#include <kfontdialog.h> +#include <kdebug.h> +#include <klocale.h> +#include <kcolorbutton.h> + +#include <ksgrd/StyleEngine.h> + +#include "LogFile.moc" + +LogFile::LogFile(QWidget *parent, const char *name, const QString& title) + : KSGRD::SensorDisplay(parent, name, title) +{ + monitor = new QListBox(this); + Q_CHECK_PTR(monitor); + + setMinimumSize(50, 25); + + setPlotterWidget(monitor); + + setModified(false); +} + +LogFile::~LogFile(void) +{ + sendRequest(sensors().at(0)->hostName(), QString("logfile_unregister %1" ).arg(logFileID), 43); +} + +bool +LogFile::addSensor(const QString& hostName, const QString& sensorName, const QString& sensorType, const QString& title) +{ + if (sensorType != "logfile") + return (false); + + registerSensor(new KSGRD::SensorProperties(hostName, sensorName, sensorType, title)); + + QString sensorID = sensorName.right(sensorName.length() - (sensorName.findRev("/") + 1)); + + sendRequest(sensors().at(0)->hostName(), QString("logfile_register %1" ).arg(sensorID), 42); + + if (title.isEmpty()) + setTitle(sensors().at(0)->hostName() + ":" + sensorID); + else + setTitle(title); + + setModified(true); + + return (true); +} + + +void LogFile::configureSettings(void) +{ + QColorGroup cgroup = monitor->colorGroup(); + + lfs = new LogFileSettings(this); + Q_CHECK_PTR(lfs); + + lfs->fgColor->setColor(cgroup.text()); + lfs->fgColor->setText(i18n("Foreground color:")); + lfs->bgColor->setColor(cgroup.base()); + lfs->bgColor->setText(i18n("Background color:")); + lfs->fontButton->setFont(monitor->font()); + lfs->ruleList->insertStringList(filterRules); + lfs->title->setText(title()); + + connect(lfs->okButton, SIGNAL(clicked()), lfs, SLOT(accept())); + connect(lfs->applyButton, SIGNAL(clicked()), this, SLOT(applySettings())); + connect(lfs->cancelButton, SIGNAL(clicked()), lfs, SLOT(reject())); + + connect(lfs->fontButton, SIGNAL(clicked()), this, SLOT(settingsFontSelection())); + connect(lfs->addButton, SIGNAL(clicked()), this, SLOT(settingsAddRule())); + connect(lfs->deleteButton, SIGNAL(clicked()), this, SLOT(settingsDeleteRule())); + connect(lfs->changeButton, SIGNAL(clicked()), this, SLOT(settingsChangeRule())); + connect(lfs->ruleList, SIGNAL(selected(int)), this, SLOT(settingsRuleListSelected(int))); + connect(lfs->ruleText, SIGNAL(returnPressed()), this, SLOT(settingsAddRule())); + + if (lfs->exec()) { + applySettings(); + } + + delete lfs; + lfs = 0; +} + +void LogFile::settingsFontSelection() +{ + QFont tmpFont = lfs->fontButton->font(); + + if (KFontDialog::getFont(tmpFont) == KFontDialog::Accepted) { + lfs->fontButton->setFont(tmpFont); + } +} + +void LogFile::settingsAddRule() +{ + if (!lfs->ruleText->text().isEmpty()) { + lfs->ruleList->insertItem(lfs->ruleText->text(), -1); + lfs->ruleText->setText(""); + } +} + +void LogFile::settingsDeleteRule() +{ + lfs->ruleList->removeItem(lfs->ruleList->currentItem()); + lfs->ruleText->setText(""); +} + +void LogFile::settingsChangeRule() +{ + lfs->ruleList->changeItem(lfs->ruleText->text(), lfs->ruleList->currentItem()); + lfs->ruleText->setText(""); +} + +void LogFile::settingsRuleListSelected(int index) +{ + lfs->ruleText->setText(lfs->ruleList->text(index)); +} + +void LogFile::applySettings(void) +{ + QColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(QColorGroup::Text, lfs->fgColor->color()); + cgroup.setColor(QColorGroup::Base, lfs->bgColor->color()); + monitor->setPalette(QPalette(cgroup, cgroup, cgroup)); + monitor->setFont(lfs->fontButton->font()); + + filterRules.clear(); + for (uint i = 0; i < lfs->ruleList->count(); i++) + filterRules.append(lfs->ruleList->text(i)); + + setTitle(lfs->title->text()); + + setModified(true); +} + +void +LogFile::applyStyle() +{ + QColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(QColorGroup::Text, KSGRD::Style->firstForegroundColor()); + cgroup.setColor(QColorGroup::Base, KSGRD::Style->backgroundColor()); + monitor->setPalette(QPalette(cgroup, cgroup, cgroup)); + + setModified(true); +} + +bool +LogFile::restoreSettings(QDomElement& element) +{ + QFont font; + QColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(QColorGroup::Text, restoreColor(element, "textColor", Qt::green)); + cgroup.setColor(QColorGroup::Base, restoreColor(element, "backgroundColor", Qt::black)); + monitor->setPalette(QPalette(cgroup, cgroup, cgroup)); + + addSensor(element.attribute("hostName"), element.attribute("sensorName"), (element.attribute("sensorType").isEmpty() ? "logfile" : element.attribute("sensorType")), element.attribute("title")); + + font.fromString( element.attribute( "font" ) ); + monitor->setFont(font); + + QDomNodeList dnList = element.elementsByTagName("filter"); + for (uint i = 0; i < dnList.count(); i++) { + QDomElement element = dnList.item(i).toElement(); + filterRules.append(element.attribute("rule")); + } + + SensorDisplay::restoreSettings(element); + + setModified(false); + + return true; +} + +bool +LogFile::saveSettings(QDomDocument& doc, QDomElement& element, bool save) +{ + element.setAttribute("hostName", sensors().at(0)->hostName()); + element.setAttribute("sensorName", sensors().at(0)->name()); + element.setAttribute("sensorType", sensors().at(0)->type()); + + element.setAttribute("font", monitor->font().toString()); + + saveColor(element, "textColor", monitor->colorGroup().text()); + saveColor(element, "backgroundColor", monitor->colorGroup().base()); + + for (QStringList::Iterator it = filterRules.begin(); + it != filterRules.end(); it++) + { + QDomElement filter = doc.createElement("filter"); + filter.setAttribute("rule", (*it)); + element.appendChild(filter); + } + + SensorDisplay::saveSettings(doc, element); + + if (save) + setModified(false); + + return true; +} + +void +LogFile::updateMonitor() +{ + sendRequest(sensors().at(0)->hostName(), + QString("%1 %2" ).arg(sensors().at(0)->name()).arg(logFileID), 19); +} + +void +LogFile::answerReceived(int id, const QString& answer) +{ + /* We received something, so the sensor is probably ok. */ + sensorError(id, false); + + switch (id) + { + case 19: { + KSGRD::SensorTokenizer lines(answer, '\n'); + + for (uint i = 0; i < lines.count(); i++) { + if (monitor->count() == MAXLINES) + monitor->removeItem(0); + + monitor->insertItem(lines[i], -1); + + for (QStringList::Iterator it = filterRules.begin(); it != filterRules.end(); it++) { + QRegExp *expr = new QRegExp((*it).latin1()); + if (expr->search(lines[i].latin1()) != -1) { + KNotifyClient::event(winId(), "pattern_match", QString("rule '%1' matched").arg((*it).latin1())); + } + delete expr; + } + } + + monitor->setCurrentItem( monitor->count() - 1 ); + monitor->ensureCurrentVisible(); + + break; + } + + case 42: { + logFileID = answer.toULong(); + break; + } + } +} + +void +LogFile::resizeEvent(QResizeEvent*) +{ + frame()->setGeometry(0, 0, this->width(), this->height()); + monitor->setGeometry(10, 20, this->width() - 20, this->height() - 30); +} diff --git a/ksysguard/gui/SensorDisplayLib/LogFile.h b/ksysguard/gui/SensorDisplayLib/LogFile.h new file mode 100644 index 000000000..9428f934d --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/LogFile.h @@ -0,0 +1,85 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + 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. + +*/ + +#ifndef _LogFile_h +#define _LogFile_h + +#define MAXLINES 500 + +class QFile; +class QListBox; + +#include <qdom.h> +#include <qpopupmenu.h> +#include <qstring.h> +#include <qstringlist.h> + +#include <SensorDisplay.h> + +#include "LogFileSettings.h" + +class LogFile : public KSGRD::SensorDisplay +{ + Q_OBJECT +public: + LogFile(QWidget *parent = 0, const char *name = 0, const QString& title = 0); + ~LogFile(void); + + bool addSensor(const QString& hostName, const QString& sensorName, + const QString& sensorType, const QString& sensorDescr); + void answerReceived(int id, const QString& answer); + void resizeEvent(QResizeEvent*); + + bool restoreSettings(QDomElement& element); + bool saveSettings(QDomDocument& doc, QDomElement& element, bool save = true); + + void updateMonitor(void); + + void configureSettings(void); + + virtual void timerEvent(QTimerEvent*) + { + updateMonitor(); + } + + virtual bool hasSettingsDialog() const + { + return (true); + } + +public slots: + void applySettings(); + void applyStyle(); + + void settingsFontSelection(); + void settingsAddRule(); + void settingsDeleteRule(); + void settingsChangeRule(); + void settingsRuleListSelected(int index); + +private: + LogFileSettings* lfs; + QListBox* monitor; + QStringList filterRules; + + unsigned long logFileID; +}; + +#endif // _LogFile_h diff --git a/ksysguard/gui/SensorDisplayLib/LogFileSettings.ui b/ksysguard/gui/SensorDisplayLib/LogFileSettings.ui new file mode 100644 index 000000000..b5dcff0ee --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/LogFileSettings.ui @@ -0,0 +1,345 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>LogFileSettings</class> +<author>Tobias Koenig <tokoe@kde.org></author> +<widget class="QDialog"> + <property name="name"> + <cstring>LogFileSettings</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>438</width> + <height>320</height> + </rect> + </property> + <property name="caption"> + <string>Log File Settings</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>tab</cstring> + </property> + <attribute name="title"> + <string>Text</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>GroupBox8</cstring> + </property> + <property name="title"> + <string>Title</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>title</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>styleGroup</cstring> + </property> + <property name="title"> + <string>Colors</string> + </property> + <property name="exclusive"> + <bool>true</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Foreground color:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KColorButton"> + <property name="name"> + <cstring>fgColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="KColorButton"> + <property name="name"> + <cstring>bgColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer8</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>GroupBox11</cstring> + </property> + <property name="title"> + <string>Font</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>Spacer14</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>fontButton</cstring> + </property> + <property name="text"> + <string>Select Font...</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Filter</string> + </attribute> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout7</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>ruleText</cstring> + </property> + </widget> + <widget class="QListBox"> + <property name="name"> + <cstring>ruleList</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout9</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>addButton</cstring> + </property> + <property name="text"> + <string>&Add</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>deleteButton</cstring> + </property> + <property name="text"> + <string>&Delete</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>changeButton</cstring> + </property> + <property name="text"> + <string>&Change</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer7_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </hbox> + </widget> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>okButton</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>applyButton</cstring> + </property> + <property name="text"> + <string>&Apply</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>cancelButton</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<tabstops> + <tabstop>okButton</tabstop> + <tabstop>applyButton</tabstop> + <tabstop>cancelButton</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in implementation">kdialog.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +</UI> diff --git a/ksysguard/gui/SensorDisplayLib/Makefile.am b/ksysguard/gui/SensorDisplayLib/Makefile.am new file mode 100644 index 000000000..a1327a4ac --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/Makefile.am @@ -0,0 +1,39 @@ + +# set the include path for X, qt and KDE +INCLUDES= -I$(srcdir)/.. -I$(srcdir)/../ksgrd -I../ksgrd $(all_includes) + +noinst_LTLIBRARIES = libsensordisplays.la + +libsensordisplays_la_LDFLAGS = $(all_libraries) -no-undefined +libsensordisplays_la_LIBADD = ../ksgrd/libksgrd.la $(LIB_KIO) + +# Which sources should be compiled for the sensor display lib. +libsensordisplays_la_SOURCES = \ + SensorDisplay.cc \ + BarGraph.cc \ + DancingBars.cc \ + DancingBarsSettings.cc \ + DummyDisplay.cc \ + FancyPlotter.cc \ + FancyPlotterSettings.cc \ + ListView.cc \ + LogFile.cc \ + MultiMeter.cc \ + MultiMeterSettings.cc \ + ProcessController.cc \ + ProcessList.cc \ + ReniceDlg.cc \ + SensorLogger.cc \ + SensorLoggerDlg.cc \ + SensorLoggerSettings.cc \ + ListViewSettings.cc \ + SignalPlotter.cc \ + ListViewSettingsWidget.ui \ + LogFileSettings.ui \ + MultiMeterSettingsWidget.ui \ + SensorLoggerDlgWidget.ui \ + SensorLoggerSettingsWidget.ui + +# just to make sure, automake makes them +METASOURCES = AUTO + diff --git a/ksysguard/gui/SensorDisplayLib/MultiMeter.cc b/ksysguard/gui/SensorDisplayLib/MultiMeter.cc new file mode 100644 index 000000000..14e805b9d --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/MultiMeter.cc @@ -0,0 +1,258 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000, 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <math.h> +#include <stdlib.h> + +#include <qdom.h> +#include <qlcdnumber.h> +#include <qtooltip.h> + +#include <kdebug.h> + +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include "MultiMeter.moc" +#include "MultiMeterSettings.h" + +MultiMeter::MultiMeter(QWidget* parent, const char* name, + const QString& title, double, double, bool nf, bool isApplet) + : KSGRD::SensorDisplay(parent, name, title, nf, isApplet) +{ + setShowUnit( true ); + lowerLimit = upperLimit = 0; + lowerLimitActive = upperLimitActive = false; + + normalDigitColor = KSGRD::Style->firstForegroundColor(); + alarmDigitColor = KSGRD::Style->alarmColor(); + if (noFrame()) + lcd = new QLCDNumber(this, "meterLCD"); + else + lcd = new QLCDNumber(frame(), "meterLCD"); + Q_CHECK_PTR(lcd); + lcd->setSegmentStyle(QLCDNumber::Filled); + setDigitColor(KSGRD::Style->backgroundColor()); + lcd->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, + QSizePolicy::Expanding, false)); + + setBackgroundColor(KSGRD::Style->backgroundColor()); + /* All RMB clicks to the lcd widget will be handled by + * SensorDisplay::eventFilter. */ + lcd->installEventFilter(this); + + setPlotterWidget(lcd); + + setMinimumSize(5, 5); + setModified(false); +} + +bool +MultiMeter::addSensor(const QString& hostName, const QString& sensorName, + const QString& sensorType, const QString& title) +{ + if (sensorType != "integer" && sensorType != "float") + return (false); + + registerSensor(new KSGRD::SensorProperties(hostName, sensorName, sensorType, title)); + + /* To differentiate between answers from value requests and info + * requests we use 100 for info requests. */ + sendRequest(hostName, sensorName + "?", 100); + + QToolTip::remove(lcd); + QToolTip::add(lcd, QString("%1:%2").arg(hostName).arg(sensorName)); + + setModified(true); + return (true); +} + +void +MultiMeter::answerReceived(int id, const QString& answer) +{ + /* We received something, so the sensor is probably ok. */ + sensorError(id, false); + + if (id == 100) + { + KSGRD::SensorIntegerInfo info(answer); + setUnit(KSGRD::SensorMgr->translateUnit(info.unit())); + } + else + { + double val = answer.toDouble(); + int digits = (int) log10(val) + 1; + + if (noFrame()) + if (digits > 4) + lcd->setNumDigits(4); + else + lcd->setNumDigits(digits); + else + { + if (digits > 5) + lcd->setNumDigits(digits); + else + lcd->setNumDigits(5); + } + + lcd->display(val); + if (lowerLimitActive && val < lowerLimit) + { + setDigitColor(alarmDigitColor); + } + else if (upperLimitActive && val > upperLimit) + { + setDigitColor(alarmDigitColor); + } + else + setDigitColor(normalDigitColor); + } +} + +void +MultiMeter::resizeEvent(QResizeEvent*) +{ + if (noFrame()) + lcd->setGeometry(0, 0, width(), height()); + else + frame()->setGeometry(0, 0, width(), height()); +} + +bool +MultiMeter::restoreSettings(QDomElement& element) +{ + lowerLimitActive = element.attribute("lowerLimitActive").toInt(); + lowerLimit = element.attribute("lowerLimit").toLong(); + upperLimitActive = element.attribute("upperLimitActive").toInt(); + upperLimit = element.attribute("upperLimit").toLong(); + + normalDigitColor = restoreColor(element, "normalDigitColor", + KSGRD::Style->firstForegroundColor()); + alarmDigitColor = restoreColor(element, "alarmDigitColor", + KSGRD::Style->alarmColor()); + setBackgroundColor(restoreColor(element, "backgroundColor", + KSGRD::Style->backgroundColor())); + + addSensor(element.attribute("hostName"), element.attribute("sensorName"), (element.attribute("sensorType").isEmpty() ? "integer" : element.attribute("sensorType")), ""); + + SensorDisplay::restoreSettings(element); + + setModified(false); + + return (true); +} + +bool +MultiMeter::saveSettings(QDomDocument& doc, QDomElement& element, bool save) +{ + element.setAttribute("hostName", sensors().at(0)->hostName()); + element.setAttribute("sensorName", sensors().at(0)->name()); + element.setAttribute("sensorType", sensors().at(0)->type()); + element.setAttribute("showUnit", showUnit()); + element.setAttribute("lowerLimitActive", (int) lowerLimitActive); + element.setAttribute("lowerLimit", (int) lowerLimit); + element.setAttribute("upperLimitActive", (int) upperLimitActive); + element.setAttribute("upperLimit", (int) upperLimit); + + saveColor(element, "normalDigitColor", normalDigitColor); + saveColor(element, "alarmDigitColor", alarmDigitColor); + saveColor(element, "backgroundColor", lcd->backgroundColor()); + + SensorDisplay::saveSettings(doc, element); + + if (save) + setModified(false); + + return (true); +} + +void +MultiMeter::configureSettings() +{ + mms = new MultiMeterSettings(this, "MultiMeterSettings"); + Q_CHECK_PTR(mms); + mms->setTitle(title()); + mms->setShowUnit(showUnit()); + mms->setLowerLimitActive(lowerLimitActive); + mms->setLowerLimit(lowerLimit); + mms->setUpperLimitActive(upperLimitActive); + mms->setUpperLimit(upperLimit); + mms->setNormalDigitColor(normalDigitColor); + mms->setAlarmDigitColor(alarmDigitColor); + mms->setMeterBackgroundColor(lcd->backgroundColor()); + + connect(mms, SIGNAL(applyClicked()), SLOT(applySettings())); + + if (mms->exec()) + applySettings(); + + delete mms; + mms = 0; +} + +void +MultiMeter::applySettings() +{ + setShowUnit( mms->showUnit() ); + setTitle(mms->title()); + lowerLimitActive = mms->lowerLimitActive(); + lowerLimit = mms->lowerLimit(); + upperLimitActive = mms->upperLimitActive(); + upperLimit = mms->upperLimit(); + + normalDigitColor = mms->normalDigitColor(); + alarmDigitColor = mms->alarmDigitColor(); + setBackgroundColor(mms->meterBackgroundColor()); + + repaint(); + setModified(true); +} + +void +MultiMeter::applyStyle() +{ + normalDigitColor = KSGRD::Style->firstForegroundColor(); + setBackgroundColor(KSGRD::Style->backgroundColor()); + repaint(); + setModified(true); +} + +void +MultiMeter::setDigitColor(const QColor& col) +{ + QPalette p = lcd->palette(); + p.setColor(QColorGroup::Foreground, col); + lcd->setPalette(p); +} + +void +MultiMeter::setBackgroundColor(const QColor& col) +{ + lcd->setBackgroundColor(col); + + QPalette p = lcd->palette(); + p.setColor(QColorGroup::Light, col); + p.setColor(QColorGroup::Dark, col); + lcd->setPalette(p); +} diff --git a/ksysguard/gui/SensorDisplayLib/MultiMeter.h b/ksysguard/gui/SensorDisplayLib/MultiMeter.h new file mode 100644 index 000000000..58d2477c1 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/MultiMeter.h @@ -0,0 +1,79 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef _MultiMeter_h_ +#define _MultiMeter_h_ + +#include <SensorDisplay.h> + +class QGroupBox; +class QLCDNumber; +class QLabel; +class MultiMeterSettings; + +class MultiMeter : public KSGRD::SensorDisplay +{ + Q_OBJECT + +public: + MultiMeter(QWidget* parent = 0, const char* name = 0, + const QString& = QString::null, double min = 0, double max = 0, bool nf = false, bool isApplet = false); + virtual ~MultiMeter() + { + } + + bool addSensor(const QString& hostName, const QString& sensorName, + const QString& sensorType, const QString& sensorDescr); + void answerReceived(int id, const QString& answer); + void resizeEvent(QResizeEvent*); + + bool restoreSettings(QDomElement& element); + bool saveSettings(QDomDocument& doc, QDomElement& element, bool save = true); + + virtual bool hasSettingsDialog() const + { + return (true); + } + + void configureSettings(); + +public slots: + void applySettings(); + void applyStyle(); + +private: + void setDigitColor(const QColor& col); + void setBackgroundColor(const QColor& col); + + QLCDNumber* lcd; + QColor normalDigitColor; + QColor alarmDigitColor; + + MultiMeterSettings* mms; + bool lowerLimitActive; + double lowerLimit; + bool upperLimitActive; + double upperLimit; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/MultiMeterSettings.cc b/ksysguard/gui/SensorDisplayLib/MultiMeterSettings.cc new file mode 100644 index 000000000..9114c583b --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/MultiMeterSettings.cc @@ -0,0 +1,127 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "MultiMeterSettings.h" +#include "MultiMeterSettingsWidget.h" + +#include <klocale.h> + +MultiMeterSettings::MultiMeterSettings( QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n( "Multimeter Settings" ), + Ok|Apply|Cancel, Ok, true ) +{ + m_settingsWidget = new MultiMeterSettingsWidget( this, "m_settingsWidget" ); + setMainWidget( m_settingsWidget ); +} + +QString MultiMeterSettings::title() +{ + return m_settingsWidget->title(); +} + +bool MultiMeterSettings::showUnit() +{ + return m_settingsWidget->showUnit(); +} + +bool MultiMeterSettings::lowerLimitActive() +{ + return m_settingsWidget->lowerLimitActive(); +} + +bool MultiMeterSettings::upperLimitActive() +{ + return m_settingsWidget->upperLimitActive(); +} + +double MultiMeterSettings::lowerLimit() +{ + return m_settingsWidget->lowerLimit(); +} + +double MultiMeterSettings::upperLimit() +{ + return m_settingsWidget->upperLimit(); +} + +QColor MultiMeterSettings::normalDigitColor() +{ + return m_settingsWidget->normalDigitColor(); +} + +QColor MultiMeterSettings::alarmDigitColor() +{ + return m_settingsWidget->alarmDigitColor(); +} + +QColor MultiMeterSettings::meterBackgroundColor() +{ + return m_settingsWidget->meterBackgroundColor(); +} + +void MultiMeterSettings::setTitle( const QString &title ) +{ + m_settingsWidget->setTitle( title ); +} + +void MultiMeterSettings::setShowUnit( bool b ) +{ + m_settingsWidget->setShowUnit( b ); +} + +void MultiMeterSettings::setLowerLimitActive( bool b ) +{ + m_settingsWidget->setLowerLimitActive( b ); +} + +void MultiMeterSettings::setUpperLimitActive( bool b ) +{ + m_settingsWidget->setUpperLimitActive( b ); +} + +void MultiMeterSettings::setLowerLimit( double limit ) +{ + m_settingsWidget->setLowerLimit( limit ); +} + +void MultiMeterSettings::setUpperLimit( double limit ) +{ + m_settingsWidget->setUpperLimit( limit ); +} + +void MultiMeterSettings::setNormalDigitColor( const QColor &c ) +{ + m_settingsWidget->setNormalDigitColor( c ); +} + +void MultiMeterSettings::setAlarmDigitColor( const QColor &c ) +{ + m_settingsWidget->setAlarmDigitColor( c ); +} + +void MultiMeterSettings::setMeterBackgroundColor( const QColor &c ) +{ + m_settingsWidget->setMeterBackgroundColor( c ); +} + +#include "MultiMeterSettings.moc" + +/* vim: et sw=2 ts=2 +*/ + diff --git a/ksysguard/gui/SensorDisplayLib/MultiMeterSettings.h b/ksysguard/gui/SensorDisplayLib/MultiMeterSettings.h new file mode 100644 index 000000000..516a02128 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/MultiMeterSettings.h @@ -0,0 +1,68 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or ( at your option ) any later version. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#ifndef MULTIMETERSETTINGS_H +#define MULTIMETERSETTINGS_H + +#include <kdialogbase.h> + +#include <qstring.h> +#include <qcolor.h> + +class MultiMeterSettingsWidget; + +class MultiMeterSettings : public KDialogBase +{ + Q_OBJECT + + public: + + MultiMeterSettings( QWidget *parent=0, const char *name=0 ); + + QString title(); + bool showUnit(); + bool lowerLimitActive(); + bool upperLimitActive(); + double lowerLimit(); + double upperLimit(); + QColor normalDigitColor(); + QColor alarmDigitColor(); + QColor meterBackgroundColor(); + + void setTitle( const QString & ); + void setShowUnit( bool ); + void setLowerLimitActive( bool ); + void setUpperLimitActive( bool ); + void setLowerLimit( double ); + void setUpperLimit( double ); + void setNormalDigitColor( const QColor & ); + void setAlarmDigitColor( const QColor & ); + void setMeterBackgroundColor( const QColor & ); + + private: + + MultiMeterSettingsWidget *m_settingsWidget; +}; + +#endif // MULTIMETERSETTINGS_H + +/* vim: et sw=2 ts=2 +*/ + diff --git a/ksysguard/gui/SensorDisplayLib/MultiMeterSettingsWidget.ui b/ksysguard/gui/SensorDisplayLib/MultiMeterSettingsWidget.ui new file mode 100644 index 000000000..7ecdef88f --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/MultiMeterSettingsWidget.ui @@ -0,0 +1,475 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>MultiMeterSettingsWidget</class> +<comment>MultiMeterSettingsWidget</comment> +<widget class="QWidget"> + <property name="name"> + <cstring>MultiMeterSettingsWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>378</width> + <height>229</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>GroupBox7</cstring> + </property> + <property name="title"> + <string>Title</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit" row="0" column="0"> + <property name="name"> + <cstring>m_title</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter the title of the display here.</string> + </property> + </widget> + <widget class="QCheckBox" row="0" column="1"> + <property name="name"> + <cstring>m_showUnit</cstring> + </property> + <property name="text"> + <string>&Show unit</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Enable this to append the unit to the title of the display.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QTabWidget"> + <property name="name"> + <cstring>TabWidget2</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Alarms</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox" row="1" column="0"> + <property name="name"> + <cstring>GroupBox1_2</cstring> + </property> + <property name="title"> + <string>Alarm for Maximum Value</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>m_upperLimitActive</cstring> + </property> + <property name="text"> + <string>E&nable alarm</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Enable the maximum value alarm.</string> + </property> + </widget> + <spacer row="0" column="1"> + <property name="name"> + <cstring>Spacer1_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>m_lblUpperLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Upper limit:</string> + </property> + </widget> + <widget class="QLineEdit" row="0" column="3"> + <property name="name"> + <cstring>m_upperLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimumSize"> + <size> + <width>70</width> + <height>0</height> + </size> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>GroupBox1</cstring> + </property> + <property name="title"> + <string>Alarm for Minimum Value</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>m_lowerLimitActive</cstring> + </property> + <property name="text"> + <string>&Enable alarm</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Enable the minimum value alarm.</string> + </property> + </widget> + <spacer row="0" column="1"> + <property name="name"> + <cstring>Spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>m_lblLowerLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Lower limit:</string> + </property> + </widget> + <widget class="QLineEdit" row="0" column="3"> + <property name="name"> + <cstring>m_lowerLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimumSize"> + <size> + <width>70</width> + <height>0</height> + </size> + </property> + </widget> + </grid> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Colors</string> + </attribute> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Normal digit color:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Alarm digit color:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_normalDigitColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>0</red> + <green>255</green> + <blue>0</blue> + </color> + </property> + </widget> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_alarmDigitColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </property> + </widget> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_backgroundColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>KColorButton</class> + <header location="local">kcolorbutton.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + <signal>destroyed()</signal> + <signal>destroyed(QObject*)</signal> + <signal>pressed()</signal> + <signal>released()</signal> + <signal>clicked()</signal> + <signal>toggled(bool)</signal> + <signal>stateChanged(int)</signal> + <signal>changed(const QColor&)</signal> + <slot access="public" specifier="">deleteLater()</slot> + <slot access="private" specifier="">cleanupEventFilter(QObject*)</slot> + <slot access="public" specifier="">setEnabled(bool)</slot> + <slot access="public" specifier="">setDisabled(bool)</slot> + <slot access="public" specifier="">setCaption(const QString&)</slot> + <slot access="public" specifier="">setIcon(const QPixmap&)</slot> + <slot access="public" specifier="">setIconText(const QString&)</slot> + <slot access="public" specifier="">setMouseTracking(bool)</slot> + <slot access="public" specifier="">setFocus()</slot> + <slot access="public" specifier="">clearFocus()</slot> + <slot access="public" specifier="">setUpdatesEnabled(bool)</slot> + <slot access="public" specifier="">update()</slot> + <slot access="public" specifier="">update(int,int,int,int)</slot> + <slot access="public" specifier="">update(const QRect&)</slot> + <slot access="public" specifier="">repaint()</slot> + <slot access="public" specifier="">repaint(bool)</slot> + <slot access="public" specifier="">repaint(int,int,int,int)</slot> + <slot access="public" specifier="">repaint(int,int,int,int,bool)</slot> + <slot access="public" specifier="">repaint(const QRect&)</slot> + <slot access="public" specifier="">repaint(const QRect&,bool)</slot> + <slot access="public" specifier="">repaint(const QRegion&)</slot> + <slot access="public" specifier="">repaint(const QRegion&,bool)</slot> + <slot access="public" specifier="">show()</slot> + <slot access="public" specifier="">hide()</slot> + <slot access="public" specifier="">setShown(bool)</slot> + <slot access="public" specifier="">setHidden(bool)</slot> + <slot access="public" specifier="">iconify()</slot> + <slot access="public" specifier="">showMinimized()</slot> + <slot access="public" specifier="">showMaximized()</slot> + <slot access="public" specifier="">showFullScreen()</slot> + <slot access="public" specifier="">showNormal()</slot> + <slot access="public" specifier="">polish()</slot> + <slot access="public" specifier="">constPolish()</slot> + <slot access="public" specifier="">close()</slot> + <slot access="public" specifier="">raise()</slot> + <slot access="public" specifier="">lower()</slot> + <slot access="public" specifier="">stackUnder(QWidget*)</slot> + <slot access="public" specifier="">move(int,int)</slot> + <slot access="public" specifier="">move(const QPoint&)</slot> + <slot access="public" specifier="">resize(int,int)</slot> + <slot access="public" specifier="">resize(const QSize&)</slot> + <slot access="public" specifier="">setGeometry(int,int,int,int)</slot> + <slot access="public" specifier="">setGeometry(const QRect&)</slot> + <slot access="public" specifier="">adjustSize()</slot> + <slot access="private" specifier="">focusProxyDestroyed()</slot> + <slot access="public" specifier="">animateClick()</slot> + <slot access="public" specifier="">toggle()</slot> + <slot access="private" specifier="">animateTimeout()</slot> + <slot access="private" specifier="">autoRepeatTimeout()</slot> + <slot access="private" specifier="">emulateClick()</slot> + <slot access="public" specifier="">setOn(bool)</slot> + <slot access="private" specifier="">popupPressed()</slot> + <slot access="protected" specifier="">chooseColor()</slot> + <property type="CString">name</property> + <property type="Bool">enabled</property> + <property type="Rect">geometry</property> + <property type="SizePolicy">sizePolicy</property> + <property type="Size">minimumSize</property> + <property type="Size">maximumSize</property> + <property type="Size">sizeIncrement</property> + <property type="Size">baseSize</property> + <property type="Color">paletteForegroundColor</property> + <property type="Color">paletteBackgroundColor</property> + <property type="Pixmap">paletteBackgroundPixmap</property> + <property type="Palette">palette</property> + <property type="BackgroundOrigin">backgroundOrigin</property> + <property type="Font">font</property> + <property type="Cursor">cursor</property> + <property type="String">caption</property> + <property type="Pixmap">icon</property> + <property type="String">iconText</property> + <property type="Bool">mouseTracking</property> + <property type="FocusPolicy">focusPolicy</property> + <property type="Bool">acceptDrops</property> + <property type="String">text</property> + <property type="Pixmap">pixmap</property> + <property type="KeySequence">accel</property> + <property type="Bool">autoRepeat</property> + <property type="Bool">autoDefault</property> + <property type="Bool">default</property> + <property type="IconSet">iconSet</property> + <property type="Bool">toggleButton</property> + <property type="Bool">on</property> + <property type="Bool">flat</property> + <property type="Bool">autoMask</property> + <property type="Color">color</property> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="827">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000030249444154789cad953188db6614c77f0e1a9ee0029fc10509ae20c30de7d1852e4733f846d30c2e74483aa5812ea54bba35590a693a640e1d0e0e0ae16e282443e1321cd499eca5d4072951e10af26090e00ef40d013d88411d3ed967f91228e4de22f4e97dbff7d7ff7b7a6a9465c9221a8d0657116559d258801ffcf080ce76076b6d996629f99bfc7f41acb524a709e33fc73067a9cc5b287dfaeb53c28f294dbb2042d1b9228b0ccf25fbd5b598afec9ec33401dd13262fb50407f7562a97a65d90d923f23c0114df578ab7423613f2730584660bda6d453640ab02721dc210262b6fb204a7594a8456508bef0baf5f1986bf5be2130b68952944dbc2eec0b0d303e66e5da46ed1129cbfc9d1b92ea1a3211cfc92b94d1b427bdb201ea43365fa8fb2ff73463635dcbe232b45df01765ac0f7e1f52ba9a04aeff380fe40687e0488a21a327a5170b097717498110411fd2f9b80ad81afad9729de0ac3e77609fdea1ba1195a104b7e26fcf13ca73ff0f9fabb00109e1d5aecf9bac4f55b0fb29910ff6d31c6d01f0878163c506bd87facc42796fc0ceede6b323e76b971ec6c7abf62a84e5f09a3eaf52be89347ee104d4bf8e48620a6a0d37527964eb532f23d60d7a72e41c4799aa786278f94f8c4151481f6a6ef9e7b0b985cb2e292e266cb25263345b5c9f8254ea91182c090cd2c0fefa7c49326e9a9eb8630f2d731f53ac5dc357fb4254cff55462f0afab77cf233c3ce0d21dcf479781fb2a9e5a76f135415d312badd8274566fb94b8a6503fa0303c0c15ec6e8b8e0eebd26dd1e44dd9cef7f6c630283b5169d2bbb838070eb92e07567dc67bad3836c66787698b1ff38637c2c743a0202e9698a9eeb72e75f434b723344bcfa87b23a2b2ee0285fdc114c1071f49beb86f8e4a2b86909fd41c46868b1aaa882b5752b96e0e434619a00d72fe0fd81b0d30b8963433a75ebe1a64ff7d382700b766f864ea497134feae04659966ec07b94ddcf8430ac5a6dce7264caa20d6bc629e209d6423c51d24cb16eb434ea6017251f16f541ffae071f1ad7c0fda3ae3a967d7c95f0b22cf90f71e859c3d57176e60000000049454e44ae426082</data> + </image> +</images> +<connections> + <connection> + <sender>m_lowerLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_lowerLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_upperLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_upperLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_lowerLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_lblLowerLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_upperLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_lblUpperLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<includes> + <include location="global" impldecl="in implementation">kdialog.h</include> + <include location="global" impldecl="in implementation">knumvalidator.h</include> + <include location="local" impldecl="in implementation">MultiMeterSettingsWidget.ui.h</include> +</includes> +<slots> + <slot>setMeterBackgroundColor( const QColor & c )</slot> +</slots> +<functions> + <function access="private" specifier="non virtual">init()</function> + <function specifier="non virtual" returnType="QString">title()</function> + <function specifier="non virtual" returnType="bool">showUnit()</function> + <function returnType="bool">lowerLimitActive()</function> + <function specifier="non virtual" returnType="double">lowerLimit()</function> + <function returnType="bool">upperLimitActive()</function> + <function returnType="double">upperLimit()</function> + <function specifier="non virtual" returnType="QColor">normalDigitColor()</function> + <function specifier="non virtual" returnType="QColor">alarmDigitColor()</function> + <function returnType="QColor">meterBackgroundColor()</function> + <function specifier="non virtual">setTitle( const QString & s )</function> + <function specifier="non virtual">setShowUnit( bool b )</function> + <function specifier="non virtual">setLowerLimitActive( bool b )</function> + <function specifier="non virtual">setLowerLimit( double d )</function> + <function specifier="non virtual">setUpperLimitActive( bool b )</function> + <function specifier="non virtual">setUpperLimit( double d )</function> + <function specifier="non virtual">setNormalDigitColor( const QColor & c )</function> + <function specifier="non virtual">setAlarmDigitColor( const QColor & c )</function> +</functions> +<layoutdefaults spacing="6" margin="11"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +<includehints> + <includehint>kcolorbutton.h</includehint> +</includehints> +</UI> diff --git a/ksysguard/gui/SensorDisplayLib/MultiMeterSettingsWidget.ui.h b/ksysguard/gui/SensorDisplayLib/MultiMeterSettingsWidget.ui.h new file mode 100644 index 000000000..81d6e73f6 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/MultiMeterSettingsWidget.ui.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + +void MultiMeterSettingsWidget::init() +{ + m_lowerLimit->setValidator(new KDoubleValidator(m_lowerLimit)); + m_upperLimit->setValidator(new KDoubleValidator(m_upperLimit)); + + m_title->setFocus(); +} + +QString MultiMeterSettingsWidget::title() +{ + return m_title->text(); +} + + +bool MultiMeterSettingsWidget::showUnit() +{ + return m_showUnit->isChecked(); +} + + +bool MultiMeterSettingsWidget::lowerLimitActive() +{ + return m_lowerLimitActive->isChecked(); +} + + +double MultiMeterSettingsWidget::lowerLimit() +{ + return m_lowerLimit->text().toDouble(); +} + + +bool MultiMeterSettingsWidget::upperLimitActive() +{ + return m_upperLimitActive->isChecked(); +} + + +double MultiMeterSettingsWidget::upperLimit() +{ + return m_upperLimit->text().toDouble(); +} + + +QColor MultiMeterSettingsWidget::normalDigitColor() +{ + return m_normalDigitColor->color(); +} + + +QColor MultiMeterSettingsWidget::alarmDigitColor() +{ + return m_alarmDigitColor->color(); +} + + +QColor MultiMeterSettingsWidget::meterBackgroundColor() +{ + return m_backgroundColor->color(); +} + + +void MultiMeterSettingsWidget::setTitle( const QString &s ) +{ + m_title->setText(s); +} + + +void MultiMeterSettingsWidget::setShowUnit( bool b ) +{ + m_showUnit->setChecked(b); +} + + +void MultiMeterSettingsWidget::setLowerLimitActive( bool b ) +{ + m_lowerLimitActive->setChecked(b); +} + + +void MultiMeterSettingsWidget::setLowerLimit( double d ) +{ + m_lowerLimit->setText(QString("%1").arg(d)); +} + + +void MultiMeterSettingsWidget::setUpperLimitActive( bool b ) +{ + m_upperLimitActive->setChecked(b); +} + + +void MultiMeterSettingsWidget::setUpperLimit( double d ) +{ + m_upperLimit->setText(QString("%1").arg(d)); +} + + +void MultiMeterSettingsWidget::setNormalDigitColor( const QColor &c ) +{ + m_normalDigitColor->setColor(c); +} + + +void MultiMeterSettingsWidget::setAlarmDigitColor( const QColor &c ) +{ + m_alarmDigitColor->setColor(c); +} + + +void MultiMeterSettingsWidget::setMeterBackgroundColor( const QColor &c ) +{ + m_backgroundColor->setColor(c); +} diff --git a/ksysguard/gui/SensorDisplayLib/ProcessController.cc b/ksysguard/gui/SensorDisplayLib/ProcessController.cc new file mode 100644 index 000000000..b9fcd4f06 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ProcessController.cc @@ -0,0 +1,472 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms version 2 of 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <assert.h> + +#include <qtimer.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kdialogbase.h> +#include <klistviewsearchline.h> + +#include <ksgrd/SensorManager.h> + +#include "ProcessController.moc" +#include "SignalIDs.h" + +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qgroupbox.h> +#include <qlayout.h> + +#include <kapplication.h> +#include <kpushbutton.h> + + + +ProcessController::ProcessController(QWidget* parent, const char* name, const QString &title, bool nf) + : KSGRD::SensorDisplay(parent, name, title, nf) +{ + dict.setAutoDelete(true); + dict.insert("Name", new QString(i18n("Name"))); + dict.insert("PID", new QString(i18n("PID"))); + dict.insert("PPID", new QString(i18n("PPID"))); + dict.insert("UID", new QString(i18n("UID"))); + dict.insert("GID", new QString(i18n("GID"))); + dict.insert("Status", new QString(i18n("Status"))); + dict.insert("User%", new QString(i18n("User%"))); + dict.insert("System%", new QString(i18n("System%"))); + dict.insert("Nice", new QString(i18n("Nice"))); + dict.insert("VmSize", new QString(i18n("VmSize"))); + dict.insert("VmRss", new QString(i18n("VmRss"))); + dict.insert("Login", new QString(i18n("Login"))); + dict.insert("Command", new QString(i18n("Command"))); + + // Setup the geometry management. + gm = new QVBoxLayout(this, 10); + Q_CHECK_PTR(gm); + gm->addSpacing(15); + + gmSearch = new QHBoxLayout(); + Q_CHECK_PTR(gmSearch); + gm->addLayout(gmSearch, 0); + + // Create the table that lists the processes. + pList = new ProcessList(this, "pList"); + Q_CHECK_PTR(pList); + pList->setShowSortIndicator(true); + pListSearchLine = new KListViewSearchLineWidget(pList, this, "process_list_search_line"); + gmSearch->addWidget(pListSearchLine, 1); + + connect(pList, SIGNAL(killProcess(int, int)), + this, SLOT(killProcess(int, int))); + connect(pList, SIGNAL(reniceProcess(const QValueList<int> &, int)), + this, SLOT(reniceProcess(const QValueList<int> &, int))); + connect(pList, SIGNAL(listModified(bool)), + this, SLOT(setModified(bool))); + + /* Create the combo box to configure the process filter. The + * cbFilter must be created prior to constructing pList as the + * pList constructor sets cbFilter to its start value. */ + cbFilter = new QComboBox(this, "pList_cbFilter"); + Q_CHECK_PTR(cbFilter); + gmSearch->addWidget(cbFilter,0); + cbFilter->insertItem(i18n("All Processes"), 0); + cbFilter->insertItem(i18n("System Processes"), 1); + cbFilter->insertItem(i18n("User Processes"), 2); + cbFilter->insertItem(i18n("Own Processes"), 3); + cbFilter->setMinimumSize(cbFilter->sizeHint()); + // Create the check box to switch between tree view and list view. + xbTreeView = new QCheckBox(i18n("&Tree"), this, "xbTreeView"); + Q_CHECK_PTR(xbTreeView); + xbTreeView->setMinimumSize(xbTreeView->sizeHint()); + connect(xbTreeView, SIGNAL(toggled(bool)), + this, SLOT(setTreeView(bool))); + + + /* When the both cbFilter and pList are constructed we can connect the + * missing link. */ + connect(cbFilter, SIGNAL(activated(int)), + this, SLOT(filterModeChanged(int))); + + // Create the 'Refresh' button. + bRefresh = new KPushButton( KGuiItem( i18n( "&Refresh" ), "reload" ), + this, "bRefresh" ); + Q_CHECK_PTR(bRefresh); + bRefresh->setMinimumSize(bRefresh->sizeHint()); + connect(bRefresh, SIGNAL(clicked()), this, SLOT(updateList())); + + // Create the 'Kill' button. + bKill = new KPushButton(i18n("&Kill"), this, "bKill"); + Q_CHECK_PTR(bKill); + bKill->setMinimumSize(bKill->sizeHint()); + connect(bKill, SIGNAL(clicked()), this, SLOT(killProcess())); + /* Disable the kill button until we know that the daemon supports the + * kill command. */ + bKill->setEnabled(false); + killSupported = false; + + gm->addWidget(pList, 1); + + gm1 = new QHBoxLayout(); + Q_CHECK_PTR(gm1); + gm->addLayout(gm1, 0); + gm1->addStretch(); + gm1->addWidget(xbTreeView); + gm1->addStretch(); + gm1->addWidget(bRefresh); + gm1->addStretch(); + gm1->addWidget(bKill); + gm1->addStretch(); + gm->addSpacing(5); + + gm->activate(); + + setPlotterWidget(pList); + + setMinimumSize(sizeHint()); + fixTabOrder(); +} + +void ProcessController::setSearchFocus() { + //stupid search line widget. See rant in fixTabOrder + if(!pListSearchLine->searchLine()) + QTimer::singleShot(100, this, SLOT(setSearchFocus())); + else { + pListSearchLine->searchLine()->setFocus(); + } +} +void ProcessController::fixTabOrder() { + + //Wow, I hate this search line widget so much. + //It creates the searchline in a singleshot timer. This makes it totally unpredictable when searchLine is actually valid. + //So we set up singleshot timer and call ourselves over and over until it's ready. + // + //Did i mention I hate this? + if(!pListSearchLine->searchLine()) + QTimer::singleShot(100, this, SLOT(fixTabOrder())); + else { + setTabOrder(pListSearchLine->searchLine(), cbFilter); + setTabOrder(cbFilter, pList); + setTabOrder(pList, xbTreeView); + setTabOrder(xbTreeView, bRefresh); + setTabOrder(bRefresh, bKill); + } +} + +void +ProcessController::resizeEvent(QResizeEvent* ev) +{ + if(frame()) + frame()->setGeometry(0, 0, width(), height()); + + QWidget::resizeEvent(ev); +} + +bool +ProcessController::addSensor(const QString& hostName, + const QString& sensorName, + const QString& sensorType, + const QString& title) +{ + if (sensorType != "table") + return (false); + + registerSensor(new KSGRD::SensorProperties(hostName, sensorName, sensorType, title)); + /* This just triggers the first communication. The full set of + * requests are send whenever the sensor reconnects (detected in + * sensorError(). */ + + sendRequest(hostName, "test kill", 4); + + if (title.isEmpty()) + setTitle(i18n("%1: Running Processes").arg(hostName)); + else + setTitle(title); + + return (true); +} + +void +ProcessController::updateList() +{ + sendRequest(sensors().at(0)->hostName(), "ps", 2); +} + +void +ProcessController::killProcess(int pid, int sig) +{ + sendRequest(sensors().at(0)->hostName(), + QString("kill %1 %2" ).arg(pid).arg(sig), 3); + + if ( !timerOn() ) + // give ksysguardd time to update its proccess list + QTimer::singleShot(3000, this, SLOT(updateList())); + else + updateList(); +} + +void +ProcessController::killProcess() +{ + const QStringList& selectedAsStrings = pList->getSelectedAsStrings(); + if (selectedAsStrings.isEmpty()) + { + KMessageBox::sorry(this, + i18n("You need to select a process first.")); + return; + } + else + { + QString msg = i18n("Do you want to kill the selected process?", + "Do you want to kill the %n selected processes?", + selectedAsStrings.count()); + + KDialogBase *dlg = new KDialogBase ( i18n ("Kill Process"), + KDialogBase::Yes | KDialogBase::Cancel, + KDialogBase::Yes, KDialogBase::Cancel, this->parentWidget(), + "killconfirmation", + true, true, KGuiItem(i18n("Kill"))); + + bool dontAgain = false; + + int res = KMessageBox::createKMessageBox(dlg, QMessageBox::Question, + msg, selectedAsStrings, + i18n("Do not ask again"), &dontAgain, + KMessageBox::Notify); + + if (res != KDialogBase::Yes) + { + return; + } + } + + const QValueList<int>& selectedPIds = pList->getSelectedPIds(); + + // send kill signal to all seleted processes + QValueListConstIterator<int> it; + for (it = selectedPIds.begin(); it != selectedPIds.end(); ++it) + sendRequest(sensors().at(0)->hostName(), QString("kill %1 %2" ).arg(*it) + .arg(MENU_ID_SIGKILL), 3); + + if ( !timerOn()) + // give ksysguardd time to update its proccess list + QTimer::singleShot(3000, this, SLOT(updateList())); + else + updateList(); +} + +void +ProcessController::reniceProcess(const QValueList<int> &pids, int niceValue) +{ + for( QValueList<int>::ConstIterator it = pids.constBegin(), end = pids.constEnd(); it != end; ++it ) + sendRequest(sensors().at(0)->hostName(), + QString("setpriority %1 %2" ).arg(*it).arg(niceValue), 5); + sendRequest(sensors().at(0)->hostName(), "ps", 2); //update the display afterwards +} + +void +ProcessController::answerReceived(int id, const QString& answer) +{ + /* We received something, so the sensor is probably ok. */ + sensorError(id, false); + + switch (id) + { + case 1: + { + /* We have received the answer to a ps? command that contains + * the information about the table headers. */ + KSGRD::SensorTokenizer lines(answer, '\n'); + if (lines.count() != 2) + { + kdDebug (1215) << "ProcessController::answerReceived(1)" + "wrong number of lines [" << answer << "]" << endl; + sensorError(id, true); + return; + } + KSGRD::SensorTokenizer headers(lines[0], '\t'); + KSGRD::SensorTokenizer colTypes(lines[1], '\t'); + + pList->removeColumns(); + for (unsigned int i = 0; i < headers.count(); i++) + { + QString header; + if (dict[headers[i]]) + header = *dict[headers[i]]; + else + header = headers[i]; + pList->addColumn(header, colTypes[i]); + } + + break; + } + case 2: + /* We have received the answer to a ps command that contains a + * list of processes with various additional information. */ + pList->update(answer); + pListSearchLine->searchLine()->updateSearch(); //re-apply the filter + break; + case 3: + { + // result of kill operation + kdDebug(1215) << answer << endl; + KSGRD::SensorTokenizer vals(answer, '\t'); + switch (vals[0].toInt()) + { + case 0: // successful kill operation + break; + case 1: // unknown error + KSGRD::SensorMgr->notify( + i18n("Error while attempting to kill process %1.") + .arg(vals[1])); + break; + case 2: + KSGRD::SensorMgr->notify( + i18n("Insufficient permissions to kill " + "process %1.").arg(vals[1])); + break; + case 3: + KSGRD::SensorMgr->notify( + i18n("Process %1 has already disappeared.") + .arg(vals[1])); + break; + case 4: + KSGRD::SensorMgr->notify(i18n("Invalid Signal.")); + break; + } + break; + } + case 4: + killSupported = (answer.toInt() == 1); + pList->setKillSupported(killSupported); + bKill->setEnabled(killSupported); + break; + case 5: + { + // result of renice operation + kdDebug(1215) << answer << endl; + KSGRD::SensorTokenizer vals(answer, '\t'); + switch (vals[0].toInt()) + { + case 0: // successful renice operation + break; + case 1: // unknown error + KSGRD::SensorMgr->notify( + i18n("Error while attempting to renice process %1.") + .arg(vals[1])); + break; + case 2: + KSGRD::SensorMgr->notify( + i18n("Insufficient permissions to renice " + "process %1.").arg(vals[1])); + break; + case 3: + KSGRD::SensorMgr->notify( + i18n("Process %1 has already disappeared.") + .arg(vals[1])); + break; + case 4: + KSGRD::SensorMgr->notify(i18n("Invalid argument.")); + break; + } + break; + } + } +} + +void +ProcessController::sensorError(int, bool err) +{ + if (err == sensors().at(0)->isOk()) + { + if (!err) + { + /* Whenever the communication with the sensor has been + * (re-)established we need to requests the full set of + * properties again, since the back-end might be a new + * one. */ + sendRequest(sensors().at(0)->hostName(), "test kill", 4); + sendRequest(sensors().at(0)->hostName(), "ps?", 1); + sendRequest(sensors().at(0)->hostName(), "ps", 2); + } + + /* This happens only when the sensorOk status needs to be changed. */ + sensors().at(0)->setIsOk( !err ); + } + setSensorOk(sensors().at(0)->isOk()); +} + +bool +ProcessController::restoreSettings(QDomElement& element) +{ + bool result = addSensor(element.attribute("hostName"), + element.attribute("sensorName"), (element.attribute("sensorType").isEmpty() ? "table" : element.attribute("sensorType")), + QString::null); + + xbTreeView->setChecked(element.attribute("tree").toInt()); + setTreeView(element.attribute("tree").toInt()); + + uint filter = element.attribute("filter").toUInt(); + cbFilter->setCurrentItem(filter); + filterModeChanged(filter); + + uint col = element.attribute("sortColumn").toUInt(); + bool inc = element.attribute("incrOrder").toUInt(); + + if (!pList->load(element)) + return (false); + + pList->setSortColumn(col, inc); + + SensorDisplay::restoreSettings(element); + + setModified(false); + + return (result); +} + +bool +ProcessController::saveSettings(QDomDocument& doc, QDomElement& element, bool save) +{ + element.setAttribute("hostName", sensors().at(0)->hostName()); + element.setAttribute("sensorName", sensors().at(0)->name()); + element.setAttribute("sensorType", sensors().at(0)->type()); + element.setAttribute("tree", (uint) xbTreeView->isChecked()); + element.setAttribute("filter", cbFilter->currentItem()); + element.setAttribute("sortColumn", pList->getSortColumn()); + element.setAttribute("incrOrder", pList->getIncreasing()); + + if (!pList->save(doc, element)) + return (false); + + SensorDisplay::saveSettings(doc, element); + + if (save) + setModified(false); + + return (true); +} diff --git a/ksysguard/gui/SensorDisplayLib/ProcessController.h b/ksysguard/gui/SensorDisplayLib/ProcessController.h new file mode 100644 index 000000000..f834efbb6 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ProcessController.h @@ -0,0 +1,154 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef _ProcessController_h_ +#define _ProcessController_h_ + +#include <qdict.h> +#include <qwidget.h> + +#include <kapplication.h> + +#include <SensorDisplay.h> + +#include "ProcessList.h" + +class QVBoxLayout; +class QHBoxLayout; +class QCheckBox; +class QComboBox; +class KPushButton; +class KListViewSearchLineWidget; + +extern KApplication* Kapp; + +/** + * This widget implements a process list page. Besides the process + * list which is implemented as a ProcessList, it contains two + * comboxes and two buttons. The combo boxes are used to set the + * update rate and the process filter. The buttons are used to force + * an immediate update and to kill a process. + */ +class ProcessController : public KSGRD::SensorDisplay +{ + Q_OBJECT + +public: + ProcessController(QWidget* parent = 0, const char* name = 0, const QString &title = QString::null, bool nf = false); + virtual ~ProcessController() { } + + void resizeEvent(QResizeEvent*); + + bool restoreSettings(QDomElement& element); + + bool saveSettings(QDomDocument& doc, QDomElement& element, bool save = true); + + void refreshList(void) + { + updateList(); + } + + virtual void timerEvent(QTimerEvent*) + { + updateList(); + } + + virtual bool addSensor(const QString&, const QString&, const QString&, const QString&); + + virtual void answerReceived(int id, const QString& answer); + + virtual void sensorError(int, bool err); + + void configureSettings() { } + + virtual bool hasSettingsDialog() const + { + return (false); + } + +public slots: + void setSearchFocus(); + void fixTabOrder(); + void filterModeChanged(int filter) + { + pList->setFilterMode(filter); + updateList(); + setModified(true); + } + + void setTreeView(bool tv) + { + pList->setTreeView(tv); + updateList(); + setModified(true); + } + + virtual void setModified(bool mfd) + { + if (mfd != modified()) + { + SensorDisplay::setModified( mfd ); + if (!mfd) + pList->setModified(0); + emit modified(modified()); + } + } + + void killProcess(); + void killProcess(int pid, int sig); + + void reniceProcess(const QValueList<int> &pids, int niceValue); + + void updateList(); + +signals: + void setFilterMode(int); + +private: + QVBoxLayout* gm; + + bool killSupported; + + /// The process list. + ProcessList* pList; + ///Layout for the search line and process filter combo box + QHBoxLayout* gmSearch; + KListViewSearchLineWidget *pListSearchLine; + + QHBoxLayout* gm1; + + /// Checkbox to switch between tree and list view + QCheckBox* xbTreeView; + + /// This combo boxes control the process filter. + QComboBox* cbFilter; + + /// These buttons force an immedeate refresh or kill a process. + KPushButton* bRefresh; + KPushButton* bKill; + + /// Dictionary for header translations. + QDict<QString> dict; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/ProcessList.cc b/ksysguard/gui/SensorDisplayLib/ProcessList.cc new file mode 100644 index 000000000..6d158c872 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ProcessList.cc @@ -0,0 +1,941 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (C) 1997 Bernd Johannes Wuebben + <wuebben@math.cornell.edu> + + Copyright (C) 1998 Nicolas Leclercq <nicknet@planete.net> + + Copyright (c) 1999, 2000, 2001, 2002 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <assert.h> +#include <config.h> +#include <ctype.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#include <qbitmap.h> +#include <qheader.h> +#include <qimage.h> +#include <qpopupmenu.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include "ProcessController.h" +#include "ProcessList.h" +#include "ReniceDlg.h" +#include "SignalIDs.h" + +#define NONE -1 +#define INIT_PID 1 + +//extern const char* intKey(const char* text); +//extern const char* timeKey(const char* text); +//extern const char* floatKey(const char* text); + +QDict<QString> ProcessList::aliases; + +int ProcessLVI::compare( QListViewItem *item, int col, bool ascending ) const +{ + int type = ((ProcessList*)listView())->columnType( col ); + + if ( type == ProcessList::Int ) { + int prev = (int)KGlobal::locale()->readNumber( key( col, ascending ) ); + int next = (int)KGlobal::locale()->readNumber( item->key( col, ascending ) ); + if ( prev < next ) + return -1; + else if ( prev == next ) + return 0; + else + return 1; + } + + if ( type == ProcessList::Float ) { + double prev = KGlobal::locale()->readNumber( key( col, ascending ) ); + double next = KGlobal::locale()->readNumber( item->key( col, ascending ) ); + if ( prev < next ) + return -1; + else + return 1; + } + + if ( type == ProcessList::Time ) { + int hourPrev, hourNext, minutesPrev, minutesNext; + sscanf( key( col, ascending ).latin1(), "%d:%d", &hourPrev, &minutesPrev ); + sscanf( item->key( col, ascending ).latin1(), "%d:%d", &hourNext, &minutesNext ); + int prev = hourPrev * 60 + minutesPrev; + int next = hourNext * 60 + minutesNext; + if ( prev < next ) + return -1; + else if ( prev == next ) + return 0; + else + return 1; + } + + return key( col, ascending ).localeAwareCompare( item->key( col, ascending ) ); +} + +ProcessList::ProcessList(QWidget *parent, const char* name) + : KListView(parent, name) +{ + iconCache.setAutoDelete(true); + + columnDict.setAutoDelete(true); + columnDict.insert("running", + new QString(i18n("process status", "running"))); + columnDict.insert("sleeping", + new QString(i18n("process status", "sleeping"))); + columnDict.insert("disk sleep", + new QString(i18n("process status", "disk sleep"))); + columnDict.insert("zombie", new QString(i18n("process status", "zombie"))); + columnDict.insert("stopped", + new QString(i18n("process status", "stopped"))); + columnDict.insert("paging", new QString(i18n("process status", "paging"))); + columnDict.insert("idle", new QString(i18n("process status", "idle"))); + + if (aliases.isEmpty()) + { +#ifdef Q_OS_LINUX + aliases.insert("init", new QString("penguin")); +#else + aliases.insert("init", new QString("system")); +#endif + /* kernel stuff */ + aliases.insert("bdflush", new QString("kernel")); + aliases.insert("dhcpcd", new QString("kernel")); + aliases.insert("kapm-idled", new QString("kernel")); + aliases.insert("keventd", new QString("kernel")); + aliases.insert("khubd", new QString("kernel")); + aliases.insert("klogd", new QString("kernel")); + aliases.insert("kreclaimd", new QString("kernel")); + aliases.insert("kreiserfsd", new QString("kernel")); + aliases.insert("ksoftirqd_CPU0", new QString("kernel")); + aliases.insert("ksoftirqd_CPU1", new QString("kernel")); + aliases.insert("ksoftirqd_CPU2", new QString("kernel")); + aliases.insert("ksoftirqd_CPU3", new QString("kernel")); + aliases.insert("ksoftirqd_CPU4", new QString("kernel")); + aliases.insert("ksoftirqd_CPU5", new QString("kernel")); + aliases.insert("ksoftirqd_CPU6", new QString("kernel")); + aliases.insert("ksoftirqd_CPU7", new QString("kernel")); + aliases.insert("kswapd", new QString("kernel")); + aliases.insert("kupdated", new QString("kernel")); + aliases.insert("mdrecoveryd", new QString("kernel")); + aliases.insert("scsi_eh_0", new QString("kernel")); + aliases.insert("scsi_eh_1", new QString("kernel")); + aliases.insert("scsi_eh_2", new QString("kernel")); + aliases.insert("scsi_eh_3", new QString("kernel")); + aliases.insert("scsi_eh_4", new QString("kernel")); + aliases.insert("scsi_eh_5", new QString("kernel")); + aliases.insert("scsi_eh_6", new QString("kernel")); + aliases.insert("scsi_eh_7", new QString("kernel")); + /* daemon and other service providers */ + aliases.insert("artsd", new QString("daemon")); + aliases.insert("atd", new QString("daemon")); + aliases.insert("automount", new QString("daemon")); + aliases.insert("cardmgr", new QString("daemon")); + aliases.insert("cron", new QString("daemon")); + aliases.insert("cupsd", new QString("daemon")); + aliases.insert("in.identd", new QString("daemon")); + aliases.insert("lpd", new QString("daemon")); + aliases.insert("mingetty", new QString("daemon")); + aliases.insert("nscd", new QString("daemon")); + aliases.insert("portmap", new QString("daemon")); + aliases.insert("rpc.statd", new QString("daemon")); + aliases.insert("rpciod", new QString("daemon")); + aliases.insert("sendmail", new QString("daemon")); + aliases.insert("sshd", new QString("daemon")); + aliases.insert("syslogd", new QString("daemon")); + aliases.insert("usbmgr", new QString("daemon")); + aliases.insert("wwwoffled", new QString("daemon")); + aliases.insert("xntpd", new QString("daemon")); + aliases.insert("ypbind", new QString("daemon")); + /* kde applications */ + aliases.insert("appletproxy", new QString("kdeapp")); + aliases.insert("dcopserver", new QString("kdeapp")); + aliases.insert("kcookiejar", new QString("kdeapp")); + aliases.insert("kde", new QString("kdeapp")); + aliases.insert("kded", new QString("kdeapp")); + aliases.insert("kdeinit", new QString("kdeapp")); + aliases.insert("kdesktop", new QString("kdeapp")); + aliases.insert("kdesud", new QString("kdeapp")); + aliases.insert("kdm", new QString("kdeapp")); + aliases.insert("khotkeys", new QString("kdeapp")); + aliases.insert("kio_file", new QString("kdeapp")); + aliases.insert("kio_uiserver", new QString("kdeapp")); + aliases.insert("klauncher", new QString("kdeapp")); + aliases.insert("ksmserver", new QString("kdeapp")); + aliases.insert("kwrapper", new QString("kdeapp")); + aliases.insert("kwrited", new QString("kdeapp")); + aliases.insert("kxmlrpcd", new QString("kdeapp")); + aliases.insert("startkde", new QString("kdeapp")); + /* other processes */ + aliases.insert("bash", new QString("shell")); + aliases.insert("cat", new QString("tools")); + aliases.insert("egrep", new QString("tools")); + aliases.insert("emacs", new QString("wordprocessing")); + aliases.insert("fgrep", new QString("tools")); + aliases.insert("find", new QString("tools")); + aliases.insert("grep", new QString("tools")); + aliases.insert("ksh", new QString("shell")); + aliases.insert("screen", new QString("openterm")); + aliases.insert("sh", new QString("shell")); + aliases.insert("sort", new QString("tools")); + aliases.insert("ssh", new QString("shell")); + aliases.insert("su", new QString("tools")); + aliases.insert("tcsh", new QString("shell")); + aliases.insert("tee", new QString("tools")); + aliases.insert("vi", new QString("wordprocessing")); + } + + /* The filter mode is controlled by a combo box of the parent. If + * the mode is changed we get a signal. */ + connect(parent, SIGNAL(setFilterMode(int)), + this, SLOT(setFilterMode(int))); + + /* We need to catch this signal to show various popup menues. */ + connect(this, + SIGNAL(rightButtonPressed(QListViewItem*, const QPoint&, int)), + this, + SLOT(handleRMBPressed(QListViewItem*, const QPoint&, int))); + + /* Since Qt does not tell us the sorting details we have to do our + * own bookkeping, so we can save and restore the sorting + * settings. */ + connect(header(), SIGNAL(clicked(int)), this, SLOT(sortingChanged(int))); + + treeViewEnabled = false; + openAll = true; + + filterMode = FILTER_ALL; + + sortColumn = 1; + increasing = false; + + // Elements in the process list may only live in this list. + pl.setAutoDelete(true); + + setItemMargin(2); + setAllColumnsShowFocus(true); + setTreeStepSize(17); + setSorting(sortColumn, increasing); + setSelectionMode(QListView::Extended); + + // Create popup menu for RMB clicks on table header + headerPM = new QPopupMenu(); + headerPM->insertItem(i18n("Remove Column"), HEADER_REMOVE); + headerPM->insertItem(i18n("Add Column"), HEADER_ADD); + headerPM->insertItem(i18n("Help on Column"), HEADER_HELP); + + connect(header(), SIGNAL(sizeChange(int, int, int)), + this, SLOT(sizeChanged(int, int, int))); + connect(header(), SIGNAL(indexChange(int, int, int)), + this, SLOT(indexChanged(int, int, int))); + + killSupported = false; + setModified(false); +} + +ProcessList::~ProcessList() +{ + delete(headerPM); +} + +const QValueList<int>& +ProcessList::getSelectedPIds() +{ + selectedPIds.clear(); + // iterate through all selected visible items of the listview + QListViewItemIterator it(this, QListViewItemIterator::Visible | QListViewItemIterator::Selected ); + for ( ; it.current(); ++it ) + selectedPIds.append(it.current()->text(1).toInt()); + + return (selectedPIds); +} + +const QStringList& +ProcessList::getSelectedAsStrings() +{ + selectedAsStrings.clear(); + // iterate through all selected visible items of the listview + QListViewItemIterator it(this, QListViewItemIterator::Visible | QListViewItemIterator::Selected ); + QString spaces; + for ( ; it.current(); ++it ) { + spaces.fill(QChar(' '), 7 - it.current()->text(1).length()); + selectedAsStrings.append("(PID: " + it.current()->text(1) + ")" + spaces + " " + it.current()->text(0)); + } + + return (selectedAsStrings); +} +bool +ProcessList::update(const QString& list) +{ + /* Disable painting to avoid flickering effects, + * especially when in tree view mode. + * Ditto for the scrollbar. */ + setUpdatesEnabled(false); + viewport()->setUpdatesEnabled(false); + + pl.clear(); + + // Convert ps answer in a list of tokenized lines + KSGRD::SensorTokenizer procs(list, '\n'); + for (unsigned int i = 0; i < procs.count(); i++) + { + KSGRD::SensorPSLine* line = new KSGRD::SensorPSLine(procs[i]); + if (line->count() != (uint) columns()) + { +#if 0 + // This is needed for debugging only. + kdDebug(1215) << list << endl; + QString l; + for (uint j = 0; j < line->count(); j++) + l += (*line)[j] + "|"; + kdDebug(1215) << "Incomplete ps line:" << l << endl; +#endif + return (false); + } + else + pl.append(line); + } + + int currItemPos = itemPos(currentItem()); + int vpos = verticalScrollBar()->value(); + int hpos = horizontalScrollBar()->value(); + + updateMetaInfo(); + + clear(); + + if (treeViewEnabled) + buildTree(); + else + buildList(); + + QListViewItemIterator it( this ); + while ( it.current() ) { + if ( itemPos( it.current() ) == currItemPos ) { + setCurrentItem( it.current() ); + break; + } + ++it; + } + + verticalScrollBar()->setValue(vpos); + horizontalScrollBar()->setValue(hpos); + + // Re-enable painting, and force an update. + setUpdatesEnabled(true); + viewport()->setUpdatesEnabled(true); + + triggerUpdate(); + + return (true); +} + +void +ProcessList::setTreeView(bool tv) +{ + if (treeViewEnabled = tv) + { + savedWidth[0] = columnWidth(0); + openAll = true; + } + else + { + /* In tree view the first column is wider than in list view mode. + * So we shrink it to 1 pixel. The next update will resize it again + * appropriately. */ + setColumnWidth(0, savedWidth[0]); + } + /* In tree view mode borders are added to the icons. So we have to clear + * the cache when we change the tree view mode. */ + iconCache.clear(); +} + +bool +ProcessList::load(QDomElement& el) +{ + QDomNodeList dnList = el.elementsByTagName("column"); + for (uint i = 0; i < dnList.count(); ++i) + { + QDomElement lel = dnList.item(i).toElement(); + if (savedWidth.count() <= i) + savedWidth.append(lel.attribute("savedWidth").toInt()); + else + savedWidth[i] = lel.attribute("savedWidth").toInt(); + if (currentWidth.count() <= i) + currentWidth.append(lel.attribute("currentWidth").toInt()); + else + currentWidth[i] = lel.attribute("currentWidth").toInt(); + if (index.count() <= i) + index.append(lel.attribute("index").toInt()); + else + index[i] = lel.attribute("index").toInt(); + } + + setModified(false); + + return (true); +} + +bool +ProcessList::save(QDomDocument& doc, QDomElement& display) +{ + for (int i = 0; i < columns(); ++i) + { + QDomElement col = doc.createElement("column"); + display.appendChild(col); + col.setAttribute("currentWidth", columnWidth(i)); + col.setAttribute("savedWidth", savedWidth[i]); + col.setAttribute("index", header()->mapToIndex(i)); + } + + setModified(false); + + return (true); +} + +void +ProcessList::sortingChanged(int col) +{ + if (col == sortColumn) + increasing = !increasing; + else + { + sortColumn = col; + increasing = true; + } + setSorting(sortColumn, increasing); + setModified(true); +} + +int ProcessList::columnType( uint pos ) const +{ + if ( pos >= mColumnTypes.count() ) + return 0; + + if ( mColumnTypes[ pos ] == "d" || mColumnTypes[ pos ] == "D" ) + return Int; + else if ( mColumnTypes[ pos ] == "f" || mColumnTypes[ pos ] == "F" ) + return Float; + else if ( mColumnTypes[ pos ] == "t" ) + return Time; + else + return Text; +} + +bool +ProcessList::matchesFilter(KSGRD::SensorPSLine* p) const +{ + // This mechanism is likely to change in the future! + + switch (filterMode) + { + case FILTER_ALL: + return (true); + + case FILTER_SYSTEM: + return (p->uid() < 100 ? true : false); + + case FILTER_USER: + return (p->uid() >= 100 ? true : false); + + case FILTER_OWN: + default: + return (p->uid() == (long) getuid() ? true : false); + } +} + +void +ProcessList::buildList() +{ + /* Get the first process in the list, check whether it matches the + * filter and append it to QListView widget if so. */ + while (!pl.isEmpty()) + { + KSGRD::SensorPSLine* p = pl.first(); + + if (matchesFilter(p)) + { + ProcessLVI* pli = new ProcessLVI(this); + + addProcess(p, pli); + + if (selectedPIds.findIndex(p->pid()) != -1) + pli->setSelected(true); + } + pl.removeFirst(); + } +} + +void +ProcessList::buildTree() +{ + // remove all leaves that do not match the filter + deleteLeaves(); + + KSGRD::SensorPSLine* ps = pl.first(); + + while (ps) + { + if (ps->pid() == INIT_PID) + { + // insert root item into the tree widget + ProcessLVI* pli = new ProcessLVI(this); + addProcess(ps, pli); + + // remove the process from the process list, ps is now invalid + int pid = ps->pid(); + pl.remove(); + + if (selectedPIds.findIndex(pid) != -1) + pli->setSelected(true); + + // insert all child processes of current process + extendTree(&pl, pli, pid); + break; + } + else + ps = pl.next(); + } +} + +void +ProcessList::deleteLeaves(void) +{ + for ( ; ; ) + { + unsigned int i; + for (i = 0; i < pl.count() && + (!isLeafProcess(pl.at(i)->pid()) || + matchesFilter(pl.at(i))); i++) + ; + if (i == pl.count()) + return; + + pl.remove(i); + } +} + +bool +ProcessList::isLeafProcess(int pid) +{ + for (unsigned int i = 0; i < pl.count(); i++) + if (pl.at(i)->ppid() == pid) + return (false); + + return (true); +} + +void +ProcessList::extendTree(QPtrList<KSGRD::SensorPSLine>* pl, ProcessLVI* parent, int ppid) +{ + KSGRD::SensorPSLine* ps; + + // start at top list + ps = pl->first(); + + while (ps) + { + // look for a child process of the current parent + if (ps->ppid() == ppid) + { + ProcessLVI* pli = new ProcessLVI(parent); + + addProcess(ps, pli); + + if (selectedPIds.findIndex(ps->pid()) != -1) + pli->setSelected(true); + + if (ps->ppid() != INIT_PID && closedSubTrees.findIndex(ps->ppid()) != -1) + parent->setOpen(false); + else + parent->setOpen(true); + + // remove the process from the process list, ps is now invalid + int pid = ps->pid(); + pl->remove(); + + // now look for the childs of the inserted process + extendTree(pl, pli, pid); + + /* Since buildTree can remove processes from the list we + * can't find a "current" process. So we start searching + * at the top again. It's no endless loops since this + * branch is only entered when there are children of the + * current parent in the list. When we have removed them + * all the while loop will exit. */ + ps = pl->first(); + } + else + ps = pl->next(); + } +} +void +ProcessList::addProcess(KSGRD::SensorPSLine* p, ProcessLVI* pli) +{ + QString name = p->name(); + if (aliases[name]) + name = *aliases[name]; + + /* Get icon from icon list that might be appropriate for a process + * with this name. */ + QPixmap pix; + if (!iconCache[name]) + { + pix = KGlobal::iconLoader()->loadIcon(name, KIcon::Small, + KIcon::SizeSmall, KIcon::DefaultState, + 0L, true); + if (pix.isNull() || !pix.mask()) + pix = KGlobal::iconLoader()->loadIcon("unknownapp", KIcon::User, + KIcon::SizeSmall); + + if (pix.width() != 16 || pix.height() != 16) + { + /* I guess this isn't needed too often. The KIconLoader should + * scale the pixmaps already appropriately. Since I got a bug + * report claiming that it doesn't work with GNOME apps I've + * added this safeguard. */ + QImage img; + img = pix; + img.smoothScale(16, 16); + pix = img; + } + /* We copy the icon into a 24x16 pixmap to add a 4 pixel margin on + * the left and right side. In tree view mode we use the original + * icon. */ + QPixmap icon(24, 16, pix.depth()); + if (!treeViewEnabled) + { + icon.fill(); + bitBlt(&icon, 4, 0, &pix, 0, 0, pix.width(), pix.height()); + QBitmap mask(24, 16, true); + bitBlt(&mask, 4, 0, pix.mask(), 0, 0, pix.width(), pix.height()); + icon.setMask(mask); + pix = icon; + } + iconCache.insert(name, new QPixmap(pix)); + } + else + pix = *(iconCache[name]); + + // icon + process name + pli->setPixmap(0, pix); + pli->setText(0, p->name()); + + // insert remaining field into table + for (unsigned int col = 1; col < p->count(); col++) + { + if (mColumnTypes[col] == "S" && columnDict[(*p)[col]]) + pli->setText(col, *columnDict[(*p)[col]]); + else if ( mColumnTypes[col] == "f" ) + pli->setText( col, KGlobal::locale()->formatNumber( (*p)[col].toFloat() ) ); + else if ( mColumnTypes[col] == "D" ) + pli->setText( col, KGlobal::locale()->formatNumber( (*p)[col].toInt(), 0 ) ); + else + pli->setText(col, (*p)[col]); + } +} + +void +ProcessList::updateMetaInfo(void) +{ + selectedPIds.clear(); + closedSubTrees.clear(); + + QListViewItemIterator it(this); + + // iterate through all items of the listview + for ( ; it.current(); ++it ) + { + if (it.current()->isSelected() && it.current()->isVisible()) + selectedPIds.append(it.current()->text(1).toInt()); + if (treeViewEnabled && !it.current()->isOpen()) + closedSubTrees.append(it.current()->text(1).toInt()); + } + + /* In list view mode all list items are set to closed by QListView. + * If the tree view is now selected, all item will be closed. This is + * annoying. So we use the openAll flag to force all trees to open when + * the treeViewEnbled flag was set to true. */ + if (openAll) + { + if (treeViewEnabled) + closedSubTrees.clear(); + openAll = false; + } +} + +void +ProcessList::removeColumns(void) +{ + for (int i = columns() - 1; i >= 0; --i) + removeColumn(i); +} + +void +ProcessList::addColumn(const QString& label, const QString& type) +{ + QListView::addColumn(label); + uint col = columns() - 1; + if (type == "s" || type == "S") + setColumnAlignment(col, AlignLeft); + else if (type == "d" || type == "D") + setColumnAlignment(col, AlignRight); + else if (type == "t") + setColumnAlignment(col, AlignRight); + else if (type == "f") + setColumnAlignment(col, AlignRight); + else + { + kdDebug(1215) << "Unknown type " << type << " of column " << label + << " in ProcessList!" << endl; + return; + } + + mColumnTypes.append(type); + + /* Just use some sensible default values as initial setting. */ + QFontMetrics fm = fontMetrics(); + setColumnWidth(col, fm.width(label) + 10); + + if (currentWidth.count() - 1 == col) + { + /* Table has been loaded from file. We can restore the settings + * when the last column has been added. */ + for (uint i = 0; i < col; ++i) + { + /* In case the language has been changed the column width + * might need to be increased. */ + if (currentWidth[i] == 0) + { + if (fm.width(header()->label(i)) + 10 > savedWidth[i]) + savedWidth[i] = fm.width(header()->label(i)) + 10; + setColumnWidth(i, 0); + } + else + { + if (fm.width(header()->label(i)) + 10 > currentWidth[i]) + setColumnWidth(i, fm.width(header()->label(i)) + 10); + else + setColumnWidth(i, currentWidth[i]); + } + setColumnWidthMode(i, currentWidth[i] == 0 ? + QListView::Manual : QListView::Maximum); + header()->moveSection(i, index[i]); + } + setSorting(sortColumn, increasing); + } +} + +void +ProcessList::handleRMBPressed(QListViewItem* lvi, const QPoint& p, int col) +{ + if (!lvi) + return; + + lvi->setSelected( true ); + + /* lvi is only valid until the next time we hit the main event + * loop. So we need to save the information we need after calling + * processPM->exec(). */ + int currentPId = lvi->text(1).toInt(); + + int currentNiceValue = 0; + for (int i = 0; i < columns(); ++i) + if (QString::compare(header()->label(i), i18n("Nice")) == 0) + currentNiceValue = lvi->text(i).toInt(); + + QPopupMenu processPM; + if (columnWidth(col) != 0) + processPM.insertItem(i18n("Hide Column"), 5); + QPopupMenu* hiddenPM = new QPopupMenu(&processPM); + for (int i = 0; i < columns(); ++i) + if (columnWidth(i) == 0) + hiddenPM->insertItem(header()->label(i), i + 100); + if(columns()) + processPM.insertItem(i18n("Show Column"), hiddenPM); + + processPM.insertSeparator(); + + processPM.insertItem(i18n("Select All Processes"), 1); + processPM.insertItem(i18n("Unselect All Processes"), 2); + + QPopupMenu* signalPM = new QPopupMenu(&processPM); + if (killSupported && lvi->isSelected()) + { + processPM.insertSeparator(); + processPM.insertItem(i18n("Select All Child Processes"), 3); + processPM.insertItem(i18n("Unselect All Child Processes"), 4); + + signalPM->insertItem(i18n("SIGABRT"), MENU_ID_SIGABRT); + signalPM->insertItem(i18n("SIGALRM"), MENU_ID_SIGALRM); + signalPM->insertItem(i18n("SIGCHLD"), MENU_ID_SIGCHLD); + signalPM->insertItem(i18n("SIGCONT"), MENU_ID_SIGCONT); + signalPM->insertItem(i18n("SIGFPE"), MENU_ID_SIGFPE); + signalPM->insertItem(i18n("SIGHUP"), MENU_ID_SIGHUP); + signalPM->insertItem(i18n("SIGILL"), MENU_ID_SIGILL); + signalPM->insertItem(i18n("SIGINT"), MENU_ID_SIGINT); + signalPM->insertItem(i18n("SIGKILL"), MENU_ID_SIGKILL); + signalPM->insertItem(i18n("SIGPIPE"), MENU_ID_SIGPIPE); + signalPM->insertItem(i18n("SIGQUIT"), MENU_ID_SIGQUIT); + signalPM->insertItem(i18n("SIGSEGV"), MENU_ID_SIGSEGV); + signalPM->insertItem(i18n("SIGSTOP"), MENU_ID_SIGSTOP); + signalPM->insertItem(i18n("SIGTERM"), MENU_ID_SIGTERM); + signalPM->insertItem(i18n("SIGTSTP"), MENU_ID_SIGTSTP); + signalPM->insertItem(i18n("SIGTTIN"), MENU_ID_SIGTTIN); + signalPM->insertItem(i18n("SIGTTOU"), MENU_ID_SIGTTOU); + signalPM->insertItem(i18n("SIGUSR1"), MENU_ID_SIGUSR1); + signalPM->insertItem(i18n("SIGUSR2"), MENU_ID_SIGUSR2); + + processPM.insertSeparator(); + processPM.insertItem(i18n("Send Signal"), signalPM); + } + + /* differ between killSupported and reniceSupported in a future + * version. */ + if (killSupported && lvi->isSelected()) + { + processPM.insertSeparator(); + processPM.insertItem(i18n("Renice Process..."), 300); + } + + int id; + switch (id = processPM.exec(p)) + { + case -1: + break; + case 1: + case 2: + selectAllItems(id & 1); + break; + case 3: + case 4: + selectAllChilds(currentPId, id & 1); + break; + case 5: + setColumnWidthMode(col, QListView::Manual); + savedWidth[col] = columnWidth(col); + setColumnWidth(col, 0); + setModified(true); + break; + case 300: + { + ReniceDlg reniceDlg(this, "reniceDlg", currentNiceValue, currentPId); + + int reniceVal; + if ((reniceVal = reniceDlg.exec()) != 40) { + emit reniceProcess(selectedPIds, reniceVal); + } + } + break; + default: + /* IDs < 100 are used for signals. */ + if (id < 100) + { + /* we go through list to get all task also + when update interval is paused */ + selectedPIds.clear(); + QListViewItemIterator it(this, QListViewItemIterator::Visible | QListViewItemIterator::Selected); + + // iterate through all selected visible items of the listview + for ( ; it.current(); ++it ) + { + selectedPIds.append(it.current()->text(1).toInt()); + } + + QString msg = i18n("Do you really want to send signal %1 to the selected process?", + "Do you really want to send signal %1 to the %n selected processes?", + selectedPIds.count()) + .arg(signalPM->text(id)); + int answ; + switch(answ = KMessageBox::questionYesNo(this, msg, QString::null, i18n("Send"), KStdGuiItem::cancel())) + { + case KMessageBox::Yes: + { + QValueList<int>::Iterator it; + for (it = selectedPIds.begin(); it != selectedPIds.end(); ++it) + emit (killProcess(*it, id)); + break; + } + default: + break; + } + } + else + { + /* IDs >= 100 are used for hidden columns. */ + int col = id - 100; + setColumnWidthMode(col, QListView::Maximum); + setColumnWidth(col, savedWidth[col]); + setModified(true); + } + } +} + +void +ProcessList::selectAllItems(bool select) +{ + selectedPIds.clear(); + + QListViewItemIterator it(this, QListViewItemIterator::Visible); + + // iterate through all items of the listview + for ( ; it.current(); ++it ) + { + it.current()->setSelected(select); + repaintItem(it.current()); + if (select) + selectedPIds.append(it.current()->text(1).toInt()); + } +} + +void +ProcessList::selectAllChilds(int pid, bool select) +{ + QListViewItemIterator it(this, QListViewItemIterator::Visible ); + + // iterate through all items of the listview + for ( ; it.current(); ++it ) + { + // Check if PPID matches the pid (current is a child of pid) + if (it.current()->text(2).toInt() == pid) + { + int currPId = it.current()->text(1).toInt(); + it.current()->setSelected(select); + repaintItem(it.current()); + if (select) + selectedPIds.append(currPId); + else + selectedPIds.remove(currPId); + selectAllChilds(currPId, select); + } + } +} + +#include "ProcessList.moc" diff --git a/ksysguard/gui/SensorDisplayLib/ProcessList.h b/ksysguard/gui/SensorDisplayLib/ProcessList.h new file mode 100644 index 000000000..b3f484484 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ProcessList.h @@ -0,0 +1,270 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me + first. Thanks! + + */ + +#ifndef _ProcessList_h_ +#define _ProcessList_h_ + +#include <qdict.h> +#include <qdom.h> +#include <qstringlist.h> +#include <qvaluelist.h> +#include <qwidget.h> + +#include <kiconloader.h> +#include <klistview.h> + +#include "SensorClient.h" + +typedef const char* (*KeyFunc)(const char*); + +/** + * To support bi-directional sorting, and sorting of text, integers etc. we + * need a specialized version of QListViewItem. + */ +class ProcessLVI : public KListViewItem +{ +public: + ProcessLVI(QListView* lv) : KListViewItem(lv) { } + ProcessLVI(QListViewItem* lvi) : KListViewItem(lvi) { } + + virtual int compare( QListViewItem *item, int column, bool ) const; +}; + +class QPopupMenu; + +/** + * This class implementes a table filled with information about the running + * processes. The table is derived from QListView. + */ +class ProcessList : public KListView +{ + Q_OBJECT + +public: + // possible values for the filter mode + enum + { + FILTER_ALL = 0, + FILTER_SYSTEM, + FILTER_USER, + FILTER_OWN + }; + + enum ColumnType { Text, Int, Float, Time }; + + /// The constructor. + ProcessList(QWidget* parent = 0, const char* name = 0); + + /// The destructor. + ~ProcessList(); + + void removeColumns(); + + void addColumn(const QString& header, const QString& type); + + void setSortColumn(uint col, bool inc) + { + sortColumn = col; + increasing = inc; + setSorting(col, inc); + } + + uint getSortColumn() const + { + return sortColumn; + } + + bool getIncreasing() const + { + return increasing; + } + + const QValueList<int>& getSelectedPIds(); + const QStringList& getSelectedAsStrings(); + + /** + * The udpate function can be used to update the displayed process + * list. A current list of processes is requested from the OS. In + * case the list contains invalid or corrupted info, FALSE is + * returned. + */ + bool update(const QString& list); + + int columnType( uint col ) const; + + void setSensorOk(bool ok); + + void setKillSupported(bool supported) + { + killSupported = supported; + } + + bool load(QDomElement& el); + bool save(QDomDocument& doc, QDomElement& display); + +public slots: + void setTreeView(bool tv); + + /** + * This slot allows the filter mode to be set by other + * widgets. Possible values are FILTER_ALL, FILTER_SYSTEM, + * FILTER_USER and FILTER_OWN. This filter mechanism will be much + * more sophisticated in the future. + */ + void setFilterMode(int fm) + { + filterMode = fm; + setModified(true); + } + + void sortingChanged(int col); + + void handleRMBPressed(QListViewItem* lvi, const QPoint& p, int col); + + void sizeChanged(int, int, int) + { + setModified(true); + } + + void indexChanged(int, int, int) + { + setModified(true); + } + + virtual void setModified(bool mfd) + { + if (mfd != modified) + { + modified = mfd; + emit listModified(modified); + } + } + +signals: + // This signal is emitted when process pid should receive signal sig. + void killProcess(int pid, int sig); + + // This signal is emitted when process pid should be reniced. + void reniceProcess(const QValueList<int> &pids, int niceValue); + + void listModified(bool); + +private: + // items of table header RMB popup menu + enum + { + HEADER_REMOVE = 0, + HEADER_ADD, + HEADER_HELP + }; + + /** + * This function updates the lists of selected PID und the closed + * sub trees. + */ + void updateMetaInfo(void); + + /** + * This function determines whether a process matches the current + * filter mode or not. If it machtes the criteria it returns true, + * false otherwise. + */ + bool matchesFilter(KSGRD::SensorPSLine* p) const; + + /** + * This function constructs the list of processes for list + * mode. It's a straightforward appending operation to the + * QListView widget. + */ + void buildList(); + + /** + * This function constructs the tree of processes for tree mode. It + * filters out leaf-sub-trees that contain no processes that match + * the filter criteria. + */ + void buildTree(); + + /** + * This function deletes the leaf-sub-trees that do not match the + * filter criteria. + */ + void deleteLeaves(void); + + /** + * This function returns true if the process is a leaf process with + * respect to the other processes in the process list. It does not + * have to be a leaf process in the overall list of processes. + */ + bool isLeafProcess(int pid); + + /** + * This function is used to recursively construct the tree by + * removing processes from the process list an inserting them into + * the tree. + */ + void extendTree(QPtrList<KSGRD::SensorPSLine>* pl, ProcessLVI* parent, int ppid); + + /** + * This function adds a process to the list/tree. + */ + void addProcess(KSGRD::SensorPSLine* p, ProcessLVI* pli); + +private: + void selectAllItems(bool select); + void selectAllChilds(int pid, bool select); + + bool modified; + int filterMode; + int sortColumn; + bool increasing; + int refreshRate; + int currColumn; + bool killSupported; + bool treeViewEnabled; + bool openAll; + + /* The following lists are primarily used to store table specs between + * load() and the actual table creation in addColumn(). */ + QValueList<int> savedWidth; + QValueList<int> currentWidth; + QValueList<int> index; + + QPtrList<KSGRD::SensorPSLine> pl; + + QStringList mColumnTypes; + QDict<QString> columnDict; + + QValueList<int> selectedPIds; + QValueList<int> closedSubTrees; + QStringList selectedAsStrings; + + static QDict<QString> aliases; + + QDict<QPixmap> iconCache; + + QPopupMenu* headerPM; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/ReniceDlg.cc b/ksysguard/gui/SensorDisplayLib/ReniceDlg.cc new file mode 100644 index 000000000..39c05eecf --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ReniceDlg.cc @@ -0,0 +1,66 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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 <cs@kde.org>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#include <klocale.h> +#include <knuminput.h> + +#include "ReniceDlg.moc" + +ReniceDlg::ReniceDlg(QWidget* parent, const char* name, int currentPPrio, + int pid) + : KDialogBase( parent, name, true, i18n("Renice Process"), + KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true ) +{ + QWidget *page = new QWidget( this ); + setMainWidget(page); + vLay = new QVBoxLayout(page, 20, -1, "ReniceLayout"); + + QString msg; + msg = i18n("You are about to change the scheduling priority of\n" + "process %1. Be aware that only the Superuser (root)\n" + "can decrease the nice level of a process. The lower\n" + "the number is the higher the priority.\n\n" + "Please enter the desired nice level:").arg(pid); + message = new QLabel(msg, page); + message->setMinimumSize(message->sizeHint()); + vLay->addWidget(message); + + /* + * Create a slider with an LCD display to the right using a horizontal + * layout. The slider and the LCD are kept in sync through signals + */ + input = new KIntNumInput(currentPPrio, page, 10); + input->setRange(-20, 19); + vLay->addWidget(input); +} + +void ReniceDlg::slotOk() +{ + done(input->value()); +} + +void ReniceDlg::slotCancel() +{ + done(40); +} diff --git a/ksysguard/gui/SensorDisplayLib/ReniceDlg.h b/ksysguard/gui/SensorDisplayLib/ReniceDlg.h new file mode 100644 index 000000000..d8f0d2685 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ReniceDlg.h @@ -0,0 +1,61 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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 <cs@kde.org>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef _ReniceDlg_h_ +#define _ReniceDlg_h_ + +#include <kdialogbase.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlcdnumber.h> +#include <qpushbutton.h> +#include <qslider.h> + +class KIntNumInput; + +/** + * This class creates and handles a simple dialog to change the scheduling + * priority of a process. + */ +class ReniceDlg : public KDialogBase +{ + Q_OBJECT + +public: + ReniceDlg(QWidget* parent, const char* name, int currentPPrio, int pid); + +public slots: + void slotOk(); + void slotCancel(); + +private: + QBoxLayout* vLay; + QBoxLayout* butLay; + QBoxLayout* sldLay; + + QLabel* message; + KIntNumInput* input; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/SensorDisplay.cc b/ksysguard/gui/SensorDisplayLib/SensorDisplay.cc new file mode 100644 index 000000000..805c9a492 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorDisplay.cc @@ -0,0 +1,611 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qcheckbox.h> +#include <qdom.h> +#include <qpopupmenu.h> +#include <qspinbox.h> +#include <qwhatsthis.h> +#include <qbitmap.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <krun.h> +#include <kservice.h> + +#include "SensorManager.h" +#include "TimerSettings.h" + +#include "SensorDisplay.h" + +using namespace KSGRD; + +SensorDisplay::SensorDisplay( QWidget *parent, const char *name, + const QString &title, bool nf, bool isApplet) + : QWidget( parent, name ) +{ + mIsApplet = isApplet; + mSensors.setAutoDelete( true ); + + // default interval is 2 seconds. + mUpdateInterval = 2; + mUseGlobalUpdateInterval = true; + mModified = false; + mShowUnit = false; + mTimerId = NONE; + mFrame = 0; + mErrorIndicator = 0; + mPlotterWdg = 0; + + setTimerOn( true ); + QWhatsThis::add( this, "dummy" ); + + if(!nf) { + mFrame = new QGroupBox( 2, Qt::Vertical, "", this, "displayFrame"); + mFrame->setFlat(true); + mFrame->setAlignment(Qt::AlignHCenter); + mFrame->setInsideMargin(2); + + setTitle( title ); + /* All RMB clicks to the box frame will be handled by + * SensorDisplay::eventFilter. */ + mFrame->installEventFilter( this ); + } + + + setMinimumSize( 16, 16 ); + setModified( false ); + setSensorOk( false ); + + /* Let's call updateWhatsThis() in case the derived class does not do + * this. */ + updateWhatsThis(); +} + +SensorDisplay::~SensorDisplay() +{ + if ( SensorMgr != 0 ) + SensorMgr->disconnectClient( this ); + + killTimer( mTimerId ); +} + +void SensorDisplay::registerSensor( SensorProperties *sp ) +{ + /* Make sure that we have a connection established to the specified + * host. When a work sheet has been saved while it had dangling + * sensors, the connect info is not saved in the work sheet. In such + * a case the user can re-enter the connect information and the + * connection will be established. */ + if ( !SensorMgr->engageHost( sp->hostName() ) ) { + QString msg = i18n( "It is impossible to connect to \'%1\'." ).arg( sp->hostName() ); + KMessageBox::error( this, msg ); + } + + mSensors.append( sp ); +} + +void SensorDisplay::unregisterSensor( uint pos ) +{ + mSensors.remove( pos ); +} + +void SensorDisplay::configureUpdateInterval() +{ + TimerSettings dlg( this ); + + dlg.setUseGlobalUpdate( mUseGlobalUpdateInterval ); + dlg.setInterval( mUpdateInterval ); + + if ( dlg.exec() ) { + if ( dlg.useGlobalUpdate() ) { + mUseGlobalUpdateInterval = true; + + SensorBoard* sb = dynamic_cast<SensorBoard*>( parentWidget() ); + if ( !sb ) { + kdDebug(1215) << "dynamic cast lacks" << endl; + setUpdateInterval( 2 ); + } else { + setUpdateInterval( sb->updateInterval() ); + } + } else { + mUseGlobalUpdateInterval = false; + setUpdateInterval( dlg.interval() ); + } + + setModified( true ); + } +} + +void SensorDisplay::timerEvent( QTimerEvent* ) +{ + int i = 0; + for ( SensorProperties *s = mSensors.first(); s; s = mSensors.next(), ++i ) + sendRequest( s->hostName(), s->name(), i ); +} + +void SensorDisplay::resizeEvent( QResizeEvent* ) +{ + if(mFrame) + mFrame->setGeometry( rect() ); +} + +bool SensorDisplay::eventFilter( QObject *object, QEvent *event ) +{ + if ( event->type() == QEvent::MouseButtonPress && + ( (QMouseEvent*)event)->button() == RightButton ) { + QPopupMenu pm; + if ( mIsApplet ) { + pm.insertItem( i18n( "Launch &System Guard"), 1 ); + pm.insertSeparator(); + } + if ( hasSettingsDialog() ) + pm.insertItem( i18n( "&Properties" ), 2 ); + pm.insertItem( i18n( "&Remove Display" ), 3 ); + pm.insertSeparator(); + pm.insertItem( i18n( "&Setup Update Interval..." ), 4 ); + if ( !timerOn() ) + pm.insertItem( i18n( "&Continue Update" ), 5 ); + else + pm.insertItem( i18n( "P&ause Update" ), 6 ); + + switch ( pm.exec( QCursor::pos() ) ) { + case 1: + KRun::run(*KService::serviceByDesktopName("ksysguard"), KURL::List()); + break; + case 2: + configureSettings(); + break; + case 3: { + QCustomEvent *e = new QCustomEvent( QEvent::User ); + e->setData( this ); + kapp->postEvent( parent(), e ); + } + break; + case 4: + configureUpdateInterval(); + break; + case 5: + setTimerOn( true ); + setModified( true ); + break; + case 6: + setTimerOn( false ); + setModified( true ); + break; + } + + return true; + } else if ( event->type() == QEvent::MouseButtonRelease && + ( ( QMouseEvent*)event)->button() == LeftButton ) { + setFocus(); + } + + return QWidget::eventFilter( object, event ); +} + +void SensorDisplay::sendRequest( const QString &hostName, + const QString &command, int id ) +{ + if ( !SensorMgr->sendRequest( hostName, command, (SensorClient*)this, id ) ) + sensorError( id, true ); +} + +void SensorDisplay::sensorError( int sensorId, bool err ) +{ + if ( sensorId >= (int)mSensors.count() || sensorId < 0 ) + return; + + if ( err == mSensors.at( sensorId )->isOk() ) { + // this happens only when the sensorOk status needs to be changed. + mSensors.at( sensorId )->setIsOk( !err ); + } + + bool ok = true; + for ( uint i = 0; i < mSensors.count(); ++i ) + if ( !mSensors.at( i )->isOk() ) { + ok = false; + break; + } + + setSensorOk( ok ); +} + +void SensorDisplay::updateWhatsThis() +{ + QWhatsThis::add( this, i18n( + "<qt><p>This is a sensor display. To customize a sensor display click " + "and hold the right mouse button on either the frame or the " + "display box and select the <i>Properties</i> entry from the popup " + "menu. Select <i>Remove</i> to delete the display from the worksheet." + "</p>%1</qt>" ).arg( additionalWhatsThis() ) ); +} + +void SensorDisplay::hosts( QStringList& list ) +{ + for ( SensorProperties *s = mSensors.first(); s; s = mSensors.next() ) + if ( !list.contains( s->hostName() ) ) + list.append( s->hostName() ); +} + +QColor SensorDisplay::restoreColor( QDomElement &element, const QString &attr, + const QColor& fallback ) +{ + bool ok; + uint c = element.attribute( attr ).toUInt( &ok ); + if ( !ok ) + return fallback; + else + return QColor( (c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF ); +} + +void SensorDisplay::saveColor( QDomElement &element, const QString &attr, + const QColor &color ) +{ + int r, g, b; + color.rgb( &r, &g, &b ); + element.setAttribute( attr, (r << 16) | (g << 8) | b ); +} + +bool SensorDisplay::addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &description ) +{ + registerSensor( new SensorProperties( hostName, name, type, description ) ); + return true; +} + +bool SensorDisplay::removeSensor( uint pos ) +{ + unregisterSensor( pos ); + return true; +} + +void SensorDisplay::setUpdateInterval( uint interval ) +{ + bool timerActive = timerOn(); + + if ( timerActive ) + setTimerOn( false ); + + mUpdateInterval = interval; + + if ( timerActive ) + setTimerOn( true ); +} + +bool SensorDisplay::hasSettingsDialog() const +{ + return false; +} + +void SensorDisplay::configureSettings() +{ +} + +void SensorDisplay::setUseGlobalUpdateInterval( bool value ) +{ + mUseGlobalUpdateInterval = value; +} + +bool SensorDisplay::useGlobalUpdateInterval() const +{ + return mUseGlobalUpdateInterval; +} + +QString SensorDisplay::additionalWhatsThis() +{ + return QString::null; +} + +void SensorDisplay::sensorLost( int reqId ) +{ + sensorError( reqId, true ); +} + +bool SensorDisplay::restoreSettings( QDomElement &element ) +{ + QString str = element.attribute( "showUnit", "X" ); + if(!str.isEmpty() && str != "X") { + mShowUnit = str.toInt(); + } + str = element.attribute( "unit", QString::null ); + if(!str.isEmpty()) + setUnit(str); + str = element.attribute( "title", QString::null ); + if(!str.isEmpty()) + setTitle(str); + + if ( element.attribute( "updateInterval" ) != QString::null ) { + mUseGlobalUpdateInterval = false; + setUpdateInterval( element.attribute( "updateInterval", "2" ).toInt() ); + } else { + mUseGlobalUpdateInterval = true; + + SensorBoard* sb = dynamic_cast<SensorBoard*>( parentWidget() ); + if ( !sb ) { + kdDebug(1215) << "dynamic cast lacks" << endl; + setUpdateInterval( 2 ); + } else + setUpdateInterval( sb->updateInterval() ); + } + + if ( element.attribute( "pause", "0" ).toInt() == 0 ) + setTimerOn( true ); + else + setTimerOn( false ); + + return true; +} + +bool SensorDisplay::saveSettings( QDomDocument&, QDomElement &element, bool ) +{ + element.setAttribute( "title", title() ); + element.setAttribute( "unit", unit() ); + element.setAttribute( "showUnit", mShowUnit ); + + if ( mUseGlobalUpdateInterval ) + element.setAttribute( "globalUpdate", "1" ); + else { + element.setAttribute( "globalUpdate", "0" ); + element.setAttribute( "updateInterval", mUpdateInterval ); + } + + if ( !timerOn() ) + element.setAttribute( "pause", 1 ); + else + element.setAttribute( "pause", 0 ); + + return true; +} + +void SensorDisplay::setTimerOn( bool on ) +{ + if ( on ) { + if ( mTimerId == NONE ) + mTimerId = startTimer( mUpdateInterval * 1000 ); + } else { + if ( mTimerId != NONE ) { + killTimer( mTimerId ); + mTimerId = NONE; + } + } +} + +bool SensorDisplay::timerOn() const +{ + return ( mTimerId != NONE ); +} + +bool SensorDisplay::modified() const +{ + return mModified; +} + +QPtrList<SensorProperties> &SensorDisplay::sensors() +{ + return mSensors; +} + +void SensorDisplay::rmbPressed() +{ + emit showPopupMenu( this ); +} + +void SensorDisplay::applySettings() +{ +} + +void SensorDisplay::applyStyle() +{ +} + +void SensorDisplay::setModified( bool value ) +{ + if ( value != mModified ) { + mModified = value; + emit modified( mModified ); + } +} + +void SensorDisplay::setSensorOk( bool ok ) +{ + if ( ok ) { + delete mErrorIndicator; + mErrorIndicator = 0; + } else { + if ( mErrorIndicator ) + return; + + QPixmap errorIcon = KGlobal::iconLoader()->loadIcon( "connect_creating", KIcon::Desktop, + KIcon::SizeSmall ); + if ( !mPlotterWdg ) + return; + + mErrorIndicator = new QWidget( mPlotterWdg ); + mErrorIndicator->setErasePixmap( errorIcon ); + mErrorIndicator->resize( errorIcon.size() ); + if ( errorIcon.mask() ) + mErrorIndicator->setMask( *errorIcon.mask() ); + mErrorIndicator->move( 0, 0 ); + mErrorIndicator->show(); + } +} + +void SensorDisplay::setTitle( const QString &title ) +{ + mTitle = title; + + if(!mFrame) { + return; //fixme. create a frame and move widget inside it. + } + + /* Changing the frame title may increase the width of the frame and + * hence breaks the layout. To avoid this, we save the original size + * and restore it after we have set the frame title. */ + QSize s = mFrame->size(); + + if ( mShowUnit && !mUnit.isEmpty() ) + mFrame->setTitle( mTitle + " [" + mUnit + "]" ); + else + mFrame->setTitle( mTitle ); + mFrame->setGeometry( 0, 0, s.width(), s.height() ); +} + +QString SensorDisplay::title() const +{ + return mTitle; +} + +void SensorDisplay::setUnit( const QString &unit ) +{ + mUnit = unit; +} + +QString SensorDisplay::unit() const +{ + return mUnit; +} + +void SensorDisplay::setShowUnit( bool value ) +{ + mShowUnit = value; +} + +bool SensorDisplay::showUnit() const +{ + return mShowUnit; +} + +void SensorDisplay::setPlotterWidget( QWidget *wdg ) +{ + mPlotterWdg = wdg; + +} + +QWidget *SensorDisplay::frame() +{ + return mFrame; +} + +//void SensorDisplay::setNoFrame( bool /*value*/ ) +//{ + //FIXME - delete or create the frame as needed +//} + +bool SensorDisplay::noFrame() const +{ + return !mFrame; +} + +void SensorDisplay::reorderSensors(const QValueList<int> &orderOfSensors) +{ + QPtrList<SensorProperties> newSensors; + for ( uint i = 0; i < orderOfSensors.count(); ++i ) { + newSensors.append( mSensors.at(orderOfSensors[i] )); + } + + mSensors.setAutoDelete( false ); + mSensors = newSensors; + mSensors.setAutoDelete( true ); +} + + +SensorProperties::SensorProperties() +{ +} + +SensorProperties::SensorProperties( const QString &hostName, const QString &name, + const QString &type, const QString &description ) + : mHostName( hostName ), mName( name ), mType( type ), mDescription( description ) +{ + mOk = false; +} + +SensorProperties::~SensorProperties() +{ +} + +void SensorProperties::setHostName( const QString &hostName ) +{ + mHostName = hostName; +} + +QString SensorProperties::hostName() const +{ + return mHostName; +} + +void SensorProperties::setName( const QString &name ) +{ + mName = name; +} + +QString SensorProperties::name() const +{ + return mName; +} + +void SensorProperties::setType( const QString &type ) +{ + mType = type; +} + +QString SensorProperties::type() const +{ + return mType; +} + +void SensorProperties::setDescription( const QString &description ) +{ + mDescription = description; +} + +QString SensorProperties::description() const +{ + return mDescription; +} + +void SensorProperties::setUnit( const QString &unit ) +{ + mUnit = unit; +} + +QString SensorProperties::unit() const +{ + return mUnit; +} + +void SensorProperties::setIsOk( bool value ) +{ + mOk = value; +} + +bool SensorProperties::isOk() const +{ + return mOk; +} + +#include "SensorDisplay.moc" diff --git a/ksysguard/gui/SensorDisplayLib/SensorDisplay.h b/ksysguard/gui/SensorDisplayLib/SensorDisplay.h new file mode 100644 index 000000000..e5e867a01 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorDisplay.h @@ -0,0 +1,331 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SENSORDISPLAY_H +#define KSG_SENSORDISPLAY_H + +#include <qgroupbox.h> +#include <qlabel.h> +#include <qvaluelist.h> +#include <qwidget.h> + +#include <knotifyclient.h> + +#include <ksgrd/SensorClient.h> + +#define NONE -1 + +class QDomDocument; +class QDomElement; + +namespace KSGRD { + +class SensorProperties; + +/** + This class is the base class for all displays for sensors. A + display is any kind of widget that can display the value of one or + more sensors in any form. It must be inherited by all displays that + should be inserted into the work sheet. + */ +class SensorDisplay : public QWidget, public SensorClient +{ + Q_OBJECT + + public: + /** + Constructor. + */ + SensorDisplay( QWidget *parent = 0, const char *name = 0, + const QString& title = 0, bool nf = false, bool isApplet = false ); + + /** + Destructor. + */ + virtual ~SensorDisplay(); + + /** + Sets the title of the display. + */ + void setTitle( const QString &title ); + + /** + Returns the title of the display. + */ + QString title() const; + + /** + Sets the unit of the display. + */ + void setUnit( const QString &unit ); + + /** + Returns the unit of the display. + */ + QString unit() const; + + /** + Sets whether the unit string should be displayed at the top + of the display frame. + */ + void setShowUnit( bool value ); + + /** + Returns whether the unit string should be displayed at the top + of the display frame. @see setShowUnit() + */ + bool showUnit() const; + + /** + Sets whether the update interval of the work sheet should be + used instead of the one, set by @ref setUpdateInterval(). + */ + void setUseGlobalUpdateInterval( bool value ); + + /** + Returns whether the update interval of the work sheet should be + used instead of the one, set by @ref setUpdateInterval(). + see @ref setUseGlobalUpdateInterval() + */ + bool useGlobalUpdateInterval() const; + + /** + Sets the update interval of the timer, which triggers the timer + events. The state of the timer can be set with @ref setTimerOn(). + */ + void setUpdateInterval( uint interval ); + + /** + Returns the update interval. + */ + uint updateInterval() const; + + /** + This method appends all hosts of the display to @ref list. + */ + void hosts( QStringList& list ); + + /** + Sets the widget on which the error icon can be drawn. + */ + void setPlotterWidget( QWidget *plotter ); + + /** + Returns the widget on which the error icon can be drawn. + */ + QWidget *plotterWidget() const; + + /** + Add a sensor to the display. + + @param hostName The name of the host, the sensor belongs to. + @param name The sensor name. + @param type The type of the sensor. + @param description A short description of the sensor. + */ + virtual bool addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &description ); + + /** + Removes the sensor from the display, that is at the position + @ref pos of the intern sensor list. + */ + virtual bool removeSensor( uint pos ); + + /** + This function is a wrapper function to SensorManager::sendRequest. + It should be used by all SensorDisplay functions that need to send + a request to a sensor since it performs an appropriate error + handling by removing the display of necessary. + */ + void sendRequest( const QString &hostName, const QString &cmd, int id ); + + /** + Raises the configure dialog to setup the update interval. + */ + void configureUpdateInterval(); + + /** + Returns whether the display provides a settings dialog. + This method should be reimplemented in the derived class. + */ + virtual bool hasSettingsDialog() const; + + /** + This method is called to raise the settings dialog of the + display. It should be reimplemented in the derived class. + */ + virtual void configureSettings(); + + /** + Reimplement this method to setup the display from config data. + */ + virtual bool restoreSettings( QDomElement& ); + + /** + Reimplement this method to save the displays config data. + */ + virtual bool saveSettings( QDomDocument&, QDomElement&, bool = true ); + + /** + Reimplement this method to catch error messages from the SensorManager. + + @param sensorId The unique id of the sensor. + @param mode The mode: true = error, false = everthing ok + */ + virtual void sensorError( int sensorId, bool mode ); + + /** + Normaly you shouldn't reimplement this methode + */ + virtual void sensorLost( int reqId ); + + public slots: + /** + If @ref value is true, this method starts the timer that triggers + timer events. If @ref value is false, the timer is stopped. + */ + void setTimerOn( bool value ); + + /** + Calling this method emits the @ref showPopupMenu() with this + display as argument. + */ + void rmbPressed(); + + /** + Sets whether the display is modified of not. + */ + void setModified( bool modified ); + + /** + This method can be used to apply the new settings. Just connect + the applyClicked() signal of your configuration dialog with this + slot and reimplement it. + */ + virtual void applySettings(); + + /** + This methid is called whenever the global style is changed. + Reimplement it to apply the new style settings to the display. + */ + virtual void applyStyle(); + + + signals: + void showPopupMenu( KSGRD::SensorDisplay *display ); + void modified( bool modified ); + + protected: + virtual bool eventFilter( QObject*, QEvent* ); + virtual void resizeEvent( QResizeEvent* ); + virtual void timerEvent( QTimerEvent* ); + + void registerSensor( SensorProperties *sp ); + void unregisterSensor( uint pos ); + + QColor restoreColor( QDomElement &element, const QString &attr, + const QColor& fallback ); + void saveColor( QDomElement &element, const QString &attr, + const QColor &color ); + + virtual QString additionalWhatsThis(); + + void setSensorOk( bool ok ); + + bool modified() const; + bool timerOn() const; + + QWidget *frame(); + +// void setNoFrame( bool value ); + bool noFrame() const; + + void reorderSensors(const QValueList<int> &orderOfSensors); + QPtrList<SensorProperties> &sensors(); + + private: + void updateWhatsThis(); + + bool mShowUnit; + bool mUseGlobalUpdateInterval; + bool mModified; + bool mNoFrame; + bool mIsApplet; + + int mTimerId; + int mUpdateInterval; + + // The frame around the other widgets. + QGroupBox* mFrame; + + QPtrList<SensorProperties> mSensors; + + QString mTitle; + QString mUnit; + + QWidget* mErrorIndicator; + QWidget* mPlotterWdg; +}; + +class SensorProperties +{ + public: + SensorProperties(); + SensorProperties( const QString &hostName, const QString &name, + const QString &type, const QString &description ); + ~SensorProperties(); + + void setHostName( const QString &hostName ); + QString hostName() const; + + void setName( const QString &name ); + QString name() const; + + void setType( const QString &type ); + QString type() const; + + void setDescription( const QString &description ); + QString description() const; + + void setUnit( const QString &unit ); + QString unit() const; + + void setIsOk( bool value ); + bool isOk() const; + + private: + QString mHostName; + QString mName; + QString mType; + QString mDescription; + QString mUnit; + + /* This flag indicates whether the communication to the sensor is + * ok or not. */ + bool mOk; +}; + +} + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/SensorLogger.cc b/ksysguard/gui/SensorDisplayLib/SensorLogger.cc new file mode 100644 index 000000000..b51ba67e0 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLogger.cc @@ -0,0 +1,437 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + 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. + +*/ + +#include <kapplication.h> +#include <kiconloader.h> +#include <klocale.h> + +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include <qfile.h> + +#include "SensorLogger.moc" +#include "SensorLoggerSettings.h" + +SLListViewItem::SLListViewItem(QListView *parent) + : QListViewItem(parent) +{ +} + +LogSensor::LogSensor(QListView *parent) + : timerID( NONE ), lowerLimitActive( 0 ), upperLimitActive( 0 ), + lowerLimit( 0 ), upperLimit( 0 ) +{ + Q_CHECK_PTR(parent); + + monitor = parent; + + lvi = new SLListViewItem(monitor); + Q_CHECK_PTR(lvi); + + pixmap_running = UserIcon( "running" ); + pixmap_waiting = UserIcon( "waiting" ); + + lvi->setPixmap(0, pixmap_waiting); + lvi->setTextColor(monitor->colorGroup().text()); + + monitor->insertItem(lvi); +} + +LogSensor::~LogSensor(void) +{ + if ((lvi) && (monitor)) + delete lvi; +} + +void +LogSensor::startLogging(void) +{ + lvi->setPixmap(0, pixmap_running); + timerOn(); +} + +void +LogSensor::stopLogging(void) +{ + lvi->setPixmap(0, pixmap_waiting); + lvi->setTextColor(monitor->colorGroup().text()); + lvi->repaint(); + timerOff(); +} + +void +LogSensor::timerEvent(QTimerEvent*) +{ + KSGRD::SensorMgr->sendRequest(hostName, sensorName, (KSGRD::SensorClient*) this, 42); +} + +void +LogSensor::answerReceived(int id, const QString& answer) +{ + QFile logFile(fileName); + + if (!logFile.open(IO_ReadWrite | IO_Append)) + { + stopLogging(); + return; + } + + switch (id) + { + case 42: { + QTextStream stream(&logFile); + double value = answer.toDouble(); + + if (lowerLimitActive && value < lowerLimit) + { + timerOff(); + lowerLimitActive = false; + lvi->setTextColor(monitor->colorGroup().foreground()); + lvi->repaint(); + KNotifyClient::event(monitor->winId(), "sensor_alarm", QString("sensor '%1' at '%2' reached lower limit").arg(sensorName).arg(hostName)); + timerOn(); + } else if (upperLimitActive && value > upperLimit) + { + timerOff(); + upperLimitActive = false; + lvi->setTextColor(monitor->colorGroup().foreground()); + lvi->repaint(); + KNotifyClient::event(monitor->winId(), "sensor_alarm", QString("sensor '%1' at '%2' reached upper limit").arg(sensorName).arg(hostName)); + timerOn(); + } + QDate date = QDateTime::currentDateTime().date(); + QTime time = QDateTime::currentDateTime().time(); + + stream << QString("%1 %2 %3 %4 %5: %6\n").arg(date.shortMonthName(date.month())).arg(date.day()).arg(time.toString()).arg(hostName).arg(sensorName).arg(value); + } + } + + logFile.close(); +} + +SensorLogger::SensorLogger(QWidget *parent, const char *name, const QString& title) + : KSGRD::SensorDisplay(parent, name, title) +{ + monitor = new QListView(this, "monitor"); + Q_CHECK_PTR(monitor); + + monitor->addColumn(i18n("Logging")); + monitor->addColumn(i18n("Timer Interval")); + monitor->addColumn(i18n("Sensor Name")); + monitor->addColumn(i18n("Host Name")); + monitor->addColumn(i18n("Log File")); + + QColorGroup cgroup = monitor->colorGroup(); + cgroup.setColor(QColorGroup::Text, KSGRD::Style->firstForegroundColor()); + cgroup.setColor(QColorGroup::Base, KSGRD::Style->backgroundColor()); + cgroup.setColor(QColorGroup::Foreground, KSGRD::Style->alarmColor()); + monitor->setPalette(QPalette(cgroup, cgroup, cgroup)); + monitor->setSelectionMode(QListView::NoSelection); + + connect(monitor, SIGNAL(rightButtonClicked(QListViewItem*, const QPoint&, int)), this, SLOT(RMBClicked(QListViewItem*, const QPoint&, int))); + + setTitle(i18n("Sensor Logger")); + + logSensors.setAutoDelete(true); + + setPlotterWidget(monitor); + + setMinimumSize(50, 25); + setModified(false); +} + +SensorLogger::~SensorLogger(void) +{ +} + +bool +SensorLogger::addSensor(const QString& hostName, const QString& sensorName, const QString& sensorType, const QString&) +{ + if (sensorType != "integer" && sensorType != "float") + return (false); + + sld = new SensorLoggerDlg(this, "SensorLoggerDlg"); + Q_CHECK_PTR(sld); + + if (sld->exec()) { + if (!sld->fileName().isEmpty()) { + LogSensor *sensor = new LogSensor(monitor); + Q_CHECK_PTR(sensor); + + sensor->setHostName(hostName); + sensor->setSensorName(sensorName); + sensor->setFileName(sld->fileName()); + sensor->setTimerInterval(sld->timerInterval()); + sensor->setLowerLimitActive(sld->lowerLimitActive()); + sensor->setUpperLimitActive(sld->upperLimitActive()); + sensor->setLowerLimit(sld->lowerLimit()); + sensor->setUpperLimit(sld->upperLimit()); + + logSensors.append(sensor); + + setModified(true); + } + } + + delete sld; + sld = 0; + + return (true); +} + +bool +SensorLogger::editSensor(LogSensor* sensor) +{ + sld = new SensorLoggerDlg(this, "SensorLoggerDlg"); + Q_CHECK_PTR(sld); + + sld->setFileName(sensor->getFileName()); + sld->setTimerInterval(sensor->getTimerInterval()); + sld->setLowerLimitActive(sensor->getLowerLimitActive()); + sld->setLowerLimit(sensor->getLowerLimit()); + sld->setUpperLimitActive(sensor->getUpperLimitActive()); + sld->setUpperLimit(sensor->getUpperLimit()); + + if (sld->exec()) { + if (!sld->fileName().isEmpty()) { + sensor->setFileName(sld->fileName()); + sensor->setTimerInterval(sld->timerInterval()); + sensor->setLowerLimitActive(sld->lowerLimitActive()); + sensor->setUpperLimitActive(sld->upperLimitActive()); + sensor->setLowerLimit(sld->lowerLimit()); + sensor->setUpperLimit(sld->upperLimit()); + + setModified(true); + } + } + + delete sld; + sld = 0; + + return (true); +} + +void +SensorLogger::configureSettings() +{ + QColorGroup cgroup = monitor->colorGroup(); + + sls = new SensorLoggerSettings(this, "SensorLoggerSettings"); + Q_CHECK_PTR(sls); + + connect( sls, SIGNAL( applyClicked() ), SLOT( applySettings() ) ); + + sls->setTitle(title()); + sls->setForegroundColor(cgroup.text()); + sls->setBackgroundColor(cgroup.base()); + sls->setAlarmColor(cgroup.foreground()); + + if (sls->exec()) + applySettings(); + + delete sls; + sls = 0; +} + +void +SensorLogger::applySettings() +{ + QColorGroup cgroup = monitor->colorGroup(); + + setTitle(sls->title()); + + cgroup.setColor(QColorGroup::Text, sls->foregroundColor()); + cgroup.setColor(QColorGroup::Base, sls->backgroundColor()); + cgroup.setColor(QColorGroup::Foreground, sls->alarmColor()); + monitor->setPalette(QPalette(cgroup, cgroup, cgroup)); + + setModified(true); +} + +void +SensorLogger::applyStyle(void) +{ + QColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(QColorGroup::Text, KSGRD::Style->firstForegroundColor()); + cgroup.setColor(QColorGroup::Base, KSGRD::Style->backgroundColor()); + cgroup.setColor(QColorGroup::Foreground, KSGRD::Style->alarmColor()); + monitor->setPalette(QPalette(cgroup, cgroup, cgroup)); + + setModified(true); +} + +bool +SensorLogger::restoreSettings(QDomElement& element) +{ + QColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(QColorGroup::Text, restoreColor(element, "textColor", Qt::green)); + cgroup.setColor(QColorGroup::Base, restoreColor(element, "backgroundColor", Qt::black)); + cgroup.setColor(QColorGroup::Foreground, restoreColor(element, "alarmColor", Qt::red)); + monitor->setPalette(QPalette(cgroup, cgroup, cgroup)); + + logSensors.clear(); + + QDomNodeList dnList = element.elementsByTagName("logsensors"); + for (uint i = 0; i < dnList.count(); i++) { + QDomElement element = dnList.item(i).toElement(); + LogSensor* sensor = new LogSensor(monitor); + Q_CHECK_PTR(sensor); + + sensor->setHostName(element.attribute("hostName")); + sensor->setSensorName(element.attribute("sensorName")); + sensor->setFileName(element.attribute("fileName")); + sensor->setTimerInterval(element.attribute("timerInterval").toInt()); + sensor->setLowerLimitActive(element.attribute("lowerLimitActive").toInt()); + sensor->setLowerLimit(element.attribute("lowerLimit").toDouble()); + sensor->setUpperLimitActive(element.attribute("upperLimitActive").toInt()); + sensor->setUpperLimit(element.attribute("upperLimit").toDouble()); + + logSensors.append(sensor); + } + + SensorDisplay::restoreSettings(element); + + setModified(false); + + return (true); +} + +bool +SensorLogger::saveSettings(QDomDocument& doc, QDomElement& element, bool save) +{ + saveColor(element, "textColor", monitor->colorGroup().text()); + saveColor(element, "backgroundColor", monitor->colorGroup().base()); + saveColor(element, "alarmColor", monitor->colorGroup().foreground()); + + for (LogSensor* sensor = logSensors.first(); sensor != 0; sensor = logSensors.next()) + { + QDomElement log = doc.createElement("logsensors"); + log.setAttribute("sensorName", sensor->getSensorName()); + log.setAttribute("hostName", sensor->getHostName()); + log.setAttribute("fileName", sensor->getFileName()); + log.setAttribute("timerInterval", sensor->getTimerInterval()); + log.setAttribute("lowerLimitActive", QString("%1").arg(sensor->getLowerLimitActive())); + log.setAttribute("lowerLimit", QString("%1").arg(sensor->getLowerLimit())); + log.setAttribute("upperLimitActive", QString("%1").arg(sensor->getUpperLimitActive())); + log.setAttribute("upperLimit", QString("%1").arg(sensor->getUpperLimit())); + + element.appendChild(log); + } + + SensorDisplay::saveSettings(doc, element); + + if (save) + setModified(false); + + return (true); +} + +void +SensorLogger::answerReceived(int, const QString&) +{ + // we do not use this, since all answers are received by the LogSensors +} + +void +SensorLogger::resizeEvent(QResizeEvent*) +{ + frame()->setGeometry(0, 0, this->width(), this->height()); + monitor->setGeometry(10, 20, this->width() - 20, this->height() - 30); +} + +LogSensor* +SensorLogger::getLogSensor(QListViewItem* item) +{ + for (LogSensor* sensor = logSensors.first(); sensor != 0; sensor = logSensors.next()) + { + if (item == sensor->getListViewItem()) { + return sensor; + } + } + + return NULL; +} + +void +SensorLogger::RMBClicked(QListViewItem* item, const QPoint& point, int) +{ + QPopupMenu pm; + if (hasSettingsDialog()) + pm.insertItem(i18n("&Properties"), 1); + pm.insertItem(i18n("&Remove Display"), 2); + pm.insertSeparator(-1); + pm.insertItem(i18n("&Remove Sensor"), 3); + pm.insertItem(i18n("&Edit Sensor..."), 4); + + if ( !item ) + { + pm.setItemEnabled( 3, false ); + pm.setItemEnabled( 4, false ); + } + else + { + LogSensor* sensor = getLogSensor(item); + + if ( sensor->isLogging() ) + pm.insertItem(i18n("St&op Logging"), 6); + else + pm.insertItem(i18n("S&tart Logging"), 5); + } + + switch (pm.exec(point)) + { + case 1: + configureSettings(); + break; + case 2: { + QCustomEvent* ev = new QCustomEvent(QEvent::User); + ev->setData(this); + kapp->postEvent(parent(), ev); + break; + } + case 3: { + LogSensor* sensor = getLogSensor(item); + if (sensor) + logSensors.remove(sensor); + break; + } + case 4: { + LogSensor* sensor = getLogSensor(item); + if (sensor) + editSensor(sensor); + break; + } + case 5: { + LogSensor* sensor = getLogSensor(item); + if (sensor) + sensor->startLogging(); + break; + } + case 6: { + LogSensor* sensor = getLogSensor(item); + if (sensor) + sensor->stopLogging(); + break; + } + } +} diff --git a/ksysguard/gui/SensorDisplayLib/SensorLogger.h b/ksysguard/gui/SensorDisplayLib/SensorLogger.h new file mode 100644 index 000000000..835e62401 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLogger.h @@ -0,0 +1,184 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + 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. + +*/ + +#ifndef _SensorLogger_h +#define _SensorLogger_h + +#include <qdom.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qlistview.h> +#include <qpopupmenu.h> +#include <qspinbox.h> +#include <qstring.h> + +#include <SensorDisplay.h> + +#include "SensorLoggerDlg.h" + +#define NONE -1 + +class SensorLoggerSettings; + +class SLListViewItem : public QListViewItem +{ +public: + SLListViewItem(QListView *parent = 0); + + void setTextColor(const QColor& color) { textColor = color; } + + void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment) { + QColorGroup cgroup(cg); + cgroup.setColor(QColorGroup::Text, textColor); + QListViewItem::paintCell(p, cgroup, column, width, alignment); + + } + + void paintFocus(QPainter *, const QColorGroup, const QRect) {} + +private: + QColor textColor; +}; + +class LogSensor : public QObject, public KSGRD::SensorClient +{ + Q_OBJECT +public: + LogSensor(QListView *parent); + ~LogSensor(void); + + void answerReceived(int id, const QString& answer); + + void setHostName(const QString& name) { hostName = name; lvi->setText(3, name); } + void setSensorName(const QString& name) { sensorName = name; lvi->setText(2, name); } + void setFileName(const QString& name) + { + fileName = name; + lvi->setText(4, name); + } + void setUpperLimitActive(bool value) { upperLimitActive = value; } + void setLowerLimitActive(bool value) { lowerLimitActive = value; } + void setUpperLimit(double value) { upperLimit = value; } + void setLowerLimit(double value) { lowerLimit = value; } + + void setTimerInterval(int interval) { + timerInterval = interval; + + if (timerID != NONE) + { + timerOff(); + timerOn(); + } + + lvi->setText(1, QString("%1").arg(interval)); + } + + QString getSensorName(void) { return sensorName; } + QString getHostName(void) { return hostName; } + QString getFileName(void) { return fileName; } + int getTimerInterval(void) { return timerInterval; } + bool getUpperLimitActive(void) { return upperLimitActive; } + bool getLowerLimitActive(void) { return lowerLimitActive; } + double getUpperLimit(void) { return upperLimit; } + double getLowerLimit(void) { return lowerLimit; } + QListViewItem* getListViewItem(void) { return lvi; } + +public slots: + void timerOff() + { + killTimer(timerID); + timerID = NONE; + } + + void timerOn() + { + timerID = startTimer(timerInterval * 1000); + } + + bool isLogging() { return timerID != NONE; } + + void startLogging(void); + void stopLogging(void); + +protected: + virtual void timerEvent(QTimerEvent*); + +private: + QListView* monitor; + SLListViewItem* lvi; + QPixmap pixmap_running; + QPixmap pixmap_waiting; + QString sensorName; + QString hostName; + QString fileName; + + int timerInterval; + int timerID; + + bool lowerLimitActive; + bool upperLimitActive; + + double lowerLimit; + double upperLimit; +}; + +class SensorLogger : public KSGRD::SensorDisplay +{ + Q_OBJECT +public: + SensorLogger(QWidget *parent = 0, const char *name = 0, const QString& title = 0); + ~SensorLogger(void); + + bool addSensor(const QString& hostName, const QString& sensorName, const QString& sensorType, + const QString& sensorDescr); + + bool editSensor(LogSensor*); + + void answerReceived(int id, const QString& answer); + void resizeEvent(QResizeEvent*); + + bool restoreSettings(QDomElement& element); + bool saveSettings(QDomDocument& doc, QDomElement& element, bool save = true); + + void configureSettings(void); + + virtual bool hasSettingsDialog() const + { + return (true); + } + +public slots: + void applySettings(); + void applyStyle(); + void RMBClicked(QListViewItem*, const QPoint&, int); + +protected: + LogSensor* getLogSensor(QListViewItem*); + +private: + QListView* monitor; + + QPtrList<LogSensor> logSensors; + + SensorLoggerDlg *sld; + SensorLoggerSettings *sls; +}; + +#endif // _SensorLogger_h diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerDlg.cc b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlg.cc new file mode 100644 index 000000000..f07b55ae4 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlg.cc @@ -0,0 +1,106 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "SensorLoggerDlg.h" +#include "SensorLoggerDlgWidget.h" + +#include <qlayout.h> + +#include <klocale.h> + +SensorLoggerDlg::SensorLoggerDlg( QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n( "Sensor Logger" ), + Ok|Cancel, Ok, true ) +{ + QWidget *main = new QWidget( this ); + + QVBoxLayout *topLayout = new QVBoxLayout( main, 0, KDialog::spacingHint() ); + + m_loggerWidget = new SensorLoggerDlgWidget( main, "m_loggerWidget" ); + topLayout->addWidget( m_loggerWidget ); + topLayout->addStretch(); + + setMainWidget( main ); +} + +QString SensorLoggerDlg::fileName() const +{ + return m_loggerWidget->fileName(); +} + +int SensorLoggerDlg::timerInterval() const +{ + return m_loggerWidget->timerInterval(); +} + +bool SensorLoggerDlg::lowerLimitActive() const +{ + return m_loggerWidget->lowerLimitActive(); +} + +bool SensorLoggerDlg::upperLimitActive() const +{ + return m_loggerWidget->upperLimitActive(); +} + +double SensorLoggerDlg::lowerLimit() const +{ + return m_loggerWidget->lowerLimit(); +} + +double SensorLoggerDlg::upperLimit() const +{ + return m_loggerWidget->upperLimit(); +} + +void SensorLoggerDlg::setFileName( const QString &url ) +{ + m_loggerWidget->setFileName( url ); +} + +void SensorLoggerDlg::setTimerInterval( int i ) +{ + m_loggerWidget->setTimerInterval( i ); +} + +void SensorLoggerDlg::setLowerLimitActive( bool b ) +{ + m_loggerWidget->setLowerLimitActive( b ); +} + +void SensorLoggerDlg::setUpperLimitActive( bool b ) +{ + m_loggerWidget->setUpperLimitActive( b ); +} + +void SensorLoggerDlg::setLowerLimit( double limit ) +{ + m_loggerWidget->setLowerLimit( limit ); +} + +void SensorLoggerDlg::setUpperLimit( double limit ) +{ + m_loggerWidget->setUpperLimit( limit ); +} + +#include "SensorLoggerDlg.moc" + +/* vim: et sw=2 ts=2 +*/ + diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerDlg.h b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlg.h new file mode 100644 index 000000000..3af8290c8 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlg.h @@ -0,0 +1,62 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or ( at your option ) any later version. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#ifndef SENSORLOGGERDLG_H +#define SENSORLOGGERDLG_H + +#include <kdialogbase.h> + +#include <qstring.h> +#include <qcolor.h> + +class SensorLoggerDlgWidget; + +class SensorLoggerDlg : public KDialogBase +{ + Q_OBJECT + + public: + + SensorLoggerDlg( QWidget *parent=0, const char *name=0 ); + + QString fileName() const; + int timerInterval() const; + bool lowerLimitActive() const; + bool upperLimitActive() const; + double lowerLimit() const; + double upperLimit() const; + + void setFileName( const QString & ); + void setTimerInterval( int ); + void setLowerLimitActive( bool ); + void setUpperLimitActive( bool ); + void setLowerLimit( double ); + void setUpperLimit( double ); + + private: + + SensorLoggerDlgWidget *m_loggerWidget; +}; + +#endif // SENSORLOGGERDLG_H + +/* vim: et sw=2 ts=2 +*/ + diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerDlgWidget.ui b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlgWidget.ui new file mode 100644 index 000000000..26d3b2d49 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlgWidget.ui @@ -0,0 +1,263 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>SensorLoggerDlgWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>SensorLoggerDlgWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>363</width> + <height>254</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>fileFrame</cstring> + </property> + <property name="frameShape"> + <enum>GroupBoxPanel</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="title"> + <string>File</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KURLRequester"> + <property name="name"> + <cstring>m_fileName</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>timerFrame</cstring> + </property> + <property name="title"> + <string>Timer Interval</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KIntNumInput"> + <property name="name"> + <cstring>m_timerInterval</cstring> + </property> + <property name="value"> + <number>2</number> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="maxValue"> + <number>99</number> + </property> + <property name="suffix"> + <string> sec</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>GroupBox1</cstring> + </property> + <property name="title"> + <string>Alarm for Minimum Value</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_lowerLimitActive</cstring> + </property> + <property name="text"> + <string>&Enable alarm</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Enable the minimum value alarm.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>m_lblLowerLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Lower limit:</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_lowerLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimumSize"> + <size> + <width>70</width> + <height>0</height> + </size> + </property> + </widget> + </hbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>GroupBox1_2</cstring> + </property> + <property name="title"> + <string>Alarm for Maximum Value</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_upperLimitActive</cstring> + </property> + <property name="text"> + <string>E&nable alarm</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Enable the maximum value alarm.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer1_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>m_lblUpperLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Upper limit:</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_upperLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimumSize"> + <size> + <width>70</width> + <height>0</height> + </size> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>m_lowerLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_lowerLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_upperLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_upperLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_lowerLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_lblLowerLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_upperLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_lblUpperLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<includes> + <include location="global" impldecl="in implementation">kdialog.h</include> + <include location="global" impldecl="in implementation">knumvalidator.h</include> + <include location="local" impldecl="in implementation">SensorLoggerDlgWidget.ui.h</include> +</includes> +<functions> + <function access="private" specifier="non virtual">init()</function> + <function specifier="non virtual" returnType="QString">fileName()</function> + <function specifier="non virtual" returnType="int">timerInterval()</function> + <function specifier="non virtual" returnType="bool">lowerLimitActive()</function> + <function specifier="non virtual" returnType="double">lowerLimit()</function> + <function returnType="bool">upperLimitActive()</function> + <function specifier="non virtual" returnType="double">upperLimit()</function> + <function specifier="non virtual">setFileName( const QString & url )</function> + <function specifier="non virtual">setTimerInterval( int i )</function> + <function specifier="non virtual">setLowerLimitActive( bool b )</function> + <function specifier="non virtual">setLowerLimit( double d )</function> + <function specifier="non virtual">setUpperLimitActive( bool b )</function> + <function specifier="non virtual">setUpperLimit( double d )</function> +</functions> + +<layoutdefaults spacing="6" margin="11"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerDlgWidget.ui.h b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlgWidget.ui.h new file mode 100644 index 000000000..afe0767e9 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlgWidget.ui.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + +void SensorLoggerDlgWidget::init() +{ + m_lowerLimit->setValidator(new KDoubleValidator(m_lowerLimit)); + m_upperLimit->setValidator(new KDoubleValidator(m_upperLimit)); + m_timerInterval->setRange(1, 99, 1, true); + + m_fileName->setFocus(); +} + + +QString SensorLoggerDlgWidget::fileName() +{ + return m_fileName->url(); +} + + +int SensorLoggerDlgWidget::timerInterval() +{ + return m_timerInterval->value(); +} + + +bool SensorLoggerDlgWidget::lowerLimitActive() +{ + return m_lowerLimitActive->isChecked(); +} + + +double SensorLoggerDlgWidget::lowerLimit() +{ + return m_lowerLimit->text().toDouble(); +} + + +bool SensorLoggerDlgWidget::upperLimitActive() +{ + return m_upperLimitActive->isChecked(); +} + + +double SensorLoggerDlgWidget::upperLimit() +{ + return m_upperLimit->text().toDouble(); +} + + +void SensorLoggerDlgWidget::setFileName( const QString &url ) +{ + m_fileName->setURL(url); +} + + +void SensorLoggerDlgWidget::setTimerInterval( int i ) +{ + m_timerInterval->setValue(i); +} + + +void SensorLoggerDlgWidget::setLowerLimitActive( bool b ) +{ + m_lowerLimitActive->setChecked(b); +} + + +void SensorLoggerDlgWidget::setLowerLimit( double d ) +{ + m_lowerLimit->setText(QString("%1").arg(d)); +} + + +void SensorLoggerDlgWidget::setUpperLimitActive( bool b ) +{ + m_upperLimitActive->setChecked(b); +} + + +void SensorLoggerDlgWidget::setUpperLimit( double d ) +{ + m_upperLimit->setText(QString("%1").arg(d)); +} diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerSettings.cc b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettings.cc new file mode 100644 index 000000000..568108547 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettings.cc @@ -0,0 +1,77 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "SensorLoggerSettings.h" +#include "SensorLoggerSettingsWidget.h" + +#include <klocale.h> + +SensorLoggerSettings::SensorLoggerSettings( QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n( "Sensor Logger Settings" ), + Ok|Apply|Cancel, Ok, true ) +{ + m_settingsWidget = new SensorLoggerSettingsWidget( this, "m_settingsWidget" ); + setMainWidget( m_settingsWidget ); +} + +QString SensorLoggerSettings::title() +{ + return m_settingsWidget->title(); +} + +QColor SensorLoggerSettings::foregroundColor() +{ + return m_settingsWidget->foregroundColor(); +} + +QColor SensorLoggerSettings::backgroundColor() +{ + return m_settingsWidget->backgroundColor(); +} + +QColor SensorLoggerSettings::alarmColor() +{ + return m_settingsWidget->alarmColor(); +} + +void SensorLoggerSettings::setTitle( const QString &title ) +{ + m_settingsWidget->setTitle( title ); +} + +void SensorLoggerSettings::setBackgroundColor( const QColor &c ) +{ + m_settingsWidget->setBackgroundColor( c ); +} + +void SensorLoggerSettings::setForegroundColor( const QColor &c ) +{ + m_settingsWidget->setForegroundColor( c ); +} + +void SensorLoggerSettings::setAlarmColor( const QColor &c ) +{ + m_settingsWidget->setAlarmColor( c ); +} + +#include "SensorLoggerSettings.moc" + +/* vim: et sw=2 ts=2 +*/ + diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerSettings.h b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettings.h new file mode 100644 index 000000000..639f55944 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettings.h @@ -0,0 +1,57 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or ( at your option ) any later version. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#ifndef SENSORLOGGERSETTINGS_H +#define SENSORLOGGERSETTINGS_H + +#include <kdialogbase.h> + +#include <qstring.h> +#include <qcolor.h> + +class SensorLoggerSettingsWidget; + +class SensorLoggerSettings : public KDialogBase +{ + Q_OBJECT + + public: + + SensorLoggerSettings( QWidget *parent=0, const char *name=0 ); + + QString title(); + QColor foregroundColor(); + QColor backgroundColor(); + QColor alarmColor(); + + void setTitle( const QString & ); + void setForegroundColor( const QColor & ); + void setBackgroundColor( const QColor & ); + void setAlarmColor( const QColor & ); + + private: + + SensorLoggerSettingsWidget *m_settingsWidget; +}; + +#endif // SENSORLOGGERSETTINGS_H + +/* vim: et sw=2 ts=2 +*/ diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerSettingsWidget.ui b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettingsWidget.ui new file mode 100644 index 000000000..c86e671b2 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettingsWidget.ui @@ -0,0 +1,180 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>SensorLoggerSettingsWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>SensorLoggerSettingsWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>415</width> + <height>202</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>titleFrame</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="title"> + <string>Title</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_title</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>colorFrame</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>Box</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="title"> + <string>Colors</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter|AlignLeft</set> + </property> + <property name="vAlign" stdset="0"> + </property> + <property name="wordwrap" stdset="0"> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Text color:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Alarm color:</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_foregroundColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>0</red> + <green>255</green> + <blue>0</blue> + </color> + </property> + </widget> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_backgroundColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_alarmColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<includes> + <include location="global" impldecl="in implementation">kdialog.h</include> + <include location="local" impldecl="in implementation">SensorLoggerSettingsWidget.ui.h</include> +</includes> +<functions> + <function specifier="non virtual" returnType="QString">title()</function> + <function specifier="non virtual" returnType="QColor">foregroundColor()</function> + <function specifier="non virtual" returnType="QColor">backgroundColor()</function> + <function specifier="non virtual" returnType="QColor">alarmColor()</function> + <function specifier="non virtual">setTitle( const QString & t )</function> + <function specifier="non virtual">setForegroundColor( const QColor & c )</function> + <function specifier="non virtual">setBackgroundColor( const QColor & c )</function> + <function specifier="non virtual">setAlarmColor( const QColor & c )</function> +</functions> +<layoutdefaults spacing="6" margin="11"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +</UI> diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerSettingsWidget.ui.h b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettingsWidget.ui.h new file mode 100644 index 000000000..751366466 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettingsWidget.ui.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + + +QString SensorLoggerSettingsWidget::title() +{ + return m_title->text(); +} + + +QColor SensorLoggerSettingsWidget::foregroundColor() +{ + return m_foregroundColor->color(); +} + + +QColor SensorLoggerSettingsWidget::backgroundColor() +{ + return m_backgroundColor->color(); +} + + +QColor SensorLoggerSettingsWidget::alarmColor() +{ + return m_alarmColor->color(); +} + + +void SensorLoggerSettingsWidget::setTitle( const QString &t ) +{ + m_title->setText(t); +} + + +void SensorLoggerSettingsWidget::setForegroundColor( const QColor &c ) +{ + m_foregroundColor->setColor(c); +} + + +void SensorLoggerSettingsWidget::setBackgroundColor( const QColor &c ) +{ + m_backgroundColor->setColor(c); +} + + +void SensorLoggerSettingsWidget::setAlarmColor( const QColor &c ) +{ + m_alarmColor->setColor(c); +} diff --git a/ksysguard/gui/SensorDisplayLib/SignalPlotter.cc b/ksysguard/gui/SensorDisplayLib/SignalPlotter.cc new file mode 100644 index 000000000..f8ad121f1 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SignalPlotter.cc @@ -0,0 +1,648 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <math.h> +#include <string.h> + +#include <qpainter.h> +#include <qpixmap.h> + +#include <kdebug.h> +#include <kglobal.h> + +#include <ksgrd/StyleEngine.h> + +#include "SignalPlotter.h" + +SignalPlotter::SignalPlotter( QWidget *parent, const char *name ) + : QWidget( parent, name ) +{ + // Auto deletion does not work for pointer to arrays. + mBeamData.setAutoDelete( false ); + + setBackgroundMode( NoBackground ); + mShowThinFrame = true; + 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 = KSGRD::Style->firstForegroundColor(); + mVerticalLinesDistance = 30; + mVerticalLinesScroll = true; + mVerticalLinesOffset = 0; + mHorizontalScale = 1; + + mShowHorizontalLines = true; + mHorizontalLinesColor = KSGRD::Style->secondForegroundColor(); + mHorizontalLinesCount = 5; + + mShowLabels = true; + mShowTopBar = false; + mFontSize = KSGRD::Style->fontSize(); + + mBackgroundColor = KSGRD::Style->backgroundColor(); +} + +SignalPlotter::~SignalPlotter() +{ + for ( double* p = mBeamData.first(); p; p = mBeamData.next() ) + delete [] p; +} + +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::reorderBeams( const QValueList<int>& newOrder ) +{ + if(newOrder.count() != mBeamData.count()) { + kdDebug() << "Serious problem in move sample" << endl; + return; + } + QPtrList<double> newBeamData; + QValueList<QColor> newBeamColor; + + for(uint i = 0; i < newOrder.count(); i++) { + int newIndex = newOrder[i]; + newBeamData.append(mBeamData.at(newIndex)); + newBeamColor.append(*mBeamColor.at(newIndex)); + } + mBeamData = newBeamData; + mBeamColor = newBeamColor; + +} + +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 ) ); + double *p = mBeamData.take( pos ); + delete [] p; +} + +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(); +} + +int 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 = kMin( 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 ) ); + + double *p = mBeamData.take( i ); + delete [] p; + 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() ) ); + if(mShowThinFrame) { + p.drawLine( 0, h - 1, w - 1, h - 1 ); + p.drawLine( w - 1, 0, w - 1, h - 1 ); + + h--; + w--; + p.setClipRect( 0, 0, w, h ); + } + 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+1); + double dim = pow( 10, floor( log10( step ) ) ) / 2; + range = dim * ceil( step / dim ) * (mHorizontalLinesCount+1); + } + double maxValue = minValue + range; + + int top = 0; + if ( mShowTopBar && h > ( mFontSize/*top bar size*/ + 2/*padding*/ +5/*smallest reasonable size for a graph*/ ) ) { + /* 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; // h0 is our new top. It's at least 5 pixels high + p.drawText(0, 0, x0, top - 2, Qt::AlignCenter, mTitle ); + + 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[ mSamples - 1 ] ) * 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 ]; + hack[ 0 ] = hack[ 1 ] = hack[ 2 ] = hack[ 3 ] = 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 always drawn. + * Values are only draw when width is greater than 60 */ + if ( mShowHorizontalLines ) { + p.setPen( mHorizontalLinesColor ); + p.setFont( QFont( p.font().family(), mFontSize ) ); + QString val; + + /* top = 0 or font.height depending on whether there's a topbar or not + * h = graphing area.height - i.e. the actual space we have to draw inside + * + * Note we are drawing from 0,0 as the top left corner. So we have to add on top to get to the top of where we are drawing + * so top+h is the height of the widget + */ + for ( uint y = 1; y <= mHorizontalLinesCount; y++ ) { + + int y_coord = top + (y * h) / (mHorizontalLinesCount+1); //Make sure it's y*h first to avoid rounding bugs + p.drawLine( 0, y_coord, w - 2, y_coord ); + + if ( mShowLabels && h > ( mFontSize + 1 ) * ( mHorizontalLinesCount + 1 ) + && w > 60 ) { + val = QString::number(maxValue - (y * range) / (mHorizontalLinesCount+1 ) ); + p.drawText( 6, y_coord - 1, val ); //draw the text one pixel raised above the line + } + } + + //Draw the bottom most (minimum) number as well + if ( mShowLabels && h > ( mFontSize + 1 ) * ( mHorizontalLinesCount + 1 ) + && w > 60 ) { + val = QString::number( minValue ); + p.drawText( 6, top + h - 2, val ); + } + } + + p.end(); + bitBlt( this, 0, 0, &pm ); +} + +#include "SignalPlotter.moc" diff --git a/ksysguard/gui/SensorDisplayLib/SignalPlotter.h b/ksysguard/gui/SensorDisplayLib/SignalPlotter.h new file mode 100644 index 000000000..9a9544b3c --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SignalPlotter.h @@ -0,0 +1,147 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SIGNALPLOTTER_H +#define KSG_SIGNALPLOTTER_H + +#include <qptrlist.h> +#include <qstring.h> +#include <qvaluelist.h> +#include <qwidget.h> + +#define GRAPH_POLYGON 0 +#define GRAPH_ORIGINAL 1 + +class QColor; + +class SignalPlotter : public QWidget +{ + Q_OBJECT + + public: + SignalPlotter( QWidget *parent = 0, const char *name = 0 ); + ~SignalPlotter(); + + 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 ); + int 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; + void reorderBeams( const QValueList<int>& newOrder ); + + void setThinFrame(bool set) { mShowThinFrame = set; } + + protected: + void updateDataBuffers(); + + virtual void resizeEvent( QResizeEvent* ); + virtual void paintEvent( QPaintEvent* ); + + private: + double mMinValue; + double mMaxValue; + bool mUseAutoRange; + bool mShowThinFrame; + + 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; + + unsigned int mSamples; + + QString mTitle; +}; + +#endif diff --git a/ksysguard/gui/SignalIDs.h b/ksysguard/gui/SignalIDs.h new file mode 100644 index 000000000..16df1b1e1 --- /dev/null +++ b/ksysguard/gui/SignalIDs.h @@ -0,0 +1,52 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2000 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SIGNALIDS_H +#define KSG_SIGNALIDS_H + +/* This file is used to correlate the entries of the process popup menu + * of the ProcessList class and the value received by the kill command + * in ksysguardd. We limit the set of available signals to the POSIX.1 + * set with job control. */ + +#define MENU_ID_SIGABRT 11 +#define MENU_ID_SIGALRM 12 +#define MENU_ID_SIGCHLD 13 +#define MENU_ID_SIGCONT 14 +#define MENU_ID_SIGFPE 15 +#define MENU_ID_SIGHUP 16 +#define MENU_ID_SIGILL 17 +#define MENU_ID_SIGINT 18 +#define MENU_ID_SIGKILL 19 +#define MENU_ID_SIGPIPE 20 +#define MENU_ID_SIGQUIT 21 +#define MENU_ID_SIGSEGV 22 +#define MENU_ID_SIGSTOP 23 +#define MENU_ID_SIGTERM 24 +#define MENU_ID_SIGTSTP 25 +#define MENU_ID_SIGTTIN 26 +#define MENU_ID_SIGTTOU 27 +#define MENU_ID_SIGUSR1 28 +#define MENU_ID_SIGUSR2 29 + +#endif diff --git a/ksysguard/gui/SystemLoad.sgrd b/ksysguard/gui/SystemLoad.sgrd new file mode 100644 index 000000000..139187e93 --- /dev/null +++ b/ksysguard/gui/SystemLoad.sgrd @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE KSysGuardWorkSheet> +<WorkSheet rows="2" interval="2" columns="2" > + <host port="-1" shell="" name="localhost" command="ksysguardd" /> + <display topBar="0" vColor="326429" title="CPU Load" bColor="3223601" graphStyle="0" class="FancyPlotter" row="0" unit="" hScale="1" column="0" showUnit="0" hLines="1" hCount="5" vLines="1" autoRange="0" min="0" max="100" hColor="326429" globalUpdate="1" pause="0" fontSize="9" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="cpu/user" hostName="localhost" color="1608191" sensorType="integer" /> + <beam sensorName="cpu/sys" hostName="localhost" color="16743688" sensorType="integer" /> + <beam sensorName="cpu/nice" hostName="localhost" color="16771600" sensorType="integer" /> + </display> + <display topBar="0" vColor="326429" title="Load Average (1 min)" bColor="3223601" graphStyle="0" class="FancyPlotter" row="0" unit="" hScale="1" column="1" showUnit="0" hLines="1" hCount="5" vLines="1" autoRange="1" min="0" max="0" hColor="326429" globalUpdate="1" pause="0" fontSize="9" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="cpu/loadavg1" hostName="localhost" color="1608191" sensorType="float" /> + </display> + <display topBar="0" vColor="326429" title="Physical Memory" +bColor="3223601" graphStyle="0" class="FancyPlotter" row="1" unit="" +hScale="1" column="0" showUnit="0" hLines="1" hCount="5" vLines="1" +autoRange="0" min="0" max="0" hColor="326429" globalUpdate="1" pause="0" fontSize="9" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="mem/physical/application" hostName="localhost" color="1608191" sensorType="integer" /> + <beam sensorName="mem/physical/buf" hostName="localhost" color="16743688" sensorType="integer" /> + <beam sensorName="mem/physical/cached" hostName="localhost" color="16771600" sensorType="integer" /> + </display> + <display topBar="0" vColor="326429" title="Swap Memory" +bColor="3223601" graphStyle="0" class="FancyPlotter" row="1" unit="" +hScale="1" column="1" showUnit="0" hLines="1" hCount="5" vLines="1" +autoRange="0" min="0" max="0" hColor="326429" globalUpdate="1" pause="0" fontSize="9" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="mem/swap/used" hostName="localhost" color="1608191" sensorType="integer" /> + </display> +</WorkSheet> diff --git a/ksysguard/gui/Taskmanager.ktop b/ksysguard/gui/Taskmanager.ktop new file mode 100644 index 000000000..00e5ec5ce --- /dev/null +++ b/ksysguard/gui/Taskmanager.ktop @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE KSysGuardWorkSheet > +<WorkSheet rows="1" columns="1"> +<host name="localhost" shell="" command="ksysguardd"/> +<display row="0" column="0" class="ProcessController" hostName="localhost" sensorName="ps" sensorType="table" tree="off" pause="off" filter="0"> +</display> +</WorkSheet> diff --git a/ksysguard/gui/WorkSheet.cc b/ksysguard/gui/WorkSheet.cc new file mode 100644 index 000000000..f6555a1c6 --- /dev/null +++ b/ksysguard/gui/WorkSheet.cc @@ -0,0 +1,698 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qclipboard.h> +#include <qcursor.h> +#include <qdragobject.h> +#include <qfile.h> +#include <qlayout.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kpopupmenu.h> + +#include <SensorManager.h> + +#include "DancingBars.h" +#include "DummyDisplay.h" +#include "FancyPlotter.h" +#include "ListView.h" +#include "LogFile.h" +#include "MultiMeter.h" +#include "ProcessController.h" +#include "SensorLogger.h" +#include "WorkSheet.h" +#include "WorkSheetSettings.h" + +WorkSheet::WorkSheet( QWidget *parent, const char *name ) + : QWidget( parent, name ) +{ + mGridLayout = 0; + mRows = mColumns = 0; + mDisplayList = 0; + mModified = false; + mFileName = ""; + + setAcceptDrops( true ); +} + +WorkSheet::WorkSheet( uint rows, uint columns, uint interval, QWidget* parent, + const char *name ) + : QWidget( parent, name ) +{ + mRows = mColumns = 0; + mGridLayout = 0; + mDisplayList = 0; + updateInterval( interval ); + mModified = false; + mFileName = ""; + + createGrid( rows, columns ); + + // Initialize worksheet with dummy displays. + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + replaceDisplay( r, c ); + + mGridLayout->activate(); + + setAcceptDrops( true ); +} + +WorkSheet::~WorkSheet() +{ +} + +bool WorkSheet::load( const QString &fileName ) +{ + setModified( false ); + + mFileName = fileName; + QFile file( mFileName ); + if ( !file.open( IO_ReadOnly ) ) { + KMessageBox::sorry( this, i18n( "Cannot open the file %1." ).arg( mFileName ) ); + return false; + } + + QDomDocument doc; + + // Read in file and check for a valid XML header. + if ( !doc.setContent( &file) ) { + KMessageBox::sorry( this, i18n( "The file %1 does not contain valid XML." ) + .arg( mFileName ) ); + return false; + } + + // Check for proper document type. + if ( doc.doctype().name() != "KSysGuardWorkSheet" ) { + KMessageBox::sorry( this, i18n( "The file %1 does not contain a valid worksheet " + "definition, which must have a document type 'KSysGuardWorkSheet'.") + .arg( mFileName ) ); + return false; + } + + // Check for proper size. + QDomElement element = doc.documentElement(); + updateInterval( element.attribute( "interval" ).toUInt() ); + if ( updateInterval() < 1 || updateInterval() > 300 ) + updateInterval( 2 ); + + bool rowsOk, columnsOk; + uint rows = element.attribute( "rows" ).toUInt( &rowsOk ); + uint columns = element.attribute( "columns" ).toUInt( &columnsOk ); + if ( !( rowsOk && columnsOk ) ) { + KMessageBox::sorry( this, i18n("The file %1 has an invalid worksheet size.") + .arg( mFileName ) ); + return false; + } + + createGrid( rows, columns ); + + uint i; + /* Load lists of hosts that are needed for the work sheet and try + * to establish a connection. */ + QDomNodeList dnList = element.elementsByTagName( "host" ); + for ( i = 0; i < dnList.count(); ++i ) { + QDomElement element = dnList.item( i ).toElement(); + bool ok; + int port = element.attribute( "port" ).toInt( &ok ); + if ( !ok ) + port = -1; + KSGRD::SensorMgr->engage( element.attribute( "name" ), + element.attribute( "shell" ), + element.attribute( "command" ), port ); + } + //if no hosts are specified, at least connect to localhost + if(dnList.count() == 0) + KSGRD::SensorMgr->engage( "localhost", "", "ksysguardd", -1); + + // Load the displays and place them into the work sheet. + dnList = element.elementsByTagName( "display" ); + for ( i = 0; i < dnList.count(); ++i ) { + QDomElement element = dnList.item( i ).toElement(); + uint row = element.attribute( "row" ).toUInt(); + uint column = element.attribute( "column" ).toUInt(); + if ( row >= mRows || column >= mColumns) { + kdDebug(1215) << "Row or Column out of range (" << row << ", " + << column << ")" << endl; + return false; + } + + replaceDisplay( row, column, element ); + } + + // Fill empty cells with dummy displays + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + if ( !mDisplayList[ r ][ c ] ) + replaceDisplay( r, c ); + + setModified( false ); + + return true; +} + +bool WorkSheet::save( const QString &fileName ) +{ + mFileName = fileName; + + QDomDocument doc( "KSysGuardWorkSheet" ); + doc.appendChild( doc.createProcessingInstruction( + "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); + + // save work sheet information + QDomElement ws = doc.createElement( "WorkSheet" ); + doc.appendChild( ws ); + ws.setAttribute( "interval", updateInterval() ); + ws.setAttribute( "rows", mRows ); + ws.setAttribute( "columns", mColumns ); + + QStringList hosts; + collectHosts( hosts ); + + // save host information (name, shell, etc.) + QStringList::Iterator it; + for ( it = hosts.begin(); it != hosts.end(); ++it ) { + QString shell, command; + int port; + + if ( KSGRD::SensorMgr->hostInfo( *it, shell, command, port ) ) { + QDomElement host = doc.createElement( "host" ); + ws.appendChild( host ); + host.setAttribute( "name", *it ); + host.setAttribute( "shell", shell ); + host.setAttribute( "command", command ); + host.setAttribute( "port", port ); + } + } + + for ( uint r = 0; r < mRows; ++r ) + for (uint c = 0; c < mColumns; ++c ) + if ( !mDisplayList[ r ][ c ]->isA( "DummyDisplay" ) ) { + KSGRD::SensorDisplay* display = (KSGRD::SensorDisplay*)mDisplayList[ r ][ c ]; + QDomElement element = doc.createElement( "display" ); + ws.appendChild( element ); + element.setAttribute( "row", r ); + element.setAttribute( "column", c ); + element.setAttribute( "class", display->className() ); + + display->saveSettings( doc, element ); + } + + QFile file( mFileName ); + if ( !file.open( IO_WriteOnly ) ) { + KMessageBox::sorry( this, i18n( "Cannot save file %1" ).arg( mFileName ) ); + return false; + } + + QTextStream s( &file ); + s.setEncoding( QTextStream::UnicodeUTF8 ); + s << doc; + file.close(); + + setModified( false ); + + return true; +} + +void WorkSheet::cut() +{ + if ( !currentDisplay() || currentDisplay()->isA( "DummyDisplay" ) ) + return; + + QClipboard* clip = QApplication::clipboard(); + + clip->setText( currentDisplayAsXML() ); + + removeDisplay( currentDisplay() ); +} + +void WorkSheet::copy() +{ + if ( !currentDisplay() || currentDisplay()->isA( "DummyDisplay" ) ) + return; + + QClipboard* clip = QApplication::clipboard(); + + clip->setText( currentDisplayAsXML() ); +} + +void WorkSheet::paste() +{ + uint row, column; + if ( !currentDisplay( &row, &column ) ) + return; + + QClipboard* clip = QApplication::clipboard(); + + QDomDocument doc; + /* Get text from clipboard and check for a valid XML header and + * proper document type. */ + if ( !doc.setContent( clip->text() ) || doc.doctype().name() != "KSysGuardDisplay" ) { + KMessageBox::sorry( this, i18n("The clipboard does not contain a valid display " + "description." ) ); + return; + } + + QDomElement element = doc.documentElement(); + replaceDisplay( row, column, element ); +} + +void WorkSheet::setFileName( const QString &fileName ) +{ + mFileName = fileName; + setModified( true ); +} + +const QString& WorkSheet::fileName() const +{ + return mFileName; +} + +bool WorkSheet::modified() const +{ + return mModified; +} + +void WorkSheet::setTitle( const QString &title ) +{ + mTitle = title; +} + +QString WorkSheet::title() const +{ + return mTitle; +} + +KSGRD::SensorDisplay *WorkSheet::addDisplay( const QString &hostName, + const QString &sensorName, + const QString &sensorType, + const QString& sensorDescr, + uint row, uint column ) +{ + if ( !KSGRD::SensorMgr->engageHost( hostName ) ) { + QString msg = i18n( "It is impossible to connect to \'%1\'." ).arg( hostName ); + KMessageBox::error( this, msg ); + + return 0; + } + + /* If the by 'row' and 'column' specified display is a QGroupBox dummy + * display we replace the widget. Otherwise we just try to add + * the new sensor to an existing display. */ + if ( mDisplayList[ row ][ column ]->isA( "DummyDisplay" ) ) { + KSGRD::SensorDisplay* newDisplay = 0; + /* If the sensor type is supported by more than one display + * type we popup a menu so the user can select what display is + * wanted. */ + if ( sensorType == "integer" || sensorType == "float" ) { + KPopupMenu pm; + pm.insertTitle( i18n( "Select Display Type" ) ); + pm.insertItem( i18n( "&Signal Plotter" ), 1 ); + pm.insertItem( i18n( "&Multimeter" ), 2 ); + pm.insertItem( i18n( "&BarGraph" ), 3 ); + pm.insertItem( i18n( "S&ensorLogger" ), 4 ); + switch ( pm.exec( QCursor::pos() ) ) { + case 1: + newDisplay = new FancyPlotter( this, "FancyPlotter", sensorDescr ); + break; + case 2: + newDisplay = new MultiMeter( this, "MultiMeter", sensorDescr ); + break; + case 3: + newDisplay = new DancingBars( this, "DancingBars", sensorDescr ); + break; + case 4: + newDisplay = new SensorLogger( this, "SensorLogger", sensorDescr ); + break; + default: + return 0; + } + } else if ( sensorType == "listview" ) + newDisplay = new ListView( this, "ListView", sensorDescr ); + else if ( sensorType == "logfile" ) + newDisplay = new LogFile( this, "LogFile", sensorDescr ); + else if ( sensorType == "sensorlogger" ) + newDisplay = new SensorLogger( this, "SensorLogger", sensorDescr ); + else if ( sensorType == "table" ) + newDisplay = new ProcessController( this ); + else { + kdDebug(1215) << "Unkown sensor type: " << sensorType << endl; + return 0; + } + + replaceDisplay( row, column, newDisplay ); + } + + mDisplayList[ row ][ column ]->addSensor( hostName, sensorName, sensorType, sensorDescr ); + + setModified( true ); + + return ((KSGRD::SensorDisplay*)mDisplayList[ row ][ column ] ); +} + +void WorkSheet::settings() +{ + WorkSheetSettings dlg( this ); + + /* The sheet name should be changed with the "Save as..." function, + * so we don't have to display the display frame. */ + dlg.setSheetTitle( mTitle ); + dlg.setRows( mRows ); + dlg.setColumns( mColumns ); + dlg.setInterval( updateInterval() ); + + if ( dlg.exec() ) { + updateInterval( dlg.interval() ); + for (uint r = 0; r < mRows; ++r) + for (uint c = 0; c < mColumns; ++c) + if ( mDisplayList[ r ][ c ]->useGlobalUpdateInterval() ) + mDisplayList[ r ][ c ]->setUpdateInterval( updateInterval() ); + + resizeGrid( dlg.rows(), dlg.columns() ); + + mTitle = dlg.sheetTitle(); + emit titleChanged( this ); + + setModified( true ); + } +} + +void WorkSheet::showPopupMenu( KSGRD::SensorDisplay *display ) +{ + display->configureSettings(); +} + +void WorkSheet::setModified( bool modified ) +{ + if ( modified != mModified ) { + mModified = modified; + if ( !modified ) + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + mDisplayList[ r ][ c ]->setModified( false ); + + emit sheetModified( this ); + } +} + +void WorkSheet::applyStyle() +{ + for ( uint r = 0; r < mRows; ++r ) + for (uint c = 0; c < mColumns; ++c ) + mDisplayList[ r ][ c ]->applyStyle(); +} + +void WorkSheet::dragEnterEvent( QDragEnterEvent *e ) +{ + e->accept( QTextDrag::canDecode( e ) ); +} + +void WorkSheet::dropEvent( QDropEvent *e ) +{ + QString dragObject; + + if ( QTextDrag::decode( e, dragObject) ) { + // The host name, sensor name and type are seperated by a ' '. + QStringList parts = QStringList::split( ' ', dragObject ); + + QString hostName = parts[ 0 ]; + QString sensorName = parts[ 1 ]; + QString sensorType = parts[ 2 ]; + QString sensorDescr = parts[ 3 ]; + + if ( hostName.isEmpty() || sensorName.isEmpty() || sensorType.isEmpty() ) { + return; + } + + /* Find the sensor display that is supposed to get the drop + * event and replace or add sensor. */ + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + if ( mDisplayList[ r ][ c ]->geometry().contains( e->pos() ) ) { + addDisplay( hostName, sensorName, sensorType, sensorDescr, r, c ); + return; + } + } +} + +QSize WorkSheet::sizeHint() const +{ + return QSize( 200,150 ); +} + +void WorkSheet::customEvent( QCustomEvent *e ) +{ + if ( e->type() == QEvent::User ) { + // SensorDisplays send out this event if they want to be removed. + + removeDisplay( (KSGRD::SensorDisplay*)e->data() ); + } +} + +bool WorkSheet::replaceDisplay( uint row, uint column, QDomElement& element ) +{ + QString classType = element.attribute( "class" ); + KSGRD::SensorDisplay* newDisplay; + if ( classType == "FancyPlotter" ) + newDisplay = new FancyPlotter( this ); + else if ( classType == "MultiMeter" ) + newDisplay = new MultiMeter( this ); + else if ( classType == "DancingBars" ) + newDisplay = new DancingBars( this ); + else if ( classType == "ListView" ) + newDisplay = new ListView( this ); + else if ( classType == "LogFile" ) + newDisplay = new LogFile( this ); + else if ( classType == "SensorLogger" ) + newDisplay = new SensorLogger( this ); + else if ( classType == "ProcessController" ) + newDisplay = new ProcessController( this ); + else { + kdDebug(1215) << "Unkown class " << classType << endl; + return false; + } + + if ( newDisplay->useGlobalUpdateInterval() ) + newDisplay->setUpdateInterval( updateInterval() ); + + // load display specific settings + if ( !newDisplay->restoreSettings( element ) ) + return false; + + replaceDisplay( row, column, newDisplay ); + + return true; +} + +void WorkSheet::replaceDisplay( uint row, uint column, KSGRD::SensorDisplay* newDisplay ) +{ + // remove the old display at this location + delete mDisplayList[ row ][ column ]; + + // insert new display + if ( !newDisplay ) + mDisplayList[ row ][ column ] = new DummyDisplay( this, "DummyDisplay" ); + else { + mDisplayList[ row ][ column ] = newDisplay; + if ( mDisplayList[ row ][ column ]->useGlobalUpdateInterval() ) + mDisplayList[ row ][ column ]->setUpdateInterval( updateInterval() ); + connect( newDisplay, SIGNAL( showPopupMenu( KSGRD::SensorDisplay* ) ), + SLOT( showPopupMenu( KSGRD::SensorDisplay* ) ) ); + connect( newDisplay, SIGNAL( modified( bool ) ), + SLOT( setModified( bool ) ) ); + } + + + mGridLayout->addWidget( mDisplayList[ row ][ column ], row, column ); + + if ( isVisible() ) { + mDisplayList[ row ][ column ]->show(); + } + + setMinimumSize(sizeHint()); + + setModified( true ); +} + +void WorkSheet::removeDisplay( KSGRD::SensorDisplay *display ) +{ + if ( !display ) + return; + + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + if ( mDisplayList[ r ][ c ] == display ) { + replaceDisplay( r, c ); + setModified( true ); + return; + } +} + +void WorkSheet::collectHosts( QStringList &list ) +{ + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + if ( !mDisplayList[ r ][ c ]->isA( "DummyDisplay" ) ) + ((KSGRD::SensorDisplay*)mDisplayList[ r ][ c ])->hosts( list ); +} + +void WorkSheet::createGrid( uint rows, uint columns ) +{ + mRows = rows; + mColumns = columns; + + // create grid layout with specified dimentions + mGridLayout = new QGridLayout( this, mRows, mColumns, 5 ); + + mDisplayList = new KSGRD::SensorDisplay**[ mRows ]; + for ( uint r = 0; r < mRows; ++r ) { + mDisplayList[ r ] = new KSGRD::SensorDisplay*[ mColumns ]; + for ( uint c = 0; c < mColumns; ++c ) + mDisplayList[ r ][ c ] = 0; + } + + /* set stretch factors for rows and columns */ + for ( uint r = 0; r < mRows; ++r ) + mGridLayout->setRowStretch( r, 100 ); + for ( uint c = 0; c < mColumns; ++c ) + mGridLayout->setColStretch( c, 100 ); +} + +void WorkSheet::resizeGrid( uint newRows, uint newColumns ) +{ + uint r, c; + + /* Create new array for display pointers */ + KSGRD::SensorDisplay*** newDisplayList = new KSGRD::SensorDisplay**[ newRows ]; + for ( r = 0; r < newRows; ++r ) { + newDisplayList[ r ] = new KSGRD::SensorDisplay*[ newColumns ]; + for ( c = 0; c < newColumns; ++c ) { + if ( c < mColumns && r < mRows ) + newDisplayList[ r ][ c ] = mDisplayList[ r ][ c ]; + else + newDisplayList[ r ][ c ] = 0; + } + } + + /* remove obsolete displays */ + for ( r = 0; r < mRows; ++r ) { + for ( c = 0; c < mColumns; ++c ) + if ( r >= newRows || c >= newColumns ) + delete mDisplayList[ r ][ c ]; + delete mDisplayList[ r ]; + } + delete [] mDisplayList; + + /* now we make the new display the regular one */ + mDisplayList = newDisplayList; + + /* create new displays */ + for ( r = 0; r < newRows; ++r ) + for ( c = 0; c < newColumns; ++c ) + if ( r >= mRows || c >= mColumns ) + replaceDisplay( r, c ); + + /* set stretch factors for new rows and columns (if any) */ + for ( r = mRows; r < newRows; ++r ) + mGridLayout->setRowStretch( r, 100 ); + for ( c = mColumns; c < newColumns; ++c ) + mGridLayout->setColStretch( c, 100 ); + + /* Obviously Qt does not shrink the size of the QGridLayout + * automatically. So we simply force the rows and columns that + * are no longer used to have a strech factor of 0 and hence be + * invisible. */ + for ( r = newRows; r < mRows; ++r ) + mGridLayout->setRowStretch( r, 0 ); + for ( c = newColumns; c < mColumns; ++c ) + mGridLayout->setColStretch( c, 0 ); + + mRows = newRows; + mColumns = newColumns; + + fixTabOrder(); + + mGridLayout->activate(); +} + +KSGRD::SensorDisplay *WorkSheet::display( uint row, uint column ) { + if(row >= mRows || column >= mColumns) return 0; + return mDisplayList[row][column]; +} +KSGRD::SensorDisplay *WorkSheet::currentDisplay( uint *row, uint *column ) +{ + for ( uint r = 0 ; r < mRows; ++r ) + for ( uint c = 0 ; c < mColumns; ++c ) + if ( mDisplayList[ r ][ c ]->hasFocus() ) { + if ( row ) + *row = r; + if ( column ) + *column = c; + return ( mDisplayList[ r ][ c ] ); + } + + return 0; +} + +void WorkSheet::fixTabOrder() +{ + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) { + if ( c + 1 < mColumns ) + setTabOrder( mDisplayList[ r ][ c ], mDisplayList[ r ][ c + 1 ] ); + else if ( r + 1 < mRows ) + setTabOrder( mDisplayList[ r ][ c ], mDisplayList[ r + 1 ][ 0 ] ); + } +} + +QString WorkSheet::currentDisplayAsXML() +{ + KSGRD::SensorDisplay* display = currentDisplay(); + if ( !display ) + return QString::null; + + /* We create an XML description of the current display. */ + QDomDocument doc( "KSysGuardDisplay" ); + doc.appendChild( doc.createProcessingInstruction( + "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); + + QDomElement element = doc.createElement( "display" ); + doc.appendChild( element ); + element.setAttribute( "class", display->className() ); + display->saveSettings( doc, element ); + + return doc.toString(); +} + +void WorkSheet::setIsOnTop( bool /* onTop */ ) +{ +/* + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + mDisplayList[ r ][ c ]->setIsOnTop( onTop ); +*/ +} + +#include "WorkSheet.moc" diff --git a/ksysguard/gui/WorkSheet.h b/ksysguard/gui/WorkSheet.h new file mode 100644 index 000000000..f706f36dc --- /dev/null +++ b/ksysguard/gui/WorkSheet.h @@ -0,0 +1,135 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_WORKSHEET_H +#define KSG_WORKSHEET_H + +#include <qwidget.h> + +#include <SensorDisplay.h> + +class QDomElement; +class QDragEnterEvent; +class QDropEvent; +class QGridLayout; +class QString; +class QStringList; + +/** + A WorkSheet contains the displays to visualize the sensor results. When + creating the WorkSheet you must specify the number of columns. Displays + can be added and removed on the fly. The grid layout will handle the + layout. The number of columns can not be changed. Displays are added by + dragging a sensor from the sensor browser over the WorkSheet. + */ +class WorkSheet : public QWidget, public KSGRD::SensorBoard +{ + Q_OBJECT + + public: + WorkSheet( QWidget* parent, const char *name = 0 ); + WorkSheet( uint rows, uint columns, uint interval, QWidget* parent, + const char *name = 0 ); + ~WorkSheet(); + + bool load( const QString &fileName ); + bool save( const QString &fileName ); + + void cut(); + void copy(); + void paste(); + + void setFileName( const QString &fileName ); + const QString& fileName() const; + + bool modified() const; + + void setTitle( const QString &title ); + QString title() const; + + KSGRD::SensorDisplay* addDisplay( const QString &hostname, + const QString &monitor, + const QString &sensorType, + const QString &sensorDescr, + uint rows, uint columns ); + //Returns the sensor at position row,column. + //Return NULL if invalid row or column + KSGRD::SensorDisplay *display( uint row, uint column ); + + void settings(); + + void setIsOnTop( bool onTop ); + + public slots: + void showPopupMenu( KSGRD::SensorDisplay *display ); + void setModified( bool mfd ); + void applyStyle(); + + signals: + void sheetModified( QWidget *sheet ); + void titleChanged( QWidget *sheet ); + + protected: + virtual QSize sizeHint() const; + void dragEnterEvent( QDragEnterEvent* ); + void dropEvent( QDropEvent* ); + void customEvent( QCustomEvent* ); + + private: + void removeDisplay( KSGRD::SensorDisplay *display ); + + bool replaceDisplay( uint row, uint column, QDomElement& element ); + + void replaceDisplay( uint row, uint column, + KSGRD::SensorDisplay* display = 0 ); + + void collectHosts( QStringList &list ); + + void createGrid( uint rows, uint columns ); + + void resizeGrid( uint rows, uint columns ); + + KSGRD::SensorDisplay* currentDisplay( uint* row = 0, uint* column = 0 ); + + void fixTabOrder(); + + QString currentDisplayAsXML(); + + bool mModified; + + uint mRows; + uint mColumns; + + QGridLayout* mGridLayout; + QString mFileName; + QString mTitle; + + /** + This two dimensional array stores the pointers to the sensor displays + or if no sensor is present at a position a pointer to a dummy widget. + The size of the array corresponds to the size of the grid layout. + */ + KSGRD::SensorDisplay*** mDisplayList; +}; + +#endif diff --git a/ksysguard/gui/WorkSheetSettings.cc b/ksysguard/gui/WorkSheetSettings.cc new file mode 100644 index 000000000..e9ba0da08 --- /dev/null +++ b/ksysguard/gui/WorkSheetSettings.cc @@ -0,0 +1,153 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <kaccelmanager.h> +#include <klineedit.h> +#include <knuminput.h> +#include <klocale.h> + +#include <qgroupbox.h> +#include <qlabel.h> +#include <qspinbox.h> +#include <qlayout.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +#include "WorkSheetSettings.h" + +WorkSheetSettings::WorkSheetSettings( QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, QString::null, Ok|Cancel, Ok, true ) +{ + setCaption( i18n( "Worksheet Properties" ) ); + + QWidget *page = new QWidget( this ); + setMainWidget( page ); + + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + + QGroupBox *group = new QGroupBox( 0, Qt::Vertical, i18n( "Title" ), page ); + group->layout()->setMargin( marginHint() ); + group->layout()->setSpacing( spacingHint() ); + + QGridLayout *groupLayout = new QGridLayout( group->layout(), 1, 1 ); + groupLayout->setAlignment( Qt::AlignTop ); + + mSheetTitle = new KLineEdit( group ); + groupLayout->addWidget( mSheetTitle, 0, 0 ); + + topLayout->addWidget( group ); + + group = new QGroupBox( 0, Qt::Vertical, i18n( "Properties" ), page ); + group->layout()->setMargin( marginHint() ); + group->layout()->setSpacing( spacingHint() ); + + groupLayout = new QGridLayout( group->layout(), 3, 2 ); + groupLayout->setAlignment( Qt::AlignTop ); + + QLabel *label = new QLabel( i18n( "Rows:" ), group ); + groupLayout->addWidget( label, 0, 0 ); + + mRows = new KIntNumInput( 1, group ); + mRows->setMaxValue( 42 ); + mRows->setMinValue( 1 ); + groupLayout->addWidget( mRows, 0, 1 ); + label->setBuddy( mRows ); + + label = new QLabel( i18n( "Columns:" ), group ); + groupLayout->addWidget( label, 1, 0 ); + + mColumns = new KIntNumInput( 1, group ); + mColumns->setMaxValue( 42 ); + mColumns->setMinValue( 1 ); + groupLayout->addWidget( mColumns, 1, 1 ); + label->setBuddy( mColumns ); + + label = new QLabel( i18n( "Update interval:" ), group ); + groupLayout->addWidget( label, 2, 0 ); + + mInterval = new KIntNumInput( 2, group ); + mInterval->setMaxValue( 300 ); + mInterval->setMinValue( 1 ); + mInterval->setSuffix( i18n( " sec" ) ); + groupLayout->addWidget( mInterval, 2, 1 ); + label->setBuddy( mInterval ); + + topLayout->addWidget( group ); + + QWhatsThis::add( mRows, i18n( "Enter the number of rows the sheet should have." ) ); + QWhatsThis::add( mColumns, i18n( "Enter the number of columns the sheet should have." ) ); + QWhatsThis::add( mInterval, i18n( "All displays of the sheet are updated at the rate specified here." ) ); + QToolTip::add( mSheetTitle, i18n( "Enter the title of the worksheet here." ) ); + + KAcceleratorManager::manage( page ); + + mSheetTitle->setFocus(); + + resize( QSize( 250, 230 ).expandedTo( minimumSizeHint() ) ); +} + +WorkSheetSettings::~WorkSheetSettings() +{ +} + +void WorkSheetSettings::setRows( int rows ) +{ + mRows->setValue( rows ); +} + +int WorkSheetSettings::rows() const +{ + return mRows->value(); +} + +void WorkSheetSettings::setColumns( int columns ) +{ + mColumns->setValue( columns ); +} + +int WorkSheetSettings::columns() const +{ + return mColumns->value(); +} + +void WorkSheetSettings::setInterval( int interval ) +{ + mInterval->setValue( interval ); +} + +int WorkSheetSettings::interval() const +{ + return mInterval->value(); +} + +void WorkSheetSettings::setSheetTitle( const QString &title ) +{ + mSheetTitle->setText( title ); +} + +QString WorkSheetSettings::sheetTitle() const +{ + return mSheetTitle->text(); +} + +#include "WorkSheetSettings.moc" diff --git a/ksysguard/gui/WorkSheetSettings.h b/ksysguard/gui/WorkSheetSettings.h new file mode 100644 index 000000000..8fe5641a5 --- /dev/null +++ b/ksysguard/gui/WorkSheetSettings.h @@ -0,0 +1,60 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_WORKSHEETSETTINGS_H +#define KSG_WORKSHEETSETTINGS_H + +#include <kdialogbase.h> + +class KLineEdit; +class KIntNumInput; + +class WorkSheetSettings : public KDialogBase +{ + Q_OBJECT + + public: + WorkSheetSettings( QWidget* parent = 0, const char* name = 0 ); + ~WorkSheetSettings(); + + void setRows( int rows ); + int rows() const; + + void setColumns( int columns ); + int columns() const; + + void setInterval( int interval ); + int interval() const; + + void setSheetTitle( const QString &title ); + QString sheetTitle() const; + + private: + KLineEdit* mSheetTitle; + + KIntNumInput* mColumns; + KIntNumInput* mInterval; + KIntNumInput* mRows; +}; + +#endif diff --git a/ksysguard/gui/Workspace.cc b/ksysguard/gui/Workspace.cc new file mode 100644 index 000000000..c179317c0 --- /dev/null +++ b/ksysguard/gui/Workspace.cc @@ -0,0 +1,463 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qlineedit.h> +#include <qspinbox.h> +#include <qwhatsthis.h> + +#include <kdebug.h> +#include <kfiledialog.h> +#include <kio/netaccess.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <kaccelmanager.h> + +#include "WorkSheet.h" +#include "WorkSheetSettings.h" +#include "ProcessController.h" + +#include "Workspace.h" + +Workspace::Workspace( QWidget* parent, const char* name ) + : QTabWidget( parent, name ) +{ + KAcceleratorManager::setNoAccel(this); + + mSheetList.setAutoDelete( true ); + mAutoSave = true; + + connect( this, SIGNAL( currentChanged( QWidget* ) ), + SLOT( updateCaption( QWidget* ) ) ); + + QWhatsThis::add( this, i18n( "This is your work space. It holds your worksheets. You need " + "to create a new worksheet (Menu File->New) before " + "you can drag sensors here." ) ); +} + +Workspace::~Workspace() +{ + /* This workaround is necessary to prevent a crash when the last + * page is not the current page. It seems like the the signal/slot + * administration data is already deleted but slots are still + * being triggered. TODO: I need to ask the Trolls about this. */ + + disconnect( this, SIGNAL( currentChanged( QWidget* ) ), this, + SLOT( updateCaption( QWidget* ) ) ); +} + +void Workspace::saveProperties( KConfig *cfg ) +{ + cfg->writePathEntry( "WorkDir", mWorkDir ); + cfg->writeEntry( "CurrentSheet", tabLabel( currentPage() ) ); + + QPtrListIterator<WorkSheet> it( mSheetList); + + QStringList list; + for ( int i = 0; it.current(); ++it, ++i ) + if ( !(*it)->fileName().isEmpty() ) + list.append( (*it)->fileName() ); + + cfg->writePathEntry( "Sheets", list ); +} + +void Workspace::readProperties( KConfig *cfg ) +{ + QString currentSheet; + + mWorkDir = cfg->readPathEntry( "WorkDir" ); + + if ( mWorkDir.isEmpty() ) { + /* If workDir is not specified in the config file, it's + * probably the first time the user has started KSysGuard. We + * then "restore" a special default configuration. */ + KStandardDirs* kstd = KGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + + mWorkDir = kstd->saveLocation( "data", "ksysguard" ); + + QString origFile = kstd->findResource( "data", "SystemLoad.sgrd" ); + QString newFile = mWorkDir + "/" + i18n( "System Load" ) + ".sgrd"; + if ( !origFile.isEmpty() ) + restoreWorkSheet( origFile, newFile ); + + origFile = kstd->findResource( "data", "ProcessTable.sgrd" ); + newFile = mWorkDir + "/" + i18n( "Process Table" ) + ".sgrd"; + if ( !origFile.isEmpty() ) + restoreWorkSheet( origFile, newFile ); + + currentSheet = i18n( "System Load" ); + } else { + currentSheet = cfg->readEntry( "CurrentSheet" ); + QStringList list = cfg->readPathListEntry( "Sheets" ); + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) + restoreWorkSheet( *it ); + } + + // Determine visible sheet. + QPtrListIterator<WorkSheet> it( mSheetList ); + for ( ; it.current(); ++it ) + if ( currentSheet == tabLabel(*it) ) { + showPage( *it ); + break; + } +} + +void Workspace::newWorkSheet() +{ + /* Find a name of the form "Sheet %d" that is not yet used by any + * of the existing worksheets. */ + QString sheetName; + bool found; + + int i = 1; + do { + sheetName = i18n( "Sheet %1" ).arg( i++ ); + QPtrListIterator<WorkSheet> it( mSheetList ); + found = false; + for ( ; it.current() && !found; ++it ) + if ( tabLabel(*it) == sheetName ) + found = true; + } while ( found ); + + WorkSheetSettings dlg( this ); + dlg.setSheetTitle( sheetName ); + if ( dlg.exec() ) { + WorkSheet* sheet = new WorkSheet( dlg.rows(), dlg.columns(), dlg.interval(), this ); + sheet->setTitle( dlg.sheetTitle() ); + insertTab( sheet, dlg.sheetTitle() ); + mSheetList.append( sheet ); + showPage( sheet ); + connect( sheet, SIGNAL( sheetModified( QWidget* ) ), + SLOT( updateCaption( QWidget* ) ) ); + connect( sheet, SIGNAL( titleChanged( QWidget* ) ), + SLOT( updateSheetTitle( QWidget* ) ) ); + } +} + +bool Workspace::saveOnQuit() +{ + QPtrListIterator<WorkSheet> it( mSheetList ); + for ( ; it.current(); ++it ) + if ( (*it)->modified() ) { + if ( !mAutoSave || (*it)->fileName().isEmpty() ) { + int res = KMessageBox::warningYesNoCancel( this, + i18n( "The worksheet '%1' contains unsaved data.\n" + "Do you want to save the worksheet?") + .arg( tabLabel( *it ) ), QString::null, KStdGuiItem::save(), KStdGuiItem::discard() ); + if ( res == KMessageBox::Yes ) + saveWorkSheet( *it ); + else if ( res == KMessageBox::Cancel ) + return false; // abort quit + } else + saveWorkSheet(*it); + } + + return true; +} + +void Workspace::loadWorkSheet() +{ + KFileDialog dlg( 0, i18n( "*.sgrd|Sensor Files" ), this, + "LoadFileDialog", true ); + + KURL url = dlg.getOpenURL( mWorkDir, "*.sgrd", 0, i18n( "Select Worksheet to Load" ) ); + + loadWorkSheet( url ); +} + +void Workspace::loadWorkSheet( const KURL &url ) +{ + if ( url.isEmpty() ) + return; + + /* It's probably not worth the effort to make this really network + * transparent. Unless s/o beats me up I use this pseudo transparent + * code. */ + QString tmpFile; + KIO::NetAccess::download( url, tmpFile, this ); + mWorkDir = tmpFile.left( tmpFile.findRev( '/' ) ); + + // Load sheet from file. + if ( !restoreWorkSheet( tmpFile ) ) + return; + + /* If we have loaded a non-local file we clear the file name so that + * the users is prompted for a new name for saving the file. */ + KURL tmpFileUrl; + tmpFileUrl.setPath( tmpFile ); + if ( tmpFileUrl != url.url() ) + mSheetList.last()->setFileName( QString::null ); + KIO::NetAccess::removeTempFile( tmpFile ); + + emit announceRecentURL( KURL( url ) ); +} + +void Workspace::saveWorkSheet() +{ + saveWorkSheet( (WorkSheet*)currentPage() ); +} + +void Workspace::saveWorkSheetAs() +{ + saveWorkSheetAs( (WorkSheet*)currentPage() ); +} + +void Workspace::saveWorkSheet( WorkSheet *sheet ) +{ + if ( !sheet ) { + KMessageBox::sorry( this, i18n( "You do not have a worksheet that could be saved." ) ); + return; + } + + QString fileName = sheet->fileName(); + if ( fileName.isEmpty() ) { + KFileDialog dlg( 0, i18n( "*.sgrd|Sensor Files" ), this, + "LoadFileDialog", true ); + fileName = dlg.getSaveFileName( mWorkDir + "/" + tabLabel( sheet ) + + ".sgrd", "*.sgrd", 0, + i18n( "Save Current Worksheet As" ) ); + if ( fileName.isEmpty() ) + return; + + mWorkDir = fileName.left( fileName.findRev( '/' ) ); + + // extract filename without path + QString baseName = fileName.right( fileName.length() - fileName.findRev( '/' ) - 1 ); + + // chop off extension (usually '.sgrd') + baseName = baseName.left( baseName.findRev( '.' ) ); + changeTab( sheet, baseName ); + } + + /* If we cannot save the file is probably write protected. So we need + * to ask the user for a new name. */ + if ( !sheet->save( fileName ) ) { + saveWorkSheetAs( sheet ); + return; + } + + /* Add file to recent documents menue. */ + KURL url; + url.setPath( fileName ); + emit announceRecentURL( url ); +} + +void Workspace::saveWorkSheetAs( WorkSheet *sheet ) +{ + if ( !sheet ) { + KMessageBox::sorry( this, i18n( "You do not have a worksheet that could be saved." ) ); + return; + } + + QString fileName; + do { + KFileDialog dlg( 0, "*.sgrd", this, "LoadFileDialog", true ); + fileName = dlg.getSaveFileName( mWorkDir + "/" + tabLabel( currentPage() ) + + ".sgrd", "*.sgrd" ); + if ( fileName.isEmpty() ) + return; + + mWorkDir = fileName.left( fileName.findRev( '/' ) ); + + // extract filename without path + QString baseName = fileName.right( fileName.length() - fileName.findRev( '/' ) - 1 ); + + // chop off extension (usually '.sgrd') + baseName = baseName.left( baseName.findRev( '.' ) ); + changeTab( sheet, baseName ); + } while ( !sheet->save( fileName ) ); + + /* Add file to recent documents menue. */ + KURL url; + url.setPath( fileName ); + emit announceRecentURL( url ); +} + +void Workspace::deleteWorkSheet() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( current ) { + if ( current->modified() ) { + if ( !mAutoSave || current->fileName().isEmpty() ) { + int res = KMessageBox::warningYesNoCancel( this, + i18n( "The worksheet '%1' contains unsaved data.\n" + "Do you want to save the worksheet?" ) + .arg( tabLabel( current ) ), QString::null, KStdGuiItem::save(), KStdGuiItem::discard() ); + if ( res == KMessageBox::Cancel ) + return; + + if ( res == KMessageBox::Yes ) + saveWorkSheet( current ); + } else + saveWorkSheet( current ); + } + + removePage( current ); + mSheetList.remove( current ); + } else { + QString msg = i18n( "There are no worksheets that could be deleted." ); + KMessageBox::error( this, msg ); + } +} + +void Workspace::removeAllWorkSheets() +{ + WorkSheet *sheet; + while ( ( sheet = (WorkSheet*)currentPage() ) != 0 ) { + removePage( sheet ); + mSheetList.remove( sheet ); + } +} + +void Workspace::deleteWorkSheet( const QString &fileName ) +{ + QPtrListIterator<WorkSheet> it( mSheetList ); + for ( ; it.current(); ++it ) + if ( (*it)->fileName() == fileName ) { + removePage( *it ); + mSheetList.remove( *it ); + return; + } +} + +WorkSheet *Workspace::restoreWorkSheet( const QString &fileName, const QString &newName ) +{ + /* We might want to save the worksheet under a different name later. This + * name can be specified by newName. If newName is empty we use the + * original name to save the work sheet. */ + QString tmpStr; + if ( newName.isEmpty() ) + tmpStr = fileName; + else + tmpStr = newName; + + // extract filename without path + QString baseName = tmpStr.right( tmpStr.length() - tmpStr.findRev( '/' ) - 1 ); + + // chop off extension (usually '.sgrd') + baseName = baseName.left( baseName.findRev( '.' ) ); + + WorkSheet *sheet = new WorkSheet( this ); + sheet->setTitle( baseName ); + insertTab( sheet, baseName ); + showPage( sheet ); + + if ( !sheet->load( fileName ) ) { + delete sheet; + return NULL; + } + + mSheetList.append( sheet ); + connect( sheet, SIGNAL( sheetModified( QWidget* ) ), + SLOT( updateCaption( QWidget* ) ) ); + + /* Force the file name to be the new name. This also sets the modified + * flag, so that the file will get saved on exit. */ + if ( !newName.isEmpty() ) + sheet->setFileName( newName ); + + return sheet; +} + +void Workspace::cut() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( current ) + current->cut(); +} + +void Workspace::copy() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( current ) + current->copy(); +} + +void Workspace::paste() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( current ) + current->paste(); +} + +void Workspace::configure() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( !current ) + return; + + current->settings(); +} + +void Workspace::updateCaption( QWidget* wdg ) +{ + if ( wdg ) + emit setCaption( tabLabel( wdg ), ((WorkSheet*)wdg)->modified() ); + else + emit setCaption( QString::null, false ); + + for ( WorkSheet* s = mSheetList.first(); s != 0; s = mSheetList.next() ) + ((WorkSheet*)s)->setIsOnTop( s == wdg ); +} + +void Workspace::updateSheetTitle( QWidget* wdg ) +{ + if ( wdg ) + changeTab( wdg, static_cast<WorkSheet*>( wdg )->title() ); +} + +void Workspace::applyStyle() +{ + if ( currentPage() ) + ((WorkSheet*)currentPage())->applyStyle(); +} + +void Workspace::showProcesses() +{ + KStandardDirs* kstd = KGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + + QString file = kstd->findResource( "data", "ProcessTable.sgrd" ); + if ( file.isEmpty() ) { + KMessageBox::error( this, i18n( "Cannot find file ProcessTable.sgrd." ) ); + return; + } + WorkSheet *processSheet = restoreWorkSheet( file ); + if(!processSheet) return; + + //Set the focus of the search line. This is nasty I know, but I don't know how better to do this :( + KSGRD::SensorDisplay *processSensor = processSheet->display( 0,0 ); + if(!processSensor || !processSensor->isA("ProcessController")) return; + ProcessController *controller = dynamic_cast<ProcessController *>(processSensor); + if(!controller) return; + controller->setSearchFocus(); + +} + +#include "Workspace.moc" diff --git a/ksysguard/gui/Workspace.h b/ksysguard/gui/Workspace.h new file mode 100644 index 000000000..af27f6303 --- /dev/null +++ b/ksysguard/gui/Workspace.h @@ -0,0 +1,84 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_WORKSPACE_H +#define KSG_WORKSPACE_H + +#include <qptrlist.h> +#include <qtabwidget.h> + +class KConfig; +class KURL; +class QString; +class WorkSheet; + +class Workspace : public QTabWidget +{ + Q_OBJECT + + public: + Workspace( QWidget* parent, const char* name = 0 ); + ~Workspace(); + + void saveProperties( KConfig* ); + void readProperties( KConfig* ); + + bool saveOnQuit(); + + void showProcesses(); + + WorkSheet *restoreWorkSheet( const QString &fileName, + const QString &newName = QString::null ); + void deleteWorkSheet( const QString &fileName ); + + public slots: + void newWorkSheet(); + void loadWorkSheet(); + void loadWorkSheet( const KURL& ); + void saveWorkSheet(); + void saveWorkSheet( WorkSheet *sheet ); + void saveWorkSheetAs(); + void saveWorkSheetAs( WorkSheet *sheet ); + void deleteWorkSheet(); + void removeAllWorkSheets(); + void cut(); + void copy(); + void paste(); + void configure(); + void updateCaption( QWidget* ); + void updateSheetTitle( QWidget* ); + void applyStyle(); + + signals: + void announceRecentURL( const KURL &url ); + void setCaption( const QString &text, bool modified ); + + private: + QPtrList<WorkSheet> mSheetList; + + // Directory that was used for the last load/save. + QString mWorkDir; + bool mAutoSave; +}; + +#endif diff --git a/ksysguard/gui/kpm.c b/ksysguard/gui/kpm.c new file mode 100644 index 000000000..5ce25516a --- /dev/null +++ b/ksysguard/gui/kpm.c @@ -0,0 +1,8 @@ +/* A small wrapper to call ksysguard --showprocesses */ + +#include <unistd.h> + +int main() +{ + return execlp( "ksysguard", "ksysguard", "--showprocesses", 0 ); +} diff --git a/ksysguard/gui/ksgrd/HostConnector.cc b/ksysguard/gui/ksgrd/HostConnector.cc new file mode 100644 index 000000000..5762d08b3 --- /dev/null +++ b/ksysguard/gui/ksgrd/HostConnector.cc @@ -0,0 +1,217 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + 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. + +*/ + +#include <kapplication.h> +#include <kaccelmanager.h> +#include <kcombobox.h> +#include <klocale.h> + +#include <qbuttongroup.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qradiobutton.h> +#include <qspinbox.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +#include "HostConnector.h" + +HostConnector::HostConnector( QWidget *parent, const char *name ) + : KDialogBase( Plain, i18n( "Connect Host" ), Help | Ok | Cancel, Ok, + parent, name, true, true ) +{ + QFrame *page = plainPage(); + QGridLayout *layout = new QGridLayout( page, 2, 2, 0, spacingHint() ); + layout->setColStretch( 1, 1 ); + + QLabel *label = new QLabel( i18n( "Host:" ), page ); + layout->addWidget( label, 0, 0 ); + + mHostNames = new KComboBox( true, page ); + mHostNames->setMaxCount( 20 ); + mHostNames->setInsertionPolicy( QComboBox::AtTop ); + mHostNames->setAutoCompletion( true ); + mHostNames->setDuplicatesEnabled( false ); + layout->addWidget( mHostNames, 0, 1 ); + label->setBuddy( mHostNames ); + QWhatsThis::add( mHostNames, i18n( "Enter the name of the host you want to connect to." ) ); + + mHostNameLabel = new QLabel( page ); + mHostNameLabel->hide(); + layout->addWidget( mHostNameLabel, 0, 1 ); + + QButtonGroup *group = new QButtonGroup( 0, Qt::Vertical, + i18n( "Connection Type" ), page ); + QGridLayout *groupLayout = new QGridLayout( group->layout(), 4, 4, + spacingHint() ); + groupLayout->setAlignment( Qt::AlignTop ); + + mUseSsh = new QRadioButton( i18n( "ssh" ), group ); + mUseSsh->setEnabled( true ); + mUseSsh->setChecked( true ); + QWhatsThis::add( mUseSsh, i18n( "Select this to use the secure shell to login to the remote host." ) ); + groupLayout->addWidget( mUseSsh, 0, 0 ); + + mUseRsh = new QRadioButton( i18n( "rsh" ), group ); + QWhatsThis::add( mUseRsh, i18n( "Select this to use the remote shell to login to the remote host." ) ); + groupLayout->addWidget( mUseRsh, 0, 1 ); + + mUseDaemon = new QRadioButton( i18n( "Daemon" ), group ); + QWhatsThis::add( mUseDaemon, i18n( "Select this if you want to connect to a ksysguard daemon that is running on the machine you want to connect to, and is listening for client requests." ) ); + groupLayout->addWidget( mUseDaemon, 0, 2 ); + + mUseCustom = new QRadioButton( i18n( "Custom command" ), group ); + QWhatsThis::add( mUseCustom, i18n( "Select this to use the command you entered below to start ksysguardd on the remote host." ) ); + groupLayout->addWidget( mUseCustom, 0, 3 ); + + label = new QLabel( i18n( "Port:" ), group ); + groupLayout->addWidget( label, 1, 0 ); + + mPort = new QSpinBox( 1, 65535, 1, group ); + mPort->setEnabled( false ); + mPort->setValue( 3112 ); + QToolTip::add( mPort, i18n( "Enter the port number on which the ksysguard daemon is listening for connections." ) ); + groupLayout->addWidget( mPort, 1, 2 ); + + label = new QLabel( i18n( "e.g. 3112" ), group ); + groupLayout->addWidget( label, 1, 3 ); + + label = new QLabel( i18n( "Command:" ), group ); + groupLayout->addWidget( label, 2, 0 ); + + mCommands = new KComboBox( true, group ); + mCommands->setEnabled( false ); + mCommands->setMaxCount( 20 ); + mCommands->setInsertionPolicy( QComboBox::AtTop ); + mCommands->setAutoCompletion( true ); + mCommands->setDuplicatesEnabled( false ); + QWhatsThis::add( mCommands, i18n( "Enter the command that runs ksysguardd on the host you want to monitor." ) ); + groupLayout->addMultiCellWidget( mCommands, 2, 2, 2, 3 ); + label->setBuddy( mCommands ); + + label = new QLabel( i18n( "e.g. ssh -l root remote.host.org ksysguardd" ), group ); + groupLayout->addMultiCellWidget( label, 3, 3, 2, 3 ); + + layout->addMultiCellWidget( group, 1, 1, 0, 1 ); + + connect( mUseCustom, SIGNAL( toggled( bool ) ), + mCommands, SLOT( setEnabled( bool ) ) ); + connect( mUseDaemon, SIGNAL( toggled( bool ) ), + mPort, SLOT( setEnabled( bool ) ) ); + connect( mHostNames->lineEdit(), SIGNAL( textChanged ( const QString & ) ), + this, SLOT( slotHostNameChanged( const QString & ) ) ); + enableButtonOK( !mHostNames->lineEdit()->text().isEmpty() ); + KAcceleratorManager::manage( this ); +} + +HostConnector::~HostConnector() +{ +} + +void HostConnector::slotHostNameChanged( const QString &_text ) +{ + enableButtonOK( !_text.isEmpty() ); +} + +void HostConnector::setHostNames( const QStringList &list ) +{ + mHostNames->insertStringList( list ); +} + +QStringList HostConnector::hostNames() const +{ + QStringList list; + + for ( int i = 0; i < mHostNames->count(); ++i ) + list.append( mHostNames->text( i ) ); + + return list; +} + +void HostConnector::setCommands( const QStringList &list ) +{ + mCommands->insertStringList( list ); +} + +QStringList HostConnector::commands() const +{ + QStringList list; + + for ( int i = 0; i < mCommands->count(); ++i ) + list.append( mCommands->text( i ) ); + + return list; +} + +void HostConnector::setCurrentHostName( const QString &hostName ) +{ + if ( !hostName.isEmpty() ) { + mHostNames->hide(); + mHostNameLabel->setText( hostName ); + mHostNameLabel->show(); + enableButtonOK( true );//enable true when mHostNames is empty and hidden fix #66955 + } else { + mHostNameLabel->hide(); + mHostNames->show(); + mHostNames->setFocus(); + } +} + +QString HostConnector::currentHostName() const +{ + return mHostNames->currentText(); +} + +QString HostConnector::currentCommand() const +{ + return mCommands->currentText(); +} + +int HostConnector::port() const +{ + return mPort->value(); +} + +bool HostConnector::useSsh() const +{ + return mUseSsh->isChecked(); +} + +bool HostConnector::useRsh() const +{ + return mUseRsh->isChecked(); +} + +bool HostConnector::useDaemon() const +{ + return mUseDaemon->isChecked(); +} + +bool HostConnector::useCustom() const +{ + return mUseCustom->isChecked(); +} + +void HostConnector::slotHelp() +{ + kapp->invokeHelp( "CONNECTINGTOOTHERHOSTS", "ksysguard/the-sensor-browser.html" ); +} + +#include "HostConnector.moc" diff --git a/ksysguard/gui/ksgrd/HostConnector.h b/ksysguard/gui/ksgrd/HostConnector.h new file mode 100644 index 000000000..eadf728cd --- /dev/null +++ b/ksysguard/gui/ksgrd/HostConnector.h @@ -0,0 +1,74 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + 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. + +*/ + +#ifndef KSG_HOSTCONNECTOR_H +#define KSG_HOSTCONNECTOR_H + +#include <kdialogbase.h> + +class KComboBox; + +class QLabel; +class QRadioButton; +class QSpinBox; + +class HostConnector : public KDialogBase +{ + Q_OBJECT + + public: + HostConnector( QWidget *parent, const char *name = 0 ); + ~HostConnector(); + + void setHostNames( const QStringList &list ); + QStringList hostNames() const; + + void setCommands( const QStringList &list ); + QStringList commands() const; + + void setCurrentHostName( const QString &hostName ); + + QString currentHostName() const; + QString currentCommand() const; + int port() const; + + bool useSsh() const; + bool useRsh() const; + bool useDaemon() const; + bool useCustom() const; + + protected slots: + virtual void slotHelp(); + void slotHostNameChanged( const QString &_text ); + private: + KComboBox *mCommands; + KComboBox *mHostNames; + + QLabel *mHostNameLabel; + + QRadioButton *mUseSsh; + QRadioButton *mUseRsh; + QRadioButton *mUseDaemon; + QRadioButton *mUseCustom; + + QSpinBox *mPort; +}; + +#endif diff --git a/ksysguard/gui/ksgrd/Makefile.am b/ksysguard/gui/ksgrd/Makefile.am new file mode 100644 index 000000000..ff5f0aa47 --- /dev/null +++ b/ksysguard/gui/ksgrd/Makefile.am @@ -0,0 +1,34 @@ + +# set the include path for X, qt and KDE +INCLUDES= -I$(srcdir)/../SensorDisplayLib $(all_includes) + +lib_LTLIBRARIES = libksgrd.la + +libksgrd_la_LDFLAGS = -no-undefined -version-info 3:0:2 $(all_libraries) +libksgrd_la_LIBADD = $(LIB_KDEUI) + +# Which sources should be compiled for ksysguard. +libksgrd_la_SOURCES = \ + HostConnector.cc \ + SensorAgent.cc \ + SensorManager.cc \ + SensorShellAgent.cc \ + SensorSocketAgent.cc \ + StyleEngine.cc \ + StyleSettings.cc \ + TimerSettings.cc + +ksgrdincludedir = $(includedir)/ksgrd +ksgrdinclude_HEADERS = \ + HostConnector.h \ + SensorAgent.h \ + SensorClient.h \ + SensorManager.h \ + SensorShellAgent.h \ + SensorSocketAgent.h \ + StyleEngine.h \ + StyleSettings.h \ + TimerSettings.h + +# just to make sure, automake makes them +libksgrd_la_METASOURCES = AUTO diff --git a/ksysguard/gui/ksgrd/SensorAgent.cc b/ksysguard/gui/ksgrd/SensorAgent.cc new file mode 100644 index 000000000..a24bf5594 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorAgent.cc @@ -0,0 +1,260 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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. + +*/ + +#include <stdlib.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kpassdlg.h> + +#include "SensorClient.h" +#include "SensorManager.h" + +#include "SensorAgent.h" + +/** + This can be used to debug communication problems with the daemon. + Should be set to 0 in any production version. +*/ +#define SA_TRACE 0 + +using namespace KSGRD; + +SensorAgent::SensorAgent( SensorManager *sm ) + : mSensorManager( sm ) +{ + /* SensorRequests migrate from the inputFIFO to the processingFIFO. So + * we only have to delete them when they are removed from the + * processingFIFO. */ + mInputFIFO.setAutoDelete( false ); + mProcessingFIFO.setAutoDelete( true ); + + mDaemonOnLine = false; + mTransmitting = false; + mState = 0; +} + +SensorAgent::~SensorAgent() +{ +} + +bool SensorAgent::sendRequest( const QString &req, SensorClient *client, int id ) +{ + /* The request is registered with the FIFO so that the answer can be + * routed back to the requesting client. */ + mInputFIFO.prepend( new SensorRequest( req, client, id ) ); + +#if SA_TRACE + kdDebug(1215) << "-> " << req << "(" << mInputFIFO.count() << "/" + << mProcessingFIFO.count() << ")" << endl; +#endif + executeCommand(); + + return false; +} + +void SensorAgent::processAnswer( const QString &buffer ) +{ +#if SA_TRACE + kdDebug(1215) << "<- " << buffer << endl; +#endif + + for ( uint i = 0; i < buffer.length(); i++ ) { + if ( buffer[ i ] == '\033' ) { + mState = ( mState + 1 ) & 1; + if ( !mErrorBuffer.isEmpty() && mState == 0 ) { + if ( mErrorBuffer == "RECONFIGURE\n" ) + emit reconfigure( this ); + else { + /* We just received the end of an error message, so we + * can display it. */ + SensorMgr->notify( i18n( "Message from %1:\n%2" ) + .arg( mHostName ) + .arg( mErrorBuffer ) ); + } + mErrorBuffer = QString::null; + } + } else if ( mState == 0 ) // receiving to answerBuffer + mAnswerBuffer += buffer[ i ]; + else // receiving to errorBuffer + mErrorBuffer += buffer[ i ]; + } + + int end; + // And now the real information + while ( ( end = mAnswerBuffer.find( "\nksysguardd> " ) ) >= 0 ) { +#if SA_TRACE + kdDebug(1215) << "<= " << mAnswerBuffer.left( end ) + << "(" << mInputFIFO.count() << "/" + << mProcessingFIFO.count() << ")" << endl; +#endif + if ( !mDaemonOnLine ) { + /* First '\nksysguardd> ' signals that the daemon is + * ready to serve requests now. */ + mDaemonOnLine = true; +#if SA_TRACE + kdDebug(1215) << "Daemon now online!" << endl; +#endif + mAnswerBuffer = QString::null; + break; + } + + // remove pending request from FIFO + SensorRequest* req = mProcessingFIFO.last(); + if ( !req ) { + kdDebug(1215) << "ERROR: Received answer but have no pending " + << "request! : " << mAnswerBuffer.left( end ) << endl; + mAnswerBuffer = QString::null; + } else { + if ( !req->client() ) { + /* The client has disappeared before receiving the answer + * to his request. */ + } else { + if ( mAnswerBuffer.left( end ) == "UNKNOWN COMMAND" ) { + /* Notify client that the sensor seems to be no longer + * available. */ + req->client()->sensorLost( req->id() ); + } else { + // Notify client of newly arrived answer. + req->client()->answerReceived( req->id(), mAnswerBuffer.left( end ) ); + } + } + mProcessingFIFO.removeLast(); + } + // chop off the processed part of the answer buffer + mAnswerBuffer.remove( 0, end + strlen( "\nksysguardd> " ) ); + } + + executeCommand(); +} + +void SensorAgent::executeCommand() +{ + /* This function is called whenever there is a chance that we have a + * command to pass to the daemon. But the command many only be send + * if the daemon is online and there is no other command currently + * being sent. */ + if ( mDaemonOnLine && txReady() && !mInputFIFO.isEmpty() ) { + // take oldest request for input FIFO + SensorRequest* req = mInputFIFO.last(); + mInputFIFO.removeLast(); + +#if SA_TRACE + kdDebug(1215) << ">> " << req->request().ascii() << "(" << mInputFIFO.count() + << "/" << mProcessingFIFO.count() << ")" << endl; +#endif + // send request to daemon + QString cmdWithNL = req->request() + "\n"; + if ( writeMsg( cmdWithNL.ascii(), cmdWithNL.length() ) ) + mTransmitting = true; + else + kdDebug(1215) << "SensorAgent::writeMsg() failed" << endl; + + // add request to processing FIFO + mProcessingFIFO.prepend( req ); + } +} + +void SensorAgent::disconnectClient( SensorClient *client ) +{ + for ( SensorRequest *req = mInputFIFO.first(); req; req = mInputFIFO.next() ) + if ( req->client() == client ) + req->setClient( 0 ); + for ( SensorRequest *req = mProcessingFIFO.first(); req; req = mProcessingFIFO.next() ) + if ( req->client() == client ) + req->setClient( 0 ); +} + +SensorManager *SensorAgent::sensorManager() +{ + return mSensorManager; +} + +void SensorAgent::setDaemonOnLine( bool value ) +{ + mDaemonOnLine = value; +} + +bool SensorAgent::daemonOnLine() const +{ + return mDaemonOnLine; +} + +void SensorAgent::setTransmitting( bool value ) +{ + mTransmitting = value; +} + +bool SensorAgent::transmitting() const +{ + return mTransmitting; +} + +void SensorAgent::setHostName( const QString &hostName ) +{ + mHostName = hostName; +} + +const QString &SensorAgent::hostName() const +{ + return mHostName; +} + + +SensorRequest::SensorRequest( const QString &request, SensorClient *client, int id ) + : mRequest( request ), mClient( client ), mId( id ) +{ +} + +SensorRequest::~SensorRequest() +{ +} + +void SensorRequest::setRequest( const QString &request ) +{ + mRequest = request; +} + +QString SensorRequest::request() const +{ + return mRequest; +} + +void SensorRequest::setClient( SensorClient *client ) +{ + mClient = client; +} + +SensorClient *SensorRequest::client() +{ + return mClient; +} + +void SensorRequest::setId( int id ) +{ + mId = id; +} + +int SensorRequest::id() +{ + return mId; +} + +#include "SensorAgent.moc" diff --git a/ksysguard/gui/ksgrd/SensorAgent.h b/ksysguard/gui/ksgrd/SensorAgent.h new file mode 100644 index 000000000..e30deb510 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorAgent.h @@ -0,0 +1,137 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + 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. + +*/ + +#ifndef KSG_SENSORAGENT_H +#define KSG_SENSORAGENT_H + +#include <qobject.h> +#include <qptrlist.h> + +class KProcess; +class KShellProcess; + +class QString; + +namespace KSGRD { + +class SensorClient; +class SensorManager; +class SensorRequest; + +/** + The SensorAgent depending on the type of requested connection + starts a ksysguardd process or connects through a tcp connection to + a running ksysguardd and handles the asynchronous communication. It + keeps a list of pending requests that have not been answered yet by + ksysguardd. The current implementation only allowes one pending + requests. Incoming requests are queued in an input FIFO. +*/ +class KDE_EXPORT SensorAgent : public QObject +{ + Q_OBJECT + + public: + SensorAgent( SensorManager *sm ); + virtual ~SensorAgent(); + + virtual bool start( const QString &host, const QString &shell, + const QString &command = "", int port = -1 ) = 0; + + /** + This function should only be used by the the SensorManager and + never by the SensorClients directly since the pointer returned by + engaged is not guaranteed to be valid. Only the SensorManager knows + whether a SensorAgent pointer is still valid or not. + + This function sends out a command to the sensor and notifies the + agent to return the answer to 'client'. The 'id' can be used by the + client to identify the answer. It is only passed through and never + used by the SensorAgent. So it can be any value the client suits to + use. + */ + bool sendRequest( const QString &req, SensorClient *client, int id = 0 ); + + virtual void hostInfo( QString &sh, QString &cmd, int &port ) const = 0; + + void disconnectClient( SensorClient *client ); + + const QString &hostName() const; + + signals: + void reconfigure( const SensorAgent* ); + + protected: + void processAnswer( const QString &buffer ); + void executeCommand(); + + SensorManager *sensorManager(); + + void setDaemonOnLine( bool value ); + bool daemonOnLine() const; + + void setTransmitting( bool value ); + bool transmitting() const; + + void setHostName( const QString &hostName ); + + private: + virtual bool writeMsg( const char *msg, int len ) = 0; + virtual bool txReady() = 0; + + int mState; + QPtrList<SensorRequest> mInputFIFO; + QPtrList<SensorRequest> mProcessingFIFO; + QString mAnswerBuffer; + QString mErrorBuffer; + + SensorManager *mSensorManager; + + bool mDaemonOnLine; + bool mTransmitting; + QString mHostName; +}; + +/** + This auxilliary class is used to store requests during their processing. +*/ +class SensorRequest +{ + public: + SensorRequest( const QString &request, SensorClient *client, int id ); + ~SensorRequest(); + + void setRequest( const QString& ); + QString request() const; + + void setClient( SensorClient* ); + SensorClient *client(); + + void setId( int ); + int id(); + + private: + QString mRequest; + SensorClient *mClient; + int mId; +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/SensorClient.h b/ksysguard/gui/ksgrd/SensorClient.h new file mode 100644 index 000000000..30586a8a2 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorClient.h @@ -0,0 +1,209 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SENSORCLIENT_H +#define KSG_SENSORCLIENT_H + +#include <qptrlist.h> +#include <qstring.h> + +namespace KSGRD { + +/** + Every object that should act as a client to a sensor must inherit from + this class. A pointer to the client object is passed as SensorClient* + to the SensorAgent. When the requested information is available or a + problem occurred one of the member functions is called. + */ +class SensorClient +{ + public: + SensorClient() { } + virtual ~SensorClient() { } + + /** + This function is called whenever the information form the sensor has + been received by the sensor agent. This function must be reimplemented + by the sensor client to receive and process this information. + */ + virtual void answerReceived( int, const QString& ) { } + + /** + In case of an unexpected fatal problem with the sensor the sensor + agent will call this function to notify the client about it. + */ + virtual void sensorLost( int ) { } +}; + +/** + Every object that has a SensorClient as a child must inherit from + this class to support the advanced update interval settings. + */ +class SensorBoard +{ + public: + SensorBoard() { } + virtual ~SensorBoard() { } + + void updateInterval( int interval ) { mUpdateInterval = interval; } + + int updateInterval() { return mUpdateInterval; } + + private: + int mUpdateInterval; +}; + +/** + The following classes are utility classes that provide a + convenient way to retrieve pieces of information from the sensor + answers. For each type of answer there is a separate class. + */ +class SensorTokenizer +{ + public: + SensorTokenizer( const QString &info, QChar separator ) + { + mTokens = QStringList::split( separator, info ); + } + + ~SensorTokenizer() { } + + const QString& operator[]( unsigned idx ) + { + return mTokens[ idx ]; + } + + uint count() + { + return mTokens.count(); + } + + private: + QStringList mTokens; +}; + +/** + An integer info contains 4 fields seperated by TABS, a description + (name), the minimum and the maximum values and the unit. + e.g. Swap Memory 0 133885952 KB + */ +class SensorIntegerInfo : public SensorTokenizer +{ + public: + SensorIntegerInfo( const QString &info ) + : SensorTokenizer( info, '\t' ) { } + + ~SensorIntegerInfo() { } + + const QString &name() + { + return (*this)[ 0 ]; + } + + long min() + { + return (*this)[ 1 ].toLong(); + } + + long max() + { + return (*this)[ 2 ].toLong(); + } + + const QString &unit() + { + return (*this)[ 3 ]; + } +}; + +/** + An float info contains 4 fields seperated by TABS, a description + (name), the minimum and the maximum values and the unit. + e.g. CPU Voltage 0.0 5.0 V + */ +class SensorFloatInfo : public SensorTokenizer +{ + public: + SensorFloatInfo( const QString &info ) + : SensorTokenizer( info, '\t' ) { } + + ~SensorFloatInfo() { } + + const QString &name() + { + return (*this)[ 0 ]; + } + + double min() + { + return (*this)[ 1 ].toDouble(); + } + + double max() + { + return (*this)[ 2 ].toDouble(); + } + + const QString &unit() + { + return (*this)[ 3 ]; + } +}; + +/** + A PS line consists of information about a process. Each piece of + information is seperated by a TAB. The first 4 fields are process name, + PID, PPID and real user ID. Those fields are mandatory. + */ +class SensorPSLine : public SensorTokenizer +{ + public: + SensorPSLine( const QString &line ) + : SensorTokenizer( line, '\t' ) { } + + ~SensorPSLine() { } + + const QString& name() + { + return (*this)[ 0 ]; + } + + long pid() + { + return (*this)[ 1 ].toLong(); + } + + long ppid() + { + return (*this)[ 2 ].toLong(); + } + + long uid() + { + return (*this)[ 3 ].toLong(); + } +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/SensorManager.cc b/ksysguard/gui/ksgrd/SensorManager.cc new file mode 100644 index 000000000..065da717a --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorManager.cc @@ -0,0 +1,432 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qcombobox.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qspinbox.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> + +#include "HostConnector.h" +#include "SensorShellAgent.h" +#include "SensorSocketAgent.h" + +#include "SensorManager.h" + +using namespace KSGRD; + +SensorManager* KSGRD::SensorMgr; + +SensorManager::SensorManager() +{ + mAgents.setAutoDelete( true ); + mDict.setAutoDelete( true ); + + // Fill the sensor description dictionary. + mDict.insert( "cpu", new QString( i18n( "CPU Load" ) ) ); + mDict.insert( "idle", new QString( i18n( "Idle Load" ) ) ); + mDict.insert( "sys", new QString( i18n( "System Load" ) ) ); + mDict.insert( "nice", new QString( i18n( "Nice Load" ) ) ); + mDict.insert( "user", new QString( i18n( "User Load" ) ) ); + mDict.insert( "mem", new QString( i18n( "Memory" ) ) ); + mDict.insert( "physical", new QString( i18n( "Physical Memory" ) ) ); + mDict.insert( "swap", new QString( i18n( "Swap Memory" ) ) ); + mDict.insert( "cached", new QString( i18n( "Cached Memory" ) ) ); + mDict.insert( "buf", new QString( i18n( "Buffered Memory" ) ) ); + mDict.insert( "used", new QString( i18n( "Used Memory" ) ) ); + mDict.insert( "application", new QString( i18n( "Application Memory" ) ) ); + mDict.insert( "free", new QString( i18n( "Free Memory" ) ) ); + mDict.insert( "pscount", new QString( i18n( "Process Count" ) ) ); + mDict.insert( "ps", new QString( i18n( "Process Controller" ) ) ); + mDict.insert( "disk", new QString( i18n( "Disk Throughput" ) ) ); + mDict.insert( "load", new QString( i18n( "CPU Load", "Load" ) ) ); + mDict.insert( "total", new QString( i18n( "Total Accesses" ) ) ); + mDict.insert( "rio", new QString( i18n( "Read Accesses" ) ) ); + mDict.insert( "wio", new QString( i18n( "Write Accesses" ) ) ); + mDict.insert( "rblk", new QString( i18n( "Read Data" ) ) ); + mDict.insert( "wblk", new QString( i18n( "Write Data" ) ) ); + mDict.insert( "pageIn", new QString( i18n( "Pages In" ) ) ); + mDict.insert( "pageOut", new QString( i18n( "Pages Out" ) ) ); + mDict.insert( "context", new QString( i18n( "Context Switches" ) ) ); + mDict.insert( "network", new QString( i18n( "Network" ) ) ); + mDict.insert( "interfaces", new QString( i18n( "Interfaces" ) ) ); + mDict.insert( "receiver", new QString( i18n( "Receiver" ) ) ); + mDict.insert( "transmitter", new QString( i18n( "Transmitter" ) ) ); + mDict.insert( "data", new QString( i18n( "Data" ) ) ); + mDict.insert( "compressed", new QString( i18n( "Compressed Packets" ) ) ); + mDict.insert( "drops", new QString( i18n( "Dropped Packets" ) ) ); + mDict.insert( "errors", new QString( i18n( "Errors" ) ) ); + mDict.insert( "fifo", new QString( i18n( "FIFO Overruns" ) ) ); + mDict.insert( "frame", new QString( i18n( "Frame Errors" ) ) ); + mDict.insert( "multicast", new QString( i18n( "Multicast" ) ) ); + mDict.insert( "packets", new QString( i18n( "Packets" ) ) ); + mDict.insert( "carrier", new QString( i18n( "Carrier" ) ) ); + mDict.insert( "collisions", new QString( i18n( "Collisions" ) ) ); + mDict.insert( "sockets", new QString( i18n( "Sockets" ) ) ); + mDict.insert( "count", new QString( i18n( "Total Number" ) ) ); + mDict.insert( "list", new QString( i18n( "Table" ) ) ); + mDict.insert( "apm", new QString( i18n( "Advanced Power Management" ) ) ); + mDict.insert( "acpi", new QString( i18n( "ACPI" ) ) ); + mDict.insert( "thermal_zone", new QString( i18n( "Thermal Zone" ) ) ); + mDict.insert( "temperature", new QString( i18n( "Temperature" ) ) ); + mDict.insert( "fan", new QString( i18n( "Fan" ) ) ); + mDict.insert( "state", new QString( i18n( "State" ) ) ); + mDict.insert( "battery", new QString( i18n( "Battery" ) ) ); + mDict.insert( "batterycharge", new QString( i18n( "Battery Charge" ) ) ); + mDict.insert( "batteryusage", new QString( i18n( "Battery Usage" ) ) ); + mDict.insert( "remainingtime", new QString( i18n( "Remaining Time" ) ) ); + mDict.insert( "interrupts", new QString( i18n( "Interrupts" ) ) ); + mDict.insert( "loadavg1", new QString( i18n( "Load Average (1 min)" ) ) ); + mDict.insert( "loadavg5", new QString( i18n( "Load Average (5 min)" ) ) ); + mDict.insert( "loadavg15", new QString( i18n( "Load Average (15 min)" ) ) ); + mDict.insert( "clock", new QString( i18n( "Clock Frequency" ) ) ); + mDict.insert( "lmsensors", new QString( i18n( "Hardware Sensors" ) ) ); + mDict.insert( "partitions", new QString( i18n( "Partition Usage" ) ) ); + mDict.insert( "usedspace", new QString( i18n( "Used Space" ) ) ); + mDict.insert( "freespace", new QString( i18n( "Free Space" ) ) ); + mDict.insert( "filllevel", new QString( i18n( "Fill Level" ) ) ); + + for ( int i = 0; i < 32; i++ ) { + mDict.insert( "cpu" + QString::number( i ), + new QString( QString( i18n( "CPU%1" ) ).arg( i ) ) ); + mDict.insert( "disk" + QString::number( i ), + new QString( QString( i18n( "Disk%1" ) ).arg( i ) ) ); + } + + for ( int i = 0; i < 6; i++) { + mDict.insert( "fan" + QString::number( i ), + new QString( QString( i18n( "Fan%1" ) ).arg( i ) ) ); + mDict.insert( "temp" + QString::number( i ), + new QString( QString( i18n( "Temperature%1" ) ).arg( i ) ) ); + } + + mDict.insert( "int00", new QString( i18n( "Total" ) ) ); + + QString num; + for ( int i = 1; i < 25; i++ ) { + num.sprintf( "%.2d", i ); + mDict.insert( "int" + num, + new QString( QString( i18n( "Int%1" ) ).arg( i - 1, 3 ) ) ); + } + + mDescriptions.setAutoDelete( true ); + // TODO: translated descriptions not yet implemented. + + mUnits.setAutoDelete( true ); + mUnits.insert( "1/s", new QString( i18n( "the unit 1 per second", "1/s" ) ) ); + mUnits.insert( "kBytes", new QString( i18n( "kBytes" ) ) ); + mUnits.insert( "min", new QString( i18n( "the unit minutes", "min" ) ) ); + mUnits.insert( "MHz", new QString( i18n( "the frequency unit", "MHz" ) ) ); + + mTypes.setAutoDelete( true ); + mTypes.insert( "integer", new QString( i18n( "Integer Value" ) ) ); + mTypes.insert( "float", new QString( i18n( "Floating Point Value" ) ) ); + mTypes.insert( "table", new QString( i18n( "Process Controller" ) ) ); + mTypes.insert( "listview", new QString( i18n( "Table" ) ) ); + + mBroadcaster = 0; + + mHostConnector = new HostConnector( 0 ); +} + +SensorManager::~SensorManager() +{ + delete mHostConnector; +} + +bool SensorManager::engageHost( const QString &hostName ) +{ + bool retVal = true; + + if ( hostName.isEmpty() || mAgents.find( hostName ) == 0 ) { + if(hostName == "localhost") { + //There was a bug where the xml file would end up not specifying to connect to localhost. + //This work around makes sure we always connect to localhost + return engage( "localhost", "", "ksysguardd", -1); + } + mHostConnector->setCurrentHostName( hostName ); + + if ( mHostConnector->exec() ) { + QString shell = ""; + QString command = ""; + int port = -1; + + /* Check which radio button is selected and set parameters + * appropriately. */ + if ( mHostConnector->useSsh() ) + shell = "ssh"; + else if ( mHostConnector->useRsh() ) + shell = "rsh"; + else if ( mHostConnector->useDaemon() ) + port = mHostConnector->port(); + else + command = mHostConnector->currentCommand(); + + if ( hostName.isEmpty() ) + retVal = engage( mHostConnector->currentHostName(), shell, + command, port ); + else + retVal = engage( hostName, shell, command, port ); + } + } + + return retVal; +} + +bool SensorManager::engage( const QString &hostName, const QString &shell, + const QString &command, int port ) +{ + SensorAgent *agent; + + if ( ( agent = mAgents.find( hostName ) ) == 0 ) { + if ( port == -1 ) + agent = new SensorShellAgent( this ); + else + agent = new SensorSocketAgent( this ); + + if ( !agent->start( hostName.ascii(), shell, command, port ) ) { + delete agent; + return false; + } + + mAgents.insert( hostName, agent ); + connect( agent, SIGNAL( reconfigure( const SensorAgent* ) ), + SLOT( reconfigure( const SensorAgent* ) ) ); + + emit update(); + return true; + } + + return false; +} + +void SensorManager::requestDisengage( const SensorAgent *agent ) +{ + /* When a sensor agent becomes disfunctional it calls this function + * to request that it is being removed from the SensorManager. It must + * not call disengage() directly since it would trigger ~SensorAgent() + * while we are still in a SensorAgent member function. + * So we have to post an event which is later caught by + * SensorManger::customEvent(). */ + QCustomEvent* event = new QCustomEvent( QEvent::User, (void*)agent ); + kapp->postEvent( this, event ); +} + +bool SensorManager::disengage( const SensorAgent *agent ) +{ + QDictIterator<SensorAgent> it( mAgents ); + + for ( ; it.current(); ++it ) + if ( it.current() == agent ) { + mAgents.remove( it.currentKey() ); + emit update(); + return true; + } + + return false; +} + +bool SensorManager::disengage( const QString &hostName ) +{ + SensorAgent *agent; + if ( ( agent = mAgents.find( hostName ) ) != 0 ) { + mAgents.remove( hostName ); + emit update(); + return true; + } + + return false; +} + +bool SensorManager::resynchronize( const QString &hostName ) +{ + SensorAgent *agent; + + if ( ( agent = mAgents.find( hostName ) ) == 0 ) + return false; + + QString shell, command; + int port; + hostInfo( hostName, shell, command, port ); + + disengage( hostName ); + + kdDebug (1215) << "Re-synchronizing connection to " << hostName << endl; + + return engage( hostName, shell, command ); +} + +void SensorManager::hostLost( const SensorAgent *agent ) +{ + emit hostConnectionLost( agent->hostName() ); + + if ( mBroadcaster ) { + QCustomEvent *event = new QCustomEvent( QEvent::User ); + event->setData( new QString( i18n( "Connection to %1 has been lost." ) + .arg( agent->hostName() ) ) ); + kapp->postEvent( mBroadcaster, event ); + } +} + +void SensorManager::notify( const QString &msg ) const +{ + /* This function relays text messages to the toplevel widget that + * displays the message in a pop-up box. It must be used for objects + * that might have been deleted before the pop-up box is closed. */ + if ( mBroadcaster ) { + QCustomEvent *event = new QCustomEvent( QEvent::User ); + event->setData( new QString( msg ) ); + kapp->postEvent( mBroadcaster, event ); + } +} + +void SensorManager::setBroadcaster( QWidget *wdg ) +{ + mBroadcaster = wdg; +} + +void SensorManager::reconfigure( const SensorAgent* ) +{ + emit update(); +} + +bool SensorManager::event( QEvent *event ) +{ + if ( event->type() == QEvent::User ) { + disengage( (const SensorAgent*)((QCustomEvent*)event)->data() ); + return true; + } + + return false; +} + +bool SensorManager::sendRequest( const QString &hostName, const QString &req, + SensorClient *client, int id ) +{ + SensorAgent *agent = mAgents.find( hostName ); + if( !agent && hostName == "localhost") { + //we should always be able to reconnect to localhost + engage("localhost", "", "ksysguardd", -1); + agent = mAgents.find( hostName ); + } + if ( agent ) { + agent->sendRequest( req, client, id ); + return true; + } + + return false; +} + +const QString SensorManager::hostName( const SensorAgent *agent) const +{ + QDictIterator<SensorAgent> it( mAgents ); + + while ( it.current() ) { + if ( it.current() == agent ) + return it.currentKey(); + ++it; + } + + return QString::null; +} + +bool SensorManager::hostInfo( const QString &hostName, QString &shell, + QString &command, int &port ) +{ + SensorAgent *agent; + if ( ( agent = mAgents.find( hostName ) ) != 0 ) { + agent->hostInfo( shell, command, port ); + return true; + } + + return false; +} + +const QString &SensorManager::translateUnit( const QString &unit ) const +{ + if ( !unit.isEmpty() && mUnits[ unit ] ) + return *mUnits[ unit ]; + else + return unit; +} + +const QString &SensorManager::translateSensorPath( const QString &path ) const +{ + if ( !path.isEmpty() && mDict[ path ] ) + return *mDict[ path ]; + else + return path; +} + +const QString &SensorManager::translateSensorType( const QString &type ) const +{ + if ( !type.isEmpty() && mTypes[ type ] ) + return *mTypes[ type ]; + else + return type; +} + +QString SensorManager::translateSensor( const QString &sensor ) const +{ + QString token, out; + int start = 0, end = 0; + for ( ; ; ) { + end = sensor.find( '/', start ); + if ( end > 0 ) + out += translateSensorPath( sensor.mid( start, end - start ) ) + "/"; + else { + out += translateSensorPath( sensor.right( sensor.length() - start ) ); + break; + } + start = end + 1; + } + + return out; +} + +void SensorManager::readProperties( KConfig *cfg ) +{ + mHostConnector->setHostNames( cfg->readListEntry( "HostList" ) ); + mHostConnector->setCommands( cfg->readListEntry( "CommandList" ) ); +} + +void +SensorManager::saveProperties( KConfig *cfg ) +{ + cfg->writeEntry( "HostList", mHostConnector->hostNames() ); + cfg->writeEntry( "CommandList", mHostConnector->commands() ); +} + +void SensorManager::disconnectClient( SensorClient *client ) +{ + QDictIterator<SensorAgent> it( mAgents ); + + for ( ; it.current(); ++it) + it.current()->disconnectClient( client ); +} + +#include "SensorManager.moc" diff --git a/ksysguard/gui/ksgrd/SensorManager.h b/ksysguard/gui/ksgrd/SensorManager.h new file mode 100644 index 000000000..8eb778009 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorManager.h @@ -0,0 +1,126 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + 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. + +*/ + +#ifndef KSG_SENSORMANAGER_H +#define KSG_SENSORMANAGER_H + +#include <kconfig.h> + +#include <qdict.h> +#include <qobject.h> + +#include <SensorAgent.h> + +class HostConnector; + +namespace KSGRD { + +class SensorManagerIterator; + +/** + The SensorManager handles all interaction with the connected + hosts. Connections to a specific hosts are handled by + SensorAgents. Use engage() to establish a connection and + disengage() to terminate the connection. If you don't know if a + certain host is already connected use engageHost(). If there is no + connection yet or the hostname is empty, a dialog will be shown to + enter the connections details. + */ +class KDE_EXPORT SensorManager : public QObject +{ + Q_OBJECT + + friend class SensorManagerIterator; + + public: + SensorManager(); + ~SensorManager(); + + bool engageHost( const QString &hostName ); + bool engage( const QString &hostName, const QString &shell = "ssh", + const QString &command = "", int port = -1 ); + + void requestDisengage( const SensorAgent *agent ); + bool disengage( const SensorAgent *agent ); + bool disengage( const QString &hostName ); + bool resynchronize( const QString &hostName ); + void hostLost( const SensorAgent *agent ); + void notify( const QString &msg ) const; + + void setBroadcaster( QWidget *wdg ); + + virtual bool event( QEvent *event ); + + bool sendRequest( const QString &hostName, const QString &request, + SensorClient *client, int id = 0 ); + + const QString hostName( const SensorAgent *sensor ) const; + bool hostInfo( const QString &host, QString &shell, + QString &command, int &port ); + + const QString& translateUnit( const QString &unit ) const; + const QString& translateSensorPath( const QString &path ) const; + const QString& translateSensorType( const QString &type ) const; + QString translateSensor(const QString& u) const; + + void readProperties( KConfig *cfg ); + void saveProperties( KConfig *cfg ); + + void disconnectClient( SensorClient *client ); + + public slots: + void reconfigure( const SensorAgent *agent ); + + signals: + void update(); + void hostConnectionLost( const QString &hostName ); + + protected: + QDict<SensorAgent> mAgents; + + private: + /** + These dictionary stores the localized versions of the sensor + descriptions and units. + */ + QDict<QString> mDescriptions; + QDict<QString> mUnits; + QDict<QString> mDict; + QDict<QString> mTypes; + + QWidget* mBroadcaster; + + HostConnector* mHostConnector; +}; + +KDE_EXPORT extern SensorManager* SensorMgr; + +class KDE_EXPORT SensorManagerIterator : public QDictIterator<SensorAgent> +{ + public: + SensorManagerIterator( const SensorManager *sm ) + : QDictIterator<SensorAgent>( sm->mAgents ) { } + + ~SensorManagerIterator() { } +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/SensorShellAgent.cc b/ksysguard/gui/ksgrd/SensorShellAgent.cc new file mode 100644 index 000000000..0f06e88fe --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorShellAgent.cc @@ -0,0 +1,141 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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. + +*/ + +#include <stdlib.h> + +#include <kdebug.h> +#include <kpassdlg.h> +#include <kprocess.h> + +#include "SensorClient.h" +#include "SensorManager.h" + +#include "SensorShellAgent.h" + +using namespace KSGRD; + +SensorShellAgent::SensorShellAgent( SensorManager *sm ) + : SensorAgent( sm ), mDaemon( 0 ) +{ +} + +SensorShellAgent::~SensorShellAgent() +{ + if ( mDaemon ) { + mDaemon->writeStdin( "quit\n", strlen( "quit\n" ) ); + delete mDaemon; + mDaemon = 0; + } +} + +bool SensorShellAgent::start( const QString &host, const QString &shell, + const QString &command, int ) +{ + mRetryCount = 3; + mDaemon = new KProcess; + mDaemon->setUseShell(true); + setHostName( host ); + mShell = shell; + mCommand = command; + + connect( mDaemon, SIGNAL( processExited( KProcess* ) ), + SLOT( daemonExited( KProcess* ) ) ); + connect( mDaemon, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + SLOT( msgRcvd( KProcess*, char*, int ) ) ); + connect( mDaemon, SIGNAL( receivedStderr( KProcess*, char*, int ) ), + SLOT( errMsgRcvd( KProcess*, char*, int ) ) ); + connect( mDaemon, SIGNAL( wroteStdin( KProcess* ) ), + SLOT( msgSent( KProcess* ) ) ); + + QString cmd; + if ( !command.isEmpty() ) + cmd = command; + else + cmd = mShell + " " + hostName() + " ksysguardd"; + *mDaemon << cmd; + + if ( !mDaemon->start( KProcess::NotifyOnExit, KProcess::All ) ) { + sensorManager()->hostLost( this ); + kdDebug (1215) << "Command '" << cmd << "' failed" << endl; + return false; + } + + return true; +} + +void SensorShellAgent::hostInfo( QString &shell, QString &command, + int &port) const +{ + shell = mShell; + command = mCommand; + port = -1; +} + +void SensorShellAgent::msgSent( KProcess* ) +{ + setTransmitting( false ); + + // Try to send next request if available. + executeCommand(); +} + +void SensorShellAgent::msgRcvd( KProcess*, char *buffer, int buflen ) +{ + if ( !buffer || buflen == 0 ) + return; + mRetryCount = 3; //we recieved an answer, so reset our retry count back to 3 + QString aux = QString::fromLocal8Bit( buffer, buflen ); + + processAnswer( aux ); +} + +void SensorShellAgent::errMsgRcvd( KProcess*, char *buffer, int buflen ) +{ + if ( !buffer || buflen == 0 ) + return; + + QString buf = QString::fromLocal8Bit( buffer, buflen ); + + kdDebug(1215) << "SensorShellAgent: Warning, received text over stderr!" + << endl << buf << endl; +} + +void SensorShellAgent::daemonExited( KProcess *process ) +{ + kdDebug() << "daemonExited" << endl; + if ( mRetryCount-- <= 0 || !mDaemon->start( KProcess::NotifyOnExit, KProcess::All ) ) { + kdDebug() << "daemon could not be restart" << endl; + setDaemonOnLine( false ); + sensorManager()->hostLost( this ); + sensorManager()->requestDisengage( this ); + } +} + +bool SensorShellAgent::writeMsg( const char *msg, int len ) +{ + return mDaemon->writeStdin( msg, len ); +} + +bool SensorShellAgent::txReady() +{ + return !transmitting(); +} + +#include "SensorShellAgent.moc" diff --git a/ksysguard/gui/ksgrd/SensorShellAgent.h b/ksysguard/gui/ksgrd/SensorShellAgent.h new file mode 100644 index 000000000..e13413d55 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorShellAgent.h @@ -0,0 +1,77 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + 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. + +*/ + +#ifndef KSG_SENSORSHELLAGENT_H +#define KSG_SENSORSHELLAGENT_H + +#include <qobject.h> +#include <qptrlist.h> +#include <qguardedptr.h> + +#include <SensorAgent.h> + +class QString; + +class KProcess; + +namespace KSGRD { + +class SensorClient; +class SensorManager; + +/** + The SensorShellAgent starts a ksysguardd process and handles the + asynchronous communication. It keeps a list of pending requests + that have not been answered yet by ksysguard. The current + implementation only allowes one pending requests. Incoming requests + are queued in an input FIFO. + */ +class SensorShellAgent : public SensorAgent +{ + Q_OBJECT + + public: + SensorShellAgent( SensorManager *sm ); + ~SensorShellAgent(); + + bool start( const QString &host, const QString &shell, + const QString &command = "", int port = -1 ); + + void hostInfo( QString &shell, QString &command, int &port) const; + + private slots: + void msgSent( KProcess* ); + void msgRcvd( KProcess*, char *buffer, int buflen ); + void errMsgRcvd( KProcess*, char *buffer, int buflen ); + void daemonExited( KProcess* ); + + private: + bool writeMsg( const char *msg, int len ); + bool txReady(); + + QGuardedPtr<KProcess> mDaemon; + QString mShell; + QString mCommand; + int mRetryCount; +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/SensorSocketAgent.cc b/ksysguard/gui/ksgrd/SensorSocketAgent.cc new file mode 100644 index 000000000..dcb5b7f3b --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorSocketAgent.cc @@ -0,0 +1,137 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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. + +*/ + +#include <stdlib.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kpassdlg.h> + +#include "SensorClient.h" +#include "SensorManager.h" + +#include "SensorSocketAgent.h" + +using namespace KSGRD; + +SensorSocketAgent::SensorSocketAgent( SensorManager *sm ) + : SensorAgent( sm ) +{ + connect( &mSocket, SIGNAL( gotError( int ) ), SLOT( error( int ) ) ); + connect( &mSocket, SIGNAL( bytesWritten( int ) ), SLOT( msgSent( int ) ) ); + connect( &mSocket, SIGNAL( readyRead() ), SLOT( msgRcvd() ) ); + connect( &mSocket, SIGNAL( closed() ), SLOT( connectionClosed() ) ); +} + +SensorSocketAgent::~SensorSocketAgent() +{ + mSocket.writeBlock( "quit\n", strlen( "quit\n" ) ); + mSocket.flush(); +} + +bool SensorSocketAgent::start( const QString &host, const QString&, + const QString&, int port ) +{ + if ( port <= 0 ) + kdDebug(1215) << "SensorSocketAgent::start: Illegal port " << port << endl; + + setHostName( host ); + mPort = port; + + mSocket.connect( hostName(), QString::number(mPort) ); + + return true; +} + +void SensorSocketAgent::hostInfo( QString &shell, QString &command, int &port ) const +{ + shell = QString::null; + command = QString::null; + port = mPort; +} + +void SensorSocketAgent::msgSent( int ) +{ + if ( mSocket.bytesToWrite() != 0 ) + return; + + setTransmitting( false ); + + // Try to send next request if available. + executeCommand(); +} + +void SensorSocketAgent::msgRcvd() +{ + int buflen = mSocket.bytesAvailable(); + char* buffer = new char[ buflen ]; + + mSocket.readBlock( buffer, buflen ); + QString buf = QString::fromLocal8Bit( buffer, buflen ); + delete [] buffer; + + processAnswer( buf ); +} + +void SensorSocketAgent::connectionClosed() +{ + setDaemonOnLine( false ); + sensorManager()->hostLost( this ); + sensorManager()->requestDisengage( this ); +} + +void SensorSocketAgent::error( int id ) +{ + switch ( id ) { + case KNetwork::KSocketBase::ConnectionRefused: + SensorMgr->notify( i18n( "Connection to %1 refused" ) + .arg( hostName() ) ); + break; + case KNetwork::KSocketBase::LookupFailure: + SensorMgr->notify( i18n( "Host %1 not found" ) + .arg( hostName() ) ); + break; + case KNetwork::KSocketBase::Timeout: + SensorMgr->notify( i18n( "Timeout at host %1") + .arg( hostName() ) ); + break; + case KNetwork::KSocketBase::NetFailure: + SensorMgr->notify( i18n( "Network failure host %1") + .arg( hostName() ) ); + break; + default: + kdDebug(1215) << "SensorSocketAgent::error() unknown error " << id << endl; + } + + setDaemonOnLine( false ); + sensorManager()->requestDisengage( this ); +} + +bool SensorSocketAgent::writeMsg( const char *msg, int len ) +{ + return ( mSocket.writeBlock( msg, len ) == len ); +} + +bool SensorSocketAgent::txReady() +{ + return !transmitting(); +} + +#include "SensorSocketAgent.moc" diff --git a/ksysguard/gui/ksgrd/SensorSocketAgent.h b/ksysguard/gui/ksgrd/SensorSocketAgent.h new file mode 100644 index 000000000..b422d3a9b --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorSocketAgent.h @@ -0,0 +1,71 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + 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. + +*/ + +#ifndef KSG_SENSORSOCKETAGENT_H +#define KSG_SENSORSOCKETAGENT_H + +#include <qptrlist.h> +#include <kbufferedsocket.h> + +#include <SensorAgent.h> + +class QString; + +namespace KSGRD { + +class SensorClient; + +/** + The SensorSocketAgent connects to a ksysguardd via a TCP + connection. It keeps a list of pending requests that have not been + answered yet by ksysguard. The current implementation only allowes + one pending requests. Incoming requests are queued in an input + FIFO. + */ +class SensorSocketAgent : public SensorAgent +{ + Q_OBJECT + + public: + SensorSocketAgent( SensorManager *sm ); + ~SensorSocketAgent(); + + bool start( const QString &host, const QString &shell, + const QString &command = "", int port = -1 ); + + void hostInfo( QString &shell, QString &command, int &port ) const; + + private slots: + void connectionClosed(); + void msgSent( int ); + void msgRcvd(); + void error( int ); + + private: + bool writeMsg( const char *msg, int len ); + bool txReady(); + + KNetwork::KBufferedSocket mSocket; + int mPort; +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/StyleEngine.cc b/ksysguard/gui/ksgrd/StyleEngine.cc new file mode 100644 index 000000000..ccea0a7c2 --- /dev/null +++ b/ksysguard/gui/ksgrd/StyleEngine.cc @@ -0,0 +1,176 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qimage.h> +#include <qpushbutton.h> +#include <qspinbox.h> + +#include <kconfig.h> +#include <klocale.h> + +#include "StyleSettings.h" + +#include "StyleEngine.h" + +using namespace KSGRD; + +StyleEngine* KSGRD::Style; + +StyleEngine::StyleEngine() +{ + mFirstForegroundColor = QColor( 0x6894c9 ); // light blue + mSecondForegroundColor = QColor( 0x6894c9 ); // light blue + mAlarmColor = QColor( 255, 0, 0 ); + mBackgroundColor = QColor( 0x313031 ); // almost black + mFontSize = 9; + + mSensorColors.append( QColor( 0x1889ff ) ); // soft blue + mSensorColors.append( QColor( 0xff7f08 ) ); // reddish + mSensorColors.append( QColor( 0xffeb14 ) ); // bright yellow + + uint v = 0x00ff00; + for ( uint i = mSensorColors.count(); i < 32; ++i ) { + v = ( ( ( v + 82 ) & 0xff ) << 23 ) | ( v >> 8 ); + mSensorColors.append( QColor( v & 0xff, ( v >> 16 ) & 0xff, ( v >> 8 ) & 0xff ) ); + } +} + +StyleEngine::~StyleEngine() +{ +} + +void StyleEngine::readProperties( KConfig *cfg ) +{ + mFirstForegroundColor = cfg->readColorEntry( "fgColor1", &mFirstForegroundColor ); + mSecondForegroundColor = cfg->readColorEntry( "fgColor2", &mSecondForegroundColor ); + mAlarmColor = cfg->readColorEntry( "alarmColor", &mAlarmColor ); + mBackgroundColor = cfg->readColorEntry( "backgroundColor", &mBackgroundColor ); + mFontSize = cfg->readNumEntry( "fontSize", mFontSize ); + + QStringList list = cfg->readListEntry( "sensorColors" ); + if ( !list.isEmpty() ) { + mSensorColors.clear(); + QStringList::Iterator it; + for ( it = list.begin(); it != list.end(); ++it ) + mSensorColors.append( QColor( *it ) ); + } +} + +void StyleEngine::saveProperties( KConfig *cfg ) +{ + cfg->writeEntry( "fgColor1", mFirstForegroundColor ); + cfg->writeEntry( "fgColor2", mSecondForegroundColor ); + cfg->writeEntry( "alarmColor", mAlarmColor ); + cfg->writeEntry( "backgroundColor", mBackgroundColor ); + cfg->writeEntry( "fontSize", mFontSize ); + + QStringList list; + QValueList<QColor>::Iterator it; + for ( it = mSensorColors.begin(); it != mSensorColors.end(); ++it ) + list.append( (*it).name() ); + + cfg->writeEntry( "sensorColors", list ); +} + +const QColor &StyleEngine::firstForegroundColor() const +{ + return mFirstForegroundColor; +} + +const QColor &StyleEngine::secondForegroundColor() const +{ + return mSecondForegroundColor; +} + +const QColor &StyleEngine::alarmColor() const +{ + return mAlarmColor; +} + +const QColor &StyleEngine::backgroundColor() const +{ + return mBackgroundColor; +} + +uint StyleEngine::fontSize() const +{ + return mFontSize; +} + +const QColor& StyleEngine::sensorColor( uint pos ) +{ + static QColor dummy; + + if ( pos < mSensorColors.count() ) + return *mSensorColors.at( pos ); + else + return dummy; +} + +uint StyleEngine::numSensorColors() const +{ + return mSensorColors.count(); +} + +void StyleEngine::configure() +{ + mSettingsDialog = new StyleSettings( 0 ); + + mSettingsDialog->setFirstForegroundColor( mFirstForegroundColor ); + mSettingsDialog->setSecondForegroundColor( mSecondForegroundColor ); + mSettingsDialog->setAlarmColor( mAlarmColor ); + mSettingsDialog->setBackgroundColor( mBackgroundColor ); + mSettingsDialog->setFontSize( mFontSize ); + mSettingsDialog->setSensorColors( mSensorColors ); + + connect( mSettingsDialog, SIGNAL( applyClicked() ), + this, SLOT( applyToWorksheet() ) ); + + if ( mSettingsDialog->exec() ) + apply(); + + delete mSettingsDialog; + mSettingsDialog = 0; +} + +void StyleEngine::applyToWorksheet() +{ + apply(); + emit applyStyleToWorksheet(); +} + +void StyleEngine::apply() +{ + if ( !mSettingsDialog ) + return; + + mFirstForegroundColor = mSettingsDialog->firstForegroundColor(); + mSecondForegroundColor = mSettingsDialog->secondForegroundColor(); + mAlarmColor = mSettingsDialog->alarmColor(); + mBackgroundColor = mSettingsDialog->backgroundColor(); + mFontSize = mSettingsDialog->fontSize(); + + mSensorColors = mSettingsDialog->sensorColors(); +} + +#include "StyleEngine.moc" diff --git a/ksysguard/gui/ksgrd/StyleEngine.h b/ksysguard/gui/ksgrd/StyleEngine.h new file mode 100644 index 000000000..d896a2422 --- /dev/null +++ b/ksysguard/gui/ksgrd/StyleEngine.h @@ -0,0 +1,86 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_STYLEENGINE_H +#define KSG_STYLEENGINE_H + +#include <qcolor.h> +#include <qobject.h> +#include <qptrlist.h> + +#include <kdemacros.h> + +class KConfig; + +class QListBoxItem; + +class StyleSettings; + +namespace KSGRD { + +class KDE_EXPORT StyleEngine : public QObject +{ + Q_OBJECT + + public: + StyleEngine(); + ~StyleEngine(); + + void readProperties( KConfig* ); + void saveProperties( KConfig* ); + + const QColor& firstForegroundColor() const; + const QColor& secondForegroundColor() const; + const QColor& alarmColor() const; + const QColor& backgroundColor() const; + + uint fontSize() const; + + const QColor& sensorColor( uint pos ); + uint numSensorColors() const; + + public slots: + void configure(); + void applyToWorksheet(); + + signals: + void applyStyleToWorksheet(); + + private: + void apply(); + + QColor mFirstForegroundColor; + QColor mSecondForegroundColor; + QColor mAlarmColor; + QColor mBackgroundColor; + uint mFontSize; + QValueList<QColor> mSensorColors; + + StyleSettings *mSettingsDialog; +}; + +KDE_EXPORT extern StyleEngine* Style; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/StyleSettings.cc b/ksysguard/gui/ksgrd/StyleSettings.cc new file mode 100644 index 000000000..19a924cbe --- /dev/null +++ b/ksysguard/gui/ksgrd/StyleSettings.cc @@ -0,0 +1,201 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qimage.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlistbox.h> +#include <qpixmap.h> +#include <qpushbutton.h> +#include <qspinbox.h> +#include <qtabwidget.h> + +#include <kaccelmanager.h> +#include <kcolorbutton.h> +#include <kcolordialog.h> +#include <klocale.h> + +#include "StyleSettings.h" + +StyleSettings::StyleSettings( QWidget *parent, const char *name ) + : KDialogBase( Tabbed, i18n( "Global Style Settings" ), Help | Ok | Apply | + Cancel, Ok, parent, name, true, true ) +{ + QFrame *page = addPage( i18n( "Display Style" ) ); + QGridLayout *layout = new QGridLayout( page, 6, 2, 0, spacingHint() ); + + QLabel *label = new QLabel( i18n( "First foreground color:" ), page ); + layout->addWidget( label, 0, 0 ); + + mFirstForegroundColor = new KColorButton( page ); + layout->addWidget( mFirstForegroundColor, 0, 1 ); + label->setBuddy( mFirstForegroundColor ); + + label = new QLabel( i18n( "Second foreground color:" ), page ); + layout->addWidget( label, 1, 0 ); + + mSecondForegroundColor = new KColorButton( page ); + layout->addWidget( mSecondForegroundColor, 1, 1 ); + label->setBuddy( mSecondForegroundColor ); + + label = new QLabel( i18n( "Alarm color:" ), page ); + layout->addWidget( label, 2, 0 ); + + mAlarmColor = new KColorButton( page ); + layout->addWidget( mAlarmColor, 2, 1 ); + label->setBuddy( mAlarmColor ); + + label = new QLabel( i18n( "Background color:" ), page ); + layout->addWidget( label, 3, 0 ); + + mBackgroundColor = new KColorButton( page ); + layout->addWidget( mBackgroundColor, 3, 1 ); + label->setBuddy( mBackgroundColor ); + + label = new QLabel( i18n( "Font size:" ), page ); + layout->addWidget( label, 4, 0 ); + + mFontSize = new QSpinBox( 7, 48, 1, page ); + mFontSize->setValue( 8 ); + layout->addWidget( mFontSize, 4, 1 ); + label->setBuddy( mFontSize ); + + layout->setRowStretch( 5, 1 ); + + page = addPage( i18n( "Sensor Colors" ) ); + layout = new QGridLayout( page, 1, 2, 0, spacingHint() ); + + mColorListBox = new QListBox( page ); + layout->addWidget( mColorListBox, 0, 0 ); + + mEditColorButton = new QPushButton( i18n( "Change Color..." ), page ); + mEditColorButton->setEnabled( false ); + layout->addWidget( mEditColorButton, 0, 1, Qt::AlignTop ); + + connect( mColorListBox, SIGNAL( selectionChanged( QListBoxItem* ) ), + SLOT( selectionChanged( QListBoxItem* ) ) ); + connect( mColorListBox, SIGNAL( doubleClicked( QListBoxItem* ) ), + SLOT( editSensorColor() ) ); + connect( mEditColorButton, SIGNAL( clicked() ), + SLOT( editSensorColor() ) ); + + KAcceleratorManager::manage( this ); +} + +StyleSettings::~StyleSettings() +{ +} + +void StyleSettings::setFirstForegroundColor( const QColor &color ) +{ + mFirstForegroundColor->setColor( color ); +} + +QColor StyleSettings::firstForegroundColor() const +{ + return mFirstForegroundColor->color(); +} + +void StyleSettings::setSecondForegroundColor( const QColor &color ) +{ + mSecondForegroundColor->setColor( color ); +} + +QColor StyleSettings::secondForegroundColor() const +{ + return mSecondForegroundColor->color(); +} + +void StyleSettings::setAlarmColor( const QColor &color ) +{ + mAlarmColor->setColor( color ); +} + +QColor StyleSettings::alarmColor() const +{ + return mAlarmColor->color(); +} + +void StyleSettings::setBackgroundColor( const QColor &color ) +{ + mBackgroundColor->setColor( color ); +} + +QColor StyleSettings::backgroundColor() const +{ + return mBackgroundColor->color(); +} + +void StyleSettings::setFontSize( uint size ) +{ + mFontSize->setValue( size ); +} + +uint StyleSettings::fontSize() const +{ + return mFontSize->value(); +} + +void StyleSettings::setSensorColors( const QValueList<QColor> &list ) +{ + mColorListBox->clear(); + + for ( uint i = 0; i < list.count(); ++i ) { + QPixmap pm( 12, 12 ); + pm.fill( *list.at( i ) ); + mColorListBox->insertItem( pm, i18n( "Color %1" ).arg( i ) ); + } +} + +QValueList<QColor> StyleSettings::sensorColors() +{ + QValueList<QColor> list; + + for ( uint i = 0; i < mColorListBox->count(); ++i ) + list.append( QColor( mColorListBox->pixmap( i )->convertToImage().pixel( 1, 1 ) ) ); + + return list; +} + +void StyleSettings::editSensorColor() +{ + int pos = mColorListBox->currentItem(); + + if ( pos < 0 ) + return; + + QColor color = mColorListBox->pixmap( pos )->convertToImage().pixel( 1, 1 ); + + if ( KColorDialog::getColor( color ) == KColorDialog::Accepted ) { + QPixmap pm( 12, 12 ); + pm.fill( color ); + mColorListBox->changeItem( pm, mColorListBox->text( pos ), pos ); + } +} + +void StyleSettings::selectionChanged( QListBoxItem *item ) +{ + mEditColorButton->setEnabled( item != 0 ); +} + +#include "StyleSettings.moc" diff --git a/ksysguard/gui/ksgrd/StyleSettings.h b/ksysguard/gui/ksgrd/StyleSettings.h new file mode 100644 index 000000000..d16b5e723 --- /dev/null +++ b/ksysguard/gui/ksgrd/StyleSettings.h @@ -0,0 +1,78 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_STYLESETTINGS_H +#define KSG_STYLESETTINGS_H + +#include <kdialogbase.h> + +#include <qcolor.h> + +class KColorButton; + +class QListBoxItem; +class QPushButton; + +class StyleSettings : public KDialogBase +{ + Q_OBJECT + + public: + StyleSettings( QWidget *parent = 0, const char *name = 0 ); + ~StyleSettings(); + + void setFirstForegroundColor( const QColor &color ); + QColor firstForegroundColor() const; + + void setSecondForegroundColor( const QColor &color ); + QColor secondForegroundColor() const; + + void setAlarmColor( const QColor &color ); + QColor alarmColor() const; + + void setBackgroundColor( const QColor &color ); + QColor backgroundColor() const; + + void setFontSize( uint size ); + uint fontSize() const; + + void setSensorColors( const QValueList<QColor> &list ); + QValueList<QColor> sensorColors(); + + private slots: + void editSensorColor(); + void selectionChanged( QListBoxItem* ); + + private: + KColorButton *mFirstForegroundColor; + KColorButton *mSecondForegroundColor; + KColorButton *mAlarmColor; + KColorButton *mBackgroundColor; + + QSpinBox *mFontSize; + + QListBox *mColorListBox; + QPushButton *mEditColorButton; +}; + +#endif diff --git a/ksysguard/gui/ksgrd/TimerSettings.cc b/ksysguard/gui/ksgrd/TimerSettings.cc new file mode 100644 index 000000000..4806f7d8a --- /dev/null +++ b/ksysguard/gui/ksgrd/TimerSettings.cc @@ -0,0 +1,94 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <kaccelmanager.h> +#include <klocale.h> + +#include <qcheckbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qspinbox.h> +#include <qwhatsthis.h> + +#include "TimerSettings.h" + +TimerSettings::TimerSettings( QWidget *parent, const char *name ) + : KDialogBase( Plain, i18n( "Timer Settings" ), Ok | Cancel, + Ok, parent, name, true, true ) +{ + QFrame *page = plainPage(); + + QGridLayout *layout = new QGridLayout( page, 2, 2, 0, spacingHint() ); + + mUseGlobalUpdate = new QCheckBox( i18n( "Use update interval of worksheet" ), page ); + layout->addMultiCellWidget( mUseGlobalUpdate, 0, 0, 0, 1 ); + + mLabel = new QLabel( i18n( "Update interval:" ), page ); + layout->addWidget( mLabel, 1, 0 ); + + mInterval = new QSpinBox( 1, 300, 1, page ); + mInterval->setValue( 2 ); + mInterval->setSuffix( i18n( " sec" ) ); + layout->addWidget( mInterval, 1, 1 ); + mLabel->setBuddy( mInterval ); + QWhatsThis::add( mInterval, i18n( "All displays of the sheet are updated at the rate specified here." ) ); + + connect( mUseGlobalUpdate, SIGNAL( toggled( bool ) ), + SLOT( globalUpdateChanged( bool ) ) ); + + mUseGlobalUpdate->setChecked( true ); + + KAcceleratorManager::manage( this ); +} + +TimerSettings::~TimerSettings() +{ +} + +void TimerSettings::setUseGlobalUpdate( bool value ) +{ + mUseGlobalUpdate->setChecked( value ); +} + +bool TimerSettings::useGlobalUpdate() const +{ + return mUseGlobalUpdate->isChecked(); +} + +void TimerSettings::setInterval( int interval ) +{ + mInterval->setValue( interval ); +} + +int TimerSettings::interval() const +{ + return mInterval->value(); +} + +void TimerSettings::globalUpdateChanged( bool value ) +{ + mInterval->setEnabled( !value ); + mLabel->setEnabled( !value ); +} + +#include "TimerSettings.moc" diff --git a/ksysguard/gui/ksgrd/TimerSettings.h b/ksysguard/gui/ksgrd/TimerSettings.h new file mode 100644 index 000000000..daf2eda6f --- /dev/null +++ b/ksysguard/gui/ksgrd/TimerSettings.h @@ -0,0 +1,56 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + 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 <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_TIMERSETTINGS_H +#define KSG_TIMERSETTINGS_H + +#include <kdialogbase.h> + +class QCheckBox; +class QLabel; +class QSpinBox; + +class KDE_EXPORT TimerSettings : public KDialogBase +{ + Q_OBJECT + + public: + TimerSettings( QWidget *parent, const char *name = 0 ); + ~TimerSettings(); + + void setUseGlobalUpdate( bool value ); + bool useGlobalUpdate() const; + + void setInterval( int interval ); + int interval() const; + + private slots: + void globalUpdateChanged( bool ); + + private: + QCheckBox* mUseGlobalUpdate; + QLabel* mLabel; + QSpinBox* mInterval; +}; + +#endif diff --git a/ksysguard/gui/ksysguard.cc b/ksysguard/gui/ksysguard.cc new file mode 100644 index 000000000..4750a380f --- /dev/null +++ b/ksysguard/gui/ksysguard.cc @@ -0,0 +1,650 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + 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 + <cs@kde.org>. Please do not commit any changes without consulting + me first. Thanks! + + KSysGuard has been written with some source code and ideas from + ktop (<1.0). Early versions of ktop have been written by Bernd + Johannes Wuebben <wuebben@math.cornell.edu> and Nicolas Leclercq + <nicknet@planete.net>. + +*/ + +#include <assert.h> +#include <ctype.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <kaboutdata.h> +#include <kaction.h> +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kedittoolbar.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <ksgrd/SensorAgent.h> +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> +#include <kstandarddirs.h> +#include <kstatusbar.h> +#include <kstdaction.h> +#include <kwin.h> +#include <kwinmodule.h> +#include <dnssd/remoteservice.h> + + +#include "../version.h" +#include "SensorBrowser.h" +#include "Workspace.h" + +#include "ksysguard.h" + +static const char Description[] = I18N_NOOP( "KDE system guard" ); +TopLevel* topLevel; + +/** + This is the constructor for the main widget. It sets up the menu and the + TaskMan widget. + */ +TopLevel::TopLevel( const char *name ) + : KMainWindow( 0, name ), DCOPObject( "KSysGuardIface" ) +{ + setPlainCaption( i18n( "KDE System Guard" ) ); + mDontSaveSession = false; + mTimerId = -1; + + mSplitter = new QSplitter( this ); + mSplitter->setOrientation( Horizontal ); + mSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() ); + setCentralWidget( mSplitter ); + + mSensorBrowser = new SensorBrowser( mSplitter, KSGRD::SensorMgr ); + + mServiceBrowser = new DNSSD::ServiceBrowser("_ksysguard._tcp", 0, true); + connect(mServiceBrowser,SIGNAL(serviceAdded(DNSSD::RemoteService::Ptr)),this, + SLOT(serviceAdded(DNSSD::RemoteService::Ptr))); + + mWorkSpace = new Workspace( mSplitter ); + connect( mWorkSpace, SIGNAL( announceRecentURL( const KURL& ) ), + SLOT( registerRecentURL( const KURL& ) ) ); + connect( mWorkSpace, SIGNAL( setCaption( const QString&, bool ) ), + SLOT( setCaption( const QString&, bool ) ) ); + connect( KSGRD::Style, SIGNAL( applyStyleToWorksheet() ), mWorkSpace, + SLOT( applyStyle() ) ); + + /* Create the status bar. It displays some information about the + * number of processes and the memory consumption of the local + * host. */ + statusBar()->insertFixedItem( i18n( "88888 Processes" ), 0 ); + statusBar()->insertFixedItem( i18n( "Memory: 88888888888 kB used, " + "88888888888 kB free" ), 1 ); + statusBar()->insertFixedItem( i18n( "Swap: 888888888 kB used, " + "888888888 kB free" ), 2 ); + statusBar()->hide(); + + // create actions for menue entries + new KAction( i18n( "&New Worksheet..." ), "tab_new", 0, mWorkSpace, + SLOT( newWorkSheet() ), actionCollection(), "new_worksheet" ); + + new KAction( i18n( "Import Worksheet..." ), "fileopen", 0, mWorkSpace, + SLOT( loadWorkSheet() ), actionCollection(), "import_worksheet" ); + + mActionOpenRecent = new KRecentFilesAction( i18n( "&Import Recent Worksheet" ),"fileopen", 0, + mWorkSpace, SLOT( loadWorkSheet( const KURL& ) ), actionCollection(), "recent_import_worksheet" ); + + new KAction( i18n( "&Remove Worksheet" ), "tab_remove", 0, mWorkSpace, + SLOT( deleteWorkSheet() ), actionCollection(), "remove_worksheet" ); + + new KAction( i18n( "&Export Worksheet..." ), "filesaveas", 0, mWorkSpace, + SLOT( saveWorkSheetAs() ), actionCollection(), "export_worksheet" ); + + KStdAction::quit( this, SLOT( close() ), actionCollection() ); + + new KAction( i18n( "C&onnect Host..." ), "connect_established", 0, this, + SLOT( connectHost() ), actionCollection(), "connect_host" ); + new KAction( i18n( "D&isconnect Host" ), "connect_no", 0, this, + SLOT( disconnectHost() ), actionCollection(), "disconnect_host" ); + +// KStdAction::cut( mWorkSpace, SLOT( cut() ), actionCollection() ); +// KStdAction::copy( mWorkSpace, SLOT( copy() ), actionCollection() ); +// KStdAction::paste( mWorkSpace, SLOT( paste() ), actionCollection() ); + new KAction( i18n( "&Worksheet Properties" ), "configure", 0, mWorkSpace, + SLOT( configure() ), actionCollection(), "configure_sheet" ); + + new KAction( i18n( "Load Standard Sheets" ), "revert", + 0, this, SLOT( resetWorkSheets() ), + actionCollection(), "revert_all_worksheets" ); + + new KAction( i18n( "Configure &Style..." ), "colorize", 0, this, + SLOT( editStyle() ), actionCollection(), "configure_style" ); + + // TODO remove resize and fix so sizeHints() determines default size. + if (!initialGeometrySet()) + resize( 640, 480 ); + setupGUI(ToolBar | Keys | StatusBar | Create); + setAutoSaveSettings(); +} + + +/* + * DCOP Interface functions + */ +void TopLevel::resetWorkSheets() +{ + if ( KMessageBox::warningContinueCancel( this, + i18n( "Do you really want to restore the default worksheets?" ), + i18n( "Reset All Worksheets" ), + i18n("Reset"), + "AskResetWorkSheets") == KMessageBox::Cancel ) + return; + + mWorkSpace->removeAllWorkSheets(); + + KStandardDirs* kstd = KGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + + QString workDir = kstd->saveLocation( "data", "ksysguard" ); + + QString file = kstd->findResource( "data", "SystemLoad.sgrd" ); + QString newFile = workDir + "/" + i18n( "System Load" ) + ".sgrd"; + if ( !file.isEmpty() ) + mWorkSpace->restoreWorkSheet( file, newFile ); + + file = kstd->findResource( "data", "ProcessTable.sgrd" ); + newFile = workDir + "/" + i18n( "Process Table" ) + ".sgrd"; + if ( !file.isEmpty() ) + mWorkSpace->restoreWorkSheet( file, newFile ); +} + +void TopLevel::showProcesses() +{ + mWorkSpace->showProcesses(); +} + +void TopLevel::showOnCurrentDesktop() +{ + KWin::setOnDesktop( winId(), KWin::currentDesktop() ); + kapp->updateUserTimestamp(); + KWin::forceActiveWindow( winId() ); +} + +void TopLevel::loadWorkSheet( const QString &fileName ) +{ + mWorkSpace->loadWorkSheet( KURL( fileName ) ); +} + +void TopLevel::removeWorkSheet( const QString &fileName ) +{ + mWorkSpace->deleteWorkSheet( fileName ); +} + +QStringList TopLevel::listSensors( const QString &hostName ) +{ + return mSensorBrowser->listSensors( hostName ); +} + +QStringList TopLevel::listHosts() +{ + return mSensorBrowser->listHosts(); +} + +QString TopLevel::readIntegerSensor( const QString &sensorLocator ) +{ + QString host = sensorLocator.left( sensorLocator.find( ':' ) ); + QString sensor = sensorLocator.right( sensorLocator.length() - + sensorLocator.find( ':' ) - 1 ); + + DCOPClientTransaction *dcopTransaction = kapp->dcopClient()->beginTransaction(); + mDCopFIFO.prepend( dcopTransaction ); + + KSGRD::SensorMgr->engage( host, "", "ksysguardd" ); + KSGRD::SensorMgr->sendRequest( host, sensor, (KSGRD::SensorClient*)this, 133 ); + + return QString::null; +} + +QStringList TopLevel::readListSensor( const QString& sensorLocator ) +{ + QStringList retval; + + QString host = sensorLocator.left( sensorLocator.find( ':' ) ); + QString sensor = sensorLocator.right( sensorLocator.length() - + sensorLocator.find( ':' ) - 1 ); + + DCOPClientTransaction *dcopTransaction = kapp->dcopClient()->beginTransaction(); + mDCopFIFO.prepend( dcopTransaction ); + + KSGRD::SensorMgr->engage( host, "", "ksysguardd" ); + KSGRD::SensorMgr->sendRequest( host, sensor, (KSGRD::SensorClient*)this, 134 ); + + return retval; +} +/* + * End of DCOP Interface section + */ + +void TopLevel::serviceAdded(DNSSD::RemoteService::Ptr srv) +{ + KSGRD::SensorMgr->engage( srv->hostName(), "", "", srv->port() ); +} + +void TopLevel::registerRecentURL( const KURL &url ) +{ + mActionOpenRecent->addURL( url ); +} + +void TopLevel::beATaskManager() +{ + mWorkSpace->showProcesses(); + + // Avoid displaying splitter widget + mSensorBrowser->hide(); + + // No toolbar and status bar in taskmanager mode. + toolBar( "mainToolBar" )->hide(); + + mDontSaveSession = true; + + stateChanged( "showProcessState" ); +} + +void TopLevel::showRequestedSheets() +{ + toolBar( "mainToolBar" )->hide(); + + QValueList<int> sizes; + sizes.append( 0 ); + sizes.append( 100 ); + mSplitter->setSizes( sizes ); +} + +void TopLevel::initStatusBar() +{ + KSGRD::SensorMgr->engage( "localhost", "", "ksysguardd" ); + /* Request info about the swap space size and the units it is + * measured in. The requested info will be received by + * answerReceived(). */ + KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/used?", + (KSGRD::SensorClient*)this, 5 ); + updateStatusBar(); + mServiceBrowser->startBrowse(); + + KToggleAction *sb = dynamic_cast<KToggleAction*>(action("options_show_statusbar")); + if (sb) + connect(sb, SIGNAL(toggled(bool)), this, SLOT(updateStatusBar())); +} + +void TopLevel::updateStatusBar() +{ + if ( mTimerId == -1 ) + mTimerId = startTimer( 2000 ); + + // call timerEvent to fill the status bar with real values + timerEvent( 0 ); +} + +void TopLevel::connectHost() +{ + KSGRD::SensorMgr->engageHost( "" ); +} + +void TopLevel::disconnectHost() +{ + mSensorBrowser->disconnect(); +} + +void TopLevel::editToolbars() +{ + saveMainWindowSettings( kapp->config() ); + KEditToolbar dlg( actionCollection() ); + connect( &dlg, SIGNAL( newToolbarConfig() ), this, + SLOT( slotNewToolbarConfig() ) ); + + dlg.exec(); +} + +void TopLevel::slotNewToolbarConfig() +{ + createGUI(); + applyMainWindowSettings( kapp->config() ); +} + +void TopLevel::editStyle() +{ + KSGRD::Style->configure(); +} + +void TopLevel::customEvent( QCustomEvent *e ) +{ + if ( e->type() == QEvent::User ) { + /* Due to the asynchronous communication between ksysguard and its + * back-ends, we sometimes need to show message boxes that were + * triggered by objects that have died already. */ + KMessageBox::error( this, *((QString*)e->data()) ); + delete (QString*)e->data(); + } +} + +void TopLevel::timerEvent( QTimerEvent* ) +{ + if ( statusBar()->isVisibleTo( this ) ) { + /* Request some info about the memory status. The requested + * information will be received by answerReceived(). */ + KSGRD::SensorMgr->sendRequest( "localhost", "pscount", + (KSGRD::SensorClient*)this, 0 ); + KSGRD::SensorMgr->sendRequest( "localhost", "mem/physical/free", + (KSGRD::SensorClient*)this, 1 ); + KSGRD::SensorMgr->sendRequest( "localhost", "mem/physical/used", + (KSGRD::SensorClient*)this, 2 ); + KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/free", + (KSGRD::SensorClient*)this, 3 ); + KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/used", + (KSGRD::SensorClient*)this, 4 ); + } +} + +bool TopLevel::queryClose() +{ + if ( !mDontSaveSession ) { + if ( !mWorkSpace->saveOnQuit() ) + return false; + + saveProperties( kapp->config() ); + kapp->config()->sync(); + } + + return true; +} + +void TopLevel::readProperties( KConfig *cfg ) +{ + /* we can ignore 'isMaximized' because we can't set the window + maximized, so we save the coordinates instead */ + if ( cfg->readBoolEntry( "isMinimized" ) == true ) + showMinimized(); + + QValueList<int> sizes = cfg->readIntListEntry( "SplitterSizeList" ); + if ( sizes.isEmpty() ) { + // start with a 30/70 ratio + sizes.append( 30 ); + sizes.append( 70 ); + } + mSplitter->setSizes( sizes ); + + KSGRD::SensorMgr->readProperties( cfg ); + KSGRD::Style->readProperties( cfg ); + + mWorkSpace->readProperties( cfg ); + + mActionOpenRecent->loadEntries( cfg ); + + applyMainWindowSettings( cfg ); +} + +void TopLevel::saveProperties( KConfig *cfg ) +{ + mActionOpenRecent->saveEntries( cfg ); + + cfg->writeEntry( "isMinimized", isMinimized() ); + cfg->writeEntry( "SplitterSizeList", mSplitter->sizes() ); + + KSGRD::Style->saveProperties( cfg ); + KSGRD::SensorMgr->saveProperties( cfg ); + + saveMainWindowSettings( cfg ); + mWorkSpace->saveProperties( cfg ); +} + +void TopLevel::answerReceived( int id, const QString &answer ) +{ + QString s; + static QString unit; + static long mUsed = 0; + static long mFree = 0; + static long sUsed = 0; + static long sFree = 0; + + switch ( id ) { + case 0: + // yes, I know there is never 1 process, but that's the way + // singular vs. plural works :/ + // + // To use pluralForms, though, you need to convert to + // an integer, not use the QString straight. + s = i18n( "1 Process", "%n Processes", answer.toInt() ); + statusBar()->changeItem( s, 0 ); + break; + + case 1: + mFree = answer.toLong(); + break; + + case 2: + mUsed = answer.toLong(); + s = i18n( "Memory: %1 %2 used, %3 %4 free" ) + .arg( KGlobal::locale()->formatNumber( mUsed, 0 ) ).arg( unit ) + .arg( KGlobal::locale()->formatNumber( mFree, 0 ) ).arg( unit ); + statusBar()->changeItem( s, 1 ); + break; + + case 3: + sFree = answer.toLong(); + setSwapInfo( sUsed, sFree, unit ); + break; + + case 4: + sUsed = answer.toLong(); + setSwapInfo( sUsed, sFree, unit ); + break; + + case 5: { + KSGRD::SensorIntegerInfo info( answer ); + unit = KSGRD::SensorMgr->translateUnit( info.unit() ); + } + + case 133: { + QCString replyType = "QString"; + QByteArray replyData; + QDataStream reply( replyData, IO_WriteOnly ); + reply << answer; + + DCOPClientTransaction *dcopTransaction = mDCopFIFO.last(); + kapp->dcopClient()->endTransaction( dcopTransaction, replyType, replyData ); + mDCopFIFO.removeLast(); + break; + } + + case 134: { + QStringList resultList; + QCString replyType = "QStringList"; + QByteArray replyData; + QDataStream reply( replyData, IO_WriteOnly ); + + KSGRD::SensorTokenizer lines( answer, '\n' ); + + for ( unsigned int i = 0; i < lines.count(); i++ ) + resultList.append( lines[ i ] ); + + reply << resultList; + + DCOPClientTransaction *dcopTransaction = mDCopFIFO.last(); + kapp->dcopClient()->endTransaction( dcopTransaction, replyType, replyData ); + mDCopFIFO.removeLast(); + break; + } + } +} + +void TopLevel::setSwapInfo( long used, long free, const QString &unit ) +{ + QString msg; + if ( used == 0 && free == 0 ) // no swap available + msg = i18n( "No swap space available" ); + else { + msg = i18n( "Swap: %1 %2 used, %3 %4 free" ) + .arg( KGlobal::locale()->formatNumber( used, 0 ) ).arg( unit ) + .arg( KGlobal::locale()->formatNumber( free, 0 ) ).arg( unit ); + } + + statusBar()->changeItem( msg, 2 ); +} + +static const KCmdLineOptions options[] = { + { "showprocesses", I18N_NOOP( "Show only process list of local host" ), 0 }, + { "+[worksheet]", I18N_NOOP( "Optional worksheet files to load" ), 0 }, + KCmdLineLastOption +}; + +/* + * Once upon a time... + */ +int main( int argc, char** argv ) +{ + // initpipe is used to keep the parent process around till the child + // has registered with dcop. + int initpipe[ 2 ]; + pipe( initpipe ); + + /* This forking will put ksysguard in it's on session not having a + * controlling terminal attached to it. This prevents ssh from + * using this terminal for password requests. Unfortunately you + * now need a ssh with ssh-askpass support to popup an X dialog to + * enter the password. Currently only the original ssh provides this + * but not open-ssh. */ + + pid_t pid; + if ( ( pid = fork() ) < 0 ) + return -1; + else + if ( pid != 0 ) { + close( initpipe[ 1 ] ); + + // wait till init is complete + char c; + while( read( initpipe[ 0 ], &c, 1 ) < 0 ); + + // then exit + close( initpipe[ 0 ] ); + exit( 0 ); + } + + close( initpipe[ 0 ] ); + setsid(); + + KAboutData aboutData( "ksysguard", I18N_NOOP( "KDE System Guard" ), + KSYSGUARD_VERSION, Description, KAboutData::License_GPL, + I18N_NOOP( "(c) 1996-2002 The KSysGuard Developers" ) ); + aboutData.addAuthor( "Chris Schlaeger", "Current Maintainer", "cs@kde.org" ); + aboutData.addAuthor( "Tobias Koenig", 0, "tokoe@kde.org" ); + aboutData.addAuthor( "Nicolas Leclercq", 0, "nicknet@planete.net" ); + aboutData.addAuthor( "Alex Sanda", 0, "alex@darkstart.ping.at" ); + aboutData.addAuthor( "Bernd Johannes Wuebben", 0, "wuebben@math.cornell.edu" ); + aboutData.addAuthor( "Ralf Mueller", 0, "rlaf@bj-ig.de" ); + aboutData.addAuthor( "Hamish Rodda", 0, "rodda@kde.org" ); + aboutData.addAuthor( "Torsten Kasch", I18N_NOOP( "Solaris Support\n" + "Parts derived (by permission) from the sunos5\n" + "module of William LeFebvre's \"top\" utility." ), + "tk@Genetik.Uni-Bielefeld.DE" ); + + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication::disableAutoDcopRegistration(); + // initialize KDE application + KApplication *app = new KApplication; + + KSGRD::SensorMgr = new KSGRD::SensorManager(); + KSGRD::Style = new KSGRD::StyleEngine(); + + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + + int result = 0; + + if ( args->isSet( "showprocesses" ) ) { + /* To avoid having multiple instances of ksysguard in + * taskmanager mode we check if another taskmanager is running + * already. If so, we terminate this one immediately. */ + if ( app->dcopClient()->registerAs( "ksysguard_taskmanager", false ) == + "ksysguard_taskmanager" ) { + // We have registered with DCOP, our parent can exit now. + char c = 0; + write( initpipe[ 1 ], &c, 1 ); + close( initpipe[ 1 ] ); + + topLevel = new TopLevel( "KSysGuard" ); + topLevel->beATaskManager(); + topLevel->initStatusBar(); + topLevel->show(); + KSGRD::SensorMgr->setBroadcaster( topLevel ); + + // run the application + result = app->exec(); + } else { + QByteArray data; + app->dcopClient()->send( "ksysguard_taskmanager", "KSysGuardIface", + "showOnCurrentDesktop()", data ); + } + } else { + app->dcopClient()->registerAs( "ksysguard" ); + app->dcopClient()->setDefaultObject( "KSysGuardIface" ); + + // We have registered with DCOP, our parent can exit now. + char c = 0; + write( initpipe[ 1 ], &c, 1 ); + close( initpipe[ 1 ] ); + + topLevel = new TopLevel( "KSysGuard" ); + + // create top-level widget + if ( args->count() > 0 ) { + /* The user has specified a list of worksheets to load. In this + * case we do not restore any previous settings but load all the + * requested worksheets. */ + topLevel->showRequestedSheets(); + for ( int i = 0; i < args->count(); ++i ) + topLevel->loadWorkSheet( args->arg( i ) ); + } else { + if ( app->isRestored() ) + topLevel->restore( 1 ); + else + topLevel->readProperties( app->config() ); + } + + topLevel->initStatusBar(); + topLevel->show(); + KSGRD::SensorMgr->setBroadcaster( topLevel ); + + // run the application + result = app->exec(); + } + + delete KSGRD::Style; + delete KSGRD::SensorMgr; + delete app; + + return result; +} + +#include "ksysguard.moc" diff --git a/ksysguard/gui/ksysguard.desktop b/ksysguard/gui/ksysguard.desktop new file mode 100644 index 000000000..76a960ec4 --- /dev/null +++ b/ksysguard/gui/ksysguard.desktop @@ -0,0 +1,102 @@ +[Desktop Entry] +Name=KSysGuard +Name[af]=Ksysguard +Name[ar]=حارس النظام +Name[bg]=Системна защита +Name[csb]=KDE Wachtôrz Systemë +Name[de]=Systemüberwachung +Name[eo]=KSistemGardilo +Name[et]=Süsteemi valvur +Name[fr]=Surveillance du système +Name[he]=משמר המערכת +Name[hi]=के-सिस-गार्ड +Name[hr]=KDE zaštitnik sustava +Name[is]=KDE álagsmælir +Name[ja]=KDE システムガード +Name[lo]=ກວດສອບແລະປ້ອງກັນລະບົບ - K +Name[mn]=Системийн хяналт +Name[nb]=KDE Systemvakt +Name[ne]=KSys रक्षक +Name[nn]=KDE Systemvakt +Name[nso]=Thlokomelo ya KSys +Name[pl]=KDE Strażnik Systemu +Name[sk]=KDE Strážca systému +Name[sv]=Systemövervakare +Name[tg]=Муҳофизати системаи-K +Name[th]=ตรวจสอบและป้องกันระบบ +Name[uz]=KDE tizim nazoratchisi +Name[uz@cyrillic]=KDE тизим назоратчиси +Name[vi]=Bảo vệ Hệ thống KDE +Name[wa]=KSisGåde +GenericName=Performance Monitor +GenericName[af]=Werkverrigting Monitor +GenericName[ar]=مراقب الإداء +GenericName[be]=Сістэмны назіральнік +GenericName[bg]=Мониторинг на системата +GenericName[bs]=Monitor performansi +GenericName[ca]=Monitor de rendiment +GenericName[cs]=Monitor výkonu +GenericName[csb]=Mònitor spòroscë +GenericName[da]=Overvågning af ydelse +GenericName[de]=Performancemonitor +GenericName[el]=Επόπτης συστήματος +GenericName[eo]=Rendimento Monitoro +GenericName[es]=Monitor de rendimiento +GenericName[et]=Jõudluse monitor +GenericName[eu]=Sistemaren errendimenduaren monitorea +GenericName[fa]=نمایشگر کارایی +GenericName[fi]=Järjestelmän suorituskyvyn monitori +GenericName[fr]=Indicateurs de performance +GenericName[fy]=Prestaasjemonitor +GenericName[gl]=Monitor de Rendemento +GenericName[he]=צג מערכת +GenericName[hr]=Nadzor performansi +GenericName[hu]=Teljesítményfigyelő +GenericName[is]=Afkasta eftirlit +GenericName[it]=Monitor delle prestazioni +GenericName[ja]=パフォーマンスモニター +GenericName[ka]=წარმადობის მონიტორი +GenericName[kk]=Жылдамдылық бақылаушысы +GenericName[km]=កម្មវិធីត្រួតពិនិត្យដំណើរការ +GenericName[lt]=Veiksenos monitorius +GenericName[mk]=Монитор на перформанси +GenericName[ms]=Pemantau Prestasi +GenericName[nb]=Ytelsesovervåker +GenericName[nds]=Leisten-Kieker +GenericName[ne]=सम्पादन मनिटर +GenericName[nl]=Prestatiemonitor +GenericName[nn]=Ytelsesovervakar +GenericName[pa]=ਪਰਦਰਸ਼ਨ ਨਿਗਰਾਨ +GenericName[pl]=Monitor wydajności +GenericName[pt]=Monitor de Performance +GenericName[pt_BR]=Monitor de Performance +GenericName[ro]=Monitor de performanță +GenericName[ru]=Монитор производительности +GenericName[rw]=Mugaragaza y'Imikorere +GenericName[se]=Buvttogoziheaddji +GenericName[sk]=Sledovač výkonu +GenericName[sl]=Nadzor delovanja +GenericName[sr]=Монитор перформанси +GenericName[sr@Latn]=Monitor performansi +GenericName[sv]=Prestandaövervakare +GenericName[ta]=செயல்திறன் திரை +GenericName[th]=สอดส่องประสิทธิภาพการทำงานของระบบ +GenericName[tr]=Sistem İzleyici +GenericName[tt]=Citezlek Küzätüçese +GenericName[uk]=Монітор швидкодії +GenericName[uz]=Tizimni nazorat qilish +GenericName[uz@cyrillic]=Тизимни назорат қилиш +GenericName[vi]=Theo dõi Hiệu năng +GenericName[wa]=Corwaitoe di ç' ki va bén +GenericName[zh_CN]=性能监视器 +GenericName[zh_TW]=效能監視器 +Exec=ksysguard %U +Icon=ksysguard +Type=Application +MimeType=application/x-ksysguard; +DocPath=ksysguard/index.html +Terminal=false +Path= +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;System; diff --git a/ksysguard/gui/ksysguard.h b/ksysguard/gui/ksysguard.h new file mode 100644 index 000000000..8d2ef15d9 --- /dev/null +++ b/ksysguard/gui/ksysguard.h @@ -0,0 +1,124 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + 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 <cs@kde.org>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_KSYSGUARD_H +#define KSG_KSYSGUARD_H + +#include <qevent.h> + +#include <dcopclient.h> +#include <dcopobject.h> +#include <kapplication.h> +#include <kmainwindow.h> +#include <dnssd/servicebrowser.h> + +#include <ksgrd/SensorClient.h> + +class KRecentFilesAction; +class KToggleAction; + +class QSplitter; +class SensorBrowser; +class Workspace; + +class TopLevel : public KMainWindow, public KSGRD::SensorClient, public DCOPObject +{ + Q_OBJECT + K_DCOP + + public: + TopLevel( const char *name = 0 ); + + virtual void saveProperties( KConfig* ); + virtual void readProperties( KConfig* ); + + virtual void answerReceived( int id, const QString& ); + + void beATaskManager(); + void showRequestedSheets(); + void initStatusBar(); + + k_dcop: + // calling ksysguard with kwin/kicker hot-key + ASYNC showProcesses(); + ASYNC showOnCurrentDesktop(); + ASYNC loadWorkSheet( const QString &fileName ); + ASYNC removeWorkSheet( const QString &fileName ); + QStringList listHosts(); + QStringList listSensors( const QString &hostName ); + QString readIntegerSensor( const QString &sensorLocator ); + QStringList readListSensor( const QString &sensorLocator ); + + public slots: + void registerRecentURL( const KURL &url ); + void resetWorkSheets(); + + protected: + virtual void customEvent( QCustomEvent* ); + virtual void timerEvent( QTimerEvent* ); + virtual bool queryClose(); + + protected slots: + void connectHost(); + void disconnectHost(); + void updateStatusBar(); + void editToolbars(); + void editStyle(); + void slotNewToolbarConfig(); + void serviceAdded(DNSSD::RemoteService::Ptr srv); + + private: + void setSwapInfo( long, long, const QString& ); + + QPtrList<DCOPClientTransaction> mDCopFIFO; + + QSplitter* mSplitter; + KRecentFilesAction* mActionOpenRecent; + + SensorBrowser* mSensorBrowser; + Workspace* mWorkSpace; + + DNSSD::ServiceBrowser* mServiceBrowser; + + bool mDontSaveSession; + int mTimerId; +}; + +extern TopLevel* Toplevel; + +/* + since there is only a forward declaration of DCOPClientTransaction + in dcopclient.h we have to redefine it here, otherwise QPtrList + causes errors +*/ +typedef unsigned long CARD32; + +class DCOPClientTransaction +{ + public: + Q_INT32 id; + CARD32 key; + QCString senderId; +}; + +#endif diff --git a/ksysguard/gui/ksysguardapplet.desktop b/ksysguard/gui/ksysguardapplet.desktop new file mode 100644 index 000000000..08441fe64 --- /dev/null +++ b/ksysguard/gui/ksysguardapplet.desktop @@ -0,0 +1,120 @@ +[Desktop Entry] +Type=Plugin +Name=System Guard +Name[af]=Stelsel Wag +Name[ar]=حارس النظام +Name[be]=Сістэмны ахоўнік +Name[bg]=Системен монитор +Name[bn]=সিস্টেম প্রহরী +Name[br]=Gward Reizhiad +Name[bs]=Nadzor sistema +Name[ca]=Vigilant del sistema +Name[cs]=Strážce systému +Name[csb]=Wachtôrz Systemë +Name[da]=Systemvagt +Name[de]=Systemüberwachung +Name[el]=Φρουρός συστήματος +Name[eo]=Sistemo Gardilo +Name[es]=Guardián del sistema +Name[et]=Süsteemi valvur +Name[eu]=Sistemaren zaintzailea +Name[fa]=محافظ سیستم +Name[fi]=Järjestelmän valvonta +Name[fr]=Surveillance du système +Name[fy]=Systeemwarder +Name[gl]=Vixiante do Sistema +Name[he]=משמר המערכת +Name[hr]=Zaštitnik sustava +Name[hu]=Rendszermonitor +Name[is]=Kerfiseftirlit +Name[it]=Controllo del sistema +Name[ja]=システムガード +Name[ka]=სისტემის მცველი +Name[kk]=Жүйе бақылаушысы +Name[km]=ឆ្មាំប្រព័ន្ធ +Name[ko]=KDE 시스템 지킴이 +Name[lt]=Sistemos apsauga +Name[mk]=Чувар на системот +Name[nb]=Systemvakt +Name[nds]=Systeemwachter +Name[ne]=प्रणाली रक्षक +Name[nl]=Systeembewaking +Name[nn]=Systemvakt +Name[pa]=ਸਿਸਟਮ ਗਾਰਡ +Name[pl]=Strażnik Systemu +Name[pt]=Vigilante do Sistema +Name[pt_BR]=Guarda do Sistema +Name[ro]=Sistem de gardă +Name[ru]=Системный монитор +Name[se]=Vuogádatfákta +Name[sk]=Strážca systému +Name[sl]=Sistemski varuh +Name[sr]=Заштита система +Name[sr@Latn]=Zaštita sistema +Name[sv]=Systemövervakare +Name[th]=ป้องกันระบบ +Name[tr]=Sistem İzleyici +Name[uk]=Системний вартовий +Name[uz]=Kengaytirilgan tizim nazoratchisi +Name[uz@cyrillic]=Кенгайтирилган тизим назоратчиси +Name[vi]=Bảo vệ Hệ thống +Name[wa]=Gåde do sistinme +Name[zh_CN]=系统卫士 +Name[zh_TW]=系統守衛 +Comment=An advanced system monitor which swallows KDE system guard displays +Comment[af]='n Gevorderde stelsel monitor wat KDE se stelsel wag skerms insluit +Comment[be]=Адмысловы сістэмны назіральнік, які "праглынае" дысплеі сістэмнага ахоўніка KDE +Comment[bg]=Системен монитор, който следи за състоянието на системата +Comment[bs]=Napredni program za nadzor sistema koji obuhvata više drugih prozora +Comment[ca]=Un monitor del sistema avançat que inclou pantalles del vigilant del sistema KDE +Comment[cs]=Pokročilý monitor systému, který pohlcuje displeje strážce KDE +Comment[csb]=Awansowóny mònitor systemë jaczi pòkazywô wskôzywôcze KDE Wachtôrza Systemë +Comment[da]=En avanceret systemovervåger som svælger skærme fra KDE's systemovervågning +Comment[de]=Erweiterte Systemüberwachung für die Kontrollleiste +Comment[el]=Ένας προχωρημένος επόπτης του συστήματος ο οποίος ενσωματώνει προβολές του φρουρού συστήματος του KDE +Comment[eo]=Malbaza sistemomonitoro kiu glutas KDE-sistemogardilo-ekranojn. +Comment[es]=Un monitor avanzado del sistema que integra los gráficos del guardián del sistema de KDE +Comment[et]=Võimas süsteemi monitor KDE süsteemi valvuri sensoritele +Comment[eu]=Sistema monitore aurreratua, KDE sistemaren zaintzailearen pantailak bistaratzen dituena +Comment[fa]=یک نمایشگر پیشرفتۀ سیستم که نمایشهای محافظ سیستم KDE را از بین میبرد +Comment[fi]=Edistynyt järjestelmän valvonta, johon sisältyy KDE järjestelmänvalvonnan näytöt +Comment[fr]=Un surveillant avancé affichant l'état du système +Comment[fy]=In avansearre systeemmonitor mei systeemwardings werjefte +Comment[gl]=Un monitor do sistema que incorpora os resultados do vixiante do sistema de KDE +Comment[he]=מנטר מערכת מתקדם המאפשר המטעה של תצוגות של משמר המערכת של KDE +Comment[hr]=Napredan sistemski nadzor koji "guta" prikaze KDE zaštitnika sustava +Comment[hu]=Rendszermonitor kijelzőkkel +Comment[is]=Þróað kerfiseftirlit sem gleypir KDE álagsmæla +Comment[it]=Un sistema di controllo del sistema avanzato che ingloba i controlli di sistema di KDE +Comment[ja]=KDE システムガードを表示する高度なシステムモニター +Comment[kk]=Жетілдірілген жүйе бақылаушысы +Comment[km]=កម្មវិធីត្រួតពិនិត្យប្រព័ន្ធកម្រិតខ្ពស់ដែលអនុញ្ញាតឲ្យប្រព័ន្ធ KDE ត្រួតពិនិត្យការបង្ហាញ +Comment[lt]=Sudėtingesnė sistemos stebėjimo priemonė, įtraukianti KDE sistemos apsaugos stebėjimo priemones +Comment[mk]=Напреден монитор на системот кој ги врамува приказите на чуварите на системот на KDE +Comment[nb]=En avansert systemovervåker som svelger visninger av KDEs systemovervåker +Comment[nds]=En verwiedert Systeemkieker, mit inbett Diagrammen vun KDE System Guard +Comment[ne]=उन्नत प्रणाली मनिटर जसले अन्त्य गर्ने KDE प्रणाली रक्षक प्रदर्शन गर्छ +Comment[nl]=Een geavanceerde systeemmonitor met systeembewakingsdisplays +Comment[nn]=Ein avansert systemovervakar som svelgjer visingar av KDE-systemovervakaren +Comment[pl]=Zaawansowany monitor systemu pokazujący wskaźniki Strażnika systemu KDE +Comment[pt]=Um monitor de sistema avançado que engloba folhas de monitorização do sistema KDE +Comment[pt_BR]=Um monitor avançado de sistema que permite monitorar o que a guarda do sistema do KDE exibe +Comment[ro]=Un monitor de sistem avansat care înghite ecranele sistemului de gardă KDE +Comment[ru]=Системный монитор +Comment[sk]=Sledovač systému, ktorý obsahuje systémových strážcov KDE +Comment[sl]=Napreden nadzor sistema, ki uporablja prikazovalnike iz Sistemskega varuha KDE +Comment[sr]=Напредни монитор који гута приказе KDE-ове заштите система +Comment[sr@Latn]=Napredni monitor koji guta prikaze KDE-ove zaštite sistema +Comment[sv]=En avancerad systemövervakare som sväljer skärmar från KDE:s systemövervakare +Comment[th]=ตัวเฝ้าตรวจสอบระบบขั้นก้าวหน้า ซึ่งกลืนหน้าจอของตัวป้องกันระบบ KDE +Comment[tr]=Gelişmiş bir sistem izleyici +Comment[uk]=Додатковий системний монітор, який поглинає показ системного вартового KDE +Comment[uz]=Tizimning protsessor, xotira, tarmoq kabi qisimlarini kuzatib turadigan kengaytirilgan tizim nazoratchisi +Comment[uz@cyrillic]=Тизимнинг процессор, хотира, тармоқ каби қисимларини кузатиб турадиган кенгайтирилган тизим назоратчиси +Comment[vi]=Một trình theo dõi hệ thống nâng cao thế chỗ cho hiển thị bảo vệ hệ thống KDE +Comment[wa]=On corwaitoe po les spepieus k' avale li håynaedje so gåde do sistinme di KDE +Comment[zh_CN]=可显示 KDE 系统卫士效果的高级系统监视器 +Comment[zh_TW]=包含 KDE 系統守衛顯示的進階系統監視器 +Icon=ksysguard +X-KDE-Library=sysguard_panelapplet +X-KDE-UniqueApplet=true diff --git a/ksysguard/gui/ksysguardui.rc b/ksysguard/gui/ksysguardui.rc new file mode 100644 index 000000000..912894ed3 --- /dev/null +++ b/ksysguard/gui/ksysguardui.rc @@ -0,0 +1,50 @@ +<!DOCTYPE kpartgui> +<kpartgui name="ksysguard" version="5"> +<State name="showProcessState"> + <Disable> + <Action name="new_worksheet"/> + <Action name="import_worksheet"/> + <Action name="recent_import_worksheet"/> + <Action name="export_worksheet"/> + <Action name="remove_worksheet"/> + <Action name="revert_all_worksheets"/> + <Action name="connect_host"/> + <Action name="disconnect_host"/> + <Action name="configure_sheet"/> + <Action name="configure_style"/> + </Disable> +</State> +<MenuBar> + <Menu name="file"><text>&File</text> + <Action name="new_worksheet"/> + <Action name="recent_import_worksheet"/> + <Action name="import_worksheet"/> + <Separator/> + <Action name="export_worksheet"/> + <Separator/> + <Action name="remove_worksheet"/> + <Action name="revert_all_worksheets"/> + <Separator/> + <Action name="connect_host"/> + <Action name="disconnect_host"/> + </Menu> + <Menu name="edit"><text>&Edit</text> + <Action name="configure_sheet"/> + </Menu> + <Menu name="settings"><text>&Settings</text> + <Action name="configure_style"/> + </Menu> +</MenuBar> +<ToolBar name="mainToolBar" noMerge="1"><text>Main Toolbar</text> + <Action name="new_worksheet"/> + <Action name="import_worksheet"/> + <Action name="export_worksheet"/> + <Separator/> + <Action name="connect_host"/> + <Action name="disconnect_host"/> + <Separator/> + <Action name="configure_sheet"/> + <Action name="configure_style"/> +</ToolBar> +</kpartgui> + diff --git a/ksysguard/gui/x-ksysguard.desktop b/ksysguard/gui/x-ksysguard.desktop new file mode 100644 index 000000000..78a0a15c9 --- /dev/null +++ b/ksysguard/gui/x-ksysguard.desktop @@ -0,0 +1,86 @@ +# KDE Config File +[Desktop Entry] +NotShowIn=GNOME; +MimeType=application/x-ksysguard +Comment=KDE System Guard +Comment[af]=KDE Stelsel Wag +Comment[ar]=حارس النظام KDE +Comment[az]=KDE Sistem Cangüdəni +Comment[be]=Ахоўнік сістэмы KDE +Comment[bg]=Системна защита +Comment[bn]=কে.ডি.ই. সিস্টেম গার্ড +Comment[br]=Gward Reizhiad KDE +Comment[bs]=KDE zaštita sistema +Comment[ca]=Vigilant del sistema KDE +Comment[cs]=Správce systému KDE +Comment[csb]=KDE Wachtôrz Systemë +Comment[cy]=Gwarchodwr Cysawd KDE +Comment[da]=KDE Systemvagt +Comment[de]=KDE-Systemüberwachung +Comment[el]=Φρουρός συστήματος του KDE +Comment[eo]=KDE-Sistemobservilo +Comment[es]=Guardián del sistema de KDE +Comment[et]=KDE süsteemi valvur +Comment[eu]=KDEren sistemaren kontrola +Comment[fa]=محافظ سیستم KDE +Comment[fi]=KDE:n järjestelmänvalvonta +Comment[fr]=Surveillance du système +Comment[fy]=KDE systeembefeiliging +Comment[ga]=Garda an Chórais KDE +Comment[gl]=Vixiante do Sistema de KDE +Comment[he]=משמר המערכת של KDE +Comment[hi]=केडीई तंत्र गार्ड +Comment[hr]=KDE zaštitnik sustava +Comment[hu]=KDE rendszermonitor +Comment[is]=KDE kerfisvörður +Comment[it]=Controllo di sistema di KDE +Comment[ja]=KDE システムガード +Comment[ka]=KDE სისტემური მონიტორი +Comment[kk]=KDE жүйелік бақылаушысы +Comment[km]=ការពារប្រព័ន្ធ KDE +Comment[ko]=KDE 시스템 지킴이 +Comment[lo]=ເຄື່ອງມືຶປ້ອງກັນລະບົບຂອງ KDE +Comment[lt]=KDE sistemos apsauga +Comment[lv]=KDE Sistēmas Sargs +Comment[mk]=KDE Системски чувар +Comment[mn]=КДЭ-Системийн хяналт +Comment[ms]=Pengawas Sistem KDE +Comment[mt]=Gwardja tas-Sistema KDE +Comment[nb]=KDE Systemovervåker +Comment[nds]=KDE-Systeemwachter +Comment[ne]=KDE प्रणाली रक्षक +Comment[nl]=KDE systeembewaking +Comment[nn]=KDE Systemvakt +Comment[nso]=Thlokomelo ya System ya KDE +Comment[pa]=KDE ਸਿਸਟਮ ਗਾਰਡ +Comment[pl]=KDE Strażnik Systemu +Comment[pt]=Vigilante do sistema do KDE +Comment[pt_BR]=Sistema de Guarda do KDE +Comment[ro]=Sistem de gardă KDE +Comment[ru]=Системный монитор +Comment[rw]=Umurinzi Sisitemu KDE +Comment[se]=KDE vuogádatfákta +Comment[sk]=KDE Strážca systému +Comment[sl]=Sistemski varuh KDE +Comment[sr]=KDE чувар система +Comment[sr@Latn]=KDE čuvar sistema +Comment[sv]=KDE:s systemövervakare +Comment[ta]=KDE கணினி காவலன் +Comment[tg]=Муҳофизи системаи KDE +Comment[th]=เครื่องมือป้องกันระบบ KDE +Comment[tr]=KDE Sistem Koruyucu +Comment[tt]=KDE'nıñ Sistem Saqçısı +Comment[uk]=Системний вартовий KDE +Comment[uz]=KDE tizim nazoratchisi +Comment[uz@cyrillic]=KDE тизим назоратчиси +Comment[ven]=Mulindi wa maitele a KDE +Comment[vi]=Trình bảo vệ Hệ thống KDE +Comment[wa]=Gåre sistinme KDE +Comment[xh]=KDE Ukhuselo lendlela yokusebenza +Comment[zh_CN]=KDE 系统卫士 +Comment[zh_TW]=KDE 系統守衛 +Comment[zu]=Unogada Wesistimu ye-KDE +Icon=ksysguard +Type=MimeType +Patterns=*.sgrd; +X-KDE-AutoEmbed=false |