diff options
Diffstat (limited to 'ksysguard/gui/SensorDisplayLib')
48 files changed, 10607 insertions, 0 deletions
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 |