diff options
Diffstat (limited to 'ksysguard/gui')
94 files changed, 17662 insertions, 0 deletions
diff --git a/ksysguard/gui/CMakeLists.txt b/ksysguard/gui/CMakeLists.txt new file mode 100644 index 000000000..7313b6b5d --- /dev/null +++ b/ksysguard/gui/CMakeLists.txt @@ -0,0 +1,64 @@ +################################################# +# +# (C) 2010-2011 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +add_subdirectory( ksgrd ) +add_subdirectory( SensorDisplayLib ) + + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/SensorDisplayLib + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/ksgrd + ${CMAKE_CURRENT_SOURCE_DIR}/SensorDisplayLib + ${TDE_INCLUDE_DIR} + ${TQT_INCLUDE_DIRS} +) + +link_directories( + ${TQT_LIBRARY_DIRS} +) + + +##### other data ################################ + +install( FILES ksysguard.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) +install( FILES x-ksysguard.desktop DESTINATION ${MIME_INSTALL_DIR}/application ) +install( FILES ProcessTable.sgrd SystemLoad.sgrd KSysGuardApplet.xml ksysguardui.rc DESTINATION ${DATA_INSTALL_DIR}/ksysguard ) +install( FILES ksysguardapplet.desktop DESTINATION ${DATA_INSTALL_DIR}/kicker/applets ) + + +##### sysguard_panelapplet (module) ############# + +tde_add_kpart( sysguard_panelapplet AUTOMOC + SOURCES KSysGuardApplet.cc KSGAppletSettings.cc + LINK sensordisplays-static ksgrd-shared + DESTINATION ${PLUGIN_INSTALL_DIR} +) + + +##### ksysguard (executable) #################### + +tde_add_executable( ksysguard AUTOMOC + SOURCES + SensorBrowser.cc WorkSheet.cc WorkSheetSettings.cc + Workspace.cc ksysguard.cc ksysguard.skel + LINK sensordisplays-static ksgrd-shared tdednssd-shared + DESTINATION ${BIN_INSTALL_DIR} +) + + +##### kpm (executable) ########################## + +tde_add_executable( kpm + SOURCES kpm.c + DESTINATION ${BIN_INSTALL_DIR} +) diff --git a/ksysguard/gui/KSGAppletSettings.cc b/ksysguard/gui/KSGAppletSettings.cc new file mode 100644 index 000000000..01b2e0b1a --- /dev/null +++ b/ksysguard/gui/KSGAppletSettings.cc @@ -0,0 +1,106 @@ +/* + This file is part of KSysGuard. + Copyright ( C ) 2002 Nadeem Hasan ( [email protected] ) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or ( at your option ) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqspinbox.h> + +#include <tdeaccelmanager.h> +#include <tdelocale.h> + +#include "KSGAppletSettings.h" + +KSGAppletSettings::KSGAppletSettings( TQWidget *parent, const char *name ) + : KDialogBase( parent, name, false, TQString::null, Ok|Apply|Cancel, + Ok, true ) +{ + setCaption( i18n( "System Guard Settings" ) ); + + TQWidget *page = new TQWidget( this ); + setMainWidget( page ); + + TQGridLayout *topLayout = new TQGridLayout( page, 3, 2, KDialog::marginHint(), + KDialog::spacingHint() ); + + TQLabel *label = new TQLabel( i18n( "Number of displays:" ), page ); + topLayout->addWidget( label, 0, 0 ); + + mNumDisplay = new TQSpinBox( 1, 32, 1, page ); + mNumDisplay->setValue(2); + topLayout->addWidget( mNumDisplay, 0, 1 ); + label->setBuddy( mNumDisplay ); + + label = new TQLabel( i18n( "Size ratio:" ), page ); + topLayout->addWidget( label, 1, 0 ); + + mSizeRatio = new TQSpinBox( 50, 500, 50, page ); + mSizeRatio->setSuffix( i18n( "%" ) ); + mSizeRatio->setValue(100); + topLayout->addWidget( mSizeRatio, 1, 1 ); + label->setBuddy( mSizeRatio ); + + label = new TQLabel( i18n( "Update interval:" ), page ); + topLayout->addWidget( label, 2, 0 ); + + mInterval = new TQSpinBox( 1, 300, 1, page ); + mInterval->setValue(2); + mInterval->setSuffix( i18n( " sec" ) ); + topLayout->addWidget( mInterval, 2, 1 ); + label->setBuddy( mInterval ); + + resize( TQSize( 250, 130 ).expandedTo( minimumSizeHint() ) ); + + TDEAcceleratorManager::manage( page ); +} + +KSGAppletSettings::~KSGAppletSettings() +{ +} + +int KSGAppletSettings::numDisplay() const +{ + return mNumDisplay->value(); +} + +void KSGAppletSettings::setNumDisplay( int value ) +{ + mNumDisplay->setValue( value ); +} + +int KSGAppletSettings::sizeRatio() const +{ + return mSizeRatio->value(); +} + +void KSGAppletSettings::setSizeRatio( int value ) +{ + mSizeRatio->setValue( value ); +} + +int KSGAppletSettings::updateInterval() const +{ + return mInterval->value(); +} + +void KSGAppletSettings::setUpdateInterval( int value ) +{ + mInterval->setValue( value ); +} + diff --git a/ksysguard/gui/KSGAppletSettings.h b/ksysguard/gui/KSGAppletSettings.h new file mode 100644 index 000000000..af49470a8 --- /dev/null +++ b/ksysguard/gui/KSGAppletSettings.h @@ -0,0 +1,49 @@ +/* + This file is part of KSysGuard. + Copyright ( C ) 2002 Nadeem Hasan ( [email protected] ) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or ( at your option ) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KSG_APPLETSETTINGS_H +#define KSG_APPLETSETTINGS_H + +#include <kdialogbase.h> + +class TQSpinBox; + +class KSGAppletSettings : public KDialogBase +{ + public: + KSGAppletSettings( TQWidget *parent = 0, const char *name = 0 ); + ~KSGAppletSettings(); + + void setNumDisplay( int ); + int numDisplay() const; + + void setSizeRatio( int ); + int sizeRatio() const; + + void setUpdateInterval( int ); + int updateInterval() const; + + private: + TQSpinBox *mInterval; + TQSpinBox *mNumDisplay; + TQSpinBox *mSizeRatio; +}; + +#endif diff --git a/ksysguard/gui/KSysGuardApplet.cc b/ksysguard/gui/KSysGuardApplet.cc new file mode 100644 index 000000000..ae31d4a60 --- /dev/null +++ b/ksysguard/gui/KSysGuardApplet.cc @@ -0,0 +1,495 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger + <[email protected]>. Please do not commit any changes without consulting + me first. Thanks! + +*/ + +#include <tqcursor.h> +#include <tqdom.h> +#include <tqdragobject.h> +#include <tqfile.h> +#include <tqpushbutton.h> +#include <tqspinbox.h> +#include <tqtooltip.h> + +#include <kdebug.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <ksavefile.h> +#include <kstandarddirs.h> +#include <tdepopupmenu.h> + +#include <ksgrd/SensorClient.h> +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include "DancingBars.h" +#include "FancyPlotter.h" +#include "KSGAppletSettings.h" +#include "MultiMeter.h" + +#include "KSysGuardApplet.h" + +extern "C" +{ + KDE_EXPORT KPanelApplet* init( TQWidget *parent, const TQString& configFile ) + { + TDEGlobal::locale()->insertCatalogue( "ksysguard" ); + return new KSysGuardApplet( configFile, KPanelApplet::Normal, + KPanelApplet::Preferences, parent, + "ksysguardapplet" ); + } +} + +KSysGuardApplet::KSysGuardApplet( const TQString& configFile, Type type, + int actions, TQWidget *parent, + const char *name ) + : KPanelApplet( configFile, type, actions, parent, name) +{ + mSettingsDlg = 0; + + KSGRD::SensorMgr = new KSGRD::SensorManager(); + + KSGRD::Style = new KSGRD::StyleEngine(); + + mDockCount = 1; + mDockList = new TQWidget*[ mDockCount ]; + + mSizeRatio = 1.0; + addEmptyDisplay( mDockList, 0 ); + + updateInterval( 2 ); + + load(); + + setAcceptDrops( true ); +} + +KSysGuardApplet::~KSysGuardApplet() +{ + save(); + + delete [] mDockList; + mDockList = 0; + + delete mSettingsDlg; + mSettingsDlg = 0; + + delete KSGRD::Style; + delete KSGRD::SensorMgr; + KSGRD::SensorMgr = 0; +} + +int KSysGuardApplet::widthForHeight( int height ) const +{ + return ( (int) ( height * mSizeRatio + 0.5 ) * mDockCount ); +} + +int KSysGuardApplet::heightForWidth( int width ) const +{ + return ( (int) ( width * mSizeRatio + 0.5 ) * mDockCount ); +} + +void KSysGuardApplet::resizeEvent( TQResizeEvent* ) +{ + layout(); +} + +void KSysGuardApplet::preferences() +{ + if(mSettingsDlg) { + return; + } + mSettingsDlg = new KSGAppletSettings( this ); + + connect( mSettingsDlg, TQT_SIGNAL( applyClicked() ), TQT_SLOT( applySettings() ) ); + connect( mSettingsDlg, TQT_SIGNAL( okClicked() ), TQT_SLOT( applySettings() ) ); + connect( mSettingsDlg, TQT_SIGNAL( finished() ), TQT_SLOT( preferencesFinished() ) ); + + mSettingsDlg->setNumDisplay( mDockCount ); + mSettingsDlg->setSizeRatio( (int) ( mSizeRatio * 100.0 + 0.5 ) ); + mSettingsDlg->setUpdateInterval( updateInterval() ); + + mSettingsDlg->show(); +} +void KSysGuardApplet::preferencesFinished() +{ + mSettingsDlg->delayedDestruct(); + mSettingsDlg = 0; +} +void KSysGuardApplet::applySettings() +{ + updateInterval( mSettingsDlg->updateInterval() ); + mSizeRatio = mSettingsDlg->sizeRatio() / 100.0; + resizeDocks( mSettingsDlg->numDisplay() ); + + for ( uint i = 0; i < mDockCount; ++i ) + if ( !mDockList[ i ]->isA( TQFRAME_OBJECT_NAME_STRING ) ) + ((KSGRD::SensorDisplay*)mDockList[ i ])->setUpdateInterval( updateInterval() ); + + save(); +} + +void KSysGuardApplet::sensorDisplayModified( bool modified ) +{ + if ( modified ) + save(); +} + +void KSysGuardApplet::layout() +{ + if ( orientation() == Qt::Horizontal ) { + int h = height(); + int w = (int) ( h * mSizeRatio + 0.5 ); + for ( uint i = 0; i < mDockCount; ++i ) + if ( mDockList[ i ] ) + mDockList[ i ]->setGeometry( i * w, 0, w, h ); + } else { + int w = width(); + int h = (int) ( w * mSizeRatio + 0.5 ); + for ( uint i = 0; i < mDockCount; ++i ) + if ( mDockList[ i ] ) + mDockList[ i ]->setGeometry( 0, i * h, w, h ); + } +} + +int KSysGuardApplet::findDock( const TQPoint& point ) +{ + if ( orientation() == Qt::Horizontal ) + return ( point.x() / (int) ( height() * mSizeRatio + 0.5 ) ); + else + return ( point.y() / (int) ( width() * mSizeRatio + 0.5 ) ); +} + +void KSysGuardApplet::dragEnterEvent( TQDragEnterEvent *e ) +{ + e->accept( TQTextDrag::canDecode( e ) ); +} + +void KSysGuardApplet::dropEvent( TQDropEvent *e ) +{ + TQString dragObject; + + if ( TQTextDrag::decode( e, dragObject ) ) { + // The host name, sensor name and type are seperated by a ' '. + TQStringList parts = TQStringList::split( ' ', dragObject ); + + TQString hostName = parts[ 0 ]; + TQString sensorName = parts[ 1 ]; + TQString sensorType = parts[ 2 ]; + TQString sensorDescr = parts[ 3 ]; + + if ( hostName.isEmpty() || sensorName.isEmpty() || sensorType.isEmpty() ) + return; + + int dock = findDock( e->pos() ); + if ( mDockList[ dock ]->isA( TQFRAME_OBJECT_NAME_STRING ) ) { + if ( sensorType == "integer" || sensorType == "float" ) { + TDEPopupMenu popup; + TQWidget *wdg = 0; + + popup.insertTitle( i18n( "Select Display Type" ) ); + popup.insertItem( i18n( "&Signal Plotter" ), 1 ); + popup.insertItem( i18n( "&Multimeter" ), 2 ); + popup.insertItem( i18n( "&Dancing Bars" ), 3 ); + switch ( popup.exec( TQCursor::pos() ) ) { + case 1: + wdg = new FancyPlotter( this, "FancyPlotter", sensorDescr, + 100.0, 100.0, true ); + break; + + case 2: + wdg = new MultiMeter( this, "MultiMeter", sensorDescr, + 100.0, 100.0, true ); + break; + + case 3: + wdg = new DancingBars( this, "DancingBars", sensorDescr, + 100, 100, true ); + break; + } + + if ( wdg ) { + delete mDockList[ dock ]; + mDockList[ dock ] = wdg; + layout(); + + connect( wdg, TQT_SIGNAL( modified( bool ) ), + TQT_SLOT( sensorDisplayModified( bool ) ) ); + + mDockList[ dock ]->show(); + } + } else { + KMessageBox::sorry( this, + i18n( "The KSysGuard applet does not support displaying of " + "this type of sensor. Please choose another sensor." ) ); + + layout(); + } + } + + if ( !mDockList[ dock ]->isA( TQFRAME_OBJECT_NAME_STRING ) ) + ((KSGRD::SensorDisplay*)mDockList[ dock ])-> + addSensor( hostName, sensorName, sensorType, sensorDescr ); + } + + save(); +} + +void KSysGuardApplet::customEvent( TQCustomEvent *e ) +{ + if ( e->type() == TQEvent::User ) { + // SensorDisplays send out this event if they want to be removed. + removeDisplay( (KSGRD::SensorDisplay*)e->data() ); + save(); + } +} + +void KSysGuardApplet::removeDisplay( KSGRD::SensorDisplay *display ) +{ + for ( uint i = 0; i < mDockCount; ++i ) + if ( display == mDockList[i] ) { + delete mDockList[ i ]; + + addEmptyDisplay( mDockList, i ); + return; + } +} + +void KSysGuardApplet::resizeDocks( uint newDockCount ) +{ + /* This function alters the number of available docks. The number of + * docks can be increased or decreased. We try to preserve existing + * docks if possible. */ + + if ( newDockCount == mDockCount ) { + emit updateLayout(); + return; + } + + // Create and initialize new dock array. + TQWidget** tmp = new TQWidget*[ newDockCount ]; + + uint i; + for ( i = 0; ( i < newDockCount ) && ( i < mDockCount ); ++i ) + tmp[ i ] = mDockList[ i ]; + + for ( i = newDockCount; i < mDockCount; ++i ) + if ( mDockList[ i ] ) + delete mDockList[ i ]; + + for ( i = mDockCount; i < newDockCount; ++i ) + addEmptyDisplay( tmp, i ); + + delete [] mDockList; + + mDockList = tmp; + mDockCount = newDockCount; + + emit updateLayout(); +} + +bool KSysGuardApplet::load() +{ + TDEStandardDirs* kstd = TDEGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + TQString fileName = kstd->findResource( "data", "KSysGuardApplet.xml" ); + + TQFile file( fileName ); + if ( !file.open( IO_ReadOnly ) ) { + KMessageBox::sorry( this, i18n( "Cannot open the file %1." ).arg( fileName ) ); + return false; + } + + // Parse the XML file. + TQDomDocument doc; + + // Read in file and check for a valid XML header. + if ( !doc.setContent( &file ) ) { + KMessageBox::sorry( this, i18n( "The file %1 does not contain valid XML." ) + .arg( fileName ) ); + return false; + } + + // Check for proper document type. + if ( doc.doctype().name() != "KSysGuardApplet" ) { + KMessageBox::sorry( this, i18n( "The file %1 does not contain a valid applet " + "definition, which must have a document type 'KSysGuardApplet'." ) + .arg( fileName ) ); + return false; + } + + TQDomElement element = doc.documentElement(); + bool ok; + uint count = element.attribute( "dockCnt" ).toUInt( &ok ); + if ( !ok ) + count = 1; + + mSizeRatio = element.attribute( "sizeRatio" ).toDouble( &ok ); + if ( !ok ) + mSizeRatio = 1.0; + + updateInterval( element.attribute( "interval" ).toUInt( &ok ) ); + if ( !ok ) + updateInterval( 2 ); + + resizeDocks( count ); + + /* Load lists of hosts that are needed for the work sheet and try + * to establish a connection. */ + TQDomNodeList dnList = element.elementsByTagName( "host" ); + uint i; + for ( i = 0; i < dnList.count(); ++i ) { + TQDomElement element = dnList.item( i ).toElement(); + int port = element.attribute( "port" ).toInt( &ok ); + if ( !ok ) + port = -1; + + KSGRD::SensorMgr->engage( element.attribute( "name" ), + element.attribute( "shell" ), + element.attribute( "command" ), port ); + } + //if no hosts are specified, at least connect to localhost + if(dnList.count() == 0) + KSGRD::SensorMgr->engage( "localhost", "", "ksysguardd", -1); + + // Load the displays and place them into the work sheet. + dnList = element.elementsByTagName( "display" ); + for ( i = 0; i < dnList.count(); ++i ) { + TQDomElement element = dnList.item( i ).toElement(); + uint dock = element.attribute( "dock" ).toUInt(); + if ( i >= mDockCount ) { + kdDebug (1215) << "Dock number " << i << " out of range " + << mDockCount << endl; + return false; + } + + TQString classType = element.attribute( "class" ); + KSGRD::SensorDisplay* newDisplay; + if ( classType == "FancyPlotter" ) + newDisplay = new FancyPlotter( this, "FancyPlotter", "Dummy", 100.0, 100.0, true /*no frame*/, true /*run ksysguard menu*/); + else if ( classType == "MultiMeter" ) + newDisplay = new MultiMeter( this, "MultiMeter", "Dummy", 100.0, 100.0, true /*no frame*/, true /*run ksysguard menu*/ ); + else if ( classType == "DancingBars" ) + newDisplay = new DancingBars( this, "DancingBars", "Dummy", 100, 100, true /*no frame*/, true /*run ksysguard menu*/); + else { + KMessageBox::sorry( this, i18n( "The KSysGuard applet does not support displaying of " + "this type of sensor. Please choose another sensor." ) ); + return false; + } + + newDisplay->setUpdateInterval( updateInterval() ); + + // load display specific settings + if ( !newDisplay->restoreSettings( element ) ) + return false; + + delete mDockList[ dock ]; + mDockList[ dock ] = newDisplay; + + connect( newDisplay, TQT_SIGNAL( modified( bool ) ), + TQT_SLOT( sensorDisplayModified( bool ) ) ); + } + + return true; +} + +bool KSysGuardApplet::save() +{ + // Parse the XML file. + TQDomDocument doc( "KSysGuardApplet" ); + doc.appendChild( doc.createProcessingInstruction( + "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); + + // save work sheet information + TQDomElement ws = doc.createElement( "WorkSheet" ); + doc.appendChild( ws ); + ws.setAttribute( "dockCnt", mDockCount ); + ws.setAttribute( "sizeRatio", mSizeRatio ); + ws.setAttribute( "interval", updateInterval() ); + + TQStringList hosts; + uint i; + for ( i = 0; i < mDockCount; ++i ) + if ( !mDockList[ i ]->isA( TQFRAME_OBJECT_NAME_STRING ) ) + ((KSGRD::SensorDisplay*)mDockList[ i ])->hosts( hosts ); + + // save host information (name, shell, etc.) + TQStringList::Iterator it; + for ( it = hosts.begin(); it != hosts.end(); ++it ) { + TQString shell, command; + int port; + + if ( KSGRD::SensorMgr->hostInfo( *it, shell, command, port ) ) { + TQDomElement host = doc.createElement( "host" ); + ws.appendChild( host ); + host.setAttribute( "name", *it ); + host.setAttribute( "shell", shell ); + host.setAttribute( "command", command ); + host.setAttribute( "port", port ); + } + } + + for ( i = 0; i < mDockCount; ++i ) + if ( !mDockList[ i ]->isA( TQFRAME_OBJECT_NAME_STRING ) ) { + TQDomElement element = doc.createElement( "display" ); + ws.appendChild( element ); + element.setAttribute( "dock", i ); + element.setAttribute( "class", mDockList[ i ]->className() ); + + ((KSGRD::SensorDisplay*)mDockList[ i ])->saveSettings( doc, element ); + } + + TDEStandardDirs* kstd = TDEGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + TQString fileName = kstd->saveLocation( "data", "ksysguard" ); + fileName += "/KSysGuardApplet.xml"; + + KSaveFile file( fileName, 0644 ); + + if ( file.status() == 0 ) + { + file.textStream()->setEncoding( TQTextStream::UnicodeUTF8 ); + *(file.textStream()) << doc; + file.close(); + } + else + { + KMessageBox::sorry( this, i18n( "Cannot save file %1" ).arg( fileName ) ); + return false; + } + + return true; +} + +void KSysGuardApplet::addEmptyDisplay( TQWidget **dock, uint pos ) +{ + dock[ pos ] = new TQFrame( this ); + ((TQFrame*)dock[ pos ])->setFrameStyle( TQFrame::WinPanel | TQFrame::Sunken ); + TQToolTip::add( dock[ pos ], + i18n( "Drag sensors from the TDE System Guard into this cell." ) ); + + layout(); + if ( isVisible() ) + dock[ pos ]->show(); +} + +#include "KSysGuardApplet.moc" diff --git a/ksysguard/gui/KSysGuardApplet.h b/ksysguard/gui/KSysGuardApplet.h new file mode 100644 index 000000000..43027b05c --- /dev/null +++ b/ksysguard/gui/KSysGuardApplet.h @@ -0,0 +1,85 @@ +/* + KKSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger + <[email protected]>. Please do not commit any changes without consulting + me first. Thanks! + +*/ + +#ifndef KSG_KSYSGUARDAPPLET_H +#define KSG_KSYSGUARDAPPLET_H + +#include <kpanelapplet.h> + +namespace KSGRD +{ +class SensorBoard; +class SensorDisplay; +} + +class TQDragEnterEvent; +class TQDropEvent; +class TQPoint; +class KSGAppletSettings; + +class KSysGuardApplet : public KPanelApplet, public KSGRD::SensorBoard +{ + Q_OBJECT + + public: + KSysGuardApplet( const TQString& configFile, Type type = Normal, + int actions = 0, TQWidget *parent = 0, + const char *name = 0 ); + virtual ~KSysGuardApplet(); + + virtual int heightForWidth( int width ) const; + virtual int widthForHeight( int height ) const; + + virtual void preferences(); + + protected: + void resizeEvent( TQResizeEvent* ); + void dragEnterEvent( TQDragEnterEvent* ); + void dropEvent( TQDropEvent* ); + void customEvent( TQCustomEvent* ); + + + private slots: + void applySettings(); + void sensorDisplayModified( bool ); + void preferencesFinished(); + + private: + void layout(); + void resizeDocks( uint newDockCount ); + void addEmptyDisplay( TQWidget **dock, uint pos ); + + bool load(); + bool save(); + + int findDock( const TQPoint& ); + void removeDisplay( KSGRD::SensorDisplay* ); + + double mSizeRatio; + uint mDockCount; + KSGAppletSettings* mSettingsDlg; + TQWidget** mDockList; +}; + +#endif diff --git a/ksysguard/gui/KSysGuardApplet.xml b/ksysguard/gui/KSysGuardApplet.xml new file mode 100644 index 000000000..2f115f61e --- /dev/null +++ b/ksysguard/gui/KSysGuardApplet.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE KSysGuardApplet> +<WorkSheet sizeRatio="1.2" dockCnt="2" interval="4" > + <host port="-1" shell="" name="localhost" command="ksysguardd" /> + <display topBar="1" vColor="326429" title="CPU" dock="0" bColor="3223601" graphStyle="0" class="FancyPlotter" unit="" hScale="1" showUnit="0" hLines="1" hCount="2" vLines="1" autoRange="1" min="0" max="0" hColor="14606046" globalUpdate="1" pause="0" fontSize="8" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="cpu/user" hostName="localhost" color="1608191" sensorType="integer" /> + <beam sensorName="cpu/sys" hostName="localhost" color="16743688" sensorType="integer" /> + <beam sensorName="cpu/nice" hostName="localhost" color="16771600" sensorType="integer" /> + </display> + <display topBar="1" vColor="4605510" title="Mem" dock="1" bColor="3223601" graphStyle="0" class="FancyPlotter" unit="" hScale="5" showUnit="0" hLines="1" hCount="2" vLines="0" autoRange="1" min="0" max="0" hColor="14606046" globalUpdate="1" pause="0" fontSize="8" labels="0" vScroll="1" vDistance="30" > + <beam sensorName="mem/physical/application" hostName="localhost" color="1608191" sensorType="integer" /> + <beam sensorName="mem/physical/buf" hostName="localhost" color="16743688" sensorType="integer" /> + <beam sensorName="mem/physical/cached" hostName="localhost" color="16771600" sensorType="integer" /> + </display> +</WorkSheet> diff --git a/ksysguard/gui/Makefile.am b/ksysguard/gui/Makefile.am new file mode 100644 index 000000000..69066d230 --- /dev/null +++ b/ksysguard/gui/Makefile.am @@ -0,0 +1,63 @@ + +kdemimedir = $(kde_mimedir)/application +kdemime_DATA = x-ksysguard.desktop + +rcdir = $(kde_datadir)/ksysguard +rc_DATA = ksysguardui.rc + +xdg_apps_DATA = ksysguard.desktop + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = ksysguardapplet.desktop + +# claim, which subdirectories you want to install +SUBDIRS = ksgrd SensorDisplayLib + +# set the include path for X, qt and KDE +INCLUDES = -I$(srcdir)/ksgrd -I$(srcdir)/SensorDisplayLib -I$(top_builddir)/ksysguard/gui/SensorDisplayLib $(all_includes) + +####### This part is very ksysguard specific +# you can add here more. This one gets installed +bin_PROGRAMS = ksysguard kpm + +# Which sources should be compiled for ksysguard. +ksysguard_SOURCES = \ + SensorBrowser.cc \ + WorkSheet.cc \ + WorkSheetSettings.cc \ + Workspace.cc \ + ksysguard.cc ksysguard.skel + +ksysguard_LDADD = \ + ksgrd/libksgrd.la \ + SensorDisplayLib/libsensordisplays.la \ + $(LIB_TDEUI) $(LIB_TDEIO) $(LIB_TDEDNSSD) +ksysguard_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor + +kpm_SOURCES = kpm.c + +appdatadir = $(kde_datadir)/ksysguard +appdata_DATA = ProcessTable.sgrd SystemLoad.sgrd KSysGuardApplet.xml + +# This stuff is now for the kicker applet +kde_module_LTLIBRARIES = sysguard_panelapplet.la + +sysguard_panelapplet_la_SOURCES = \ + KSysGuardApplet.cc \ + KSGAppletSettings.cc + +sysguard_panelapplet_la_LIBADD = \ + ksgrd/libksgrd.la \ + SensorDisplayLib/libsensordisplays.la \ + $(LIB_TDEUI) $(LIB_TDEIO) +sysguard_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) + +EXTRA_DIST = $(lnk_DATA) + +# just to make sure, automake makes them +METASOURCES = AUTO + +messages: rc.cpp + $(EXTRACTRC) `find . -name "*.ui"` >> rc.cpp + extractattr --attr=display,title SystemLoad.sgrd KSysGuardApplet.xml >> rc.cpp + $(XGETTEXT) `find . -name "*.cpp" -o -name "*.cc"` -o $(podir)/ksysguard.pot diff --git a/ksysguard/gui/ProcessTable.sgrd b/ksysguard/gui/ProcessTable.sgrd new file mode 100644 index 000000000..2717a2b9d --- /dev/null +++ b/ksysguard/gui/ProcessTable.sgrd @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE KSysGuardWorkSheet> +<WorkSheet rows="1" interval="2" columns="1" > + <host port="-1" shell="" name="localhost" command="ksysguardd" /> + <display title="" class="ProcessController" row="0" unit="" sensorName="ps" column="0" filter="0" showUnit="0" sortColumn="0" hostName="localhost" globalUpdate="1" incrOrder="1" tree="0" sensorType="table" pause="0" > + <column currentWidth="127" savedWidth="126" index="0" /> + <column currentWidth="42" savedWidth="46" index="1" /> + <column currentWidth="0" savedWidth="42" index="2" /> + <column currentWidth="0" savedWidth="33" index="3" /> + <column currentWidth="0" savedWidth="42" index="4" /> + <column currentWidth="0" savedWidth="66" index="5" /> + <column currentWidth="52" savedWidth="45" index="6" /> + <column currentWidth="72" savedWidth="48" index="7" /> + <column currentWidth="38" savedWidth="36" index="8" /> + <column currentWidth="57" savedWidth="65" index="9" /> + <column currentWidth="52" savedWidth="30" index="10" /> + <column currentWidth="56" savedWidth="150" index="11" /> + <column currentWidth="402" savedWidth="150" index="12" /> + </display> +</WorkSheet> diff --git a/ksysguard/gui/SensorBrowser.cc b/ksysguard/gui/SensorBrowser.cc new file mode 100644 index 000000000..801091d98 --- /dev/null +++ b/ksysguard/gui/SensorBrowser.cc @@ -0,0 +1,412 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#include <tqdragobject.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> + +#include <kdebug.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <ksgrd/SensorManager.h> + +#include "SensorBrowser.h" + +class HostItem : public TQListViewItem +{ + public: + HostItem( SensorBrowser *parent, const TQString &text, int id, + KSGRD::SensorAgent *host) + : TQListViewItem( parent, text ), mInited( false ), mId( id ), + mHost( host ), mParent( parent ) + { + setExpandable( true ); + } + + void setOpen( bool open ) + { + if ( open && !mInited ) { + mInited = true; + // request sensor list from host + mHost->sendRequest( "monitors", mParent, mId ); + } + + TQListViewItem::setOpen( open ); + } + + private: + bool mInited; + int mId; + KSGRD::SensorAgent* mHost; + SensorBrowser* mParent; +}; + +SensorBrowser::SensorBrowser( TQWidget* parent, KSGRD::SensorManager* sm, + const char* name) + : TDEListView( parent, name ), mSensorManager( sm ) +{ + mHostInfoList.setAutoDelete(true); + + connect( mSensorManager, TQT_SIGNAL( update() ), TQT_SLOT( update() ) ); + connect( this, TQT_SIGNAL( clicked( TQListViewItem* ) ), + TQT_SLOT( newItemSelected( TQListViewItem* ) ) ); + connect( this, TQT_SIGNAL( returnPressed( TQListViewItem* ) ), + TQT_SLOT( newItemSelected( TQListViewItem* ) ) ); + + addColumn( i18n( "Sensor Browser" ) ); + addColumn( i18n( "Sensor Type" ) ); + setFullWidth( true ); + + TQToolTip::add( this, i18n( "Drag sensors to empty cells of a worksheet " + "or the panel applet." ) ); + setRootIsDecorated( true ); + + // The sensor browser can be completely hidden. + setMinimumWidth( 1 ); + + TQWhatsThis::add( this, i18n( "The sensor browser lists the connected hosts and the sensors " + "that they provide. Click and drag sensors into drop zones " + "of a worksheet or the panel applet. A display will appear " + "that visualizes the " + "values provided by the sensor. Some sensor displays can " + "display values of multiple sensors. Simply drag other " + "sensors on to the display to add more sensors." ) ); +} + +SensorBrowser::~SensorBrowser() +{ +} + +void SensorBrowser::disconnect() +{ + TQPtrListIterator<HostInfo> it( mHostInfoList ); + + for ( ; it.current(); ++it ) + if ( (*it)->listViewItem()->isSelected() ) { + kdDebug(1215) << "Disconnecting " << (*it)->hostName() << endl; + KSGRD::SensorMgr->requestDisengage( (*it)->sensorAgent() ); + } +} + +void SensorBrowser::hostReconfigured( const TQString& ) +{ + // TODO: not yet implemented. +} + +void SensorBrowser::update() +{ + static int id = 0; + + KSGRD::SensorManagerIterator it( mSensorManager ); + + mHostInfoList.clear(); + clear(); + + KSGRD::SensorAgent* host; + for ( int i = 0 ; ( host = it.current() ); ++it, ++i ) { + TQString hostName = mSensorManager->hostName( host ); + HostItem* lvi = new HostItem( this, hostName, id, host ); + + TQPixmap pix = TDEGlobal::iconLoader()->loadIcon( "computer", TDEIcon::Desktop, TDEIcon::SizeSmall ); + lvi->setPixmap( 0, pix ); + + HostInfo* hostInfo = new HostInfo( id, host, hostName, lvi ); + mHostInfoList.append( hostInfo ); + ++id; + } + + setMouseTracking( false ); +} + +void SensorBrowser::newItemSelected( TQListViewItem *item ) +{ + static bool showAnnoyingPopup = true; + if ( item && item->pixmap( 0 ) && showAnnoyingPopup) + { + showAnnoyingPopup = false; + KMessageBox::information( this, i18n( "Drag sensors to empty fields in a worksheet." ), + TQString::null, "ShowSBUseInfo" ); + } +} + +void SensorBrowser::answerReceived( int id, const TQString &answer ) +{ + /* An answer has the following format: + + cpu/idle integer + cpu/sys integer + cpu/nice integer + cpu/user integer + ps table + */ + + TQPtrListIterator<HostInfo> it( mHostInfoList ); + + /* Check if id is still valid. It can get obsolete by rapid calls + * of update() or when the sensor died. */ + for ( ; it.current(); ++it ) + if ( (*it)->id() == id ) + break; + + if ( !it.current() ) + return; + + KSGRD::SensorTokenizer lines( answer, '\n' ); + + for ( uint i = 0; i < lines.count(); ++i ) { + if ( lines[ i ].isEmpty() ) + break; + + KSGRD::SensorTokenizer words( lines[ i ], '\t' ); + TQString sensorName = words[ 0 ]; + TQString sensorType = words[ 1 ]; + + /* Calling update() a rapid sequence will create pending + * requests that do not get erased by calling + * clear(). Subsequent updates will receive the old pending + * answers so we need to make sure that we register each + * sensor only once. */ + if ( (*it)->isRegistered( sensorName ) ) + return; + + /* The sensor browser can display sensors in a hierachical order. + * Sensors can be grouped into nodes by seperating the hierachical + * nodes through slashes in the sensor name. E. g. cpu/user is + * the sensor user in the cpu node. There is no limit for the + * depth of nodes. */ + KSGRD::SensorTokenizer absolutePath( sensorName, '/' ); + + TQListViewItem* parent = (*it)->listViewItem(); + for ( uint j = 0; j < absolutePath.count(); ++j ) { + // Localize the sensor name part by part. + TQString name = KSGRD::SensorMgr->translateSensorPath( absolutePath[ j ] ); + + bool found = false; + TQListViewItem* sibling = parent->firstChild(); + while ( sibling && !found ) { + if (sibling->text( 0 ) == name ) { + // The node or sensor is already known. + found = true; + } else + sibling = sibling->nextSibling(); + } + if ( !found ) { + TQListViewItem* lvi = new TQListViewItem( parent, name ); + if ( j == absolutePath.count() - 1 ) { + TQPixmap pix = TDEGlobal::iconLoader()->loadIcon( "ksysguardd", TDEIcon::Desktop, + TDEIcon::SizeSmall ); + lvi->setPixmap( 0, pix ); + lvi->setText( 1, KSGRD::SensorMgr->translateSensorType( sensorType ) ); + + // add sensor info to internal data structure + (*it)->addSensor( lvi, sensorName, name, sensorType ); + } else + parent = lvi; + + // The child indicator might need to be updated. + repaintItem( parent ); + } else + parent = sibling; + } + } + + repaintItem( (*it)->listViewItem() ); +} + +void SensorBrowser::viewportMouseMoveEvent( TQMouseEvent *e ) +{ + /* setMouseTracking(false) seems to be broken. With current Qt + * mouse tracking cannot be turned off. So we have to check each event + * whether the LMB is really pressed. */ + + if ( !( e->state() & Qt::LeftButton ) ) + return; + + TQListViewItem* item = itemAt( e->pos() ); + if ( !item ) // no item under cursor + return; + + // Make sure that a sensor and not a node or hostname has been picked. + TQPtrListIterator<HostInfo> it( mHostInfoList ); + for ( ; it.current() && !(*it)->isRegistered( item ); ++it ); + if ( !it.current() ) + return; + + // Create text drag object as + // "<hostname> <sensorname> <sensortype> <sensordescription>". + // Only the description may contain blanks. + mDragText = (*it)->hostName() + " " + + (*it)->sensorName( item ) + " " + + (*it)->sensorType( item ) + " " + + (*it)->sensorDescription( item ); + + TQDragObject* dragObject = new TQTextDrag( mDragText, this ); + dragObject->dragCopy(); +} + +TQStringList SensorBrowser::listHosts() +{ + TQStringList hostList; + + TQPtrListIterator<HostInfo> it( mHostInfoList ); + for ( ; it.current(); ++it ) + hostList.append( (*it)->hostName() ); + + return hostList; +} + +TQStringList SensorBrowser::listSensors( const TQString &hostName ) +{ + TQPtrListIterator<HostInfo> it( mHostInfoList ); + for ( ; it.current(); ++it ) { + if ( (*it)->hostName() == hostName ) { + return (*it)->allSensorNames(); + } + } + + return TQStringList(); +} + +/** + Helper classes + */ +SensorInfo::SensorInfo( TQListViewItem *lvi, const TQString &name, + const TQString &desc, const TQString &type ) + : mLvi( lvi ), mName( name ), mDesc( desc ), mType( type ) +{ +} + +TQListViewItem* SensorInfo::listViewItem() const +{ + return mLvi; +} + +const TQString& SensorInfo::name() const +{ + return mName; +} + +const TQString& SensorInfo::type() const +{ + return mType; +} + +const TQString& SensorInfo::description() const +{ + return mDesc; +} + +HostInfo::HostInfo( int id, const KSGRD::SensorAgent *agent, + const TQString &name, TQListViewItem *lvi ) + : mId( id ), mSensorAgent( agent ), mHostName( name ), mLvi( lvi ) +{ + mSensorList.setAutoDelete( true ); +} + +int HostInfo::id() const +{ + return ( mId ); +} + +const KSGRD::SensorAgent* HostInfo::sensorAgent() const +{ + return mSensorAgent; +} + +const TQString& HostInfo::hostName() const +{ + return mHostName; +} + +TQListViewItem* HostInfo::listViewItem() const +{ + return mLvi; +} + +const TQString& HostInfo::sensorName( const TQListViewItem *lvi ) const +{ + TQPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current() && (*it)->listViewItem() != lvi; ++it ); + + Q_ASSERT( it.current() ); + return ( (*it)->name() ); +} + +TQStringList HostInfo::allSensorNames() const +{ + TQStringList list; + + TQPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current(); ++it ) + list.append( it.current()->name() ); + + return list; +} + +const TQString& HostInfo::sensorType( const TQListViewItem *lvi ) const +{ + TQPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current() && (*it)->listViewItem() != lvi; ++it ); + + Q_ASSERT( it.current() ); + return ( (*it)->type() ); +} + +const TQString& HostInfo::sensorDescription( const TQListViewItem *lvi ) const +{ + TQPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current() && (*it)->listViewItem() != lvi; ++it ); + + Q_ASSERT( it.current() ); + return ( (*it)->description() ); +} + +void HostInfo::addSensor( TQListViewItem *lvi, const TQString& name, + const TQString& desc, const TQString& type ) +{ + SensorInfo* info = new SensorInfo( lvi, name, desc, type ); + mSensorList.append( info ); +} + +bool HostInfo::isRegistered( const TQString& name ) const +{ + TQPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current(); ++it ) + if ( (*it)->name() == name ) + return true; + + return false; +} + +bool HostInfo::isRegistered( TQListViewItem *lvi ) const +{ + TQPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current(); ++it ) + if ( (*it)->listViewItem() == lvi ) + return true; + + return false; +} + +#include "SensorBrowser.moc" diff --git a/ksysguard/gui/SensorBrowser.h b/ksysguard/gui/SensorBrowser.h new file mode 100644 index 000000000..aec4f343d --- /dev/null +++ b/ksysguard/gui/SensorBrowser.h @@ -0,0 +1,193 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SENSORBROWSER_H +#define KSG_SENSORBROWSER_H + +#include <tqdict.h> + +#include <tdelistview.h> +#include <ksgrd/SensorClient.h> + +class TQMouseEvent; + +namespace KSGRD { +class SensorManager; +class SensorAgent; +} + +class SensorInfo; +class HostInfo; + +/** + * The SensorBrowser is the graphical front-end of the SensorManager. It + * displays the currently available hosts and their sensors. + */ +class SensorBrowser : public TDEListView, public KSGRD::SensorClient +{ + Q_OBJECT + + public: + SensorBrowser( TQWidget* parent, KSGRD::SensorManager* sm, const char* name = 0 ); + ~SensorBrowser(); + + TQStringList listHosts(); + TQStringList listSensors( const TQString &hostName ); + + public slots: + void disconnect(); + void hostReconfigured( const TQString &hostName ); + void update(); + void newItemSelected( TQListViewItem *item ); + + protected: + virtual void viewportMouseMoveEvent( TQMouseEvent* ); + + private: + void answerReceived( int id, const TQString& ); + + KSGRD::SensorManager* mSensorManager; + + TQPtrList<HostInfo> mHostInfoList; + TQString mDragText; + +}; + +/** + Helper classes + */ +class SensorInfo +{ + public: + SensorInfo( TQListViewItem *lvi, const TQString &name, const TQString &desc, + const TQString &type ); + ~SensorInfo() {} + + /** + Returns a pointer to the list view item of the sensor. + */ + TQListViewItem* listViewItem() const; + + /** + Returns the name of the sensor. + */ + const TQString& name() const; + + /** + Returns the description of the sensor. + */ + const TQString& description() const; + + /** + Returns the type of the sensor. + */ + const TQString& type() const; + + private: + TQListViewItem* mLvi; + TQString mName; + TQString mDesc; + TQString mType; +}; + +class HostInfo +{ + public: + HostInfo( int id, const KSGRD::SensorAgent *agent, const TQString &name, + TQListViewItem *lvi ); + ~HostInfo() { } + + /** + Returns the unique id of the host. + */ + int id() const; + + /** + Returns a pointer to the sensor agent of the host. + */ + const KSGRD::SensorAgent* sensorAgent() const; + + /** + Returns the name of the host. + */ + const TQString& hostName() const; + + /** + Returns the a pointer to the list view item of the host. + */ + TQListViewItem* listViewItem() const; + + /** + Returns the sensor name of a special list view item. + */ + const TQString& sensorName( const TQListViewItem *lvi ) const; + + /** + Returns all sensor names of the host. + */ + TQStringList allSensorNames() const; + + /** + Returns the type of a special list view item. + */ + const TQString& sensorType( const TQListViewItem *lvi ) const; + + /** + Returns the description of a special list view item. + */ + const TQString& sensorDescription( const TQListViewItem *lvi ) const; + + /** + Adds a new Sensor to the host. + + @param lvi The list view item. + @param name The sensor name. + @param desc A description. + @param type The type of the sensor. + */ + void addSensor( TQListViewItem *lvi, const TQString& name, + const TQString& desc, const TQString& type ); + + /** + Returns whether the sensor with @ref name + is registered at the host. + */ + bool isRegistered( const TQString& name ) const; + + /** + Returns whether the sensor with @ref lvi + is registered at the host. + */ + bool isRegistered( TQListViewItem *lvi ) const; + + private: + int mId; + + const KSGRD::SensorAgent* mSensorAgent; + const TQString mHostName; + TQListViewItem* mLvi; + + TQPtrList<SensorInfo> mSensorList; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/BarGraph.cc b/ksysguard/gui/SensorDisplayLib/BarGraph.cc new file mode 100644 index 000000000..8d2b5e302 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/BarGraph.cc @@ -0,0 +1,177 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <assert.h> +#include <string.h> + +#include <tqpainter.h> + +#include <kdebug.h> +#include <kiconloader.h> + +#include <ksgrd/StyleEngine.h> + +#include "BarGraph.h" + +BarGraph::BarGraph( TQWidget *parent, const char *name ) + : TQWidget( 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( TQSizePolicy( TQSizePolicy::Expanding, + TQSizePolicy::Expanding, false ) ); +} + +BarGraph::~BarGraph() +{ +} + +bool BarGraph::addBar( const TQString &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 TQMemArray<double> &newSamples ) +{ + samples = newSamples; + update(); +} + +void BarGraph::changeRange( double min, double max ) +{ + minValue = min; + maxValue = max; +} + +void BarGraph::paintEvent( TQPaintEvent* ) +{ + int w = width(); + int h = height(); + + TQPixmap pm( w, h ); + TQPainter p; + p.begin( &pm, this ); + p.setFont( TQFont( p.font().family(), fontSize ) ); + TQFontMetrics 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( TQColor( 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, + TQString( "%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..1a1262594 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/BarGraph.h @@ -0,0 +1,94 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_BARGRAPH_H +#define KSG_BARGRAPH_H + +#include <tqmemarray.h> +#include <tqptrvector.h> +#include <tqwidget.h> + +class BarGraph : public TQWidget +{ + Q_OBJECT + + friend class DancingBars; + + public: + BarGraph( TQWidget *parent, const char *name = 0 ); + ~BarGraph(); + + bool addBar( const TQString &footer ); + bool removeBar( uint idx ); + + void updateSamples( const TQMemArray<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( TQPaintEvent* ); + + private: + double minValue; + double maxValue; + double lowerLimit; + double lowerLimitActive; + double upperLimit; + bool upperLimitActive; + bool autoRange; + TQMemArray<double> samples; + TQStringList footers; + uint bars; + TQColor normalColor; + TQColor alarmColor; + TQColor backgroundColor; + int fontSize; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/CMakeLists.txt b/ksysguard/gui/SensorDisplayLib/CMakeLists.txt new file mode 100644 index 000000000..0fe416a0b --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/CMakeLists.txt @@ -0,0 +1,40 @@ +################################################# +# +# (C) 2010-2011 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/ksysguard/gui/ksgrd + ${CMAKE_SOURCE_DIR}/ksysguard/gui + ${TDE_INCLUDE_DIR} + ${TQT_INCLUDE_DIRS} +) + +link_directories( + ${TQT_LIBRARY_DIRS} +) + + +##### sensordisplays (static) ################### + +tde_add_library( sensordisplays STATIC_PIC AUTOMOC + 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 + LINK ksgrd-shared tdeio-shared +) diff --git a/ksysguard/gui/SensorDisplayLib/DancingBars.cc b/ksysguard/gui/SensorDisplayLib/DancingBars.cc new file mode 100644 index 000000000..5b09addc0 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DancingBars.cc @@ -0,0 +1,353 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000, 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <tqcheckbox.h> +#include <tqdom.h> +#include <tqlineedit.h> +#include <tqlistview.h> +#include <tqpushbutton.h> +#include <tqspinbox.h> +#include <tqtooltip.h> + +#include <kdebug.h> +#include <tdelocale.h> +#include <knumvalidator.h> +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include "BarGraph.h" +#include "DancingBarsSettings.h" + +#include "DancingBars.h" + +DancingBars::DancingBars( TQWidget *parent, const char *name, const TQString &title, + int, int, bool noFrame_, bool isApplet ) + : KSGRD::SensorDisplay( parent, name, title, noFrame_, isApplet ) +{ + mBars = 0; + mFlags = TQBitArray(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 ); + + TQValueList< TQStringList > list; + for ( uint i = mBars - 1; i < mBars; i-- ) { + TQStringList 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, TQT_SIGNAL( applyClicked() ), TQT_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(); + + TQValueList< TQStringList > list = mSettingsDialog->sensors(); + TQValueList< TQStringList >::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 TQString &hostName, const TQString &name, + const TQString &type, const TQString &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 ); + + TQString tooltip; + for ( uint i = 0; i < mBars; ++i ) { + tooltip += TQString( "%1%2:%3" ).arg( i != 0 ? "\n" : "" ) + .arg( sensors().at( i )->hostName() ) + .arg( sensors().at( i )->name() ); + } + TQToolTip::remove( mPlotter ); + TQToolTip::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 ); + + TQString tooltip; + for ( uint i = 0; i < mBars; ++i ) { + tooltip += TQString( "%1%2:%3" ).arg( i != 0 ? "\n" : "" ) + .arg( sensors().at( i )->hostName() ) + .arg( sensors().at( i )->name() ); + } + TQToolTip::remove( mPlotter ); + TQToolTip::add( mPlotter, tooltip ); + + return true; +} + +void DancingBars::updateSamples( const TQMemArray<double> &samples ) +{ + mPlotter->updateSamples( samples ); +} + +void DancingBars::resizeEvent( TQResizeEvent* ) +{ + if ( noFrame() ) + mPlotter->setGeometry( 0, 0, width(), height() ); + else + frame()->setGeometry( 0, 0, width(), height() ); +} + +TQSize DancingBars::sizeHint() +{ + if ( noFrame() ) + return ( mPlotter->sizeHint() ); + else + return ( frame()->sizeHint() ); +} + +void DancingBars::answerReceived( int id, const TQString &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( TQDomElement &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", TQString( "%1" ).arg( + KSGRD::Style->fontSize() ) ).toInt(); + + TQDomNodeList dnList = element.elementsByTagName( "beam" ); + for ( uint i = 0; i < dnList.count(); ++i ) { + TQDomElement 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( TQDomDocument &doc, TQDomElement &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 ) { + TQDomElement 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..3ccc03f86 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DancingBars.h @@ -0,0 +1,90 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_DANCINGBARS_H +#define KSG_DANCINGBARS_H + +#include <SensorDisplay.h> +#include <tqbitarray.h> + +class KIntNumInput; + +class TQGroupBox; +class TQLineEdit; +class TQListViewItem; + +class BarGraph; +class DancingBarsSettings; + +class DancingBars : public KSGRD::SensorDisplay +{ + Q_OBJECT + + public: + DancingBars( TQWidget *parent = 0, const char *name = 0, + const TQString &title = TQString::null, int min = 0, + int max = 100, bool noFrame = false, bool isApplet = false ); + virtual ~DancingBars(); + + void configureSettings(); + + bool addSensor( const TQString &hostName, const TQString &name, + const TQString &type, const TQString &title ); + bool removeSensor( uint pos ); + + void updateSamples( const TQMemArray<double> &samples ); + + virtual TQSize sizeHint(); + + virtual void answerReceived( int id, const TQString &answer ); + + bool restoreSettings( TQDomElement& ); + bool saveSettings( TQDomDocument&, TQDomElement&, bool save = true ); + + virtual bool hasSettingsDialog() const; + + public slots: + void applySettings(); + virtual void applyStyle(); + + protected: + virtual void resizeEvent( TQResizeEvent* ); + + 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. + */ + TQMemArray<double> mSampleBuffer; + TQBitArray mFlags; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.cc b/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.cc new file mode 100644 index 000000000..ee03f9e94 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.cc @@ -0,0 +1,398 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <tdeaccelmanager.h> +#include <kcolorbutton.h> +#include <klineedit.h> +#include <kinputdialog.h> +#include <tdelistview.h> +#include <tdelocale.h> +#include <knuminput.h> + +#include <tqcheckbox.h> +#include <tqframe.h> +#include <tqgroupbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqwhatsthis.h> + +#include "DancingBarsSettings.h" + +DancingBarsSettings::DancingBarsSettings( TQWidget* parent, const char* name ) + : KDialogBase( Tabbed, i18n( "Edit BarGraph Preferences" ), + Ok | Apply | Cancel, Ok, parent, name, true, true ) +{ + // Range page + TQFrame *page = addPage( i18n( "Range" ) ); + TQGridLayout *pageLayout = new TQGridLayout( page, 3, 1, 0, spacingHint() ); + + TQGroupBox *groupBox = new TQGroupBox( 0, Qt::Vertical, i18n( "Title" ), page ); + TQGridLayout *boxLayout = new TQGridLayout( groupBox->layout(), 1, 1 ); + + mTitle = new KLineEdit( groupBox ); + TQWhatsThis::add( mTitle, i18n( "Enter the title of the display here." ) ); + boxLayout->addWidget( mTitle, 0, 0 ); + + pageLayout->addWidget( groupBox, 0, 0 ); + + groupBox = new TQGroupBox( 0, Qt::Vertical, i18n( "Display Range" ), page ); + boxLayout = new TQGridLayout( groupBox->layout(), 1, 5 ); + boxLayout->setColStretch( 2, 1 ); + + TQLabel *label = new TQLabel( i18n( "Minimum value:" ), groupBox ); + boxLayout->addWidget( label, 0, 0 ); + + mMinValue = new KDoubleSpinBox( 0, 100, 0.5, 0, 2, groupBox ); + TQWhatsThis::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 TQLabel( i18n( "Maximum value:" ), groupBox ); + boxLayout->addWidget( label, 0, 3 ); + + mMaxValue = new KDoubleSpinBox( 0, 10000, 0.5, 100, 2, groupBox ); + TQWhatsThis::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 TQGridLayout( page, 3, 1, 0, spacingHint() ); + + groupBox = new TQGroupBox( 0, Qt::Vertical, i18n( "Alarm for Minimum Value" ), page ); + boxLayout = new TQGridLayout( groupBox->layout(), 1, 4 ); + boxLayout->setColStretch( 1, 1 ); + + mUseLowerLimit = new TQCheckBox( i18n( "Enable alarm" ), groupBox ); + TQWhatsThis::add( mUseLowerLimit, i18n( "Enable the minimum value alarm." ) ); + boxLayout->addWidget( mUseLowerLimit, 0, 0 ); + + label = new TQLabel( 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 TQGroupBox( 0, Qt::Vertical, i18n( "Alarm for Maximum Value" ), page ); + boxLayout = new TQGridLayout( groupBox->layout(), 1, 4 ); + boxLayout->setColStretch( 1, 1 ); + + mUseUpperLimit = new TQCheckBox( i18n( "Enable alarm" ), groupBox ); + TQWhatsThis::add( mUseUpperLimit, i18n( "Enable the maximum value alarm." ) ); + boxLayout->addWidget( mUseUpperLimit, 0, 0 ); + + label = new TQLabel( 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 TQGridLayout( page, 5, 2, 0, spacingHint() ); + + label = new TQLabel( i18n( "Normal bar color:" ), page ); + pageLayout->addWidget( label, 0, 0 ); + + mForegroundColor = new KColorButton( page ); + pageLayout->addWidget( mForegroundColor, 0, 1 ); + label->setBuddy( mForegroundColor ); + + label = new TQLabel( 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 TQLabel( i18n( "Background color:" ), page ); + pageLayout->addWidget( label, 2, 0 ); + + mBackgroundColor = new KColorButton( page ); + pageLayout->addWidget( mBackgroundColor, 2, 1 ); + label->setBuddy( mBackgroundColor ); + + label = new TQLabel( i18n( "Font size:" ), page ); + pageLayout->addWidget( label, 3, 0 ); + + mFontSize = new KIntNumInput( 9, page ); + TQWhatsThis::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 TQGridLayout( page, 3, 2, 0, spacingHint() ); + pageLayout->setRowStretch( 2, 1 ); + + mSensorView = new TDEListView( 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 TQPushButton( i18n( "Edit..." ), page ); + mEditButton->setEnabled( false ); + TQWhatsThis::add( mEditButton, i18n( "Push this button to configure the label." ) ); + pageLayout->addWidget( mEditButton, 0, 1 ); + + mRemoveButton = new TQPushButton( i18n( "Delete" ), page ); + mRemoveButton->setEnabled( false ); + TQWhatsThis::add( mRemoveButton, i18n( "Push this button to delete the sensor." ) ); + pageLayout->addWidget( mRemoveButton, 1, 1 ); + + connect( mUseLowerLimit, TQT_SIGNAL( toggled( bool ) ), + mLowerLimit, TQT_SLOT( setEnabled( bool ) ) ); + connect( mUseUpperLimit, TQT_SIGNAL( toggled( bool ) ), + mUpperLimit, TQT_SLOT( setEnabled( bool ) ) ); + + connect( mSensorView, TQT_SIGNAL( selectionChanged( TQListViewItem* ) ), + TQT_SLOT( selectionChanged( TQListViewItem* ) ) ); + connect( mEditButton, TQT_SIGNAL( clicked() ), TQT_SLOT( editSensor() ) ); + connect( mRemoveButton, TQT_SIGNAL( clicked() ), TQT_SLOT( removeSensor() ) ); + + TDEAcceleratorManager::manage( this ); + + mTitle->setFocus(); +} + +DancingBarsSettings::~DancingBarsSettings() +{ +} + +void DancingBarsSettings::setTitle( const TQString& title ) +{ + mTitle->setText( title ); +} + +TQString 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 TQColor &color ) +{ + mForegroundColor->setColor( color ); +} + +TQColor DancingBarsSettings::foregroundColor() const +{ + return mForegroundColor->color(); +} + +void DancingBarsSettings::setAlarmColor( const TQColor &color ) +{ + mAlarmColor->setColor( color ); +} + +TQColor DancingBarsSettings::alarmColor() const +{ + return mAlarmColor->color(); +} + +void DancingBarsSettings::setBackgroundColor( const TQColor &color ) +{ + mBackgroundColor->setColor( color ); +} + +TQColor 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 TQValueList< TQStringList > &list ) +{ + mSensorView->clear(); + + TQValueList< TQStringList >::ConstIterator it; + for ( it = list.begin(); it != list.end(); ++it ) { + new TQListViewItem( mSensorView, + (*it)[ 0 ], // host name + (*it)[ 1 ], // sensor name + (*it)[ 2 ], // footer title + (*it)[ 3 ], // unit + (*it)[ 4 ] ); // status + } +} + +TQValueList< TQStringList > DancingBarsSettings::sensors() const +{ + TQValueList< TQStringList > list; + + TQListViewItemIterator it( mSensorView ); + while ( it.current() && !it.current()->text( 0 ).isEmpty() ) { + TQStringList 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() +{ + TQListViewItem *lvi = mSensorView->currentItem(); + + if ( !lvi ) + return; + + bool ok; + TQString 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() +{ + TQListViewItem *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. */ + TQListViewItem* 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( TQListViewItem* 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..aa9d580bd --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.h @@ -0,0 +1,106 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_DANCINGBARSSETTINGS_H +#define KSG_DANCINGBARSSETTINGS_H + +#include <kdialogbase.h> + +class KColorButton; +class KDoubleSpinBox; +class KIntNumInput; +class KLineEdit; +class TDEListView; + +class TQCheckBox; +class TQListViewItem; +class TQPushButton; + +class DancingBarsSettings : public KDialogBase +{ + Q_OBJECT + + public: + DancingBarsSettings( TQWidget* parent = 0, const char* name = 0 ); + ~DancingBarsSettings(); + + void setTitle( const TQString& title ); + TQString 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 TQColor &color ); + TQColor foregroundColor() const; + + void setAlarmColor( const TQColor &color ); + TQColor alarmColor() const; + + void setBackgroundColor( const TQColor &color ); + TQColor backgroundColor() const; + + void setFontSize( int size ); + int fontSize() const; + + void setSensors( const TQValueList< TQStringList > &list ); + TQValueList< TQStringList > sensors() const; + + private slots: + void editSensor(); + void removeSensor(); + void selectionChanged( TQListViewItem* ); + + private: + KColorButton *mForegroundColor; + KColorButton *mAlarmColor; + KColorButton *mBackgroundColor; + KDoubleSpinBox *mMinValue; + KDoubleSpinBox *mMaxValue; + KDoubleSpinBox *mLowerLimit; + KDoubleSpinBox *mUpperLimit; + KLineEdit *mTitle; + TDEListView *mSensorView; + KIntNumInput *mFontSize; + + TQCheckBox *mUseLowerLimit; + TQCheckBox *mUseUpperLimit; + TQPushButton *mEditButton; + TQPushButton *mRemoveButton; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/DummyDisplay.cc b/ksysguard/gui/SensorDisplayLib/DummyDisplay.cc new file mode 100644 index 000000000..13696c502 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DummyDisplay.cc @@ -0,0 +1,58 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000, 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <tdelocale.h> +#include <ksgrd/SensorManager.h> + +#include <tqwhatsthis.h> + +#include "DummyDisplay.h" + +DummyDisplay::DummyDisplay( TQWidget* parent, const char* name, + const TQString&, double, double ) + : KSGRD::SensorDisplay( parent, name, i18n( "Drop Sensor Here" ) ) +{ + setMinimumSize( 16, 16 ); + + TQWhatsThis::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( TQResizeEvent* ) +{ + frame()->setGeometry( 0, 0, width(), height() ); +} + +bool DummyDisplay::eventFilter( TQObject* object, TQEvent* event ) +{ + if ( event->type() == TQEvent::MouseButtonRelease && + ( (TQMouseEvent*)event)->button() == Qt::LeftButton ) + setFocus(); + + return TQWidget::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..cd00a6fd6 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DummyDisplay.h @@ -0,0 +1,44 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_DUMMYDISPLAY_H +#define KSG_DUMMYDISPLAY_H + +#include <SensorDisplay.h> + +class DummyDisplay : public KSGRD::SensorDisplay +{ + Q_OBJECT + + public: + DummyDisplay( TQWidget* parent = 0, const char* name = 0, + const TQString& = TQString::null, double min = 0, + double max = 0 ); + virtual ~DummyDisplay() {} + + void resizeEvent( TQResizeEvent* ); + + virtual bool eventFilter( TQObject*, TQEvent* ); +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/FancyPlotter.cc b/ksysguard/gui/SensorDisplayLib/FancyPlotter.cc new file mode 100644 index 000000000..22894afea --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/FancyPlotter.cc @@ -0,0 +1,457 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <tqdom.h> +#include <tqimage.h> +#include <tqtooltip.h> + +#include <kdebug.h> +#include <tdelocale.h> +#include <tdemessagebox.h> + +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> +#include "SensorDisplay.h" +#include "FancyPlotterSettings.h" + +#include "FancyPlotter.h" + +FancyPlotter::FancyPlotter( TQWidget* parent, const char* name, + const TQString &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( TQT_TQWIDGET(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() ); + + TQValueList< TQStringList > list; + for ( uint i = 0; i < mBeams; ++i ) { + TQStringList entry; + entry << TQString::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, TQT_SIGNAL( applyClicked() ), TQT_SLOT( applySettings() ) ); + connect( mSettingsDialog, TQT_SIGNAL( okClicked() ), TQT_SLOT( applySettings() ) ); + connect( mSettingsDialog, TQT_SIGNAL( finished() ), TQT_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 TQResizeEvent 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() ); + + + TQValueList<int> orderOfSensors = mSettingsDialog->order(); + TQValueList<int> deletedSensors = mSettingsDialog->deleted(); + mSettingsDialog->clearDeleted(); + mSettingsDialog->resetOrder(); + TQValueList< int >::Iterator itDelete; + for ( itDelete = deletedSensors.begin(); itDelete != deletedSensors.end(); ++itDelete ) + removeSensor(*itDelete); + + TQValueList< int >::Iterator itOrder; + mPlotter->reorderBeams(orderOfSensors); + reorderSensors(orderOfSensors); + + TQValueList< TQStringList > list = mSettingsDialog->sensors(); + TQValueList< TQStringList >::Iterator it; + + for ( uint i = 0; i < sensors().count(); ++i ) + mPlotter->beamColors()[ i ] = TQColor( 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 TQString &hostName, const TQString &name, + const TQString &type, const TQString &title ) +{ + return addSensor( hostName, name, type, title, + KSGRD::Style->sensorColor( mBeams ) ); +} + +bool FancyPlotter::addSensor( const TQString &hostName, const TQString &name, + const TQString &type, const TQString &title, + const TQColor &color ) +{ + if ( type != "integer" && type != "float" ) + return false; + + if ( mBeams > 0 && hostName != sensors().at( 0 )->hostName() ) { + KMessageBox::sorry( this, TQString( "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; + + TQString tooltip; + for ( uint i = 0; i < mBeams; ++i ) { + tooltip += TQString( "%1%2:%3" ).arg( i != 0 ? "\n" : "" ) + .arg( sensors().at( mBeams - i - 1 )->hostName() ) + .arg( sensors().at( mBeams - i - 1 )->name() ); + } + + TQToolTip::remove( TQT_TQWIDGET(mPlotter) ); + TQToolTip::add( TQT_TQWIDGET(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 ); + + TQString tooltip; + for ( uint i = 0; i < mBeams; ++i ) { + tooltip += TQString( "%1%2:%3" ).arg( i != 0 ? "\n" : "" ) + .arg( sensors().at( mBeams - i - 1 )->hostName() ) + .arg( sensors().at( mBeams - i - 1 )->name() ); + } + + TQToolTip::remove( TQT_TQWIDGET(mPlotter) ); + TQToolTip::add( TQT_TQWIDGET(mPlotter), tooltip ); + + return true; +} + +void FancyPlotter::resizeEvent( TQResizeEvent* ) +{ + if ( noFrame() ) + mPlotter->setGeometry( 0, 0, width(), height() ); + else + frame()->setGeometry( 0, 0, width(), height() ); +} + +TQSize FancyPlotter::sizeHint() +{ + if ( noFrame() ) + return mPlotter->sizeHint(); + else + return frame()->sizeHint(); +} + +void FancyPlotter::answerReceived( int id, const TQString &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( TQDomElement &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", + TQString( "%1" ).arg( KSGRD::Style->fontSize() ) ).toUInt() ); + + mPlotter->setBackgroundColor( restoreColor( element, "bColor", + KSGRD::Style->backgroundColor() ) ); + + TQDomNodeList dnList = element.elementsByTagName( "beam" ); + for ( uint i = 0; i < dnList.count(); ++i ) { + TQDomElement 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( TQDomDocument &doc, TQDomElement &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 ) { + TQDomElement 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 TQString &hostName, + const TQString &name, + const TQString &type, + const TQString &description, + const TQColor &color ) + : KSGRD::SensorProperties( hostName, name, type, description ), + mColor( color ) +{ +} + +FPSensorProperties::~FPSensorProperties() +{ +} + +void FPSensorProperties::setColor( const TQColor &color ) +{ + mColor = color; +} + +TQColor 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..2f0e36c60 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/FancyPlotter.h @@ -0,0 +1,103 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef KSG_FANCYPLOTTER_H +#define KSG_FANCYPLOTTER_H + +#include <kdialogbase.h> + +#include <SensorDisplay.h> + +#include "SignalPlotter.h" + +class TQListViewItem; +class FancyPlotterSettings; + +class FPSensorProperties : public KSGRD::SensorProperties +{ + public: + FPSensorProperties(); + FPSensorProperties( const TQString &hostName, const TQString &name, + const TQString &type, const TQString &description, + const TQColor &color ); + ~FPSensorProperties(); + + void setColor( const TQColor &color ); + TQColor color() const; + + private: + TQColor mColor; +}; + +class FancyPlotter : public KSGRD::SensorDisplay +{ + Q_OBJECT + + public: + FancyPlotter( TQWidget* parent = 0, const char* name = 0, + const TQString& title = TQString::null, double min = 0, + double max = 100, bool noFrame = false, bool isApplet = false ); + virtual ~FancyPlotter(); + + void configureSettings(); + + bool addSensor( const TQString &hostName, const TQString &name, + const TQString &type, const TQString &title ); + bool addSensor( const TQString &hostName, const TQString &name, + const TQString &type, const TQString &title, + const TQColor &color ); + + bool removeSensor( uint pos ); + + virtual TQSize sizeHint(void); + + virtual void answerReceived( int id, const TQString &answer ); + + virtual bool restoreSettings( TQDomElement &element ); + virtual bool saveSettings( TQDomDocument &doc, TQDomElement &element, + bool save = true ); + + virtual bool hasSettingsDialog() const; + + public slots: + void applySettings(); + virtual void applyStyle(); + void killDialog(); + + protected: + virtual void resizeEvent( TQResizeEvent* ); + + 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. + */ + TQValueList<double> mSampleBuf; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.cc b/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.cc new file mode 100644 index 000000000..ef53bab75 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.cc @@ -0,0 +1,637 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <tdeaccelmanager.h> +#include <kcolorbutton.h> +#include <kcolordialog.h> +#include <klineedit.h> +#include <tdelistview.h> +#include <tdelocale.h> +#include <knuminput.h> + +#include <tqcheckbox.h> +#include <tqbuttongroup.h> +#include <tqgroupbox.h> +#include <tqimage.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpixmap.h> +#include <tqpushbutton.h> +#include <tqradiobutton.h> +#include <tqwhatsthis.h> +#include <tqheader.h> + +#include "FancyPlotterSettings.h" + +FancyPlotterSettings::FancyPlotterSettings( TQWidget* parent, const char* name ) + : KDialogBase( Tabbed, i18n( "Signal Plotter Settings" ), Ok | Apply | Cancel, + Ok, parent, name, false, true ) +{ + TQFrame *page = 0; + TQGridLayout *pageLayout = 0; + TQGridLayout *boxLayout = 0; + TQGroupBox *groupBox = 0; + TQLabel *label = 0; + + // Style page + page = addPage( i18n( "Style" ) ); + pageLayout = new TQGridLayout( page, 3, 2, 0, spacingHint() ); + + label = new TQLabel( i18n( "Title:" ), page ); + pageLayout->addWidget( label, 0, 0 ); + + mTitle = new KLineEdit( page ); + TQWhatsThis::add( mTitle, i18n( "Enter the title of the display here." ) ); + pageLayout->addWidget( mTitle, 0, 1 ); + label->setBuddy( mTitle ); + + TQButtonGroup *buttonBox = new TQButtonGroup( 2, Qt::Vertical, + i18n( "Graph Drawing Style" ), page ); + + mUsePolygonStyle = new TQRadioButton( i18n( "Basic polygons" ), buttonBox ); + mUsePolygonStyle->setChecked( true ); + mUseOriginalStyle = new TQRadioButton( i18n( "Original - single line per data point" ), buttonBox ); + + pageLayout->addMultiCellWidget( buttonBox, 1, 1, 0, 1 ); + + // Scales page + page = addPage( i18n( "Scales" ) ); + pageLayout = new TQGridLayout( page, 2, 1, 0, spacingHint() ); + + groupBox = new TQGroupBox( 0, Qt::Vertical, i18n( "Vertical Scale" ), page ); + boxLayout = new TQGridLayout( groupBox->layout(), 2, 5, spacingHint() ); + boxLayout->setColStretch( 2, 1 ); + + mUseAutoRange = new TQCheckBox( i18n( "Automatic range detection" ), groupBox ); + TQWhatsThis::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 TQLabel( i18n( "Minimum value:" ), groupBox ); + boxLayout->addWidget( label, 1, 0 ); + + mMinValue = new KLineEdit( groupBox ); + mMinValue->setAlignment( AlignRight ); + mMinValue->setEnabled( false ); + TQWhatsThis::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 TQLabel( i18n( "Maximum value:" ), groupBox ); + boxLayout->addWidget( label, 1, 3 ); + + mMaxValue = new KLineEdit( groupBox ); + mMaxValue->setAlignment( AlignRight ); + mMaxValue->setEnabled( false ); + TQWhatsThis::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 TQGroupBox( 0, Qt::Vertical, i18n( "Horizontal Scale" ), page ); + boxLayout = new TQGridLayout( 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 TQLabel( 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 TQGridLayout( page, 3, 2, 0, spacingHint() ); + + groupBox = new TQGroupBox( 0, Qt::Vertical, i18n( "Lines" ), page ); + boxLayout = new TQGridLayout( groupBox->layout(), 2, 5, spacingHint() ); + boxLayout->setColStretch( 1, 1 ); + + mShowVerticalLines = new TQCheckBox( i18n( "Vertical lines" ), groupBox ); + TQWhatsThis::add( mShowVerticalLines, i18n( "Check this to activate the vertical lines if display is large enough." ) ); + boxLayout->addWidget( mShowVerticalLines, 0, 0 ); + + label = new TQLabel( i18n( "Distance:" ), groupBox ); + boxLayout->addWidget( label, 0, 2 ); + + mVerticalLinesDistance = new KIntNumInput( 0, groupBox ); + mVerticalLinesDistance->setMinValue( 10 ); + mVerticalLinesDistance->setMaxValue( 120 ); + TQWhatsThis::add( mVerticalLinesDistance, i18n( "Enter the distance between two vertical lines here." ) ); + boxLayout->addWidget( mVerticalLinesDistance , 0, 3 ); + label->setBuddy( mVerticalLinesDistance ); + + mVerticalLinesScroll = new TQCheckBox( i18n( "Vertical lines scroll" ), groupBox ); + boxLayout->addWidget( mVerticalLinesScroll, 0, 4 ); + + mShowHorizontalLines = new TQCheckBox( i18n( "Horizontal lines" ), groupBox ); + TQWhatsThis::add( mShowHorizontalLines, i18n( "Check this to enable horizontal lines if display is large enough." ) ); + boxLayout->addWidget( mShowHorizontalLines, 1, 0 ); + + label = new TQLabel( i18n( "Count:" ), groupBox ); + boxLayout->addWidget( label, 1, 2 ); + + mHorizontalLinesCount = new KIntNumInput( 0, groupBox ); + mHorizontalLinesCount->setMinValue( 1 ); + mHorizontalLinesCount->setMaxValue( 100 ); + TQWhatsThis::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 TQGroupBox( 0, Qt::Vertical, i18n( "Text" ), page ); + boxLayout = new TQGridLayout( groupBox->layout(), 3, 4, spacingHint() ); + boxLayout->setColStretch( 1, 1 ); + + mShowLabels = new TQCheckBox( i18n( "Labels" ), groupBox ); + TQWhatsThis::add( mShowLabels, i18n( "Check this box if horizontal lines should be decorated with the values they mark." ) ); + boxLayout->addWidget( mShowLabels, 0, 0 ); + + label = new TQLabel( 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 TQCheckBox( i18n( "Top bar" ), groupBox ); + TQWhatsThis::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 TQGroupBox( 0, Qt::Vertical, i18n( "Colors" ), page ); + boxLayout = new TQGridLayout( groupBox->layout(), 4, 2, spacingHint() ); + + label = new TQLabel( i18n( "Vertical lines:" ), groupBox ); + boxLayout->addWidget( label, 0, 0 ); + + mVerticalLinesColor = new KColorButton( groupBox ); + boxLayout->addWidget( mVerticalLinesColor, 0, 1 ); + label->setBuddy( mVerticalLinesColor ); + + label = new TQLabel( i18n( "Horizontal lines:" ), groupBox ); + boxLayout->addWidget( label, 1, 0 ); + + mHorizontalLinesColor = new KColorButton( groupBox ); + boxLayout->addWidget( mHorizontalLinesColor, 1, 1 ); + label->setBuddy( mHorizontalLinesColor ); + + label = new TQLabel( 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 TQGridLayout( page, 6, 2, 0, spacingHint() ); + pageLayout->setRowStretch( 2, 1 ); + pageLayout->setRowStretch( 5, 1 ); + + mSensorView = new TDEListView( page ); + mSensorView->addColumn("" , 0); + mSensorView->addColumn( i18n( "Host" ) ); + mSensorView->addColumn( i18n( "Sensor" ) ); + mSensorView->addColumn( i18n( "Unit" ) ); + mSensorView->addColumn( i18n( "Status" ) ); + mSensorView->setResizeMode(TQListView::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 TQPushButton( i18n( "Set Color..." ), page ); + mEditButton->setEnabled( false ); + TQWhatsThis::add( mEditButton, i18n( "Push this button to configure the color of the sensor in the diagram." ) ); + pageLayout->addWidget( mEditButton, 0, 1 ); + + mRemoveButton = new TQPushButton( i18n( "Delete" ), page ); + mRemoveButton->setEnabled( false ); + TQWhatsThis::add( mRemoveButton, i18n( "Push this button to delete the sensor." ) ); + pageLayout->addWidget( mRemoveButton, 1, 1 ); + + mMoveUpButton = new TQPushButton( i18n( "Move Up" ), page ); + mMoveUpButton->setEnabled( false ); + pageLayout->addWidget( mMoveUpButton, 3, 1 ); + + mMoveDownButton = new TQPushButton( i18n( "Move Down" ), page ); + mMoveDownButton->setEnabled( false ); + pageLayout->addWidget( mMoveDownButton, 4, 1 ); + + connect( mUseAutoRange, TQT_SIGNAL( toggled( bool ) ), mMinValue, + TQT_SLOT( setDisabled( bool ) ) ); + connect( mUseAutoRange, TQT_SIGNAL( toggled( bool ) ), mMaxValue, + TQT_SLOT( setDisabled( bool ) ) ); + connect( mShowVerticalLines, TQT_SIGNAL( toggled( bool ) ), mVerticalLinesDistance, + TQT_SLOT( setEnabled( bool ) ) ); + connect( mShowVerticalLines, TQT_SIGNAL( toggled( bool ) ), mVerticalLinesScroll, + TQT_SLOT( setEnabled( bool ) ) ); + connect( mShowVerticalLines, TQT_SIGNAL( toggled( bool ) ), mVerticalLinesColor, + TQT_SLOT( setEnabled( bool ) ) ); + connect( mShowHorizontalLines, TQT_SIGNAL( toggled( bool ) ), mHorizontalLinesCount, + TQT_SLOT( setEnabled( bool ) ) ); + connect( mShowHorizontalLines, TQT_SIGNAL( toggled( bool ) ), mHorizontalLinesColor, + TQT_SLOT( setEnabled( bool ) ) ); + connect( mShowHorizontalLines, TQT_SIGNAL( toggled( bool ) ), mShowLabels, + TQT_SLOT( setEnabled( bool ) ) ); + connect( mSensorView, TQT_SIGNAL( selectionChanged( TQListViewItem* ) ), + TQT_SLOT( selectionChanged( TQListViewItem* ) ) ); + + connect( mEditButton, TQT_SIGNAL( clicked() ), TQT_SLOT( editSensor() ) ); + connect( mRemoveButton, TQT_SIGNAL( clicked() ), TQT_SLOT( removeSensor() ) ); + connect( mMoveUpButton, TQT_SIGNAL( clicked() ), TQT_SLOT( moveUpSensor() ) ); + connect( mMoveDownButton, TQT_SIGNAL( clicked() ), TQT_SLOT( moveDownSensor() ) ); + connect ( mSensorView, TQT_SIGNAL( doubleClicked( TQListViewItem *, const TQPoint &, int )), TQT_SLOT(editSensor())); + + TDEAcceleratorManager::manage( this ); +} + +FancyPlotterSettings::~FancyPlotterSettings() +{ +} + +void FancyPlotterSettings::setTitle( const TQString &title ) +{ + mTitle->setText( title ); +} + +TQString 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( TQString::number( min ) ); +} + +double FancyPlotterSettings::minValue() const +{ + return mMinValue->text().toDouble(); +} + +void FancyPlotterSettings::setMaxValue( double max ) +{ + mMaxValue->setText( TQString::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 TQColor &color ) +{ + mVerticalLinesColor->setColor( color ); +} + +TQColor 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 TQColor &color ) +{ + mHorizontalLinesColor->setColor( color ); +} + +TQColor 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 TQColor &color ) +{ + mBackgroundColor->setColor( color ); +} + +TQColor FancyPlotterSettings::backgroundColor() const +{ + return mBackgroundColor->color(); +} +void FancyPlotterSettings::clearDeleted() +{ + mDeleted.clear(); +} +TQValueList<int> FancyPlotterSettings::deleted() const +{ + return mDeleted; +} + +TQValueList<int> FancyPlotterSettings::order() const +{ + TQValueList<int> newOrder; + + TQListViewItemIterator it( mSensorView ); + for ( ; it.current(); ++it ) { + newOrder.prepend(it.current()->text(0).toInt()); + } + return newOrder; +} + +void FancyPlotterSettings::resetOrder() +{ + int i = mSensorView->childCount()-1; + TQListViewItemIterator it( mSensorView ); + for ( ; it.current(); ++it, --i) { + it.current()->setText(0, TQString::number(i)); + } +} + +void FancyPlotterSettings::setSensors( const TQValueList< TQStringList > &list ) +{ + mSensorView->clear(); + + TQValueList< TQStringList >::ConstIterator it; + for ( it = list.begin(); it != list.end(); ++it ) { + TQListViewItem* lvi = new TQListViewItem( mSensorView, + (*it)[ 0 ], // id + (*it)[ 1 ], // host name + (*it)[ 2 ], // sensor name + (*it)[ 3 ], // unit + (*it)[ 4 ] ); // status + TQPixmap pm( 12, 12 ); + pm.fill( TQColor( (*it)[ 5 ] ) ); + lvi->setPixmap( 2, pm ); + mSensorView->insertItem( lvi ); + } +} + +TQValueList< TQStringList > FancyPlotterSettings::sensors() const +{ + TQValueList< TQStringList > list; + + TQListViewItemIterator it( mSensorView ); + + for ( ; it.current(); ++it ) { + TQStringList 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 ); + TQColor color( tqRed( rgb ), tqGreen( rgb ), tqBlue( rgb ) ); + entry << ( color.name() ); + + list.prepend( entry ); + } + + return list; +} + +void FancyPlotterSettings::editSensor() +{ + TQListViewItem* lvi = mSensorView->currentItem(); + + if ( !lvi ) + return; + + TQColor color = lvi->pixmap( 2 )->convertToImage().pixel( 1, 1 ); + int result = KColorDialog::getColor( color, parentWidget() ); + if ( result == KColorDialog::Accepted ) { + TQPixmap newPm( 12, 12 ); + newPm.fill( color ); + lvi->setPixmap( 2, newPm ); + } +} + +void FancyPlotterSettings::removeSensor() +{ + TQListViewItem* 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. */ + TQListViewItem* 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; + + TQListViewItemIterator it( mSensorView ); + for ( ; it.current(); ++it ) { + if(it.current()->text(0).toInt() > id) + it.current()->setText(0, TQString::number(it.current()->text(0).toInt() -1)); + } + + + if ( newSelected ) + mSensorView->ensureItemVisible( newSelected ); + } +} + +void FancyPlotterSettings::moveUpSensor() +{ + if ( mSensorView->currentItem() != 0 ) { + TQListViewItem* 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( TQListViewItem *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..010b4938b --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.h @@ -0,0 +1,143 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef FANCYPLOTTERSETTINGS_H +#define FANCYPLOTTERSETTINGS_H + +#include <kdialogbase.h> + +class KColorButton; +class KIntNumInput; +class KLineEdit; +class TDEListView; + +class TQCheckBox; +class TQListViewItem; +class TQPushButton; +class TQRadioButton; + +class FancyPlotterSettings : public KDialogBase +{ + Q_OBJECT + + public: + FancyPlotterSettings( TQWidget* parent = 0, const char* name = 0 ); + ~FancyPlotterSettings(); + + void setTitle( const TQString &title ); + TQString 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 TQColor &color ); + TQColor 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 TQColor &color ); + TQColor 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 TQColor &color ); + TQColor backgroundColor() const; + + void setSensors( const TQValueList< TQStringList > &list ); + TQValueList< TQStringList > sensors() const; + TQValueList<int> order() const; + TQValueList<int> deleted() const; + void clearDeleted(); + void resetOrder(); + + private slots: + void editSensor(); + void removeSensor(); + void moveUpSensor(); + void moveDownSensor(); + void selectionChanged( TQListViewItem* ); + + private: + + KColorButton *mVerticalLinesColor; + KColorButton *mHorizontalLinesColor; + KColorButton *mBackgroundColor; + KLineEdit *mMinValue; + KLineEdit *mMaxValue; + KLineEdit *mTitle; + KIntNumInput *mHorizontalScale; + KIntNumInput *mVerticalLinesDistance; + KIntNumInput *mHorizontalLinesCount; + KIntNumInput *mFontSize; + TDEListView *mSensorView; + + TQCheckBox *mShowVerticalLines; + TQCheckBox *mShowHorizontalLines; + TQCheckBox *mVerticalLinesScroll; + TQCheckBox *mUseAutoRange; + TQCheckBox *mShowLabels; + TQCheckBox *mShowTopBar; + TQPushButton *mEditButton; + TQPushButton *mRemoveButton; + TQPushButton *mMoveUpButton; + TQPushButton *mMoveDownButton; + TQRadioButton *mUsePolygonStyle; + TQRadioButton *mUseOriginalStyle; + + /** The numbers of the sensors to be delete.*/ + TQValueList<int> mDeleted; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/ListView.cc b/ksysguard/gui/SensorDisplayLib/ListView.cc new file mode 100644 index 000000000..5b748e9c0 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ListView.cc @@ -0,0 +1,371 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> + +#include <config.h> +#include <tqdom.h> + +#include <kcolorbutton.h> +#include <kdebug.h> +#include <tdeglobal.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include "ListView.h" +#include "ListView.moc" +#include "ListViewSettings.h" + +PrivateListViewItem::PrivateListViewItem(PrivateListView *parent) + : TQListViewItem(parent) +{ + _parent = parent; +} + +int PrivateListViewItem::compare( TQListViewItem *item, int col, bool ascending ) const +{ + int type = ((PrivateListView*)listView())->columnType( col ); + + if ( type == PrivateListView::Int ) { + int prev = (int)TDEGlobal::locale()->readNumber( key( col, ascending ) ); + int next = (int)TDEGlobal::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 = TDEGlobal::locale()->readNumber( key( col, ascending ) ); + double next = TDEGlobal::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 ) { + TQString prev = key( col, ascending ); + TQString next = item->key( col, ascending ); + TQString 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(TQWidget *parent, const char *name) + : TQListView(parent, name) +{ + TQColorGroup cg = colorGroup(); + + cg.setColor(TQColorGroup::Link, KSGRD::Style->firstForegroundColor()); + cg.setColor(TQColorGroup::Text, KSGRD::Style->secondForegroundColor()); + cg.setColor(TQColorGroup::Base, KSGRD::Style->backgroundColor()); + + setPalette(TQPalette(cg, cg, cg)); +} + +void PrivateListView::update(const TQString& 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, TDEGlobal::locale()->formatNumber( records[j].toFloat() ) ); + else if ( mColumnTypes[ j ] == "D" ) + item->setText(j, TDEGlobal::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 TQString& label, const TQString& type) +{ + TQListView::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. */ + TQFontMetrics fm = fontMetrics(); + setColumnWidth(col, fm.width(label) + 10); +} + +ListView::ListView(TQWidget* parent, const char* name, const TQString& title, int, int) + : KSGRD::SensorDisplay(parent, name, title) +{ + setBackgroundColor(KSGRD::Style->backgroundColor()); + + monitor = new PrivateListView( frame() ); + TQ_CHECK_PTR(monitor); + monitor->setSelectionMode(TQListView::NoSelection); + monitor->setItemMargin(2); + + setMinimumSize(50, 25); + + setPlotterWidget(monitor); + + setModified(false); +} + +bool +ListView::addSensor(const TQString& hostName, const TQString& sensorName, const TQString& sensorType, const TQString& 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 TQString& 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(TQResizeEvent*) +{ + frame()->setGeometry(0, 0, width(), height()); + monitor->setGeometry(10, 20, width() - 20, height() - 30); +} + +bool +ListView::restoreSettings(TQDomElement& element) +{ + addSensor(element.attribute("hostName"), element.attribute("sensorName"), (element.attribute("sensorType").isEmpty() ? "listview" : element.attribute("sensorType")), element.attribute("title")); + + TQColorGroup colorGroup = monitor->colorGroup(); + colorGroup.setColor(TQColorGroup::Link, restoreColor(element, "gridColor", KSGRD::Style->firstForegroundColor())); + colorGroup.setColor(TQColorGroup::Text, restoreColor(element, "textColor", KSGRD::Style->secondForegroundColor())); + colorGroup.setColor(TQColorGroup::Base, restoreColor(element, "backgroundColor", KSGRD::Style->backgroundColor())); + + monitor->setPalette(TQPalette(colorGroup, colorGroup, colorGroup)); + + SensorDisplay::restoreSettings(element); + + setModified(false); + + return (true); +} + +bool +ListView::saveSettings(TQDomDocument& doc, TQDomElement& element, bool save) +{ + element.setAttribute("hostName", sensors().at(0)->hostName()); + element.setAttribute("sensorName", sensors().at(0)->name()); + element.setAttribute("sensorType", sensors().at(0)->type()); + + TQColorGroup colorGroup = monitor->colorGroup(); + saveColor(element, "gridColor", colorGroup.color(TQColorGroup::Link)); + saveColor(element, "textColor", colorGroup.color(TQColorGroup::Text)); + saveColor(element, "backgroundColor", colorGroup.color(TQColorGroup::Base)); + + SensorDisplay::saveSettings(doc, element); + + if (save) + setModified(false); + + return (true); +} + +void +ListView::configureSettings() +{ + lvs = new ListViewSettings(this, "ListViewSettings"); + TQ_CHECK_PTR(lvs); + connect(lvs, TQT_SIGNAL(applyClicked()), TQT_SLOT(applySettings())); + + TQColorGroup colorGroup = monitor->colorGroup(); + lvs->setGridColor(colorGroup.color(TQColorGroup::Link)); + lvs->setTextColor(colorGroup.color(TQColorGroup::Text)); + lvs->setBackgroundColor(colorGroup.color(TQColorGroup::Base)); + lvs->setTitle(title()); + + if (lvs->exec()) + applySettings(); + + delete lvs; + lvs = 0; +} + +void +ListView::applySettings() +{ + TQColorGroup colorGroup = monitor->colorGroup(); + colorGroup.setColor(TQColorGroup::Link, lvs->gridColor()); + colorGroup.setColor(TQColorGroup::Text, lvs->textColor()); + colorGroup.setColor(TQColorGroup::Base, lvs->backgroundColor()); + monitor->setPalette(TQPalette(colorGroup, colorGroup, colorGroup)); + + setTitle(lvs->title()); + + setModified(true); +} + +void +ListView::applyStyle() +{ + TQColorGroup colorGroup = monitor->colorGroup(); + colorGroup.setColor(TQColorGroup::Link, KSGRD::Style->firstForegroundColor()); + colorGroup.setColor(TQColorGroup::Text, KSGRD::Style->secondForegroundColor()); + colorGroup.setColor(TQColorGroup::Base, KSGRD::Style->backgroundColor()); + monitor->setPalette(TQPalette(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..643df8747 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ListView.h @@ -0,0 +1,112 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef _ListView_h_ +#define _ListView_h_ + +#include <tqlistview.h> +#include <tqpainter.h> + +#include <SensorDisplay.h> + +typedef const char* (*KeyFunc)(const char*); + +class TQLabel; +class QBoxGroup; +class ListViewSettings; + +class PrivateListView : public TQListView +{ + Q_OBJECT +public: + enum ColumnType { Text, Int, Float, Time, DiskStat }; + + PrivateListView(TQWidget *parent = 0, const char *name = 0); + + void addColumn(const TQString& label, const TQString& type); + void removeColumns(void); + void update(const TQString& answer); + int columnType( uint pos ) const; + +private: + TQStringList mColumnTypes; +}; + +class PrivateListViewItem : public TQListViewItem +{ +public: + PrivateListViewItem(PrivateListView *parent = 0); + + void paintCell(TQPainter *p, const TQColorGroup &, int column, int width, int alignment) { + TQColorGroup cgroup = _parent->colorGroup(); + TQListViewItem::paintCell(p, cgroup, column, width, alignment); + p->setPen(cgroup.color(TQColorGroup::Link)); + p->drawLine(0, height() - 1, width - 1, height() - 1); + } + + void paintFocus(TQPainter *, const TQColorGroup, const TQRect) {} + + virtual int compare( TQListViewItem*, int column, bool ascending ) const; + +private: + TQWidget *_parent; +}; + +class ListView : public KSGRD::SensorDisplay +{ + Q_OBJECT +public: + ListView(TQWidget* parent = 0, const char* name = 0, + const TQString& = TQString::null, int min = 0, int max = 0); + ~ListView() {} + + bool addSensor(const TQString& hostName, const TQString& sensorName, const TQString& sensorType, const TQString& sensorDescr); + void answerReceived(int id, const TQString& answer); + void resizeEvent(TQResizeEvent*); + void updateList(); + + bool restoreSettings(TQDomElement& element); + bool saveSettings(TQDomDocument& doc, TQDomElement& element, bool save = true); + + virtual bool hasSettingsDialog() const + { + return (true); + } + + virtual void timerEvent(TQTimerEvent*) + { + 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..e8e8ca336 --- /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 <[email protected]> + + 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 <tdelocale.h> + +ListViewSettings::ListViewSettings( TQWidget *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 ); +} + +TQString ListViewSettings::title() const +{ + return m_settingsWidget->title(); +} + +TQColor ListViewSettings::textColor() const +{ + return m_settingsWidget->textColor(); +} + +TQColor ListViewSettings::backgroundColor() const +{ + return m_settingsWidget->backgroundColor(); +} + +TQColor ListViewSettings::gridColor() const +{ + return m_settingsWidget->gridColor(); +} + +void ListViewSettings::setTitle( const TQString &title ) +{ + m_settingsWidget->setTitle( title ); +} + +void ListViewSettings::setBackgroundColor( const TQColor &c ) +{ + m_settingsWidget->setBackgroundColor( c ); +} + +void ListViewSettings::setTextColor( const TQColor &c ) +{ + m_settingsWidget->setTextColor( c ); +} + +void ListViewSettings::setGridColor( const TQColor &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..06a0b4002 --- /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 <[email protected]> + + 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 <tqstring.h> +#include <tqcolor.h> + +class ListViewSettingsWidget; + +class ListViewSettings : public KDialogBase +{ + Q_OBJECT + + public: + + ListViewSettings( TQWidget *parent=0, const char *name=0 ); + + TQString title() const; + TQColor textColor() const; + TQColor backgroundColor() const; + TQColor gridColor() const; + + void setTitle( const TQString & ); + void setTextColor( const TQColor & ); + void setBackgroundColor( const TQColor & ); + void setGridColor( const TQColor & ); + + 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..98bf0e207 --- /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="TQWidget"> + <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="TQGroupBox"> + <property name="name"> + <cstring>titleFrame</cstring> + </property> + <property name="title"> + <string>Title</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLineEdit"> + <property name="name"> + <cstring>m_title</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="TQGroupBox"> + <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="TQLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Text color:</string> + </property> + </widget> + <widget class="TQLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Grid color:</string> + </property> + </widget> + <widget class="TQLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + </widget> + </vbox> + </widget> + <widget class="TQLayoutWidget" 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="TQString">title()</function> + <function specifier="non virtual" returnType="TQColor">gridColor()</function> + <function specifier="non virtual" returnType="TQColor">backgroundColor()</function> + <function specifier="non virtual" returnType="TQColor">textColor()</function> + <function specifier="non virtual">setTitle( const TQString & t )</function> + <function specifier="non virtual">setBackgroundColor( const TQColor & c )</function> + <function specifier="non virtual">setTextColor( const TQColor & c )</function> + <function specifier="non virtual">setGridColor( const TQColor & 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..e12bf2132 --- /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. +*****************************************************************************/ + + +TQString ListViewSettingsWidget::title() +{ + return m_title->text(); +} + + +TQColor ListViewSettingsWidget::gridColor() +{ + return m_gridColor->color(); +} + + +TQColor ListViewSettingsWidget::backgroundColor() +{ + return m_backgroundColor->color(); +} + + +TQColor ListViewSettingsWidget::textColor() +{ + return m_textColor->color(); +} + + +void ListViewSettingsWidget::setTitle( const TQString &t ) +{ + m_title->setText(t); +} + + +void ListViewSettingsWidget::setBackgroundColor( const TQColor &c ) +{ + m_backgroundColor->setColor(c); +} + + +void ListViewSettingsWidget::setTextColor( const TQColor &c ) +{ + m_textColor->setColor(c); +} + + +void ListViewSettingsWidget::setGridColor( const TQColor &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..a8b22569d --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/LogFile.cc @@ -0,0 +1,285 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#include <stdio.h> +#include <sys/types.h> + +#include <tqpushbutton.h> +#include <tqregexp.h> + +#include <tqfile.h> +#include <tqlistbox.h> + +#include <tdefontdialog.h> +#include <kdebug.h> +#include <tdelocale.h> +#include <kcolorbutton.h> + +#include <ksgrd/StyleEngine.h> + +#include "LogFile.moc" + +LogFile::LogFile(TQWidget *parent, const char *name, const TQString& title) + : KSGRD::SensorDisplay(parent, name, title) +{ + monitor = new TQListBox(this); + TQ_CHECK_PTR(monitor); + + setMinimumSize(50, 25); + + setPlotterWidget(monitor); + + setModified(false); +} + +LogFile::~LogFile(void) +{ + sendRequest(sensors().at(0)->hostName(), TQString("logfile_unregister %1" ).arg(logFileID), 43); +} + +bool +LogFile::addSensor(const TQString& hostName, const TQString& sensorName, const TQString& sensorType, const TQString& title) +{ + if (sensorType != "logfile") + return (false); + + registerSensor(new KSGRD::SensorProperties(hostName, sensorName, sensorType, title)); + + TQString sensorID = sensorName.right(sensorName.length() - (sensorName.findRev("/") + 1)); + + sendRequest(sensors().at(0)->hostName(), TQString("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) +{ + TQColorGroup cgroup = monitor->colorGroup(); + + lfs = new LogFileSettings(this); + TQ_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, TQT_SIGNAL(clicked()), lfs, TQT_SLOT(accept())); + connect(lfs->applyButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(applySettings())); + connect(lfs->cancelButton, TQT_SIGNAL(clicked()), lfs, TQT_SLOT(reject())); + + connect(lfs->fontButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(settingsFontSelection())); + connect(lfs->addButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(settingsAddRule())); + connect(lfs->deleteButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(settingsDeleteRule())); + connect(lfs->changeButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(settingsChangeRule())); + connect(lfs->ruleList, TQT_SIGNAL(selected(int)), this, TQT_SLOT(settingsRuleListSelected(int))); + connect(lfs->ruleText, TQT_SIGNAL(returnPressed()), this, TQT_SLOT(settingsAddRule())); + + if (lfs->exec()) { + applySettings(); + } + + delete lfs; + lfs = 0; +} + +void LogFile::settingsFontSelection() +{ + TQFont tmpFont = lfs->fontButton->font(); + + if (TDEFontDialog::getFont(tmpFont) == TDEFontDialog::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) +{ + TQColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(TQColorGroup::Text, lfs->fgColor->color()); + cgroup.setColor(TQColorGroup::Base, lfs->bgColor->color()); + monitor->setPalette(TQPalette(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() +{ + TQColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(TQColorGroup::Text, KSGRD::Style->firstForegroundColor()); + cgroup.setColor(TQColorGroup::Base, KSGRD::Style->backgroundColor()); + monitor->setPalette(TQPalette(cgroup, cgroup, cgroup)); + + setModified(true); +} + +bool +LogFile::restoreSettings(TQDomElement& element) +{ + TQFont font; + TQColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(TQColorGroup::Text, restoreColor(element, "textColor", Qt::green)); + cgroup.setColor(TQColorGroup::Base, restoreColor(element, "backgroundColor", Qt::black)); + monitor->setPalette(TQPalette(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); + + TQDomNodeList dnList = element.elementsByTagName("filter"); + for (uint i = 0; i < dnList.count(); i++) { + TQDomElement element = dnList.item(i).toElement(); + filterRules.append(element.attribute("rule")); + } + + SensorDisplay::restoreSettings(element); + + setModified(false); + + return true; +} + +bool +LogFile::saveSettings(TQDomDocument& doc, TQDomElement& 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 (TQStringList::Iterator it = filterRules.begin(); + it != filterRules.end(); it++) + { + TQDomElement 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(), + TQString("%1 %2" ).arg(sensors().at(0)->name()).arg(logFileID), 19); +} + +void +LogFile::answerReceived(int id, const TQString& 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 (TQStringList::Iterator it = filterRules.begin(); it != filterRules.end(); it++) { + TQRegExp *expr = new TQRegExp((*it).latin1()); + if (expr->search(lines[i].latin1()) != -1) { + KNotifyClient::event(winId(), "pattern_match", TQString("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(TQResizeEvent*) +{ + 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..786cf7e60 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/LogFile.h @@ -0,0 +1,85 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef _LogFile_h +#define _LogFile_h + +#define MAXLINES 500 + +class TQFile; +class TQListBox; + +#include <tqdom.h> +#include <tqpopupmenu.h> +#include <tqstring.h> +#include <tqstringlist.h> + +#include <SensorDisplay.h> + +#include "LogFileSettings.h" + +class LogFile : public KSGRD::SensorDisplay +{ + Q_OBJECT +public: + LogFile(TQWidget *parent = 0, const char *name = 0, const TQString& title = 0); + ~LogFile(void); + + bool addSensor(const TQString& hostName, const TQString& sensorName, + const TQString& sensorType, const TQString& sensorDescr); + void answerReceived(int id, const TQString& answer); + void resizeEvent(TQResizeEvent*); + + bool restoreSettings(TQDomElement& element); + bool saveSettings(TQDomDocument& doc, TQDomElement& element, bool save = true); + + void updateMonitor(void); + + void configureSettings(void); + + virtual void timerEvent(TQTimerEvent*) + { + 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; + TQListBox* monitor; + TQStringList 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..c346dfbe3 --- /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 <[email protected]></author> +<widget class="TQDialog"> + <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="TQTabWidget"> + <property name="name"> + <cstring>TabWidget</cstring> + </property> + <widget class="TQWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Text</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQGroupBox"> + <property name="name"> + <cstring>GroupBox8</cstring> + </property> + <property name="title"> + <string>Title</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLineEdit"> + <property name="name"> + <cstring>title</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="TQButtonGroup"> + <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="TQLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Foreground color:</string> + </property> + </widget> + <widget class="TQLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + </widget> + </vbox> + </widget> + <widget class="TQLayoutWidget"> + <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="TQGroupBox"> + <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="TQPushButton"> + <property name="name"> + <cstring>fontButton</cstring> + </property> + <property name="text"> + <string>Select Font...</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="TQWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Filter</string> + </attribute> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLayoutWidget"> + <property name="name"> + <cstring>Layout7</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLineEdit"> + <property name="name"> + <cstring>ruleText</cstring> + </property> + </widget> + <widget class="TQListBox"> + <property name="name"> + <cstring>ruleList</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="TQLayoutWidget"> + <property name="name"> + <cstring>Layout9</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQPushButton"> + <property name="name"> + <cstring>addButton</cstring> + </property> + <property name="text"> + <string>&Add</string> + </property> + </widget> + <widget class="TQPushButton"> + <property name="name"> + <cstring>deleteButton</cstring> + </property> + <property name="text"> + <string>&Delete</string> + </property> + </widget> + <widget class="TQPushButton"> + <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="TQLayoutWidget"> + <property name="name"> + <cstring>Layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQPushButton"> + <property name="name"> + <cstring>okButton</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="TQPushButton"> + <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="TQPushButton"> + <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..d3f82a3a7 --- /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_TDEIO) + +# 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..111c4787b --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/MultiMeter.cc @@ -0,0 +1,258 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000, 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <math.h> +#include <stdlib.h> + +#include <tqdom.h> +#include <tqlcdnumber.h> +#include <tqtooltip.h> + +#include <kdebug.h> + +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include "MultiMeter.moc" +#include "MultiMeterSettings.h" + +MultiMeter::MultiMeter(TQWidget* parent, const char* name, + const TQString& 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 TQLCDNumber(this, "meterLCD"); + else + lcd = new TQLCDNumber(frame(), "meterLCD"); + TQ_CHECK_PTR(lcd); + lcd->setSegmentStyle(TQLCDNumber::Filled); + setDigitColor(KSGRD::Style->backgroundColor()); + lcd->setSizePolicy(TQSizePolicy(TQSizePolicy::Expanding, + TQSizePolicy::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 TQString& hostName, const TQString& sensorName, + const TQString& sensorType, const TQString& 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); + + TQToolTip::remove(lcd); + TQToolTip::add(lcd, TQString("%1:%2").arg(hostName).arg(sensorName)); + + setModified(true); + return (true); +} + +void +MultiMeter::answerReceived(int id, const TQString& 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(TQResizeEvent*) +{ + if (noFrame()) + lcd->setGeometry(0, 0, width(), height()); + else + frame()->setGeometry(0, 0, width(), height()); +} + +bool +MultiMeter::restoreSettings(TQDomElement& 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(TQDomDocument& doc, TQDomElement& 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"); + TQ_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, TQT_SIGNAL(applyClicked()), TQT_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 TQColor& col) +{ + TQPalette p = lcd->palette(); + p.setColor(TQColorGroup::Foreground, col); + lcd->setPalette(p); +} + +void +MultiMeter::setBackgroundColor(const TQColor& col) +{ + lcd->setBackgroundColor(col); + + TQPalette p = lcd->palette(); + p.setColor(TQColorGroup::Light, col); + p.setColor(TQColorGroup::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..49a97dbd7 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/MultiMeter.h @@ -0,0 +1,79 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef _MultiMeter_h_ +#define _MultiMeter_h_ + +#include <SensorDisplay.h> + +class TQGroupBox; +class TQLCDNumber; +class TQLabel; +class MultiMeterSettings; + +class MultiMeter : public KSGRD::SensorDisplay +{ + Q_OBJECT + +public: + MultiMeter(TQWidget* parent = 0, const char* name = 0, + const TQString& = TQString::null, double min = 0, double max = 0, bool nf = false, bool isApplet = false); + virtual ~MultiMeter() + { + } + + bool addSensor(const TQString& hostName, const TQString& sensorName, + const TQString& sensorType, const TQString& sensorDescr); + void answerReceived(int id, const TQString& answer); + void resizeEvent(TQResizeEvent*); + + bool restoreSettings(TQDomElement& element); + bool saveSettings(TQDomDocument& doc, TQDomElement& element, bool save = true); + + virtual bool hasSettingsDialog() const + { + return (true); + } + + void configureSettings(); + +public slots: + void applySettings(); + void applyStyle(); + +private: + void setDigitColor(const TQColor& col); + void setBackgroundColor(const TQColor& col); + + TQLCDNumber* lcd; + TQColor normalDigitColor; + TQColor 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..903369889 --- /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 <[email protected]> + + 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 <tdelocale.h> + +MultiMeterSettings::MultiMeterSettings( TQWidget *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 ); +} + +TQString 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(); +} + +TQColor MultiMeterSettings::normalDigitColor() +{ + return m_settingsWidget->normalDigitColor(); +} + +TQColor MultiMeterSettings::alarmDigitColor() +{ + return m_settingsWidget->alarmDigitColor(); +} + +TQColor MultiMeterSettings::meterBackgroundColor() +{ + return m_settingsWidget->meterBackgroundColor(); +} + +void MultiMeterSettings::setTitle( const TQString &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 TQColor &c ) +{ + m_settingsWidget->setNormalDigitColor( c ); +} + +void MultiMeterSettings::setAlarmDigitColor( const TQColor &c ) +{ + m_settingsWidget->setAlarmDigitColor( c ); +} + +void MultiMeterSettings::setMeterBackgroundColor( const TQColor &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..e05946a08 --- /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 <[email protected]> + + 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 <tqstring.h> +#include <tqcolor.h> + +class MultiMeterSettingsWidget; + +class MultiMeterSettings : public KDialogBase +{ + Q_OBJECT + + public: + + MultiMeterSettings( TQWidget *parent=0, const char *name=0 ); + + TQString title(); + bool showUnit(); + bool lowerLimitActive(); + bool upperLimitActive(); + double lowerLimit(); + double upperLimit(); + TQColor normalDigitColor(); + TQColor alarmDigitColor(); + TQColor meterBackgroundColor(); + + void setTitle( const TQString & ); + void setShowUnit( bool ); + void setLowerLimitActive( bool ); + void setUpperLimitActive( bool ); + void setLowerLimit( double ); + void setUpperLimit( double ); + void setNormalDigitColor( const TQColor & ); + void setAlarmDigitColor( const TQColor & ); + void setMeterBackgroundColor( const TQColor & ); + + 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..4558e2374 --- /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="TQWidget"> + <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="TQGroupBox"> + <property name="name"> + <cstring>GroupBox7</cstring> + </property> + <property name="title"> + <string>Title</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLineEdit" 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="TQCheckBox" 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="TQTabWidget"> + <property name="name"> + <cstring>TabWidget2</cstring> + </property> + <widget class="TQWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Alarms</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQGroupBox" 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="TQCheckBox" 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="TQLabel" 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="TQLineEdit" 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="TQGroupBox" 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="TQCheckBox" 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="TQLabel" 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="TQLineEdit" 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="TQWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Colors</string> + </attribute> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Normal digit color:</string> + </property> + </widget> + <widget class="TQLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Alarm digit color:</string> + </property> + </widget> + <widget class="TQLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + </widget> + </vbox> + </widget> + <widget class="TQLayoutWidget"> + <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(TQObject*)</signal> + <signal>pressed()</signal> + <signal>released()</signal> + <signal>clicked()</signal> + <signal>toggled(bool)</signal> + <signal>stateChanged(int)</signal> + <signal>changed(const TQColor&)</signal> + <slot access="public" specifier="">deleteLater()</slot> + <slot access="private" specifier="">cleanupEventFilter(TQObject*)</slot> + <slot access="public" specifier="">setEnabled(bool)</slot> + <slot access="public" specifier="">setDisabled(bool)</slot> + <slot access="public" specifier="">setCaption(const TQString&)</slot> + <slot access="public" specifier="">setIcon(const TQPixmap&)</slot> + <slot access="public" specifier="">setIconText(const TQString&)</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 TQRect&)</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 TQRect&)</slot> + <slot access="public" specifier="">repaint(const TQRect&,bool)</slot> + <slot access="public" specifier="">repaint(const TQRegion&)</slot> + <slot access="public" specifier="">repaint(const TQRegion&,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(TQWidget*)</slot> + <slot access="public" specifier="">move(int,int)</slot> + <slot access="public" specifier="">move(const TQPoint&)</slot> + <slot access="public" specifier="">resize(int,int)</slot> + <slot access="public" specifier="">resize(const TQSize&)</slot> + <slot access="public" specifier="">setGeometry(int,int,int,int)</slot> + <slot access="public" specifier="">setGeometry(const TQRect&)</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> +<Q_SLOTS> + <slot>setMeterBackgroundColor( const TQColor & c )</slot> +</Q_SLOTS> +<functions> + <function access="private" specifier="non virtual">init()</function> + <function specifier="non virtual" returnType="TQString">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="TQColor">normalDigitColor()</function> + <function specifier="non virtual" returnType="TQColor">alarmDigitColor()</function> + <function returnType="TQColor">meterBackgroundColor()</function> + <function specifier="non virtual">setTitle( const TQString & 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 TQColor & c )</function> + <function specifier="non virtual">setAlarmDigitColor( const TQColor & 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..fe88f292f --- /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(TQT_TQOBJECT(m_lowerLimit))); + m_upperLimit->setValidator(new KDoubleValidator(TQT_TQOBJECT(m_upperLimit))); + + m_title->setFocus(); +} + +TQString 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(); +} + + +TQColor MultiMeterSettingsWidget::normalDigitColor() +{ + return m_normalDigitColor->color(); +} + + +TQColor MultiMeterSettingsWidget::alarmDigitColor() +{ + return m_alarmDigitColor->color(); +} + + +TQColor MultiMeterSettingsWidget::meterBackgroundColor() +{ + return m_backgroundColor->color(); +} + + +void MultiMeterSettingsWidget::setTitle( const TQString &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(TQString("%1").arg(d)); +} + + +void MultiMeterSettingsWidget::setUpperLimitActive( bool b ) +{ + m_upperLimitActive->setChecked(b); +} + + +void MultiMeterSettingsWidget::setUpperLimit( double d ) +{ + m_upperLimit->setText(TQString("%1").arg(d)); +} + + +void MultiMeterSettingsWidget::setNormalDigitColor( const TQColor &c ) +{ + m_normalDigitColor->setColor(c); +} + + +void MultiMeterSettingsWidget::setAlarmDigitColor( const TQColor &c ) +{ + m_alarmDigitColor->setColor(c); +} + + +void MultiMeterSettingsWidget::setMeterBackgroundColor( const TQColor &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..8daaeacf7 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ProcessController.cc @@ -0,0 +1,472 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms 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 <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <assert.h> + +#include <tqtimer.h> + +#include <tdeapplication.h> +#include <kdebug.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <kdialogbase.h> +#include <tdelistviewsearchline.h> + +#include <ksgrd/SensorManager.h> + +#include "ProcessController.moc" +#include "SignalIDs.h" + +#include <tqcheckbox.h> +#include <tqcombobox.h> +#include <tqgroupbox.h> +#include <tqlayout.h> + +#include <tdeapplication.h> +#include <kpushbutton.h> + + + +ProcessController::ProcessController(TQWidget* parent, const char* name, const TQString &title, bool nf) + : KSGRD::SensorDisplay(parent, name, title, nf) +{ + dict.setAutoDelete(true); + dict.insert("Name", new TQString(i18n("Name"))); + dict.insert("PID", new TQString(i18n("PID"))); + dict.insert("PPID", new TQString(i18n("PPID"))); + dict.insert("UID", new TQString(i18n("UID"))); + dict.insert("GID", new TQString(i18n("GID"))); + dict.insert("Status", new TQString(i18n("Status"))); + dict.insert("User%", new TQString(i18n("User%"))); + dict.insert("System%", new TQString(i18n("System%"))); + dict.insert("Nice", new TQString(i18n("Nice"))); + dict.insert("VmSize", new TQString(i18n("VmSize"))); + dict.insert("VmRss", new TQString(i18n("VmRss"))); + dict.insert("Login", new TQString(i18n("Login"))); + dict.insert("Command", new TQString(i18n("Command"))); + + // Setup the geometry management. + gm = new TQVBoxLayout(this, 10); + TQ_CHECK_PTR(gm); + gm->addSpacing(15); + + gmSearch = new TQHBoxLayout(); + TQ_CHECK_PTR(gmSearch); + gm->addLayout(gmSearch, 0); + + // Create the table that lists the processes. + pList = new ProcessList(this, "pList"); + TQ_CHECK_PTR(pList); + pList->setShowSortIndicator(true); + pListSearchLine = new TDEListViewSearchLineWidget(pList, this, "process_list_search_line"); + gmSearch->addWidget(pListSearchLine, 1); + + connect(pList, TQT_SIGNAL(killProcess(int, int)), + this, TQT_SLOT(killProcess(int, int))); + connect(pList, TQT_SIGNAL(reniceProcess(const TQValueList<int> &, int)), + this, TQT_SLOT(reniceProcess(const TQValueList<int> &, int))); + connect(pList, TQT_SIGNAL(listModified(bool)), + this, TQT_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 TQComboBox(this, "pList_cbFilter"); + TQ_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 TQCheckBox(i18n("&Tree"), this, "xbTreeView"); + TQ_CHECK_PTR(xbTreeView); + xbTreeView->setMinimumSize(xbTreeView->sizeHint()); + connect(xbTreeView, TQT_SIGNAL(toggled(bool)), + this, TQT_SLOT(setTreeView(bool))); + + + /* When the both cbFilter and pList are constructed we can connect the + * missing link. */ + connect(cbFilter, TQT_SIGNAL(activated(int)), + this, TQT_SLOT(filterModeChanged(int))); + + // Create the 'Refresh' button. + bRefresh = new KPushButton( KGuiItem( i18n( "&Refresh" ), "reload" ), + this, "bRefresh" ); + TQ_CHECK_PTR(bRefresh); + bRefresh->setMinimumSize(bRefresh->sizeHint()); + connect(bRefresh, TQT_SIGNAL(clicked()), this, TQT_SLOT(updateList())); + + // Create the 'Kill' button. + bKill = new KPushButton(i18n("&Kill"), this, "bKill"); + TQ_CHECK_PTR(bKill); + bKill->setMinimumSize(bKill->sizeHint()); + connect(bKill, TQT_SIGNAL(clicked()), this, TQT_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 TQHBoxLayout(); + TQ_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()) + TQTimer::singleShot(100, this, TQT_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()) + TQTimer::singleShot(100, this, TQT_SLOT(fixTabOrder())); + else { + setTabOrder(pListSearchLine->searchLine(), cbFilter); + setTabOrder(cbFilter, pList); + setTabOrder(pList, xbTreeView); + setTabOrder(xbTreeView, bRefresh); + setTabOrder(bRefresh, bKill); + } +} + +void +ProcessController::resizeEvent(TQResizeEvent* ev) +{ + if(frame()) + frame()->setGeometry(0, 0, width(), height()); + + TQWidget::resizeEvent(ev); +} + +bool +ProcessController::addSensor(const TQString& hostName, + const TQString& sensorName, + const TQString& sensorType, + const TQString& 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(), + TQString("kill %1 %2" ).arg(pid).arg(sig), 3); + + if ( !timerOn() ) + // give ksysguardd time to update its proccess list + TQTimer::singleShot(3000, this, TQT_SLOT(updateList())); + else + updateList(); +} + +void +ProcessController::killProcess() +{ + const TQStringList& selectedAsStrings = pList->getSelectedAsStrings(); + if (selectedAsStrings.isEmpty()) + { + KMessageBox::sorry(this, + i18n("You need to select a process first.")); + return; + } + else + { + TQString 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, TQMessageBox::Question, + msg, selectedAsStrings, + i18n("Do not ask again"), &dontAgain, + KMessageBox::Notify); + + if (res != KDialogBase::Yes) + { + return; + } + } + + const TQValueList<int>& selectedPIds = pList->getSelectedPIds(); + + // send kill signal to all seleted processes + TQValueListConstIterator<int> it; + for (it = selectedPIds.begin(); it != selectedPIds.end(); ++it) + sendRequest(sensors().at(0)->hostName(), TQString("kill %1 %2" ).arg(*it) + .arg(MENU_ID_SIGKILL), 3); + + if ( !timerOn()) + // give ksysguardd time to update its proccess list + TQTimer::singleShot(3000, this, TQT_SLOT(updateList())); + else + updateList(); +} + +void +ProcessController::reniceProcess(const TQValueList<int> &pids, int niceValue) +{ + for( TQValueList<int>::ConstIterator it = pids.constBegin(), end = pids.constEnd(); it != end; ++it ) + sendRequest(sensors().at(0)->hostName(), + TQString("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 TQString& 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++) + { + TQString 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(TQDomElement& element) +{ + bool result = addSensor(element.attribute("hostName"), + element.attribute("sensorName"), (element.attribute("sensorType").isEmpty() ? "table" : element.attribute("sensorType")), + TQString::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(TQDomDocument& doc, TQDomElement& 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..848d77294 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ProcessController.h @@ -0,0 +1,154 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef _ProcessController_h_ +#define _ProcessController_h_ + +#include <tqdict.h> +#include <tqwidget.h> + +#include <tdeapplication.h> + +#include <SensorDisplay.h> + +#include "ProcessList.h" + +class TQVBoxLayout; +class TQHBoxLayout; +class TQCheckBox; +class TQComboBox; +class KPushButton; +class TDEListViewSearchLineWidget; + +extern TDEApplication* 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(TQWidget* parent = 0, const char* name = 0, const TQString &title = TQString::null, bool nf = false); + virtual ~ProcessController() { } + + void resizeEvent(TQResizeEvent*); + + bool restoreSettings(TQDomElement& element); + + bool saveSettings(TQDomDocument& doc, TQDomElement& element, bool save = true); + + void refreshList(void) + { + updateList(); + } + + virtual void timerEvent(TQTimerEvent*) + { + updateList(); + } + + virtual bool addSensor(const TQString&, const TQString&, const TQString&, const TQString&); + + virtual void answerReceived(int id, const TQString& 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 TQValueList<int> &pids, int niceValue); + + void updateList(); + +signals: + void setFilterMode(int); + +private: + TQVBoxLayout* gm; + + bool killSupported; + + /// The process list. + ProcessList* pList; + ///Layout for the search line and process filter combo box + TQHBoxLayout* gmSearch; + TDEListViewSearchLineWidget *pListSearchLine; + + TQHBoxLayout* gm1; + + /// Checkbox to switch between tree and list view + TQCheckBox* xbTreeView; + + /// This combo boxes control the process filter. + TQComboBox* cbFilter; + + /// These buttons force an immedeate refresh or kill a process. + KPushButton* bRefresh; + KPushButton* bKill; + + /// Dictionary for header translations. + TQDict<TQString> dict; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/ProcessList.cc b/ksysguard/gui/SensorDisplayLib/ProcessList.cc new file mode 100644 index 000000000..9293ef6a0 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ProcessList.cc @@ -0,0 +1,977 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (C) 1997 Bernd Johannes Wuebben + + Copyright (C) 1998 Nicolas Leclercq <[email protected]> + + Copyright (c) 1999, 2000, 2001, 2002 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#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 <tqbitmap.h> +#include <tqheader.h> +#include <tqimage.h> +#include <tqpopupmenu.h> + +#include <kdebug.h> +#include <tdeglobal.h> +#include <tdelocale.h> +#include <tdemessagebox.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); + +TQDict<TQString> ProcessList::aliases; + +int ProcessLVI::compare( TQListViewItem *item, int col, bool ascending ) const +{ + int type = ((ProcessList*)listView())->columnType( col ); + + if ( type == ProcessList::Int ) { + int prev = (int)TDEGlobal::locale()->readNumber( key( col, ascending ) ); + int next = (int)TDEGlobal::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 = TDEGlobal::locale()->readNumber( key( col, ascending ) ); + double next = TDEGlobal::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(TQWidget *parent, const char* name) + : TDEListView(parent, name) +{ + iconCache.setAutoDelete(true); + + columnDict.setAutoDelete(true); + columnDict.insert("running", + new TQString(i18n("process status", "running"))); + columnDict.insert("sleeping", + new TQString(i18n("process status", "sleeping"))); + columnDict.insert("disk sleep", + new TQString(i18n("process status", "disk sleep"))); + columnDict.insert("zombie", new TQString(i18n("process status", "zombie"))); + columnDict.insert("stopped", + new TQString(i18n("process status", "stopped"))); + columnDict.insert("paging", new TQString(i18n("process status", "paging"))); + columnDict.insert("idle", new TQString(i18n("process status", "idle"))); + + if (aliases.isEmpty()) + { +#ifdef Q_OS_LINUX + aliases.insert("init", new TQString("penguin")); +#else + aliases.insert("init", new TQString("system")); +#endif + /* kernel stuff */ + aliases.insert("bdflush", new TQString("kernel")); + aliases.insert("dhcpcd", new TQString("kernel")); + aliases.insert("kapm-idled", new TQString("kernel")); + aliases.insert("keventd", new TQString("kernel")); + aliases.insert("khubd", new TQString("kernel")); + aliases.insert("klogd", new TQString("kernel")); + aliases.insert("kreclaimd", new TQString("kernel")); + aliases.insert("kreiserfsd", new TQString("kernel")); + aliases.insert("ksoftirqd_CPU0", new TQString("kernel")); + aliases.insert("ksoftirqd_CPU1", new TQString("kernel")); + aliases.insert("ksoftirqd_CPU2", new TQString("kernel")); + aliases.insert("ksoftirqd_CPU3", new TQString("kernel")); + aliases.insert("ksoftirqd_CPU4", new TQString("kernel")); + aliases.insert("ksoftirqd_CPU5", new TQString("kernel")); + aliases.insert("ksoftirqd_CPU6", new TQString("kernel")); + aliases.insert("ksoftirqd_CPU7", new TQString("kernel")); + aliases.insert("kswapd", new TQString("kernel")); + aliases.insert("kupdated", new TQString("kernel")); + aliases.insert("mdrecoveryd", new TQString("kernel")); + aliases.insert("scsi_eh_0", new TQString("kernel")); + aliases.insert("scsi_eh_1", new TQString("kernel")); + aliases.insert("scsi_eh_2", new TQString("kernel")); + aliases.insert("scsi_eh_3", new TQString("kernel")); + aliases.insert("scsi_eh_4", new TQString("kernel")); + aliases.insert("scsi_eh_5", new TQString("kernel")); + aliases.insert("scsi_eh_6", new TQString("kernel")); + aliases.insert("scsi_eh_7", new TQString("kernel")); + /* daemon and other service providers */ + aliases.insert("artsd", new TQString("daemon")); + aliases.insert("atd", new TQString("daemon")); + aliases.insert("automount", new TQString("daemon")); + aliases.insert("cardmgr", new TQString("daemon")); + aliases.insert("cron", new TQString("daemon")); + aliases.insert("cupsd", new TQString("daemon")); + aliases.insert("in.identd", new TQString("daemon")); + aliases.insert("lpd", new TQString("daemon")); + aliases.insert("mingetty", new TQString("daemon")); + aliases.insert("nscd", new TQString("daemon")); + aliases.insert("portmap", new TQString("daemon")); + aliases.insert("rpc.statd", new TQString("daemon")); + aliases.insert("rpciod", new TQString("daemon")); + aliases.insert("sendmail", new TQString("daemon")); + aliases.insert("sshd", new TQString("daemon")); + aliases.insert("syslogd", new TQString("daemon")); + aliases.insert("usbmgr", new TQString("daemon")); + aliases.insert("wwwoffled", new TQString("daemon")); + aliases.insert("xntpd", new TQString("daemon")); + aliases.insert("ypbind", new TQString("daemon")); + aliases.insert("apmd", new TQString("daemon")); + aliases.insert("getty", new TQString("daemon")); + aliases.insert("mountd", new TQString("daemon")); + aliases.insert("inetd", new TQString("daemon")); + aliases.insert("nfsd", new TQString("daemon")); + aliases.insert("wsmoused", new TQString("daemon")); + /* kde applications */ + aliases.insert("appletproxy", new TQString("tdeapp")); + aliases.insert("dcopserver", new TQString("tdeapp")); + aliases.insert("kcookiejar", new TQString("tdeapp")); + aliases.insert("kde", new TQString("tdeapp")); + aliases.insert("kded", new TQString("tdeapp")); + aliases.insert("tdeinit", new TQString("tdeapp")); + aliases.insert("kdesktop", new TQString("tdeapp")); + aliases.insert("tdesud", new TQString("tdeapp")); + aliases.insert("tdm", new TQString("tdeapp")); + aliases.insert("khotkeys", new TQString("tdeapp")); + aliases.insert("tdeio_file", new TQString("tdeapp")); + aliases.insert("tdeio_uiserver", new TQString("tdeapp")); + aliases.insert("tdelauncher", new TQString("tdeapp")); + aliases.insert("ksmserver", new TQString("tdeapp")); + aliases.insert("kwrapper", new TQString("tdeapp")); + aliases.insert("kwrited", new TQString("tdeapp")); + aliases.insert("kxmlrpcd", new TQString("tdeapp")); + aliases.insert("starttde", new TQString("tdeapp")); + /* other processes */ + aliases.insert("bash", new TQString("shell")); + aliases.insert("cat", new TQString("tools")); + aliases.insert("egrep", new TQString("tools")); + aliases.insert("emacs", new TQString("application-vnd.oasis.opendocument.text")); + aliases.insert("fgrep", new TQString("tools")); + aliases.insert("find", new TQString("tools")); + aliases.insert("grep", new TQString("tools")); + aliases.insert("ksh", new TQString("shell")); + aliases.insert("screen", new TQString("openterm")); + aliases.insert("sh", new TQString("shell")); + aliases.insert("sort", new TQString("tools")); + aliases.insert("ssh", new TQString("shell")); + aliases.insert("su", new TQString("tools")); + aliases.insert("tcsh", new TQString("shell")); + aliases.insert("tee", new TQString("tools")); + aliases.insert("vi", new TQString("application-vnd.oasis.opendocument.text")); + aliases.insert("vim", new TQString("application-vnd.oasis.opendocument.text")); + } + + /* The filter mode is controlled by a combo box of the parent. If + * the mode is changed we get a signal. */ + connect(parent, TQT_SIGNAL(setFilterMode(int)), + this, TQT_SLOT(setFilterMode(int))); + + /* We need to catch this signal to show various popup menues. */ + connect(this, + TQT_SIGNAL(rightButtonPressed(TQListViewItem*, const TQPoint&, int)), + this, + TQT_SLOT(handleRMBPressed(TQListViewItem*, const TQPoint&, 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(), TQT_SIGNAL(clicked(int)), this, TQT_SLOT(sortingChanged(int))); + + ctrlKeyDown = false; + shiftKeyDown = false; + 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(TQListView::Extended); + + // Create popup menu for RMB clicks on table header + headerPM = new TQPopupMenu(); + headerPM->insertItem(i18n("Remove Column"), HEADER_REMOVE); + headerPM->insertItem(i18n("Add Column"), HEADER_ADD); + headerPM->insertItem(i18n("Help on Column"), HEADER_HELP); + + connect(header(), TQT_SIGNAL(sizeChange(int, int, int)), + this, TQT_SLOT(sizeChanged(int, int, int))); + connect(header(), TQT_SIGNAL(indexChange(int, int, int)), + this, TQT_SLOT(indexChanged(int, int, int))); + + killSupported = false; + setModified(false); +} + +ProcessList::~ProcessList() +{ + delete(headerPM); +} + +const TQValueList<int>& +ProcessList::getSelectedPIds() +{ + selectedPIds.clear(); + // iterate through all selected visible items of the listview + TQListViewItemIterator it(this, TQListViewItemIterator::Visible | TQListViewItemIterator::Selected ); + for ( ; it.current(); ++it ) + selectedPIds.append(it.current()->text(1).toInt()); + + return (selectedPIds); +} + +const TQStringList& +ProcessList::getSelectedAsStrings() +{ + selectedAsStrings.clear(); + // iterate through all selected visible items of the listview + TQListViewItemIterator it(this, TQListViewItemIterator::Visible | TQListViewItemIterator::Selected ); + TQString spaces; + for ( ; it.current(); ++it ) { + spaces.fill(TQChar(' '), 7 - it.current()->text(1).length()); + selectedAsStrings.append("(PID: " + it.current()->text(1) + ")" + spaces + " " + it.current()->text(0)); + } + + return (selectedAsStrings); +} +bool +ProcessList::update(const TQString& list) +{ + if ((!shiftKeyDown) && (!ctrlKeyDown)) + { + /* 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; + TQString 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(); + + TQListViewItemIterator 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(TQDomElement& el) +{ + TQDomNodeList dnList = el.elementsByTagName("column"); + for (uint i = 0; i < dnList.count(); ++i) + { + TQDomElement 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(TQDomDocument& doc, TQDomElement& display) +{ + for (int i = 0; i < columns(); ++i) + { + TQDomElement 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 TQListView 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(TQPtrList<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) +{ + TQString name = p->name(); + if (aliases[name]) + name = *aliases[name]; + + /* Get icon from icon list that might be appropriate for a process + * with this name. */ + TQPixmap pix; + if (!iconCache[name]) + { + pix = TDEGlobal::iconLoader()->loadIcon(name, TDEIcon::Small, + TDEIcon::SizeSmall, TDEIcon::DefaultState, + 0L, true); + if (pix.isNull() || !pix.mask()) + pix = TDEGlobal::iconLoader()->loadIcon("unknownapp", TDEIcon::User, + TDEIcon::SizeSmall); + + if (pix.width() != 16 || pix.height() != 16) + { + /* I guess this isn't needed too often. The TDEIconLoader 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. */ + TQImage 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. */ + TQPixmap icon(24, 16, pix.depth()); + if (!treeViewEnabled) + { + icon.fill(); + bitBlt(&icon, 4, 0, &pix, 0, 0, pix.width(), pix.height()); + TQBitmap 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 TQPixmap(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, TDEGlobal::locale()->formatNumber( (*p)[col].toFloat() ) ); + else if ( mColumnTypes[col] == "D" ) + pli->setText( col, TDEGlobal::locale()->formatNumber( (*p)[col].toInt(), 0 ) ); + else + pli->setText(col, (*p)[col]); + } +} + +void +ProcessList::updateMetaInfo(void) +{ + selectedPIds.clear(); + closedSubTrees.clear(); + + TQListViewItemIterator 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 TQListView. + * 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 TQString& label, const TQString& type) +{ + TQListView::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. */ + TQFontMetrics 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 ? + TQListView::Manual : TQListView::Maximum); + header()->moveSection(i, index[i]); + } + setSorting(sortColumn, increasing); + } +} + +void +ProcessList::handleRMBPressed(TQListViewItem* lvi, const TQPoint& 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 (TQString::compare(header()->label(i), i18n("Nice")) == 0) + currentNiceValue = lvi->text(i).toInt(); + + TQPopupMenu processPM; + if (columnWidth(col) != 0) + processPM.insertItem(i18n("Hide Column"), 5); + TQPopupMenu* hiddenPM = new TQPopupMenu(&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); + + TQPopupMenu* signalPM = new TQPopupMenu(&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, TQListView::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(); + TQListViewItemIterator it(this, TQListViewItemIterator::Visible | TQListViewItemIterator::Selected); + + // iterate through all selected visible items of the listview + for ( ; it.current(); ++it ) + { + selectedPIds.append(it.current()->text(1).toInt()); + } + + TQString 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, TQString::null, i18n("Send"), KStdGuiItem::cancel())) + { + case KMessageBox::Yes: + { + TQValueList<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, TQListView::Maximum); + setColumnWidth(col, savedWidth[col]); + setModified(true); + } + } +} + +void +ProcessList::selectAllItems(bool select) +{ + selectedPIds.clear(); + + TQListViewItemIterator it(this, TQListViewItemIterator::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) +{ + TQListViewItemIterator it(this, TQListViewItemIterator::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); + } + } +} + +void +ProcessList::keyPressEvent(TQKeyEvent *e) +{ + if (e->key() == Key_Shift) { + shiftKeyDown = true; + } + if (e->key() == Key_Control) { + ctrlKeyDown = true; + } + TDEListView::keyPressEvent(e); +} + +void +ProcessList::keyReleaseEvent(TQKeyEvent *e) +{ + if (e->key() == Key_Shift) { + shiftKeyDown = false; + } + if (e->key() == Key_Control) { + ctrlKeyDown = false; + } + TDEListView::keyReleaseEvent(e); +} + +#include "ProcessList.moc" diff --git a/ksysguard/gui/SensorDisplayLib/ProcessList.h b/ksysguard/gui/SensorDisplayLib/ProcessList.h new file mode 100644 index 000000000..51ac510e2 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ProcessList.h @@ -0,0 +1,276 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me + first. Thanks! + + */ + +#ifndef _ProcessList_h_ +#define _ProcessList_h_ + +#include <tqdict.h> +#include <tqdom.h> +#include <tqstringlist.h> +#include <tqvaluelist.h> +#include <tqwidget.h> + +#include <kiconloader.h> +#include <tdelistview.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 TQListViewItem. + */ +class ProcessLVI : public TDEListViewItem +{ +public: + ProcessLVI(TQListView* lv) : TDEListViewItem(lv) { } + ProcessLVI(TQListViewItem* lvi) : TDEListViewItem(lvi) { } + + virtual int compare( TQListViewItem *item, int column, bool ) const; +}; + +class TQPopupMenu; + +/** + * This class implementes a table filled with information about the running + * processes. The table is derived from TQListView. + */ +class ProcessList : public TDEListView +{ + 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(TQWidget* parent = 0, const char* name = 0); + + /// The destructor. + ~ProcessList(); + + void removeColumns(); + + void addColumn(const TQString& header, const TQString& 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 TQValueList<int>& getSelectedPIds(); + const TQStringList& 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 TQString& list); + + int columnType( uint col ) const; + + void setSensorOk(bool ok); + + void setKillSupported(bool supported) + { + killSupported = supported; + } + + bool load(TQDomElement& el); + bool save(TQDomDocument& doc, TQDomElement& 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(TQListViewItem* lvi, const TQPoint& 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 TQValueList<int> &pids, int niceValue); + + void listModified(bool); + +protected: + void keyPressEvent(TQKeyEvent *e); + void keyReleaseEvent(TQKeyEvent *e); + +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 + * TQListView 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(TQPtrList<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; + bool ctrlKeyDown; + bool shiftKeyDown; + + /* The following lists are primarily used to store table specs between + * load() and the actual table creation in addColumn(). */ + TQValueList<int> savedWidth; + TQValueList<int> currentWidth; + TQValueList<int> index; + + TQPtrList<KSGRD::SensorPSLine> pl; + + TQStringList mColumnTypes; + TQDict<TQString> columnDict; + + TQValueList<int> selectedPIds; + TQValueList<int> closedSubTrees; + TQStringList selectedAsStrings; + + static TQDict<TQString> aliases; + + TQDict<TQPixmap> iconCache; + + TQPopupMenu* headerPM; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/ReniceDlg.cc b/ksysguard/gui/SensorDisplayLib/ReniceDlg.cc new file mode 100644 index 000000000..e71c6e0a0 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ReniceDlg.cc @@ -0,0 +1,70 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <[email protected]> + + 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 <[email protected]>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#include <tdelocale.h> +#include <knuminput.h> + +#include "ReniceDlg.moc" + +ReniceDlg::ReniceDlg(TQWidget* parent, const char* name, int currentPPrio, + int pid) + : KDialogBase( parent, name, true, i18n("Renice Process"), + KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true ) +{ + TQWidget *page = new TQWidget( this ); + setMainWidget(page); + vLay = new TQVBoxLayout(page, 20, -1, "ReniceLayout"); + + TQString 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 TQLabel(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); +} + +ReniceDlg::~ReniceDlg() { + // +} + +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..a9d506eb7 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ReniceDlg.h @@ -0,0 +1,62 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <[email protected]> + + 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 <[email protected]>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef _ReniceDlg_h_ +#define _ReniceDlg_h_ + +#include <kdialogbase.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqlcdnumber.h> +#include <tqpushbutton.h> +#include <tqslider.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(TQWidget* parent, const char* name, int currentPPrio, int pid); + virtual ~ReniceDlg(); + +public slots: + void slotOk(); + void slotCancel(); + +private: + TQBoxLayout* vLay; + TQBoxLayout* butLay; + TQBoxLayout* sldLay; + + TQLabel* message; + KIntNumInput* input; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/SensorDisplay.cc b/ksysguard/gui/SensorDisplayLib/SensorDisplay.cc new file mode 100644 index 000000000..4dfff7957 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorDisplay.cc @@ -0,0 +1,611 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <tqcheckbox.h> +#include <tqdom.h> +#include <tqpopupmenu.h> +#include <tqspinbox.h> +#include <tqwhatsthis.h> +#include <tqbitmap.h> + +#include <tdeapplication.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <krun.h> +#include <kservice.h> + +#include "SensorManager.h" +#include "TimerSettings.h" + +#include "SensorDisplay.h" + +using namespace KSGRD; + +SensorDisplay::SensorDisplay( TQWidget *parent, const char *name, + const TQString &title, bool nf, bool isApplet) + : TQWidget( 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 ); + TQWhatsThis::add( this, "dummy" ); + + if(!nf) { + mFrame = new TQGroupBox( 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() ) ) { + TQString 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( TQTimerEvent* ) +{ + int i = 0; + for ( SensorProperties *s = mSensors.first(); s; s = mSensors.next(), ++i ) + sendRequest( s->hostName(), s->name(), i ); +} + +void SensorDisplay::resizeEvent( TQResizeEvent* ) +{ + if(mFrame) + mFrame->setGeometry( rect() ); +} + +bool SensorDisplay::eventFilter( TQObject *object, TQEvent *event ) +{ + if ( event->type() == TQEvent::MouseButtonPress && + ( (TQMouseEvent*)event)->button() == Qt::RightButton ) { + TQPopupMenu 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( TQCursor::pos() ) ) { + case 1: + KRun::run(*KService::serviceByDesktopName("ksysguard"), KURL::List()); + break; + case 2: + configureSettings(); + break; + case 3: { + TQCustomEvent *e = new TQCustomEvent( TQEvent::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() == TQEvent::MouseButtonRelease && + ( ( TQMouseEvent*)event)->button() == Qt::LeftButton ) { + setFocus(); + } + + return TQWidget::eventFilter( object, event ); +} + +void SensorDisplay::sendRequest( const TQString &hostName, + const TQString &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() +{ + TQWhatsThis::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( TQStringList& list ) +{ + for ( SensorProperties *s = mSensors.first(); s; s = mSensors.next() ) + if ( !list.contains( s->hostName() ) ) + list.append( s->hostName() ); +} + +TQColor SensorDisplay::restoreColor( TQDomElement &element, const TQString &attr, + const TQColor& fallback ) +{ + bool ok; + uint c = element.attribute( attr ).toUInt( &ok ); + if ( !ok ) + return fallback; + else + return TQColor( (c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF ); +} + +void SensorDisplay::saveColor( TQDomElement &element, const TQString &attr, + const TQColor &color ) +{ + int r, g, b; + color.rgb( &r, &g, &b ); + element.setAttribute( attr, (r << 16) | (g << 8) | b ); +} + +bool SensorDisplay::addSensor( const TQString &hostName, const TQString &name, + const TQString &type, const TQString &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; +} + +TQString SensorDisplay::additionalWhatsThis() +{ + return TQString::null; +} + +void SensorDisplay::sensorLost( int reqId ) +{ + sensorError( reqId, true ); +} + +bool SensorDisplay::restoreSettings( TQDomElement &element ) +{ + TQString str = element.attribute( "showUnit", "X" ); + if(!str.isEmpty() && str != "X") { + mShowUnit = str.toInt(); + } + str = element.attribute( "unit", TQString::null ); + if(!str.isEmpty()) + setUnit(str); + str = element.attribute( "title", TQString::null ); + if(!str.isEmpty()) + setTitle(str); + + if ( element.attribute( "updateInterval" ) != TQString::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( TQDomDocument&, TQDomElement &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; +} + +TQPtrList<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; + + TQPixmap errorIcon = TDEGlobal::iconLoader()->loadIcon( "connect_creating", TDEIcon::Desktop, + TDEIcon::SizeSmall ); + if ( !mPlotterWdg ) + return; + + mErrorIndicator = new TQWidget( 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 TQString &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. */ + TQSize s = mFrame->size(); + + if ( mShowUnit && !mUnit.isEmpty() ) + mFrame->setTitle( mTitle + " [" + mUnit + "]" ); + else + mFrame->setTitle( mTitle ); + mFrame->setGeometry( 0, 0, s.width(), s.height() ); +} + +TQString SensorDisplay::title() const +{ + return mTitle; +} + +void SensorDisplay::setUnit( const TQString &unit ) +{ + mUnit = unit; +} + +TQString SensorDisplay::unit() const +{ + return mUnit; +} + +void SensorDisplay::setShowUnit( bool value ) +{ + mShowUnit = value; +} + +bool SensorDisplay::showUnit() const +{ + return mShowUnit; +} + +void SensorDisplay::setPlotterWidget( TQWidget *wdg ) +{ + mPlotterWdg = wdg; + +} + +TQWidget *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 TQValueList<int> &orderOfSensors) +{ + TQPtrList<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 TQString &hostName, const TQString &name, + const TQString &type, const TQString &description ) + : mHostName( hostName ), mName( name ), mType( type ), mDescription( description ) +{ + mOk = false; +} + +SensorProperties::~SensorProperties() +{ +} + +void SensorProperties::setHostName( const TQString &hostName ) +{ + mHostName = hostName; +} + +TQString SensorProperties::hostName() const +{ + return mHostName; +} + +void SensorProperties::setName( const TQString &name ) +{ + mName = name; +} + +TQString SensorProperties::name() const +{ + return mName; +} + +void SensorProperties::setType( const TQString &type ) +{ + mType = type; +} + +TQString SensorProperties::type() const +{ + return mType; +} + +void SensorProperties::setDescription( const TQString &description ) +{ + mDescription = description; +} + +TQString SensorProperties::description() const +{ + return mDescription; +} + +void SensorProperties::setUnit( const TQString &unit ) +{ + mUnit = unit; +} + +TQString 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..c59f17468 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorDisplay.h @@ -0,0 +1,331 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SENSORDISPLAY_H +#define KSG_SENSORDISPLAY_H + +#include <tqgroupbox.h> +#include <tqlabel.h> +#include <tqvaluelist.h> +#include <tqwidget.h> + +#include <knotifyclient.h> + +#include <ksgrd/SensorClient.h> + +#define NONE -1 + +class TQDomDocument; +class TQDomElement; + +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 TQWidget, public SensorClient +{ + Q_OBJECT + + public: + /** + Constructor. + */ + SensorDisplay( TQWidget *parent = 0, const char *name = 0, + const TQString& title = 0, bool nf = false, bool isApplet = false ); + + /** + Destructor. + */ + virtual ~SensorDisplay(); + + /** + Sets the title of the display. + */ + void setTitle( const TQString &title ); + + /** + Returns the title of the display. + */ + TQString title() const; + + /** + Sets the unit of the display. + */ + void setUnit( const TQString &unit ); + + /** + Returns the unit of the display. + */ + TQString 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( TQStringList& list ); + + /** + Sets the widget on which the error icon can be drawn. + */ + void setPlotterWidget( TQWidget *plotter ); + + /** + Returns the widget on which the error icon can be drawn. + */ + TQWidget *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 TQString &hostName, const TQString &name, + const TQString &type, const TQString &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 TQString &hostName, const TQString &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( TQDomElement& ); + + /** + Reimplement this method to save the displays config data. + */ + virtual bool saveSettings( TQDomDocument&, TQDomElement&, 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( TQObject*, TQEvent* ); + virtual void resizeEvent( TQResizeEvent* ); + virtual void timerEvent( TQTimerEvent* ); + + void registerSensor( SensorProperties *sp ); + void unregisterSensor( uint pos ); + + TQColor restoreColor( TQDomElement &element, const TQString &attr, + const TQColor& fallback ); + void saveColor( TQDomElement &element, const TQString &attr, + const TQColor &color ); + + virtual TQString additionalWhatsThis(); + + void setSensorOk( bool ok ); + + bool modified() const; + bool timerOn() const; + + TQWidget *frame(); + +// void setNoFrame( bool value ); + bool noFrame() const; + + void reorderSensors(const TQValueList<int> &orderOfSensors); + TQPtrList<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. + TQGroupBox* mFrame; + + TQPtrList<SensorProperties> mSensors; + + TQString mTitle; + TQString mUnit; + + TQWidget* mErrorIndicator; + TQWidget* mPlotterWdg; +}; + +class SensorProperties +{ + public: + SensorProperties(); + SensorProperties( const TQString &hostName, const TQString &name, + const TQString &type, const TQString &description ); + ~SensorProperties(); + + void setHostName( const TQString &hostName ); + TQString hostName() const; + + void setName( const TQString &name ); + TQString name() const; + + void setType( const TQString &type ); + TQString type() const; + + void setDescription( const TQString &description ); + TQString description() const; + + void setUnit( const TQString &unit ); + TQString unit() const; + + void setIsOk( bool value ); + bool isOk() const; + + private: + TQString mHostName; + TQString mName; + TQString mType; + TQString mDescription; + TQString 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..88083fca1 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLogger.cc @@ -0,0 +1,437 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#include <tdeapplication.h> +#include <kiconloader.h> +#include <tdelocale.h> + +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include <tqfile.h> + +#include "SensorLogger.moc" +#include "SensorLoggerSettings.h" + +SLListViewItem::SLListViewItem(TQListView *parent) + : TQListViewItem(parent) +{ +} + +LogSensor::LogSensor(TQListView *parent) + : timerID( NONE ), lowerLimitActive( 0 ), upperLimitActive( 0 ), + lowerLimit( 0 ), upperLimit( 0 ) +{ + TQ_CHECK_PTR(parent); + + monitor = parent; + + lvi = new SLListViewItem(monitor); + TQ_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(TQTimerEvent*) +{ + KSGRD::SensorMgr->sendRequest(hostName, sensorName, (KSGRD::SensorClient*) this, 42); +} + +void +LogSensor::answerReceived(int id, const TQString& answer) +{ + TQFile logFile(fileName); + + if (!logFile.open(IO_ReadWrite | IO_Append)) + { + stopLogging(); + return; + } + + switch (id) + { + case 42: { + TQTextStream 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", TQString("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", TQString("sensor '%1' at '%2' reached upper limit").arg(sensorName).arg(hostName)); + timerOn(); + } + TQDate date = TQT_TQDATE_OBJECT(TQDateTime::currentDateTime().date()); + TQTime time = TQT_TQTIME_OBJECT(TQDateTime::currentDateTime().time()); + + stream << TQString("%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(TQWidget *parent, const char *name, const TQString& title) + : KSGRD::SensorDisplay(parent, name, title) +{ + monitor = new TQListView(this, "monitor"); + TQ_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")); + + TQColorGroup cgroup = monitor->colorGroup(); + cgroup.setColor(TQColorGroup::Text, KSGRD::Style->firstForegroundColor()); + cgroup.setColor(TQColorGroup::Base, KSGRD::Style->backgroundColor()); + cgroup.setColor(TQColorGroup::Foreground, KSGRD::Style->alarmColor()); + monitor->setPalette(TQPalette(cgroup, cgroup, cgroup)); + monitor->setSelectionMode(TQListView::NoSelection); + + connect(monitor, TQT_SIGNAL(rightButtonClicked(TQListViewItem*, const TQPoint&, int)), this, TQT_SLOT(RMBClicked(TQListViewItem*, const TQPoint&, int))); + + setTitle(i18n("Sensor Logger")); + + logSensors.setAutoDelete(true); + + setPlotterWidget(monitor); + + setMinimumSize(50, 25); + setModified(false); +} + +SensorLogger::~SensorLogger(void) +{ +} + +bool +SensorLogger::addSensor(const TQString& hostName, const TQString& sensorName, const TQString& sensorType, const TQString&) +{ + if (sensorType != "integer" && sensorType != "float") + return (false); + + sld = new SensorLoggerDlg(this, "SensorLoggerDlg"); + TQ_CHECK_PTR(sld); + + if (sld->exec()) { + if (!sld->fileName().isEmpty()) { + LogSensor *sensor = new LogSensor(monitor); + TQ_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"); + TQ_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() +{ + TQColorGroup cgroup = monitor->colorGroup(); + + sls = new SensorLoggerSettings(this, "SensorLoggerSettings"); + TQ_CHECK_PTR(sls); + + connect( sls, TQT_SIGNAL( applyClicked() ), TQT_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() +{ + TQColorGroup cgroup = monitor->colorGroup(); + + setTitle(sls->title()); + + cgroup.setColor(TQColorGroup::Text, sls->foregroundColor()); + cgroup.setColor(TQColorGroup::Base, sls->backgroundColor()); + cgroup.setColor(TQColorGroup::Foreground, sls->alarmColor()); + monitor->setPalette(TQPalette(cgroup, cgroup, cgroup)); + + setModified(true); +} + +void +SensorLogger::applyStyle(void) +{ + TQColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(TQColorGroup::Text, KSGRD::Style->firstForegroundColor()); + cgroup.setColor(TQColorGroup::Base, KSGRD::Style->backgroundColor()); + cgroup.setColor(TQColorGroup::Foreground, KSGRD::Style->alarmColor()); + monitor->setPalette(TQPalette(cgroup, cgroup, cgroup)); + + setModified(true); +} + +bool +SensorLogger::restoreSettings(TQDomElement& element) +{ + TQColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(TQColorGroup::Text, restoreColor(element, "textColor", Qt::green)); + cgroup.setColor(TQColorGroup::Base, restoreColor(element, "backgroundColor", Qt::black)); + cgroup.setColor(TQColorGroup::Foreground, restoreColor(element, "alarmColor", Qt::red)); + monitor->setPalette(TQPalette(cgroup, cgroup, cgroup)); + + logSensors.clear(); + + TQDomNodeList dnList = element.elementsByTagName("logsensors"); + for (uint i = 0; i < dnList.count(); i++) { + TQDomElement element = dnList.item(i).toElement(); + LogSensor* sensor = new LogSensor(monitor); + TQ_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(TQDomDocument& doc, TQDomElement& 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()) + { + TQDomElement 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", TQString("%1").arg(sensor->getLowerLimitActive())); + log.setAttribute("lowerLimit", TQString("%1").arg(sensor->getLowerLimit())); + log.setAttribute("upperLimitActive", TQString("%1").arg(sensor->getUpperLimitActive())); + log.setAttribute("upperLimit", TQString("%1").arg(sensor->getUpperLimit())); + + element.appendChild(log); + } + + SensorDisplay::saveSettings(doc, element); + + if (save) + setModified(false); + + return (true); +} + +void +SensorLogger::answerReceived(int, const TQString&) +{ + // we do not use this, since all answers are received by the LogSensors +} + +void +SensorLogger::resizeEvent(TQResizeEvent*) +{ + frame()->setGeometry(0, 0, this->width(), this->height()); + monitor->setGeometry(10, 20, this->width() - 20, this->height() - 30); +} + +LogSensor* +SensorLogger::getLogSensor(TQListViewItem* item) +{ + for (LogSensor* sensor = logSensors.first(); sensor != 0; sensor = logSensors.next()) + { + if (item == sensor->getListViewItem()) { + return sensor; + } + } + + return NULL; +} + +void +SensorLogger::RMBClicked(TQListViewItem* item, const TQPoint& point, int) +{ + TQPopupMenu 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: { + TQCustomEvent* ev = new TQCustomEvent(TQEvent::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..6630d57e1 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLogger.h @@ -0,0 +1,184 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef _SensorLogger_h +#define _SensorLogger_h + +#include <tqdom.h> +#include <tqlabel.h> +#include <tqlineedit.h> +#include <tqlistview.h> +#include <tqpopupmenu.h> +#include <tqspinbox.h> +#include <tqstring.h> + +#include <SensorDisplay.h> + +#include "SensorLoggerDlg.h" + +#define NONE -1 + +class SensorLoggerSettings; + +class SLListViewItem : public TQListViewItem +{ +public: + SLListViewItem(TQListView *parent = 0); + + void setTextColor(const TQColor& color) { textColor = color; } + + void paintCell(TQPainter *p, const TQColorGroup &cg, int column, int width, int alignment) { + TQColorGroup cgroup(cg); + cgroup.setColor(TQColorGroup::Text, textColor); + TQListViewItem::paintCell(p, cgroup, column, width, alignment); + + } + + void paintFocus(TQPainter *, const TQColorGroup, const TQRect) {} + +private: + TQColor textColor; +}; + +class LogSensor : public TQObject, public KSGRD::SensorClient +{ + Q_OBJECT +public: + LogSensor(TQListView *parent); + ~LogSensor(void); + + void answerReceived(int id, const TQString& answer); + + void setHostName(const TQString& name) { hostName = name; lvi->setText(3, name); } + void setSensorName(const TQString& name) { sensorName = name; lvi->setText(2, name); } + void setFileName(const TQString& 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, TQString("%1").arg(interval)); + } + + TQString getSensorName(void) { return sensorName; } + TQString getHostName(void) { return hostName; } + TQString 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; } + TQListViewItem* 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(TQTimerEvent*); + +private: + TQListView* monitor; + SLListViewItem* lvi; + TQPixmap pixmap_running; + TQPixmap pixmap_waiting; + TQString sensorName; + TQString hostName; + TQString fileName; + + int timerInterval; + int timerID; + + bool lowerLimitActive; + bool upperLimitActive; + + double lowerLimit; + double upperLimit; +}; + +class SensorLogger : public KSGRD::SensorDisplay +{ + Q_OBJECT +public: + SensorLogger(TQWidget *parent = 0, const char *name = 0, const TQString& title = 0); + ~SensorLogger(void); + + bool addSensor(const TQString& hostName, const TQString& sensorName, const TQString& sensorType, + const TQString& sensorDescr); + + bool editSensor(LogSensor*); + + void answerReceived(int id, const TQString& answer); + void resizeEvent(TQResizeEvent*); + + bool restoreSettings(TQDomElement& element); + bool saveSettings(TQDomDocument& doc, TQDomElement& element, bool save = true); + + void configureSettings(void); + + virtual bool hasSettingsDialog() const + { + return (true); + } + +public slots: + void applySettings(); + void applyStyle(); + void RMBClicked(TQListViewItem*, const TQPoint&, int); + +protected: + LogSensor* getLogSensor(TQListViewItem*); + +private: + TQListView* monitor; + + TQPtrList<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..422c6a835 --- /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 <[email protected]> + + 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 <tqlayout.h> + +#include <tdelocale.h> + +SensorLoggerDlg::SensorLoggerDlg( TQWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n( "Sensor Logger" ), + Ok|Cancel, Ok, true ) +{ + TQWidget *main = new TQWidget( this ); + + TQVBoxLayout *topLayout = new TQVBoxLayout( main, 0, KDialog::spacingHint() ); + + m_loggerWidget = new SensorLoggerDlgWidget( main, "m_loggerWidget" ); + topLayout->addWidget( m_loggerWidget ); + topLayout->addStretch(); + + setMainWidget( main ); +} + +TQString 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 TQString &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..e5061c722 --- /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 <[email protected]> + + 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 <tqstring.h> +#include <tqcolor.h> + +class SensorLoggerDlgWidget; + +class SensorLoggerDlg : public KDialogBase +{ + Q_OBJECT + + public: + + SensorLoggerDlg( TQWidget *parent=0, const char *name=0 ); + + TQString fileName() const; + int timerInterval() const; + bool lowerLimitActive() const; + bool upperLimitActive() const; + double lowerLimit() const; + double upperLimit() const; + + void setFileName( const TQString & ); + 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..144335654 --- /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="TQWidget"> + <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="TQGroupBox"> + <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="TQGroupBox"> + <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="TQGroupBox"> + <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="TQCheckBox"> + <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="TQLabel"> + <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="TQLineEdit"> + <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="TQGroupBox"> + <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="TQCheckBox"> + <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="TQLabel"> + <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="TQLineEdit"> + <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="TQString">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 TQString & 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..515cb13f6 --- /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(TQT_TQOBJECT(m_lowerLimit))); + m_upperLimit->setValidator(new KDoubleValidator(TQT_TQOBJECT(m_upperLimit))); + m_timerInterval->setRange(1, 99, 1, true); + + m_fileName->setFocus(); +} + + +TQString 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 TQString &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(TQString("%1").arg(d)); +} + + +void SensorLoggerDlgWidget::setUpperLimitActive( bool b ) +{ + m_upperLimitActive->setChecked(b); +} + + +void SensorLoggerDlgWidget::setUpperLimit( double d ) +{ + m_upperLimit->setText(TQString("%1").arg(d)); +} diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerSettings.cc b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettings.cc new file mode 100644 index 000000000..e029d9149 --- /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 <[email protected]> + + 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 <tdelocale.h> + +SensorLoggerSettings::SensorLoggerSettings( TQWidget *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 ); +} + +TQString SensorLoggerSettings::title() +{ + return m_settingsWidget->title(); +} + +TQColor SensorLoggerSettings::foregroundColor() +{ + return m_settingsWidget->foregroundColor(); +} + +TQColor SensorLoggerSettings::backgroundColor() +{ + return m_settingsWidget->backgroundColor(); +} + +TQColor SensorLoggerSettings::alarmColor() +{ + return m_settingsWidget->alarmColor(); +} + +void SensorLoggerSettings::setTitle( const TQString &title ) +{ + m_settingsWidget->setTitle( title ); +} + +void SensorLoggerSettings::setBackgroundColor( const TQColor &c ) +{ + m_settingsWidget->setBackgroundColor( c ); +} + +void SensorLoggerSettings::setForegroundColor( const TQColor &c ) +{ + m_settingsWidget->setForegroundColor( c ); +} + +void SensorLoggerSettings::setAlarmColor( const TQColor &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..e3f937166 --- /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 <[email protected]> + + 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 <tqstring.h> +#include <tqcolor.h> + +class SensorLoggerSettingsWidget; + +class SensorLoggerSettings : public KDialogBase +{ + Q_OBJECT + + public: + + SensorLoggerSettings( TQWidget *parent=0, const char *name=0 ); + + TQString title(); + TQColor foregroundColor(); + TQColor backgroundColor(); + TQColor alarmColor(); + + void setTitle( const TQString & ); + void setForegroundColor( const TQColor & ); + void setBackgroundColor( const TQColor & ); + void setAlarmColor( const TQColor & ); + + 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..7a546e7b6 --- /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="TQWidget"> + <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="TQGroupBox"> + <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="TQLineEdit"> + <property name="name"> + <cstring>m_title</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="TQGroupBox"> + <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="TQLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Text color:</string> + </property> + </widget> + <widget class="TQLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + </widget> + <widget class="TQLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Alarm color:</string> + </property> + </widget> + </vbox> + </widget> + <widget class="TQLayoutWidget"> + <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="TQString">title()</function> + <function specifier="non virtual" returnType="TQColor">foregroundColor()</function> + <function specifier="non virtual" returnType="TQColor">backgroundColor()</function> + <function specifier="non virtual" returnType="TQColor">alarmColor()</function> + <function specifier="non virtual">setTitle( const TQString & t )</function> + <function specifier="non virtual">setForegroundColor( const TQColor & c )</function> + <function specifier="non virtual">setBackgroundColor( const TQColor & c )</function> + <function specifier="non virtual">setAlarmColor( const TQColor & 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..a655a1751 --- /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. +*****************************************************************************/ + + +TQString SensorLoggerSettingsWidget::title() +{ + return m_title->text(); +} + + +TQColor SensorLoggerSettingsWidget::foregroundColor() +{ + return m_foregroundColor->color(); +} + + +TQColor SensorLoggerSettingsWidget::backgroundColor() +{ + return m_backgroundColor->color(); +} + + +TQColor SensorLoggerSettingsWidget::alarmColor() +{ + return m_alarmColor->color(); +} + + +void SensorLoggerSettingsWidget::setTitle( const TQString &t ) +{ + m_title->setText(t); +} + + +void SensorLoggerSettingsWidget::setForegroundColor( const TQColor &c ) +{ + m_foregroundColor->setColor(c); +} + + +void SensorLoggerSettingsWidget::setBackgroundColor( const TQColor &c ) +{ + m_backgroundColor->setColor(c); +} + + +void SensorLoggerSettingsWidget::setAlarmColor( const TQColor &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..bcb0b821b --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SignalPlotter.cc @@ -0,0 +1,648 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <math.h> +#include <string.h> + +#include <tqpainter.h> +#include <tqpixmap.h> + +#include <kdebug.h> +#include <tdeglobal.h> + +#include <ksgrd/StyleEngine.h> + +#include "SignalPlotter.h" + +SignalPlotter::SignalPlotter( TQWidget *parent, const char *name ) + : TQWidget( 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( TQSizePolicy( TQSizePolicy::Expanding, + TQSizePolicy::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 TQColor &color ) +{ + double* d = new double[ mSamples ]; + memset( d, 0, sizeof(double) * mSamples ); + mBeamData.append( d ); + mBeamColor.append( color ); + + return true; +} + +void SignalPlotter::addSample( const TQValueList<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. + TQValueList<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 TQValueList<int>& newOrder ) +{ + if(newOrder.count() != mBeamData.count()) { + kdDebug() << "Serious problem in move sample" << endl; + return; + } + TQPtrList<double> newBeamData; + TQValueList<TQColor> 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; +} + +TQValueList<TQColor> &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 TQString &title ) +{ + mTitle = title; +} + +TQString 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 TQColor &color ) +{ + mVerticalLinesColor = color; +} + +TQColor 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 TQColor &color ) +{ + mHorizontalLinesColor = color; +} + +TQColor 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 TQColor &color ) +{ + mBackgroundColor = color; +} + +TQColor SignalPlotter::backgroundColor() const +{ + return mBackgroundColor; +} + +void SignalPlotter::resizeEvent( TQResizeEvent* ) +{ + 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( TQPaintEvent* ) +{ + uint w = width(); + uint h = height(); + + /* Do not do repaints when the widget is not yet setup properly. */ + if ( w <= 2 ) + return; + + TQPixmap pm( w, h ); + TQPainter 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( TQColor( 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( TQFont( 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; + TQValueList<TQColor>::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; + TQValueList<TQColor>::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++ ) { + TQValueList<TQColor>::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. */ + TQPen lastPen = TQPen( p.pen() ); + p.setPen( (*col).dark( 150 ) ); + p.setBrush( (*col).dark( 150 ) ); + TQPointArray 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( TQFont( p.font().family(), mFontSize ) ); + TQString 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 = TQString::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 = TQString::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..cc632ac94 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SignalPlotter.h @@ -0,0 +1,147 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SIGNALPLOTTER_H +#define KSG_SIGNALPLOTTER_H + +#include <tqptrlist.h> +#include <tqstring.h> +#include <tqvaluelist.h> +#include <tqwidget.h> + +#define GRAPH_POLYGON 0 +#define GRAPH_ORIGINAL 1 + +class TQColor; + +class SignalPlotter : public TQWidget +{ + Q_OBJECT + + public: + SignalPlotter( TQWidget *parent = 0, const char *name = 0 ); + ~SignalPlotter(); + + bool addBeam( const TQColor &color ); + void addSample( const TQValueList<double> &samples ); + + void removeBeam( uint pos ); + + void changeRange( int beam, double min, double max ); + + TQValueList<TQColor> &beamColors(); + + void setTitle( const TQString &title ); + TQString 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 TQColor &color ); + TQColor 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 TQColor &color ); + TQColor 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 TQColor &color ); + TQColor backgroundColor() const; + void reorderBeams( const TQValueList<int>& newOrder ); + + void setThinFrame(bool set) { mShowThinFrame = set; } + + protected: + void updateDataBuffers(); + + virtual void resizeEvent( TQResizeEvent* ); + virtual void paintEvent( TQPaintEvent* ); + + private: + double mMinValue; + double mMaxValue; + bool mUseAutoRange; + bool mShowThinFrame; + + uint mGraphStyle; + + bool mShowVerticalLines; + TQColor mVerticalLinesColor; + uint mVerticalLinesDistance; + bool mVerticalLinesScroll; + uint mVerticalLinesOffset; + uint mHorizontalScale; + + bool mShowHorizontalLines; + TQColor mHorizontalLinesColor; + uint mHorizontalLinesCount; + + bool mShowLabels; + bool mShowTopBar; + uint mFontSize; + + TQColor mBackgroundColor; + + TQPtrList<double> mBeamData; + TQValueList<TQColor> mBeamColor; + + unsigned int mSamples; + + TQString mTitle; +}; + +#endif diff --git a/ksysguard/gui/SignalIDs.h b/ksysguard/gui/SignalIDs.h new file mode 100644 index 000000000..16df1b1e1 --- /dev/null +++ b/ksysguard/gui/SignalIDs.h @@ -0,0 +1,52 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SIGNALIDS_H +#define KSG_SIGNALIDS_H + +/* This file is used to correlate the entries of the process popup menu + * of the ProcessList class and the value received by the kill command + * in ksysguardd. We limit the set of available signals to the POSIX.1 + * set with job control. */ + +#define MENU_ID_SIGABRT 11 +#define MENU_ID_SIGALRM 12 +#define MENU_ID_SIGCHLD 13 +#define MENU_ID_SIGCONT 14 +#define MENU_ID_SIGFPE 15 +#define MENU_ID_SIGHUP 16 +#define MENU_ID_SIGILL 17 +#define MENU_ID_SIGINT 18 +#define MENU_ID_SIGKILL 19 +#define MENU_ID_SIGPIPE 20 +#define MENU_ID_SIGQUIT 21 +#define MENU_ID_SIGSEGV 22 +#define MENU_ID_SIGSTOP 23 +#define MENU_ID_SIGTERM 24 +#define MENU_ID_SIGTSTP 25 +#define MENU_ID_SIGTTIN 26 +#define MENU_ID_SIGTTOU 27 +#define MENU_ID_SIGUSR1 28 +#define MENU_ID_SIGUSR2 29 + +#endif diff --git a/ksysguard/gui/SystemLoad.sgrd b/ksysguard/gui/SystemLoad.sgrd new file mode 100644 index 000000000..139187e93 --- /dev/null +++ b/ksysguard/gui/SystemLoad.sgrd @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE KSysGuardWorkSheet> +<WorkSheet rows="2" interval="2" columns="2" > + <host port="-1" shell="" name="localhost" command="ksysguardd" /> + <display topBar="0" vColor="326429" title="CPU Load" bColor="3223601" graphStyle="0" class="FancyPlotter" row="0" unit="" hScale="1" column="0" showUnit="0" hLines="1" hCount="5" vLines="1" autoRange="0" min="0" max="100" hColor="326429" globalUpdate="1" pause="0" fontSize="9" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="cpu/user" hostName="localhost" color="1608191" sensorType="integer" /> + <beam sensorName="cpu/sys" hostName="localhost" color="16743688" sensorType="integer" /> + <beam sensorName="cpu/nice" hostName="localhost" color="16771600" sensorType="integer" /> + </display> + <display topBar="0" vColor="326429" title="Load Average (1 min)" bColor="3223601" graphStyle="0" class="FancyPlotter" row="0" unit="" hScale="1" column="1" showUnit="0" hLines="1" hCount="5" vLines="1" autoRange="1" min="0" max="0" hColor="326429" globalUpdate="1" pause="0" fontSize="9" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="cpu/loadavg1" hostName="localhost" color="1608191" sensorType="float" /> + </display> + <display topBar="0" vColor="326429" title="Physical Memory" +bColor="3223601" graphStyle="0" class="FancyPlotter" row="1" unit="" +hScale="1" column="0" showUnit="0" hLines="1" hCount="5" vLines="1" +autoRange="0" min="0" max="0" hColor="326429" globalUpdate="1" pause="0" fontSize="9" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="mem/physical/application" hostName="localhost" color="1608191" sensorType="integer" /> + <beam sensorName="mem/physical/buf" hostName="localhost" color="16743688" sensorType="integer" /> + <beam sensorName="mem/physical/cached" hostName="localhost" color="16771600" sensorType="integer" /> + </display> + <display topBar="0" vColor="326429" title="Swap Memory" +bColor="3223601" graphStyle="0" class="FancyPlotter" row="1" unit="" +hScale="1" column="1" showUnit="0" hLines="1" hCount="5" vLines="1" +autoRange="0" min="0" max="0" hColor="326429" globalUpdate="1" pause="0" fontSize="9" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="mem/swap/used" hostName="localhost" color="1608191" sensorType="integer" /> + </display> +</WorkSheet> diff --git a/ksysguard/gui/Taskmanager.ktop b/ksysguard/gui/Taskmanager.ktop new file mode 100644 index 000000000..00e5ec5ce --- /dev/null +++ b/ksysguard/gui/Taskmanager.ktop @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE KSysGuardWorkSheet > +<WorkSheet rows="1" columns="1"> +<host name="localhost" shell="" command="ksysguardd"/> +<display row="0" column="0" class="ProcessController" hostName="localhost" sensorName="ps" sensorType="table" tree="off" pause="off" filter="0"> +</display> +</WorkSheet> diff --git a/ksysguard/gui/WorkSheet.cc b/ksysguard/gui/WorkSheet.cc new file mode 100644 index 000000000..d465a998d --- /dev/null +++ b/ksysguard/gui/WorkSheet.cc @@ -0,0 +1,698 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <tqclipboard.h> +#include <tqcursor.h> +#include <tqdragobject.h> +#include <tqfile.h> +#include <tqlayout.h> + +#include <kdebug.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <tdepopupmenu.h> + +#include <SensorManager.h> + +#include "DancingBars.h" +#include "DummyDisplay.h" +#include "FancyPlotter.h" +#include "ListView.h" +#include "LogFile.h" +#include "MultiMeter.h" +#include "ProcessController.h" +#include "SensorLogger.h" +#include "WorkSheet.h" +#include "WorkSheetSettings.h" + +WorkSheet::WorkSheet( TQWidget *parent, const char *name ) + : TQWidget( parent, name ) +{ + mGridLayout = 0; + mRows = mColumns = 0; + mDisplayList = 0; + mModified = false; + mFileName = ""; + + setAcceptDrops( true ); +} + +WorkSheet::WorkSheet( uint rows, uint columns, uint interval, TQWidget* parent, + const char *name ) + : TQWidget( parent, name ) +{ + mRows = mColumns = 0; + mGridLayout = 0; + mDisplayList = 0; + updateInterval( interval ); + mModified = false; + mFileName = ""; + + createGrid( rows, columns ); + + // Initialize worksheet with dummy displays. + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + replaceDisplay( r, c ); + + mGridLayout->activate(); + + setAcceptDrops( true ); +} + +WorkSheet::~WorkSheet() +{ +} + +bool WorkSheet::load( const TQString &fileName ) +{ + setModified( false ); + + mFileName = fileName; + TQFile file( mFileName ); + if ( !file.open( IO_ReadOnly ) ) { + KMessageBox::sorry( this, i18n( "Cannot open the file %1." ).arg( mFileName ) ); + return false; + } + + TQDomDocument doc; + + // Read in file and check for a valid XML header. + if ( !doc.setContent( &file) ) { + KMessageBox::sorry( this, i18n( "The file %1 does not contain valid XML." ) + .arg( mFileName ) ); + return false; + } + + // Check for proper document type. + if ( doc.doctype().name() != "KSysGuardWorkSheet" ) { + KMessageBox::sorry( this, i18n( "The file %1 does not contain a valid worksheet " + "definition, which must have a document type 'KSysGuardWorkSheet'.") + .arg( mFileName ) ); + return false; + } + + // Check for proper size. + TQDomElement element = doc.documentElement(); + updateInterval( element.attribute( "interval" ).toUInt() ); + if ( updateInterval() < 1 || updateInterval() > 300 ) + updateInterval( 2 ); + + bool rowsOk, columnsOk; + uint rows = element.attribute( "rows" ).toUInt( &rowsOk ); + uint columns = element.attribute( "columns" ).toUInt( &columnsOk ); + if ( !( rowsOk && columnsOk ) ) { + KMessageBox::sorry( this, i18n("The file %1 has an invalid worksheet size.") + .arg( mFileName ) ); + return false; + } + + createGrid( rows, columns ); + + uint i; + /* Load lists of hosts that are needed for the work sheet and try + * to establish a connection. */ + TQDomNodeList dnList = element.elementsByTagName( "host" ); + for ( i = 0; i < dnList.count(); ++i ) { + TQDomElement element = dnList.item( i ).toElement(); + bool ok; + int port = element.attribute( "port" ).toInt( &ok ); + if ( !ok ) + port = -1; + KSGRD::SensorMgr->engage( element.attribute( "name" ), + element.attribute( "shell" ), + element.attribute( "command" ), port ); + } + //if no hosts are specified, at least connect to localhost + if(dnList.count() == 0) + KSGRD::SensorMgr->engage( "localhost", "", "ksysguardd", -1); + + // Load the displays and place them into the work sheet. + dnList = element.elementsByTagName( "display" ); + for ( i = 0; i < dnList.count(); ++i ) { + TQDomElement element = dnList.item( i ).toElement(); + uint row = element.attribute( "row" ).toUInt(); + uint column = element.attribute( "column" ).toUInt(); + if ( row >= mRows || column >= mColumns) { + kdDebug(1215) << "Row or Column out of range (" << row << ", " + << column << ")" << endl; + return false; + } + + replaceDisplay( row, column, element ); + } + + // Fill empty cells with dummy displays + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + if ( !mDisplayList[ r ][ c ] ) + replaceDisplay( r, c ); + + setModified( false ); + + return true; +} + +bool WorkSheet::save( const TQString &fileName ) +{ + mFileName = fileName; + + TQDomDocument doc( "KSysGuardWorkSheet" ); + doc.appendChild( doc.createProcessingInstruction( + "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); + + // save work sheet information + TQDomElement ws = doc.createElement( "WorkSheet" ); + doc.appendChild( ws ); + ws.setAttribute( "interval", updateInterval() ); + ws.setAttribute( "rows", mRows ); + ws.setAttribute( "columns", mColumns ); + + TQStringList hosts; + collectHosts( hosts ); + + // save host information (name, shell, etc.) + TQStringList::Iterator it; + for ( it = hosts.begin(); it != hosts.end(); ++it ) { + TQString shell, command; + int port; + + if ( KSGRD::SensorMgr->hostInfo( *it, shell, command, port ) ) { + TQDomElement host = doc.createElement( "host" ); + ws.appendChild( host ); + host.setAttribute( "name", *it ); + host.setAttribute( "shell", shell ); + host.setAttribute( "command", command ); + host.setAttribute( "port", port ); + } + } + + for ( uint r = 0; r < mRows; ++r ) + for (uint c = 0; c < mColumns; ++c ) + if ( !mDisplayList[ r ][ c ]->isA( "DummyDisplay" ) ) { + KSGRD::SensorDisplay* display = (KSGRD::SensorDisplay*)mDisplayList[ r ][ c ]; + TQDomElement element = doc.createElement( "display" ); + ws.appendChild( element ); + element.setAttribute( "row", r ); + element.setAttribute( "column", c ); + element.setAttribute( "class", display->className() ); + + display->saveSettings( doc, element ); + } + + TQFile file( mFileName ); + if ( !file.open( IO_WriteOnly ) ) { + KMessageBox::sorry( this, i18n( "Cannot save file %1" ).arg( mFileName ) ); + return false; + } + + TQTextStream s( &file ); + s.setEncoding( TQTextStream::UnicodeUTF8 ); + s << doc; + file.close(); + + setModified( false ); + + return true; +} + +void WorkSheet::cut() +{ + if ( !currentDisplay() || currentDisplay()->isA( "DummyDisplay" ) ) + return; + + TQClipboard* clip = TQApplication::clipboard(); + + clip->setText( currentDisplayAsXML() ); + + removeDisplay( currentDisplay() ); +} + +void WorkSheet::copy() +{ + if ( !currentDisplay() || currentDisplay()->isA( "DummyDisplay" ) ) + return; + + TQClipboard* clip = TQApplication::clipboard(); + + clip->setText( currentDisplayAsXML() ); +} + +void WorkSheet::paste() +{ + uint row, column; + if ( !currentDisplay( &row, &column ) ) + return; + + TQClipboard* clip = TQApplication::clipboard(); + + TQDomDocument doc; + /* Get text from clipboard and check for a valid XML header and + * proper document type. */ + if ( !doc.setContent( clip->text() ) || doc.doctype().name() != "KSysGuardDisplay" ) { + KMessageBox::sorry( this, i18n("The clipboard does not contain a valid display " + "description." ) ); + return; + } + + TQDomElement element = doc.documentElement(); + replaceDisplay( row, column, element ); +} + +void WorkSheet::setFileName( const TQString &fileName ) +{ + mFileName = fileName; + setModified( true ); +} + +const TQString& WorkSheet::fileName() const +{ + return mFileName; +} + +bool WorkSheet::modified() const +{ + return mModified; +} + +void WorkSheet::setTitle( const TQString &title ) +{ + mTitle = title; +} + +TQString WorkSheet::title() const +{ + return mTitle; +} + +KSGRD::SensorDisplay *WorkSheet::addDisplay( const TQString &hostName, + const TQString &sensorName, + const TQString &sensorType, + const TQString& sensorDescr, + uint row, uint column ) +{ + if ( !KSGRD::SensorMgr->engageHost( hostName ) ) { + TQString msg = i18n( "It is impossible to connect to \'%1\'." ).arg( hostName ); + KMessageBox::error( this, msg ); + + return 0; + } + + /* If the by 'row' and 'column' specified display is a TQGroupBox dummy + * display we replace the widget. Otherwise we just try to add + * the new sensor to an existing display. */ + if ( mDisplayList[ row ][ column ]->isA( "DummyDisplay" ) ) { + KSGRD::SensorDisplay* newDisplay = 0; + /* If the sensor type is supported by more than one display + * type we popup a menu so the user can select what display is + * wanted. */ + if ( sensorType == "integer" || sensorType == "float" ) { + TDEPopupMenu pm; + pm.insertTitle( i18n( "Select Display Type" ) ); + pm.insertItem( i18n( "&Signal Plotter" ), 1 ); + pm.insertItem( i18n( "&Multimeter" ), 2 ); + pm.insertItem( i18n( "&BarGraph" ), 3 ); + pm.insertItem( i18n( "S&ensorLogger" ), 4 ); + switch ( pm.exec( TQCursor::pos() ) ) { + case 1: + newDisplay = new FancyPlotter( this, "FancyPlotter", sensorDescr ); + break; + case 2: + newDisplay = new MultiMeter( this, "MultiMeter", sensorDescr ); + break; + case 3: + newDisplay = new DancingBars( this, "DancingBars", sensorDescr ); + break; + case 4: + newDisplay = new SensorLogger( this, "SensorLogger", sensorDescr ); + break; + default: + return 0; + } + } else if ( sensorType == "listview" ) + newDisplay = new ListView( this, "ListView", sensorDescr ); + else if ( sensorType == "logfile" ) + newDisplay = new LogFile( this, "LogFile", sensorDescr ); + else if ( sensorType == "sensorlogger" ) + newDisplay = new SensorLogger( this, "SensorLogger", sensorDescr ); + else if ( sensorType == "table" ) + newDisplay = new ProcessController( this ); + else { + kdDebug(1215) << "Unkown sensor type: " << sensorType << endl; + return 0; + } + + replaceDisplay( row, column, newDisplay ); + } + + mDisplayList[ row ][ column ]->addSensor( hostName, sensorName, sensorType, sensorDescr ); + + setModified( true ); + + return ((KSGRD::SensorDisplay*)mDisplayList[ row ][ column ] ); +} + +void WorkSheet::settings() +{ + WorkSheetSettings dlg( this ); + + /* The sheet name should be changed with the "Save as..." function, + * so we don't have to display the display frame. */ + dlg.setSheetTitle( mTitle ); + dlg.setRows( mRows ); + dlg.setColumns( mColumns ); + dlg.setInterval( updateInterval() ); + + if ( dlg.exec() ) { + updateInterval( dlg.interval() ); + for (uint r = 0; r < mRows; ++r) + for (uint c = 0; c < mColumns; ++c) + if ( mDisplayList[ r ][ c ]->useGlobalUpdateInterval() ) + mDisplayList[ r ][ c ]->setUpdateInterval( updateInterval() ); + + resizeGrid( dlg.rows(), dlg.columns() ); + + mTitle = dlg.sheetTitle(); + emit titleChanged( this ); + + setModified( true ); + } +} + +void WorkSheet::showPopupMenu( KSGRD::SensorDisplay *display ) +{ + display->configureSettings(); +} + +void WorkSheet::setModified( bool modified ) +{ + if ( modified != mModified ) { + mModified = modified; + if ( !modified ) + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + mDisplayList[ r ][ c ]->setModified( false ); + + emit sheetModified( this ); + } +} + +void WorkSheet::applyStyle() +{ + for ( uint r = 0; r < mRows; ++r ) + for (uint c = 0; c < mColumns; ++c ) + mDisplayList[ r ][ c ]->applyStyle(); +} + +void WorkSheet::dragEnterEvent( TQDragEnterEvent *e ) +{ + e->accept( TQTextDrag::canDecode( e ) ); +} + +void WorkSheet::dropEvent( TQDropEvent *e ) +{ + TQString dragObject; + + if ( TQTextDrag::decode( e, dragObject) ) { + // The host name, sensor name and type are seperated by a ' '. + TQStringList parts = TQStringList::split( ' ', dragObject ); + + TQString hostName = parts[ 0 ]; + TQString sensorName = parts[ 1 ]; + TQString sensorType = parts[ 2 ]; + TQString sensorDescr = parts[ 3 ]; + + if ( hostName.isEmpty() || sensorName.isEmpty() || sensorType.isEmpty() ) { + return; + } + + /* Find the sensor display that is supposed to get the drop + * event and replace or add sensor. */ + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + if ( mDisplayList[ r ][ c ]->geometry().contains( e->pos() ) ) { + addDisplay( hostName, sensorName, sensorType, sensorDescr, r, c ); + return; + } + } +} + +TQSize WorkSheet::sizeHint() const +{ + return TQSize( 200,150 ); +} + +void WorkSheet::customEvent( TQCustomEvent *e ) +{ + if ( e->type() == TQEvent::User ) { + // SensorDisplays send out this event if they want to be removed. + + removeDisplay( (KSGRD::SensorDisplay*)e->data() ); + } +} + +bool WorkSheet::replaceDisplay( uint row, uint column, TQDomElement& element ) +{ + TQString classType = element.attribute( "class" ); + KSGRD::SensorDisplay* newDisplay; + if ( classType == "FancyPlotter" ) + newDisplay = new FancyPlotter( this ); + else if ( classType == "MultiMeter" ) + newDisplay = new MultiMeter( this ); + else if ( classType == "DancingBars" ) + newDisplay = new DancingBars( this ); + else if ( classType == "ListView" ) + newDisplay = new ListView( this ); + else if ( classType == "LogFile" ) + newDisplay = new LogFile( this ); + else if ( classType == "SensorLogger" ) + newDisplay = new SensorLogger( this ); + else if ( classType == "ProcessController" ) + newDisplay = new ProcessController( this ); + else { + kdDebug(1215) << "Unkown class " << classType << endl; + return false; + } + + if ( newDisplay->useGlobalUpdateInterval() ) + newDisplay->setUpdateInterval( updateInterval() ); + + // load display specific settings + if ( !newDisplay->restoreSettings( element ) ) + return false; + + replaceDisplay( row, column, newDisplay ); + + return true; +} + +void WorkSheet::replaceDisplay( uint row, uint column, KSGRD::SensorDisplay* newDisplay ) +{ + // remove the old display at this location + delete mDisplayList[ row ][ column ]; + + // insert new display + if ( !newDisplay ) + mDisplayList[ row ][ column ] = new DummyDisplay( this, "DummyDisplay" ); + else { + mDisplayList[ row ][ column ] = newDisplay; + if ( mDisplayList[ row ][ column ]->useGlobalUpdateInterval() ) + mDisplayList[ row ][ column ]->setUpdateInterval( updateInterval() ); + connect( newDisplay, TQT_SIGNAL( showPopupMenu( KSGRD::SensorDisplay* ) ), + TQT_SLOT( showPopupMenu( KSGRD::SensorDisplay* ) ) ); + connect( newDisplay, TQT_SIGNAL( modified( bool ) ), + TQT_SLOT( setModified( bool ) ) ); + } + + + mGridLayout->addWidget( mDisplayList[ row ][ column ], row, column ); + + if ( isVisible() ) { + mDisplayList[ row ][ column ]->show(); + } + + setMinimumSize(sizeHint()); + + setModified( true ); +} + +void WorkSheet::removeDisplay( KSGRD::SensorDisplay *display ) +{ + if ( !display ) + return; + + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + if ( mDisplayList[ r ][ c ] == display ) { + replaceDisplay( r, c ); + setModified( true ); + return; + } +} + +void WorkSheet::collectHosts( TQStringList &list ) +{ + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + if ( !mDisplayList[ r ][ c ]->isA( "DummyDisplay" ) ) + ((KSGRD::SensorDisplay*)mDisplayList[ r ][ c ])->hosts( list ); +} + +void WorkSheet::createGrid( uint rows, uint columns ) +{ + mRows = rows; + mColumns = columns; + + // create grid layout with specified dimentions + mGridLayout = new TQGridLayout( this, mRows, mColumns, 5 ); + + mDisplayList = new KSGRD::SensorDisplay**[ mRows ]; + for ( uint r = 0; r < mRows; ++r ) { + mDisplayList[ r ] = new KSGRD::SensorDisplay*[ mColumns ]; + for ( uint c = 0; c < mColumns; ++c ) + mDisplayList[ r ][ c ] = 0; + } + + /* set stretch factors for rows and columns */ + for ( uint r = 0; r < mRows; ++r ) + mGridLayout->setRowStretch( r, 100 ); + for ( uint c = 0; c < mColumns; ++c ) + mGridLayout->setColStretch( c, 100 ); +} + +void WorkSheet::resizeGrid( uint newRows, uint newColumns ) +{ + uint r, c; + + /* Create new array for display pointers */ + KSGRD::SensorDisplay*** newDisplayList = new KSGRD::SensorDisplay**[ newRows ]; + for ( r = 0; r < newRows; ++r ) { + newDisplayList[ r ] = new KSGRD::SensorDisplay*[ newColumns ]; + for ( c = 0; c < newColumns; ++c ) { + if ( c < mColumns && r < mRows ) + newDisplayList[ r ][ c ] = mDisplayList[ r ][ c ]; + else + newDisplayList[ r ][ c ] = 0; + } + } + + /* remove obsolete displays */ + for ( r = 0; r < mRows; ++r ) { + for ( c = 0; c < mColumns; ++c ) + if ( r >= newRows || c >= newColumns ) + delete mDisplayList[ r ][ c ]; + delete mDisplayList[ r ]; + } + delete [] mDisplayList; + + /* now we make the new display the regular one */ + mDisplayList = newDisplayList; + + /* create new displays */ + for ( r = 0; r < newRows; ++r ) + for ( c = 0; c < newColumns; ++c ) + if ( r >= mRows || c >= mColumns ) + replaceDisplay( r, c ); + + /* set stretch factors for new rows and columns (if any) */ + for ( r = mRows; r < newRows; ++r ) + mGridLayout->setRowStretch( r, 100 ); + for ( c = mColumns; c < newColumns; ++c ) + mGridLayout->setColStretch( c, 100 ); + + /* Obviously Qt does not shrink the size of the QGridLayout + * automatically. So we simply force the rows and columns that + * are no longer used to have a strech factor of 0 and hence be + * invisible. */ + for ( r = newRows; r < mRows; ++r ) + mGridLayout->setRowStretch( r, 0 ); + for ( c = newColumns; c < mColumns; ++c ) + mGridLayout->setColStretch( c, 0 ); + + mRows = newRows; + mColumns = newColumns; + + fixTabOrder(); + + mGridLayout->activate(); +} + +KSGRD::SensorDisplay *WorkSheet::display( uint row, uint column ) { + if(row >= mRows || column >= mColumns) return 0; + return mDisplayList[row][column]; +} +KSGRD::SensorDisplay *WorkSheet::currentDisplay( uint *row, uint *column ) +{ + for ( uint r = 0 ; r < mRows; ++r ) + for ( uint c = 0 ; c < mColumns; ++c ) + if ( mDisplayList[ r ][ c ]->hasFocus() ) { + if ( row ) + *row = r; + if ( column ) + *column = c; + return ( mDisplayList[ r ][ c ] ); + } + + return 0; +} + +void WorkSheet::fixTabOrder() +{ + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) { + if ( c + 1 < mColumns ) + setTabOrder( mDisplayList[ r ][ c ], mDisplayList[ r ][ c + 1 ] ); + else if ( r + 1 < mRows ) + setTabOrder( mDisplayList[ r ][ c ], mDisplayList[ r + 1 ][ 0 ] ); + } +} + +TQString WorkSheet::currentDisplayAsXML() +{ + KSGRD::SensorDisplay* display = currentDisplay(); + if ( !display ) + return TQString::null; + + /* We create an XML description of the current display. */ + TQDomDocument doc( "KSysGuardDisplay" ); + doc.appendChild( doc.createProcessingInstruction( + "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); + + TQDomElement element = doc.createElement( "display" ); + doc.appendChild( element ); + element.setAttribute( "class", display->className() ); + display->saveSettings( doc, element ); + + return doc.toString(); +} + +void WorkSheet::setIsOnTop( bool /* onTop */ ) +{ +/* + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + mDisplayList[ r ][ c ]->setIsOnTop( onTop ); +*/ +} + +#include "WorkSheet.moc" diff --git a/ksysguard/gui/WorkSheet.h b/ksysguard/gui/WorkSheet.h new file mode 100644 index 000000000..37bafbda3 --- /dev/null +++ b/ksysguard/gui/WorkSheet.h @@ -0,0 +1,135 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_WORKSHEET_H +#define KSG_WORKSHEET_H + +#include <tqwidget.h> + +#include <SensorDisplay.h> + +class TQDomElement; +class TQDragEnterEvent; +class TQDropEvent; +class TQGridLayout; +class TQString; +class TQStringList; + +/** + A WorkSheet contains the displays to visualize the sensor results. When + creating the WorkSheet you must specify the number of columns. Displays + can be added and removed on the fly. The grid layout will handle the + layout. The number of columns can not be changed. Displays are added by + dragging a sensor from the sensor browser over the WorkSheet. + */ +class WorkSheet : public TQWidget, public KSGRD::SensorBoard +{ + Q_OBJECT + + public: + WorkSheet( TQWidget* parent, const char *name = 0 ); + WorkSheet( uint rows, uint columns, uint interval, TQWidget* parent, + const char *name = 0 ); + ~WorkSheet(); + + bool load( const TQString &fileName ); + bool save( const TQString &fileName ); + + void cut(); + void copy(); + void paste(); + + void setFileName( const TQString &fileName ); + const TQString& fileName() const; + + bool modified() const; + + void setTitle( const TQString &title ); + TQString title() const; + + KSGRD::SensorDisplay* addDisplay( const TQString &hostname, + const TQString &monitor, + const TQString &sensorType, + const TQString &sensorDescr, + uint rows, uint columns ); + //Returns the sensor at position row,column. + //Return NULL if invalid row or column + KSGRD::SensorDisplay *display( uint row, uint column ); + + void settings(); + + void setIsOnTop( bool onTop ); + + public slots: + void showPopupMenu( KSGRD::SensorDisplay *display ); + void setModified( bool mfd ); + void applyStyle(); + + signals: + void sheetModified( TQWidget *sheet ); + void titleChanged( TQWidget *sheet ); + + protected: + virtual TQSize sizeHint() const; + void dragEnterEvent( TQDragEnterEvent* ); + void dropEvent( TQDropEvent* ); + void customEvent( TQCustomEvent* ); + + private: + void removeDisplay( KSGRD::SensorDisplay *display ); + + bool replaceDisplay( uint row, uint column, TQDomElement& element ); + + void replaceDisplay( uint row, uint column, + KSGRD::SensorDisplay* display = 0 ); + + void collectHosts( TQStringList &list ); + + void createGrid( uint rows, uint columns ); + + void resizeGrid( uint rows, uint columns ); + + KSGRD::SensorDisplay* currentDisplay( uint* row = 0, uint* column = 0 ); + + void fixTabOrder(); + + TQString currentDisplayAsXML(); + + bool mModified; + + uint mRows; + uint mColumns; + + TQGridLayout* mGridLayout; + TQString mFileName; + TQString mTitle; + + /** + This two dimensional array stores the pointers to the sensor displays + or if no sensor is present at a position a pointer to a dummy widget. + The size of the array corresponds to the size of the grid layout. + */ + KSGRD::SensorDisplay*** mDisplayList; +}; + +#endif diff --git a/ksysguard/gui/WorkSheetSettings.cc b/ksysguard/gui/WorkSheetSettings.cc new file mode 100644 index 000000000..703be57d5 --- /dev/null +++ b/ksysguard/gui/WorkSheetSettings.cc @@ -0,0 +1,153 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <tdeaccelmanager.h> +#include <klineedit.h> +#include <knuminput.h> +#include <tdelocale.h> + +#include <tqgroupbox.h> +#include <tqlabel.h> +#include <tqspinbox.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> + +#include "WorkSheetSettings.h" + +WorkSheetSettings::WorkSheetSettings( TQWidget* parent, const char* name ) + : KDialogBase( parent, name, true, TQString::null, Ok|Cancel, Ok, true ) +{ + setCaption( i18n( "Worksheet Properties" ) ); + + TQWidget *page = new TQWidget( this ); + setMainWidget( page ); + + TQVBoxLayout *topLayout = new TQVBoxLayout( page, 0, spacingHint() ); + + TQGroupBox *group = new TQGroupBox( 0, Qt::Vertical, i18n( "Title" ), page ); + group->layout()->setMargin( marginHint() ); + group->layout()->setSpacing( spacingHint() ); + + TQGridLayout *groupLayout = new TQGridLayout( group->layout(), 1, 1 ); + groupLayout->setAlignment( Qt::AlignTop ); + + mSheetTitle = new KLineEdit( group ); + groupLayout->addWidget( mSheetTitle, 0, 0 ); + + topLayout->addWidget( group ); + + group = new TQGroupBox( 0, Qt::Vertical, i18n( "Properties" ), page ); + group->layout()->setMargin( marginHint() ); + group->layout()->setSpacing( spacingHint() ); + + groupLayout = new TQGridLayout( group->layout(), 3, 2 ); + groupLayout->setAlignment( Qt::AlignTop ); + + TQLabel *label = new TQLabel( i18n( "Rows:" ), group ); + groupLayout->addWidget( label, 0, 0 ); + + mRows = new KIntNumInput( 1, group ); + mRows->setMaxValue( 42 ); + mRows->setMinValue( 1 ); + groupLayout->addWidget( mRows, 0, 1 ); + label->setBuddy( mRows ); + + label = new TQLabel( i18n( "Columns:" ), group ); + groupLayout->addWidget( label, 1, 0 ); + + mColumns = new KIntNumInput( 1, group ); + mColumns->setMaxValue( 42 ); + mColumns->setMinValue( 1 ); + groupLayout->addWidget( mColumns, 1, 1 ); + label->setBuddy( mColumns ); + + label = new TQLabel( i18n( "Update interval:" ), group ); + groupLayout->addWidget( label, 2, 0 ); + + mInterval = new KIntNumInput( 2, group ); + mInterval->setMaxValue( 300 ); + mInterval->setMinValue( 1 ); + mInterval->setSuffix( i18n( " sec" ) ); + groupLayout->addWidget( mInterval, 2, 1 ); + label->setBuddy( mInterval ); + + topLayout->addWidget( group ); + + TQWhatsThis::add( mRows, i18n( "Enter the number of rows the sheet should have." ) ); + TQWhatsThis::add( mColumns, i18n( "Enter the number of columns the sheet should have." ) ); + TQWhatsThis::add( mInterval, i18n( "All displays of the sheet are updated at the rate specified here." ) ); + TQToolTip::add( mSheetTitle, i18n( "Enter the title of the worksheet here." ) ); + + TDEAcceleratorManager::manage( page ); + + mSheetTitle->setFocus(); + + resize( TQSize( 250, 230 ).expandedTo( minimumSizeHint() ) ); +} + +WorkSheetSettings::~WorkSheetSettings() +{ +} + +void WorkSheetSettings::setRows( int rows ) +{ + mRows->setValue( rows ); +} + +int WorkSheetSettings::rows() const +{ + return mRows->value(); +} + +void WorkSheetSettings::setColumns( int columns ) +{ + mColumns->setValue( columns ); +} + +int WorkSheetSettings::columns() const +{ + return mColumns->value(); +} + +void WorkSheetSettings::setInterval( int interval ) +{ + mInterval->setValue( interval ); +} + +int WorkSheetSettings::interval() const +{ + return mInterval->value(); +} + +void WorkSheetSettings::setSheetTitle( const TQString &title ) +{ + mSheetTitle->setText( title ); +} + +TQString WorkSheetSettings::sheetTitle() const +{ + return mSheetTitle->text(); +} + +#include "WorkSheetSettings.moc" diff --git a/ksysguard/gui/WorkSheetSettings.h b/ksysguard/gui/WorkSheetSettings.h new file mode 100644 index 000000000..5f7d8da0c --- /dev/null +++ b/ksysguard/gui/WorkSheetSettings.h @@ -0,0 +1,60 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_WORKSHEETSETTINGS_H +#define KSG_WORKSHEETSETTINGS_H + +#include <kdialogbase.h> + +class KLineEdit; +class KIntNumInput; + +class WorkSheetSettings : public KDialogBase +{ + Q_OBJECT + + public: + WorkSheetSettings( TQWidget* parent = 0, const char* name = 0 ); + ~WorkSheetSettings(); + + void setRows( int rows ); + int rows() const; + + void setColumns( int columns ); + int columns() const; + + void setInterval( int interval ); + int interval() const; + + void setSheetTitle( const TQString &title ); + TQString sheetTitle() const; + + private: + KLineEdit* mSheetTitle; + + KIntNumInput* mColumns; + KIntNumInput* mInterval; + KIntNumInput* mRows; +}; + +#endif diff --git a/ksysguard/gui/Workspace.cc b/ksysguard/gui/Workspace.cc new file mode 100644 index 000000000..c5e622248 --- /dev/null +++ b/ksysguard/gui/Workspace.cc @@ -0,0 +1,463 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <tqlineedit.h> +#include <tqspinbox.h> +#include <tqwhatsthis.h> + +#include <kdebug.h> +#include <tdefiledialog.h> +#include <tdeio/netaccess.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <kstandarddirs.h> +#include <tdeaccelmanager.h> + +#include "WorkSheet.h" +#include "WorkSheetSettings.h" +#include "ProcessController.h" + +#include "Workspace.h" + +Workspace::Workspace( TQWidget* parent, const char* name ) + : TQTabWidget( parent, name ) +{ + TDEAcceleratorManager::setNoAccel(this); + + mSheetList.setAutoDelete( true ); + mAutoSave = true; + + connect( this, TQT_SIGNAL( currentChanged( TQWidget* ) ), + TQT_SLOT( updateCaption( TQWidget* ) ) ); + + TQWhatsThis::add( this, i18n( "This is your work space. It holds your worksheets. You need " + "to create a new worksheet (Menu File->New) before " + "you can drag sensors here." ) ); +} + +Workspace::~Workspace() +{ + /* This workaround is necessary to prevent a crash when the last + * page is not the current page. It seems like the the signal/slot + * administration data is already deleted but slots are still + * being triggered. TODO: I need to ask the Trolls about this. */ + + disconnect( this, TQT_SIGNAL( currentChanged( TQWidget* ) ), this, + TQT_SLOT( updateCaption( TQWidget* ) ) ); +} + +void Workspace::saveProperties( TDEConfig *cfg ) +{ + cfg->writePathEntry( "WorkDir", mWorkDir ); + cfg->writeEntry( "CurrentSheet", tabLabel( currentPage() ) ); + + TQPtrListIterator<WorkSheet> it( mSheetList); + + TQStringList list; + for ( int i = 0; it.current(); ++it, ++i ) + if ( !(*it)->fileName().isEmpty() ) + list.append( (*it)->fileName() ); + + cfg->writePathEntry( "Sheets", list ); +} + +void Workspace::readProperties( TDEConfig *cfg ) +{ + TQString currentSheet; + + mWorkDir = cfg->readPathEntry( "WorkDir" ); + + if ( mWorkDir.isEmpty() ) { + /* If workDir is not specified in the config file, it's + * probably the first time the user has started KSysGuard. We + * then "restore" a special default configuration. */ + TDEStandardDirs* kstd = TDEGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + + mWorkDir = kstd->saveLocation( "data", "ksysguard" ); + + TQString origFile = kstd->findResource( "data", "SystemLoad.sgrd" ); + TQString newFile = mWorkDir + "/" + i18n( "System Load" ) + ".sgrd"; + if ( !origFile.isEmpty() ) + restoreWorkSheet( origFile, newFile ); + + origFile = kstd->findResource( "data", "ProcessTable.sgrd" ); + newFile = mWorkDir + "/" + i18n( "Process Table" ) + ".sgrd"; + if ( !origFile.isEmpty() ) + restoreWorkSheet( origFile, newFile ); + + currentSheet = i18n( "System Load" ); + } else { + currentSheet = cfg->readEntry( "CurrentSheet" ); + TQStringList list = cfg->readPathListEntry( "Sheets" ); + for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) + restoreWorkSheet( *it ); + } + + // Determine visible sheet. + TQPtrListIterator<WorkSheet> it( mSheetList ); + for ( ; it.current(); ++it ) + if ( currentSheet == tabLabel(*it) ) { + showPage( *it ); + break; + } +} + +void Workspace::newWorkSheet() +{ + /* Find a name of the form "Sheet %d" that is not yet used by any + * of the existing worksheets. */ + TQString sheetName; + bool found; + + int i = 1; + do { + sheetName = i18n( "Sheet %1" ).arg( i++ ); + TQPtrListIterator<WorkSheet> it( mSheetList ); + found = false; + for ( ; it.current() && !found; ++it ) + if ( tabLabel(*it) == sheetName ) + found = true; + } while ( found ); + + WorkSheetSettings dlg( this ); + dlg.setSheetTitle( sheetName ); + if ( dlg.exec() ) { + WorkSheet* sheet = new WorkSheet( dlg.rows(), dlg.columns(), dlg.interval(), this ); + sheet->setTitle( dlg.sheetTitle() ); + insertTab( sheet, dlg.sheetTitle() ); + mSheetList.append( sheet ); + showPage( sheet ); + connect( sheet, TQT_SIGNAL( sheetModified( TQWidget* ) ), + TQT_SLOT( updateCaption( TQWidget* ) ) ); + connect( sheet, TQT_SIGNAL( titleChanged( TQWidget* ) ), + TQT_SLOT( updateSheetTitle( TQWidget* ) ) ); + } +} + +bool Workspace::saveOnQuit() +{ + TQPtrListIterator<WorkSheet> it( mSheetList ); + for ( ; it.current(); ++it ) + if ( (*it)->modified() ) { + if ( !mAutoSave || (*it)->fileName().isEmpty() ) { + int res = KMessageBox::warningYesNoCancel( this, + i18n( "The worksheet '%1' contains unsaved data.\n" + "Do you want to save the worksheet?") + .arg( tabLabel( *it ) ), TQString::null, KStdGuiItem::save(), KStdGuiItem::discard() ); + if ( res == KMessageBox::Yes ) + saveWorkSheet( *it ); + else if ( res == KMessageBox::Cancel ) + return false; // abort quit + } else + saveWorkSheet(*it); + } + + return true; +} + +void Workspace::loadWorkSheet() +{ + KFileDialog dlg( 0, i18n( "*.sgrd|Sensor Files" ), this, + "LoadFileDialog", true ); + + KURL url = dlg.getOpenURL( mWorkDir, "*.sgrd", 0, i18n( "Select Worksheet to Load" ) ); + + loadWorkSheet( url ); +} + +void Workspace::loadWorkSheet( const KURL &url ) +{ + if ( url.isEmpty() ) + return; + + /* It's probably not worth the effort to make this really network + * transparent. Unless s/o beats me up I use this pseudo transparent + * code. */ + TQString tmpFile; + TDEIO::NetAccess::download( url, tmpFile, this ); + mWorkDir = tmpFile.left( tmpFile.findRev( '/' ) ); + + // Load sheet from file. + if ( !restoreWorkSheet( tmpFile ) ) + return; + + /* If we have loaded a non-local file we clear the file name so that + * the users is prompted for a new name for saving the file. */ + KURL tmpFileUrl; + tmpFileUrl.setPath( tmpFile ); + if ( tmpFileUrl != url.url() ) + mSheetList.last()->setFileName( TQString::null ); + TDEIO::NetAccess::removeTempFile( tmpFile ); + + emit announceRecentURL( KURL( url ) ); +} + +void Workspace::saveWorkSheet() +{ + saveWorkSheet( (WorkSheet*)currentPage() ); +} + +void Workspace::saveWorkSheetAs() +{ + saveWorkSheetAs( (WorkSheet*)currentPage() ); +} + +void Workspace::saveWorkSheet( WorkSheet *sheet ) +{ + if ( !sheet ) { + KMessageBox::sorry( this, i18n( "You do not have a worksheet that could be saved." ) ); + return; + } + + TQString fileName = sheet->fileName(); + if ( fileName.isEmpty() ) { + KFileDialog dlg( 0, i18n( "*.sgrd|Sensor Files" ), this, + "LoadFileDialog", true ); + fileName = dlg.getSaveFileName( mWorkDir + "/" + tabLabel( sheet ) + + ".sgrd", "*.sgrd", 0, + i18n( "Save Current Worksheet As" ) ); + if ( fileName.isEmpty() ) + return; + + mWorkDir = fileName.left( fileName.findRev( '/' ) ); + + // extract filename without path + TQString baseName = fileName.right( fileName.length() - fileName.findRev( '/' ) - 1 ); + + // chop off extension (usually '.sgrd') + baseName = baseName.left( baseName.findRev( '.' ) ); + changeTab( sheet, baseName ); + } + + /* If we cannot save the file is probably write protected. So we need + * to ask the user for a new name. */ + if ( !sheet->save( fileName ) ) { + saveWorkSheetAs( sheet ); + return; + } + + /* Add file to recent documents menue. */ + KURL url; + url.setPath( fileName ); + emit announceRecentURL( url ); +} + +void Workspace::saveWorkSheetAs( WorkSheet *sheet ) +{ + if ( !sheet ) { + KMessageBox::sorry( this, i18n( "You do not have a worksheet that could be saved." ) ); + return; + } + + TQString fileName; + do { + KFileDialog dlg( 0, "*.sgrd", this, "LoadFileDialog", true ); + fileName = dlg.getSaveFileName( mWorkDir + "/" + tabLabel( currentPage() ) + + ".sgrd", "*.sgrd" ); + if ( fileName.isEmpty() ) + return; + + mWorkDir = fileName.left( fileName.findRev( '/' ) ); + + // extract filename without path + TQString baseName = fileName.right( fileName.length() - fileName.findRev( '/' ) - 1 ); + + // chop off extension (usually '.sgrd') + baseName = baseName.left( baseName.findRev( '.' ) ); + changeTab( sheet, baseName ); + } while ( !sheet->save( fileName ) ); + + /* Add file to recent documents menue. */ + KURL url; + url.setPath( fileName ); + emit announceRecentURL( url ); +} + +void Workspace::deleteWorkSheet() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( current ) { + if ( current->modified() ) { + if ( !mAutoSave || current->fileName().isEmpty() ) { + int res = KMessageBox::warningYesNoCancel( this, + i18n( "The worksheet '%1' contains unsaved data.\n" + "Do you want to save the worksheet?" ) + .arg( tabLabel( current ) ), TQString::null, KStdGuiItem::save(), KStdGuiItem::discard() ); + if ( res == KMessageBox::Cancel ) + return; + + if ( res == KMessageBox::Yes ) + saveWorkSheet( current ); + } else + saveWorkSheet( current ); + } + + removePage( current ); + mSheetList.remove( current ); + } else { + TQString msg = i18n( "There are no worksheets that could be deleted." ); + KMessageBox::error( this, msg ); + } +} + +void Workspace::removeAllWorkSheets() +{ + WorkSheet *sheet; + while ( ( sheet = (WorkSheet*)currentPage() ) != 0 ) { + removePage( sheet ); + mSheetList.remove( sheet ); + } +} + +void Workspace::deleteWorkSheet( const TQString &fileName ) +{ + TQPtrListIterator<WorkSheet> it( mSheetList ); + for ( ; it.current(); ++it ) + if ( (*it)->fileName() == fileName ) { + removePage( *it ); + mSheetList.remove( *it ); + return; + } +} + +WorkSheet *Workspace::restoreWorkSheet( const TQString &fileName, const TQString &newName ) +{ + /* We might want to save the worksheet under a different name later. This + * name can be specified by newName. If newName is empty we use the + * original name to save the work sheet. */ + TQString tmpStr; + if ( newName.isEmpty() ) + tmpStr = fileName; + else + tmpStr = newName; + + // extract filename without path + TQString baseName = tmpStr.right( tmpStr.length() - tmpStr.findRev( '/' ) - 1 ); + + // chop off extension (usually '.sgrd') + baseName = baseName.left( baseName.findRev( '.' ) ); + + WorkSheet *sheet = new WorkSheet( this ); + sheet->setTitle( baseName ); + insertTab( sheet, baseName ); + showPage( sheet ); + + if ( !sheet->load( fileName ) ) { + delete sheet; + return NULL; + } + + mSheetList.append( sheet ); + connect( sheet, TQT_SIGNAL( sheetModified( TQWidget* ) ), + TQT_SLOT( updateCaption( TQWidget* ) ) ); + + /* Force the file name to be the new name. This also sets the modified + * flag, so that the file will get saved on exit. */ + if ( !newName.isEmpty() ) + sheet->setFileName( newName ); + + return sheet; +} + +void Workspace::cut() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( current ) + current->cut(); +} + +void Workspace::copy() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( current ) + current->copy(); +} + +void Workspace::paste() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( current ) + current->paste(); +} + +void Workspace::configure() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( !current ) + return; + + current->settings(); +} + +void Workspace::updateCaption( TQWidget* wdg ) +{ + if ( wdg ) + emit setCaption( tabLabel( wdg ), ((WorkSheet*)wdg)->modified() ); + else + emit setCaption( TQString::null, false ); + + for ( WorkSheet* s = mSheetList.first(); s != 0; s = mSheetList.next() ) + ((WorkSheet*)s)->setIsOnTop( s == wdg ); +} + +void Workspace::updateSheetTitle( TQWidget* wdg ) +{ + if ( wdg ) + changeTab( wdg, static_cast<WorkSheet*>( wdg )->title() ); +} + +void Workspace::applyStyle() +{ + if ( currentPage() ) + ((WorkSheet*)currentPage())->applyStyle(); +} + +void Workspace::showProcesses() +{ + TDEStandardDirs* kstd = TDEGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + + TQString file = kstd->findResource( "data", "ProcessTable.sgrd" ); + if ( file.isEmpty() ) { + KMessageBox::error( this, i18n( "Cannot find file ProcessTable.sgrd." ) ); + return; + } + WorkSheet *processSheet = restoreWorkSheet( file ); + if(!processSheet) return; + + //Set the focus of the search line. This is nasty I know, but I don't know how better to do this :( + KSGRD::SensorDisplay *processSensor = processSheet->display( 0,0 ); + if(!processSensor || !processSensor->isA("ProcessController")) return; + ProcessController *controller = dynamic_cast<ProcessController *>(processSensor); + if(!controller) return; + controller->setSearchFocus(); + +} + +#include "Workspace.moc" diff --git a/ksysguard/gui/Workspace.h b/ksysguard/gui/Workspace.h new file mode 100644 index 000000000..40302ac4a --- /dev/null +++ b/ksysguard/gui/Workspace.h @@ -0,0 +1,84 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_WORKSPACE_H +#define KSG_WORKSPACE_H + +#include <tqptrlist.h> +#include <tqtabwidget.h> + +class TDEConfig; +class KURL; +class TQString; +class WorkSheet; + +class Workspace : public TQTabWidget +{ + Q_OBJECT + + public: + Workspace( TQWidget* parent, const char* name = 0 ); + ~Workspace(); + + void saveProperties( TDEConfig* ); + void readProperties( TDEConfig* ); + + bool saveOnQuit(); + + void showProcesses(); + + WorkSheet *restoreWorkSheet( const TQString &fileName, + const TQString &newName = TQString::null ); + void deleteWorkSheet( const TQString &fileName ); + + public slots: + void newWorkSheet(); + void loadWorkSheet(); + void loadWorkSheet( const KURL& ); + void saveWorkSheet(); + void saveWorkSheet( WorkSheet *sheet ); + void saveWorkSheetAs(); + void saveWorkSheetAs( WorkSheet *sheet ); + void deleteWorkSheet(); + void removeAllWorkSheets(); + void cut(); + void copy(); + void paste(); + void configure(); + void updateCaption( TQWidget* ); + void updateSheetTitle( TQWidget* ); + void applyStyle(); + + signals: + void announceRecentURL( const KURL &url ); + void setCaption( const TQString &text, bool modified ); + + private: + TQPtrList<WorkSheet> mSheetList; + + // Directory that was used for the last load/save. + TQString mWorkDir; + bool mAutoSave; +}; + +#endif diff --git a/ksysguard/gui/kpm.c b/ksysguard/gui/kpm.c new file mode 100644 index 000000000..9f41b3065 --- /dev/null +++ b/ksysguard/gui/kpm.c @@ -0,0 +1,8 @@ +/* A small wrapper to call ksysguard --showprocesses */ + +#include <unistd.h> + +int main() +{ + return execlp( "ksysguard", "ksysguard", "--showprocesses", NULL ); +} diff --git a/ksysguard/gui/ksgrd/CMakeLists.txt b/ksysguard/gui/ksgrd/CMakeLists.txt new file mode 100644 index 000000000..b1ec7c5f8 --- /dev/null +++ b/ksysguard/gui/ksgrd/CMakeLists.txt @@ -0,0 +1,43 @@ +################################################# +# +# (C) 2010-2011 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${TDE_INCLUDE_DIR} + ${TQT_INCLUDE_DIRS} +) + +link_directories( + ${TQT_LIBRARY_DIRS} +) + + +##### headers ################################### + +install( FILES + HostConnector.h SensorAgent.h SensorClient.h + SensorManager.h SensorShellAgent.h SensorSocketAgent.h + StyleEngine.h StyleSettings.h TimerSettings.h + DESTINATION ${INCLUDE_INSTALL_DIR}/ksgrd ) + + +##### ksgrd (shared) ############################ + +tde_add_library( ksgrd SHARED AUTOMOC + SOURCES + HostConnector.cc SensorAgent.cc SensorManager.cc + SensorShellAgent.cc SensorSocketAgent.cc StyleEngine.cc + StyleSettings.cc TimerSettings.cc + VERSION 1.2.0 + LINK tdeui-shared + DESTINATION ${LIB_INSTALL_DIR} +) diff --git a/ksysguard/gui/ksgrd/HostConnector.cc b/ksysguard/gui/ksgrd/HostConnector.cc new file mode 100644 index 000000000..b6e85b795 --- /dev/null +++ b/ksysguard/gui/ksgrd/HostConnector.cc @@ -0,0 +1,217 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#include <tdeapplication.h> +#include <tdeaccelmanager.h> +#include <kcombobox.h> +#include <tdelocale.h> + +#include <tqbuttongroup.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqradiobutton.h> +#include <tqspinbox.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> + +#include "HostConnector.h" + +HostConnector::HostConnector( TQWidget *parent, const char *name ) + : KDialogBase( Plain, i18n( "Connect Host" ), Help | Ok | Cancel, Ok, + parent, name, true, true ) +{ + TQFrame *page = plainPage(); + TQGridLayout *layout = new TQGridLayout( page, 2, 2, 0, spacingHint() ); + layout->setColStretch( 1, 1 ); + + TQLabel *label = new TQLabel( i18n( "Host:" ), page ); + layout->addWidget( label, 0, 0 ); + + mHostNames = new KComboBox( true, page ); + mHostNames->setMaxCount( 20 ); + mHostNames->setInsertionPolicy( TQComboBox::AtTop ); + mHostNames->setAutoCompletion( true ); + mHostNames->setDuplicatesEnabled( false ); + layout->addWidget( mHostNames, 0, 1 ); + label->setBuddy( mHostNames ); + TQWhatsThis::add( mHostNames, i18n( "Enter the name of the host you want to connect to." ) ); + + mHostNameLabel = new TQLabel( page ); + mHostNameLabel->hide(); + layout->addWidget( mHostNameLabel, 0, 1 ); + + TQButtonGroup *group = new TQButtonGroup( 0, Qt::Vertical, + i18n( "Connection Type" ), page ); + TQGridLayout *groupLayout = new TQGridLayout( group->layout(), 4, 4, + spacingHint() ); + groupLayout->setAlignment( Qt::AlignTop ); + + mUseSsh = new TQRadioButton( i18n( "ssh" ), group ); + mUseSsh->setEnabled( true ); + mUseSsh->setChecked( true ); + TQWhatsThis::add( mUseSsh, i18n( "Select this to use the secure shell to login to the remote host." ) ); + groupLayout->addWidget( mUseSsh, 0, 0 ); + + mUseRsh = new TQRadioButton( i18n( "rsh" ), group ); + TQWhatsThis::add( mUseRsh, i18n( "Select this to use the remote shell to login to the remote host." ) ); + groupLayout->addWidget( mUseRsh, 0, 1 ); + + mUseDaemon = new TQRadioButton( i18n( "Daemon" ), group ); + TQWhatsThis::add( mUseDaemon, i18n( "Select this if you want to connect to a ksysguard daemon that is running on the machine you want to connect to, and is listening for client requests." ) ); + groupLayout->addWidget( mUseDaemon, 0, 2 ); + + mUseCustom = new TQRadioButton( i18n( "Custom command" ), group ); + TQWhatsThis::add( mUseCustom, i18n( "Select this to use the command you entered below to start ksysguardd on the remote host." ) ); + groupLayout->addWidget( mUseCustom, 0, 3 ); + + label = new TQLabel( i18n( "Port:" ), group ); + groupLayout->addWidget( label, 1, 0 ); + + mPort = new TQSpinBox( 1, 65535, 1, group ); + mPort->setEnabled( false ); + mPort->setValue( 3112 ); + TQToolTip::add( mPort, i18n( "Enter the port number on which the ksysguard daemon is listening for connections." ) ); + groupLayout->addWidget( mPort, 1, 2 ); + + label = new TQLabel( i18n( "e.g. 3112" ), group ); + groupLayout->addWidget( label, 1, 3 ); + + label = new TQLabel( i18n( "Command:" ), group ); + groupLayout->addWidget( label, 2, 0 ); + + mCommands = new KComboBox( true, group ); + mCommands->setEnabled( false ); + mCommands->setMaxCount( 20 ); + mCommands->setInsertionPolicy( TQComboBox::AtTop ); + mCommands->setAutoCompletion( true ); + mCommands->setDuplicatesEnabled( false ); + TQWhatsThis::add( mCommands, i18n( "Enter the command that runs ksysguardd on the host you want to monitor." ) ); + groupLayout->addMultiCellWidget( mCommands, 2, 2, 2, 3 ); + label->setBuddy( mCommands ); + + label = new TQLabel( i18n( "e.g. ssh -l root remote.host.org ksysguardd" ), group ); + groupLayout->addMultiCellWidget( label, 3, 3, 2, 3 ); + + layout->addMultiCellWidget( group, 1, 1, 0, 1 ); + + connect( mUseCustom, TQT_SIGNAL( toggled( bool ) ), + mCommands, TQT_SLOT( setEnabled( bool ) ) ); + connect( mUseDaemon, TQT_SIGNAL( toggled( bool ) ), + mPort, TQT_SLOT( setEnabled( bool ) ) ); + connect( mHostNames->lineEdit(), TQT_SIGNAL( textChanged ( const TQString & ) ), + this, TQT_SLOT( slotHostNameChanged( const TQString & ) ) ); + enableButtonOK( !mHostNames->lineEdit()->text().isEmpty() ); + TDEAcceleratorManager::manage( this ); +} + +HostConnector::~HostConnector() +{ +} + +void HostConnector::slotHostNameChanged( const TQString &_text ) +{ + enableButtonOK( !_text.isEmpty() ); +} + +void HostConnector::setHostNames( const TQStringList &list ) +{ + mHostNames->insertStringList( list ); +} + +TQStringList HostConnector::hostNames() const +{ + TQStringList list; + + for ( int i = 0; i < mHostNames->count(); ++i ) + list.append( mHostNames->text( i ) ); + + return list; +} + +void HostConnector::setCommands( const TQStringList &list ) +{ + mCommands->insertStringList( list ); +} + +TQStringList HostConnector::commands() const +{ + TQStringList list; + + for ( int i = 0; i < mCommands->count(); ++i ) + list.append( mCommands->text( i ) ); + + return list; +} + +void HostConnector::setCurrentHostName( const TQString &hostName ) +{ + if ( !hostName.isEmpty() ) { + mHostNames->hide(); + mHostNameLabel->setText( hostName ); + mHostNameLabel->show(); + enableButtonOK( true );//enable true when mHostNames is empty and hidden fix #66955 + } else { + mHostNameLabel->hide(); + mHostNames->show(); + mHostNames->setFocus(); + } +} + +TQString HostConnector::currentHostName() const +{ + return mHostNames->currentText(); +} + +TQString HostConnector::currentCommand() const +{ + return mCommands->currentText(); +} + +int HostConnector::port() const +{ + return mPort->value(); +} + +bool HostConnector::useSsh() const +{ + return mUseSsh->isChecked(); +} + +bool HostConnector::useRsh() const +{ + return mUseRsh->isChecked(); +} + +bool HostConnector::useDaemon() const +{ + return mUseDaemon->isChecked(); +} + +bool HostConnector::useCustom() const +{ + return mUseCustom->isChecked(); +} + +void HostConnector::slotHelp() +{ + kapp->invokeHelp( "CONNECTINGTOOTHERHOSTS", "ksysguard/the-sensor-browser.html" ); +} + +#include "HostConnector.moc" diff --git a/ksysguard/gui/ksgrd/HostConnector.h b/ksysguard/gui/ksgrd/HostConnector.h new file mode 100644 index 000000000..dbf654b7e --- /dev/null +++ b/ksysguard/gui/ksgrd/HostConnector.h @@ -0,0 +1,74 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef KSG_HOSTCONNECTOR_H +#define KSG_HOSTCONNECTOR_H + +#include <kdialogbase.h> + +class KComboBox; + +class TQLabel; +class TQRadioButton; +class TQSpinBox; + +class HostConnector : public KDialogBase +{ + Q_OBJECT + + public: + HostConnector( TQWidget *parent, const char *name = 0 ); + ~HostConnector(); + + void setHostNames( const TQStringList &list ); + TQStringList hostNames() const; + + void setCommands( const TQStringList &list ); + TQStringList commands() const; + + void setCurrentHostName( const TQString &hostName ); + + TQString currentHostName() const; + TQString currentCommand() const; + int port() const; + + bool useSsh() const; + bool useRsh() const; + bool useDaemon() const; + bool useCustom() const; + + protected slots: + virtual void slotHelp(); + void slotHostNameChanged( const TQString &_text ); + private: + KComboBox *mCommands; + KComboBox *mHostNames; + + TQLabel *mHostNameLabel; + + TQRadioButton *mUseSsh; + TQRadioButton *mUseRsh; + TQRadioButton *mUseDaemon; + TQRadioButton *mUseCustom; + + TQSpinBox *mPort; +}; + +#endif diff --git a/ksysguard/gui/ksgrd/Makefile.am b/ksysguard/gui/ksgrd/Makefile.am new file mode 100644 index 000000000..52f5bfd01 --- /dev/null +++ b/ksysguard/gui/ksgrd/Makefile.am @@ -0,0 +1,34 @@ + +# set the include path for X, qt and KDE +INCLUDES= -I$(srcdir)/../SensorDisplayLib $(all_includes) + +lib_LTLIBRARIES = libksgrd.la + +libksgrd_la_LDFLAGS = -no-undefined -version-info 3:0:2 $(all_libraries) +libksgrd_la_LIBADD = $(LIB_TDEUI) + +# Which sources should be compiled for ksysguard. +libksgrd_la_SOURCES = \ + HostConnector.cc \ + SensorAgent.cc \ + SensorManager.cc \ + SensorShellAgent.cc \ + SensorSocketAgent.cc \ + StyleEngine.cc \ + StyleSettings.cc \ + TimerSettings.cc + +ksgrdincludedir = $(includedir)/ksgrd +ksgrdinclude_HEADERS = \ + HostConnector.h \ + SensorAgent.h \ + SensorClient.h \ + SensorManager.h \ + SensorShellAgent.h \ + SensorSocketAgent.h \ + StyleEngine.h \ + StyleSettings.h \ + TimerSettings.h + +# just to make sure, automake makes them +libksgrd_la_METASOURCES = AUTO diff --git a/ksysguard/gui/ksgrd/SensorAgent.cc b/ksysguard/gui/ksgrd/SensorAgent.cc new file mode 100644 index 000000000..7f9615985 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorAgent.cc @@ -0,0 +1,260 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#include <stdlib.h> + +#include <kdebug.h> +#include <tdelocale.h> +#include <kpassdlg.h> + +#include "SensorClient.h" +#include "SensorManager.h" + +#include "SensorAgent.h" + +/** + This can be used to debug communication problems with the daemon. + Should be set to 0 in any production version. +*/ +#define SA_TRACE 0 + +using namespace KSGRD; + +SensorAgent::SensorAgent( SensorManager *sm ) + : mSensorManager( sm ) +{ + /* SensorRequests migrate from the inputFIFO to the processingFIFO. So + * we only have to delete them when they are removed from the + * processingFIFO. */ + mInputFIFO.setAutoDelete( false ); + mProcessingFIFO.setAutoDelete( true ); + + mDaemonOnLine = false; + mTransmitting = false; + mState = 0; +} + +SensorAgent::~SensorAgent() +{ +} + +bool SensorAgent::sendRequest( const TQString &req, SensorClient *client, int id ) +{ + /* The request is registered with the FIFO so that the answer can be + * routed back to the requesting client. */ + mInputFIFO.prepend( new SensorRequest( req, client, id ) ); + +#if SA_TRACE + kdDebug(1215) << "-> " << req << "(" << mInputFIFO.count() << "/" + << mProcessingFIFO.count() << ")" << endl; +#endif + executeCommand(); + + return false; +} + +void SensorAgent::processAnswer( const TQString &buffer ) +{ +#if SA_TRACE + kdDebug(1215) << "<- " << buffer << endl; +#endif + + for ( uint i = 0; i < buffer.length(); i++ ) { + if ( buffer[ i ] == '\033' ) { + mState = ( mState + 1 ) & 1; + if ( !mErrorBuffer.isEmpty() && mState == 0 ) { + if ( mErrorBuffer == "RECONFIGURE\n" ) + emit reconfigure( this ); + else { + /* We just received the end of an error message, so we + * can display it. */ + SensorMgr->notify( i18n( "Message from %1:\n%2" ) + .arg( mHostName ) + .arg( mErrorBuffer ) ); + } + mErrorBuffer = TQString::null; + } + } else if ( mState == 0 ) // receiving to answerBuffer + mAnswerBuffer += buffer[ i ]; + else // receiving to errorBuffer + mErrorBuffer += buffer[ i ]; + } + + int end; + // And now the real information + while ( ( end = mAnswerBuffer.find( "\nksysguardd> " ) ) >= 0 ) { +#if SA_TRACE + kdDebug(1215) << "<= " << mAnswerBuffer.left( end ) + << "(" << mInputFIFO.count() << "/" + << mProcessingFIFO.count() << ")" << endl; +#endif + if ( !mDaemonOnLine ) { + /* First '\nksysguardd> ' signals that the daemon is + * ready to serve requests now. */ + mDaemonOnLine = true; +#if SA_TRACE + kdDebug(1215) << "Daemon now online!" << endl; +#endif + mAnswerBuffer = TQString::null; + break; + } + + // remove pending request from FIFO + SensorRequest* req = mProcessingFIFO.last(); + if ( !req ) { + kdDebug(1215) << "ERROR: Received answer but have no pending " + << "request! : " << mAnswerBuffer.left( end ) << endl; + mAnswerBuffer = TQString::null; + } else { + if ( !req->client() ) { + /* The client has disappeared before receiving the answer + * to his request. */ + } else { + if ( mAnswerBuffer.left( end ) == "UNKNOWN COMMAND" ) { + /* Notify client that the sensor seems to be no longer + * available. */ + req->client()->sensorLost( req->id() ); + } else { + // Notify client of newly arrived answer. + req->client()->answerReceived( req->id(), mAnswerBuffer.left( end ) ); + } + } + mProcessingFIFO.removeLast(); + } + // chop off the processed part of the answer buffer + mAnswerBuffer.remove( 0, end + strlen( "\nksysguardd> " ) ); + } + + executeCommand(); +} + +void SensorAgent::executeCommand() +{ + /* This function is called whenever there is a chance that we have a + * command to pass to the daemon. But the command many only be send + * if the daemon is online and there is no other command currently + * being sent. */ + if ( mDaemonOnLine && txReady() && !mInputFIFO.isEmpty() ) { + // take oldest request for input FIFO + SensorRequest* req = mInputFIFO.last(); + mInputFIFO.removeLast(); + +#if SA_TRACE + kdDebug(1215) << ">> " << req->request().ascii() << "(" << mInputFIFO.count() + << "/" << mProcessingFIFO.count() << ")" << endl; +#endif + // send request to daemon + TQString cmdWithNL = req->request() + "\n"; + if ( writeMsg( cmdWithNL.ascii(), cmdWithNL.length() ) ) + mTransmitting = true; + else + kdDebug(1215) << "SensorAgent::writeMsg() failed" << endl; + + // add request to processing FIFO + mProcessingFIFO.prepend( req ); + } +} + +void SensorAgent::disconnectClient( SensorClient *client ) +{ + for ( SensorRequest *req = mInputFIFO.first(); req; req = mInputFIFO.next() ) + if ( req->client() == client ) + req->setClient( 0 ); + for ( SensorRequest *req = mProcessingFIFO.first(); req; req = mProcessingFIFO.next() ) + if ( req->client() == client ) + req->setClient( 0 ); +} + +SensorManager *SensorAgent::sensorManager() +{ + return mSensorManager; +} + +void SensorAgent::setDaemonOnLine( bool value ) +{ + mDaemonOnLine = value; +} + +bool SensorAgent::daemonOnLine() const +{ + return mDaemonOnLine; +} + +void SensorAgent::setTransmitting( bool value ) +{ + mTransmitting = value; +} + +bool SensorAgent::transmitting() const +{ + return mTransmitting; +} + +void SensorAgent::setHostName( const TQString &hostName ) +{ + mHostName = hostName; +} + +const TQString &SensorAgent::hostName() const +{ + return mHostName; +} + + +SensorRequest::SensorRequest( const TQString &request, SensorClient *client, int id ) + : mRequest( request ), mClient( client ), mId( id ) +{ +} + +SensorRequest::~SensorRequest() +{ +} + +void SensorRequest::setRequest( const TQString &request ) +{ + mRequest = request; +} + +TQString SensorRequest::request() const +{ + return mRequest; +} + +void SensorRequest::setClient( SensorClient *client ) +{ + mClient = client; +} + +SensorClient *SensorRequest::client() +{ + return mClient; +} + +void SensorRequest::setId( int id ) +{ + mId = id; +} + +int SensorRequest::id() +{ + return mId; +} + +#include "SensorAgent.moc" diff --git a/ksysguard/gui/ksgrd/SensorAgent.h b/ksysguard/gui/ksgrd/SensorAgent.h new file mode 100644 index 000000000..36c44095c --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorAgent.h @@ -0,0 +1,137 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef KSG_SENSORAGENT_H +#define KSG_SENSORAGENT_H + +#include <tqobject.h> +#include <tqptrlist.h> + +class TDEProcess; +class KShellProcess; + +class TQString; + +namespace KSGRD { + +class SensorClient; +class SensorManager; +class SensorRequest; + +/** + The SensorAgent depending on the type of requested connection + starts a ksysguardd process or connects through a tcp connection to + a running ksysguardd and handles the asynchronous communication. It + keeps a list of pending requests that have not been answered yet by + ksysguardd. The current implementation only allowes one pending + requests. Incoming requests are queued in an input FIFO. +*/ +class KDE_EXPORT SensorAgent : public QObject +{ + Q_OBJECT + + public: + SensorAgent( SensorManager *sm ); + virtual ~SensorAgent(); + + virtual bool start( const TQString &host, const TQString &shell, + const TQString &command = "", int port = -1 ) = 0; + + /** + This function should only be used by the the SensorManager and + never by the SensorClients directly since the pointer returned by + engaged is not guaranteed to be valid. Only the SensorManager knows + whether a SensorAgent pointer is still valid or not. + + This function sends out a command to the sensor and notifies the + agent to return the answer to 'client'. The 'id' can be used by the + client to identify the answer. It is only passed through and never + used by the SensorAgent. So it can be any value the client suits to + use. + */ + bool sendRequest( const TQString &req, SensorClient *client, int id = 0 ); + + virtual void hostInfo( TQString &sh, TQString &cmd, int &port ) const = 0; + + void disconnectClient( SensorClient *client ); + + const TQString &hostName() const; + + signals: + void reconfigure( const SensorAgent* ); + + protected: + void processAnswer( const TQString &buffer ); + void executeCommand(); + + SensorManager *sensorManager(); + + void setDaemonOnLine( bool value ); + bool daemonOnLine() const; + + void setTransmitting( bool value ); + bool transmitting() const; + + void setHostName( const TQString &hostName ); + + private: + virtual bool writeMsg( const char *msg, int len ) = 0; + virtual bool txReady() = 0; + + int mState; + TQPtrList<SensorRequest> mInputFIFO; + TQPtrList<SensorRequest> mProcessingFIFO; + TQString mAnswerBuffer; + TQString mErrorBuffer; + + SensorManager *mSensorManager; + + bool mDaemonOnLine; + bool mTransmitting; + TQString mHostName; +}; + +/** + This auxilliary class is used to store requests during their processing. +*/ +class SensorRequest +{ + public: + SensorRequest( const TQString &request, SensorClient *client, int id ); + ~SensorRequest(); + + void setRequest( const TQString& ); + TQString request() const; + + void setClient( SensorClient* ); + SensorClient *client(); + + void setId( int ); + int id(); + + private: + TQString mRequest; + SensorClient *mClient; + int mId; +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/SensorClient.h b/ksysguard/gui/ksgrd/SensorClient.h new file mode 100644 index 000000000..d4e286cb1 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorClient.h @@ -0,0 +1,209 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SENSORCLIENT_H +#define KSG_SENSORCLIENT_H + +#include <tqptrlist.h> +#include <tqstring.h> + +namespace KSGRD { + +/** + Every object that should act as a client to a sensor must inherit from + this class. A pointer to the client object is passed as SensorClient* + to the SensorAgent. When the requested information is available or a + problem occurred one of the member functions is called. + */ +class SensorClient +{ + public: + SensorClient() { } + virtual ~SensorClient() { } + + /** + This function is called whenever the information form the sensor has + been received by the sensor agent. This function must be reimplemented + by the sensor client to receive and process this information. + */ + virtual void answerReceived( int, const TQString& ) { } + + /** + In case of an unexpected fatal problem with the sensor the sensor + agent will call this function to notify the client about it. + */ + virtual void sensorLost( int ) { } +}; + +/** + Every object that has a SensorClient as a child must inherit from + this class to support the advanced update interval settings. + */ +class SensorBoard +{ + public: + SensorBoard() { } + virtual ~SensorBoard() { } + + void updateInterval( int interval ) { mUpdateInterval = interval; } + + int updateInterval() { return mUpdateInterval; } + + private: + int mUpdateInterval; +}; + +/** + The following classes are utility classes that provide a + convenient way to retrieve pieces of information from the sensor + answers. For each type of answer there is a separate class. + */ +class SensorTokenizer +{ + public: + SensorTokenizer( const TQString &info, TQChar separator ) + { + mTokens = TQStringList::split( separator, info ); + } + + ~SensorTokenizer() { } + + const TQString& operator[]( unsigned idx ) + { + return mTokens[ idx ]; + } + + uint count() + { + return mTokens.count(); + } + + private: + TQStringList mTokens; +}; + +/** + An integer info contains 4 fields seperated by TABS, a description + (name), the minimum and the maximum values and the unit. + e.g. Swap Memory 0 133885952 KB + */ +class SensorIntegerInfo : public SensorTokenizer +{ + public: + SensorIntegerInfo( const TQString &info ) + : SensorTokenizer( info, '\t' ) { } + + ~SensorIntegerInfo() { } + + const TQString &name() + { + return (*this)[ 0 ]; + } + + long min() + { + return (*this)[ 1 ].toLong(); + } + + long max() + { + return (*this)[ 2 ].toLong(); + } + + const TQString &unit() + { + return (*this)[ 3 ]; + } +}; + +/** + An float info contains 4 fields seperated by TABS, a description + (name), the minimum and the maximum values and the unit. + e.g. CPU Voltage 0.0 5.0 V + */ +class SensorFloatInfo : public SensorTokenizer +{ + public: + SensorFloatInfo( const TQString &info ) + : SensorTokenizer( info, '\t' ) { } + + ~SensorFloatInfo() { } + + const TQString &name() + { + return (*this)[ 0 ]; + } + + double min() + { + return (*this)[ 1 ].toDouble(); + } + + double max() + { + return (*this)[ 2 ].toDouble(); + } + + const TQString &unit() + { + return (*this)[ 3 ]; + } +}; + +/** + A PS line consists of information about a process. Each piece of + information is seperated by a TAB. The first 4 fields are process name, + PID, PPID and real user ID. Those fields are mandatory. + */ +class SensorPSLine : public SensorTokenizer +{ + public: + SensorPSLine( const TQString &line ) + : SensorTokenizer( line, '\t' ) { } + + ~SensorPSLine() { } + + const TQString& name() + { + return (*this)[ 0 ]; + } + + long pid() + { + return (*this)[ 1 ].toLong(); + } + + long ppid() + { + return (*this)[ 2 ].toLong(); + } + + long uid() + { + return (*this)[ 3 ].toLong(); + } +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/SensorManager.cc b/ksysguard/gui/ksgrd/SensorManager.cc new file mode 100644 index 000000000..7794d9c10 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorManager.cc @@ -0,0 +1,432 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <tqcombobox.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqradiobutton.h> +#include <tqspinbox.h> + +#include <tdeapplication.h> +#include <kdebug.h> +#include <tdelocale.h> + +#include "HostConnector.h" +#include "SensorShellAgent.h" +#include "SensorSocketAgent.h" + +#include "SensorManager.h" + +using namespace KSGRD; + +SensorManager* KSGRD::SensorMgr; + +SensorManager::SensorManager() +{ + mAgents.setAutoDelete( true ); + mDict.setAutoDelete( true ); + + // Fill the sensor description dictionary. + mDict.insert( "cpu", new TQString( i18n( "CPU Load" ) ) ); + mDict.insert( "idle", new TQString( i18n( "Idle Load" ) ) ); + mDict.insert( "sys", new TQString( i18n( "System Load" ) ) ); + mDict.insert( "nice", new TQString( i18n( "Nice Load" ) ) ); + mDict.insert( "user", new TQString( i18n( "User Load" ) ) ); + mDict.insert( "mem", new TQString( i18n( "Memory" ) ) ); + mDict.insert( "physical", new TQString( i18n( "Physical Memory" ) ) ); + mDict.insert( "swap", new TQString( i18n( "Swap Memory" ) ) ); + mDict.insert( "cached", new TQString( i18n( "Cached Memory" ) ) ); + mDict.insert( "buf", new TQString( i18n( "Buffered Memory" ) ) ); + mDict.insert( "used", new TQString( i18n( "Used Memory" ) ) ); + mDict.insert( "application", new TQString( i18n( "Application Memory" ) ) ); + mDict.insert( "free", new TQString( i18n( "Free Memory" ) ) ); + mDict.insert( "pscount", new TQString( i18n( "Process Count" ) ) ); + mDict.insert( "ps", new TQString( i18n( "Process Controller" ) ) ); + mDict.insert( "disk", new TQString( i18n( "Disk Throughput" ) ) ); + mDict.insert( "load", new TQString( i18n( "CPU Load", "Load" ) ) ); + mDict.insert( "total", new TQString( i18n( "Total Accesses" ) ) ); + mDict.insert( "rio", new TQString( i18n( "Read Accesses" ) ) ); + mDict.insert( "wio", new TQString( i18n( "Write Accesses" ) ) ); + mDict.insert( "rblk", new TQString( i18n( "Read Data" ) ) ); + mDict.insert( "wblk", new TQString( i18n( "Write Data" ) ) ); + mDict.insert( "pageIn", new TQString( i18n( "Pages In" ) ) ); + mDict.insert( "pageOut", new TQString( i18n( "Pages Out" ) ) ); + mDict.insert( "context", new TQString( i18n( "Context Switches" ) ) ); + mDict.insert( "network", new TQString( i18n( "Network" ) ) ); + mDict.insert( "interfaces", new TQString( i18n( "Interfaces" ) ) ); + mDict.insert( "receiver", new TQString( i18n( "Receiver" ) ) ); + mDict.insert( "transmitter", new TQString( i18n( "Transmitter" ) ) ); + mDict.insert( "data", new TQString( i18n( "Data" ) ) ); + mDict.insert( "compressed", new TQString( i18n( "Compressed Packets" ) ) ); + mDict.insert( "drops", new TQString( i18n( "Dropped Packets" ) ) ); + mDict.insert( "errors", new TQString( i18n( "Errors" ) ) ); + mDict.insert( "fifo", new TQString( i18n( "FIFO Overruns" ) ) ); + mDict.insert( "frame", new TQString( i18n( "Frame Errors" ) ) ); + mDict.insert( "multicast", new TQString( i18n( "Multicast" ) ) ); + mDict.insert( "packets", new TQString( i18n( "Packets" ) ) ); + mDict.insert( "carrier", new TQString( i18n( "Carrier" ) ) ); + mDict.insert( "collisions", new TQString( i18n( "Collisions" ) ) ); + mDict.insert( "sockets", new TQString( i18n( "Sockets" ) ) ); + mDict.insert( "count", new TQString( i18n( "Total Number" ) ) ); + mDict.insert( "list", new TQString( i18n( "Table" ) ) ); + mDict.insert( "apm", new TQString( i18n( "Advanced Power Management" ) ) ); + mDict.insert( "acpi", new TQString( i18n( "ACPI" ) ) ); + mDict.insert( "thermal_zone", new TQString( i18n( "Thermal Zone" ) ) ); + mDict.insert( "temperature", new TQString( i18n( "Temperature" ) ) ); + mDict.insert( "fan", new TQString( i18n( "Fan" ) ) ); + mDict.insert( "state", new TQString( i18n( "State" ) ) ); + mDict.insert( "battery", new TQString( i18n( "Battery" ) ) ); + mDict.insert( "batterycharge", new TQString( i18n( "Battery Charge" ) ) ); + mDict.insert( "batteryusage", new TQString( i18n( "Battery Usage" ) ) ); + mDict.insert( "remainingtime", new TQString( i18n( "Remaining Time" ) ) ); + mDict.insert( "interrupts", new TQString( i18n( "Interrupts" ) ) ); + mDict.insert( "loadavg1", new TQString( i18n( "Load Average (1 min)" ) ) ); + mDict.insert( "loadavg5", new TQString( i18n( "Load Average (5 min)" ) ) ); + mDict.insert( "loadavg15", new TQString( i18n( "Load Average (15 min)" ) ) ); + mDict.insert( "clock", new TQString( i18n( "Clock Frequency" ) ) ); + mDict.insert( "lmsensors", new TQString( i18n( "Hardware Sensors" ) ) ); + mDict.insert( "partitions", new TQString( i18n( "Partition Usage" ) ) ); + mDict.insert( "usedspace", new TQString( i18n( "Used Space" ) ) ); + mDict.insert( "freespace", new TQString( i18n( "Free Space" ) ) ); + mDict.insert( "filllevel", new TQString( i18n( "Fill Level" ) ) ); + + for ( int i = 0; i < 32; i++ ) { + mDict.insert( "cpu" + TQString::number( i ), + new TQString( TQString( i18n( "CPU%1" ) ).arg( i ) ) ); + mDict.insert( "disk" + TQString::number( i ), + new TQString( TQString( i18n( "Disk%1" ) ).arg( i ) ) ); + } + + for ( int i = 0; i < 6; i++) { + mDict.insert( "fan" + TQString::number( i ), + new TQString( TQString( i18n( "Fan%1" ) ).arg( i ) ) ); + mDict.insert( "temp" + TQString::number( i ), + new TQString( TQString( i18n( "Temperature%1" ) ).arg( i ) ) ); + } + + mDict.insert( "int00", new TQString( i18n( "Total" ) ) ); + + TQString num; + for ( int i = 1; i < 25; i++ ) { + num.sprintf( "%.2d", i ); + mDict.insert( "int" + num, + new TQString( TQString( i18n( "Int%1" ) ).arg( i - 1, 3 ) ) ); + } + + mDescriptions.setAutoDelete( true ); + // TODO: translated descriptions not yet implemented. + + mUnits.setAutoDelete( true ); + mUnits.insert( "1/s", new TQString( i18n( "the unit 1 per second", "1/s" ) ) ); + mUnits.insert( "kBytes", new TQString( i18n( "kBytes" ) ) ); + mUnits.insert( "min", new TQString( i18n( "the unit minutes", "min" ) ) ); + mUnits.insert( "MHz", new TQString( i18n( "the frequency unit", "MHz" ) ) ); + + mTypes.setAutoDelete( true ); + mTypes.insert( "integer", new TQString( i18n( "Integer Value" ) ) ); + mTypes.insert( "float", new TQString( i18n( "Floating Point Value" ) ) ); + mTypes.insert( "table", new TQString( i18n( "Process Controller" ) ) ); + mTypes.insert( "listview", new TQString( i18n( "Table" ) ) ); + + mBroadcaster = 0; + + mHostConnector = new HostConnector( 0 ); +} + +SensorManager::~SensorManager() +{ + delete mHostConnector; +} + +bool SensorManager::engageHost( const TQString &hostName ) +{ + bool retVal = true; + + if ( hostName.isEmpty() || mAgents.find( hostName ) == 0 ) { + if(hostName == "localhost") { + //There was a bug where the xml file would end up not specifying to connect to localhost. + //This work around makes sure we always connect to localhost + return engage( "localhost", "", "ksysguardd", -1); + } + mHostConnector->setCurrentHostName( hostName ); + + if ( mHostConnector->exec() ) { + TQString shell = ""; + TQString command = ""; + int port = -1; + + /* Check which radio button is selected and set parameters + * appropriately. */ + if ( mHostConnector->useSsh() ) + shell = "ssh"; + else if ( mHostConnector->useRsh() ) + shell = "rsh"; + else if ( mHostConnector->useDaemon() ) + port = mHostConnector->port(); + else + command = mHostConnector->currentCommand(); + + if ( hostName.isEmpty() ) + retVal = engage( mHostConnector->currentHostName(), shell, + command, port ); + else + retVal = engage( hostName, shell, command, port ); + } + } + + return retVal; +} + +bool SensorManager::engage( const TQString &hostName, const TQString &shell, + const TQString &command, int port ) +{ + SensorAgent *agent; + + if ( ( agent = mAgents.find( hostName ) ) == 0 ) { + if ( port == -1 ) + agent = new SensorShellAgent( this ); + else + agent = new SensorSocketAgent( this ); + + if ( !agent->start( hostName.ascii(), shell, command, port ) ) { + delete agent; + return false; + } + + mAgents.insert( hostName, agent ); + connect( agent, TQT_SIGNAL( reconfigure( const SensorAgent* ) ), + TQT_SLOT( reconfigure( const SensorAgent* ) ) ); + + emit update(); + return true; + } + + return false; +} + +void SensorManager::requestDisengage( const SensorAgent *agent ) +{ + /* When a sensor agent becomes disfunctional it calls this function + * to request that it is being removed from the SensorManager. It must + * not call disengage() directly since it would trigger ~SensorAgent() + * while we are still in a SensorAgent member function. + * So we have to post an event which is later caught by + * SensorManger::customEvent(). */ + TQCustomEvent* event = new TQCustomEvent( TQEvent::User, (void*)agent ); + kapp->postEvent( this, event ); +} + +bool SensorManager::disengage( const SensorAgent *agent ) +{ + TQDictIterator<SensorAgent> it( mAgents ); + + for ( ; it.current(); ++it ) + if ( it.current() == agent ) { + mAgents.remove( it.currentKey() ); + emit update(); + return true; + } + + return false; +} + +bool SensorManager::disengage( const TQString &hostName ) +{ + SensorAgent *agent; + if ( ( agent = mAgents.find( hostName ) ) != 0 ) { + mAgents.remove( hostName ); + emit update(); + return true; + } + + return false; +} + +bool SensorManager::resynchronize( const TQString &hostName ) +{ + SensorAgent *agent; + + if ( ( agent = mAgents.find( hostName ) ) == 0 ) + return false; + + TQString shell, command; + int port; + hostInfo( hostName, shell, command, port ); + + disengage( hostName ); + + kdDebug (1215) << "Re-synchronizing connection to " << hostName << endl; + + return engage( hostName, shell, command ); +} + +void SensorManager::hostLost( const SensorAgent *agent ) +{ + emit hostConnectionLost( agent->hostName() ); + + if ( mBroadcaster ) { + TQCustomEvent *event = new TQCustomEvent( TQEvent::User ); + event->setData( new TQString( i18n( "Connection to %1 has been lost." ) + .arg( agent->hostName() ) ) ); + kapp->postEvent( mBroadcaster, event ); + } +} + +void SensorManager::notify( const TQString &msg ) const +{ + /* This function relays text messages to the toplevel widget that + * displays the message in a pop-up box. It must be used for objects + * that might have been deleted before the pop-up box is closed. */ + if ( mBroadcaster ) { + TQCustomEvent *event = new TQCustomEvent( TQEvent::User ); + event->setData( new TQString( msg ) ); + kapp->postEvent( mBroadcaster, event ); + } +} + +void SensorManager::setBroadcaster( TQWidget *wdg ) +{ + mBroadcaster = wdg; +} + +void SensorManager::reconfigure( const SensorAgent* ) +{ + emit update(); +} + +bool SensorManager::event( TQEvent *event ) +{ + if ( event->type() == TQEvent::User ) { + disengage( (const SensorAgent*)((TQCustomEvent*)event)->data() ); + return true; + } + + return false; +} + +bool SensorManager::sendRequest( const TQString &hostName, const TQString &req, + SensorClient *client, int id ) +{ + SensorAgent *agent = mAgents.find( hostName ); + if( !agent && hostName == "localhost") { + //we should always be able to reconnect to localhost + engage("localhost", "", "ksysguardd", -1); + agent = mAgents.find( hostName ); + } + if ( agent ) { + agent->sendRequest( req, client, id ); + return true; + } + + return false; +} + +const TQString SensorManager::hostName( const SensorAgent *agent) const +{ + TQDictIterator<SensorAgent> it( mAgents ); + + while ( it.current() ) { + if ( it.current() == agent ) + return it.currentKey(); + ++it; + } + + return TQString::null; +} + +bool SensorManager::hostInfo( const TQString &hostName, TQString &shell, + TQString &command, int &port ) +{ + SensorAgent *agent; + if ( ( agent = mAgents.find( hostName ) ) != 0 ) { + agent->hostInfo( shell, command, port ); + return true; + } + + return false; +} + +const TQString &SensorManager::translateUnit( const TQString &unit ) const +{ + if ( !unit.isEmpty() && mUnits[ unit ] ) + return *mUnits[ unit ]; + else + return unit; +} + +const TQString &SensorManager::translateSensorPath( const TQString &path ) const +{ + if ( !path.isEmpty() && mDict[ path ] ) + return *mDict[ path ]; + else + return path; +} + +const TQString &SensorManager::translateSensorType( const TQString &type ) const +{ + if ( !type.isEmpty() && mTypes[ type ] ) + return *mTypes[ type ]; + else + return type; +} + +TQString SensorManager::translateSensor( const TQString &sensor ) const +{ + TQString token, out; + int start = 0, end = 0; + for ( ; ; ) { + end = sensor.find( '/', start ); + if ( end > 0 ) + out += translateSensorPath( sensor.mid( start, end - start ) ) + "/"; + else { + out += translateSensorPath( sensor.right( sensor.length() - start ) ); + break; + } + start = end + 1; + } + + return out; +} + +void SensorManager::readProperties( TDEConfig *cfg ) +{ + mHostConnector->setHostNames( cfg->readListEntry( "HostList" ) ); + mHostConnector->setCommands( cfg->readListEntry( "CommandList" ) ); +} + +void +SensorManager::saveProperties( TDEConfig *cfg ) +{ + cfg->writeEntry( "HostList", mHostConnector->hostNames() ); + cfg->writeEntry( "CommandList", mHostConnector->commands() ); +} + +void SensorManager::disconnectClient( SensorClient *client ) +{ + TQDictIterator<SensorAgent> it( mAgents ); + + for ( ; it.current(); ++it) + it.current()->disconnectClient( client ); +} + +#include "SensorManager.moc" diff --git a/ksysguard/gui/ksgrd/SensorManager.h b/ksysguard/gui/ksgrd/SensorManager.h new file mode 100644 index 000000000..1e859c638 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorManager.h @@ -0,0 +1,126 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef KSG_SENSORMANAGER_H +#define KSG_SENSORMANAGER_H + +#include <tdeconfig.h> + +#include <tqdict.h> +#include <tqobject.h> + +#include <SensorAgent.h> + +class HostConnector; + +namespace KSGRD { + +class SensorManagerIterator; + +/** + The SensorManager handles all interaction with the connected + hosts. Connections to a specific hosts are handled by + SensorAgents. Use engage() to establish a connection and + disengage() to terminate the connection. If you don't know if a + certain host is already connected use engageHost(). If there is no + connection yet or the hostname is empty, a dialog will be shown to + enter the connections details. + */ +class KDE_EXPORT SensorManager : public QObject +{ + Q_OBJECT + + friend class SensorManagerIterator; + + public: + SensorManager(); + ~SensorManager(); + + bool engageHost( const TQString &hostName ); + bool engage( const TQString &hostName, const TQString &shell = "ssh", + const TQString &command = "", int port = -1 ); + + void requestDisengage( const SensorAgent *agent ); + bool disengage( const SensorAgent *agent ); + bool disengage( const TQString &hostName ); + bool resynchronize( const TQString &hostName ); + void hostLost( const SensorAgent *agent ); + void notify( const TQString &msg ) const; + + void setBroadcaster( TQWidget *wdg ); + + virtual bool event( TQEvent *event ); + + bool sendRequest( const TQString &hostName, const TQString &request, + SensorClient *client, int id = 0 ); + + const TQString hostName( const SensorAgent *sensor ) const; + bool hostInfo( const TQString &host, TQString &shell, + TQString &command, int &port ); + + const TQString& translateUnit( const TQString &unit ) const; + const TQString& translateSensorPath( const TQString &path ) const; + const TQString& translateSensorType( const TQString &type ) const; + TQString translateSensor(const TQString& u) const; + + void readProperties( TDEConfig *cfg ); + void saveProperties( TDEConfig *cfg ); + + void disconnectClient( SensorClient *client ); + + public slots: + void reconfigure( const SensorAgent *agent ); + + signals: + void update(); + void hostConnectionLost( const TQString &hostName ); + + protected: + TQDict<SensorAgent> mAgents; + + private: + /** + These dictionary stores the localized versions of the sensor + descriptions and units. + */ + TQDict<TQString> mDescriptions; + TQDict<TQString> mUnits; + TQDict<TQString> mDict; + TQDict<TQString> mTypes; + + TQWidget* mBroadcaster; + + HostConnector* mHostConnector; +}; + +KDE_EXPORT extern SensorManager* SensorMgr; + +class KDE_EXPORT SensorManagerIterator : public TQDictIterator<SensorAgent> +{ + public: + SensorManagerIterator( const SensorManager *sm ) + : TQDictIterator<SensorAgent>( sm->mAgents ) { } + + ~SensorManagerIterator() { } +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/SensorShellAgent.cc b/ksysguard/gui/ksgrd/SensorShellAgent.cc new file mode 100644 index 000000000..7e137ad56 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorShellAgent.cc @@ -0,0 +1,141 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#include <stdlib.h> + +#include <kdebug.h> +#include <kpassdlg.h> +#include <kprocess.h> + +#include "SensorClient.h" +#include "SensorManager.h" + +#include "SensorShellAgent.h" + +using namespace KSGRD; + +SensorShellAgent::SensorShellAgent( SensorManager *sm ) + : SensorAgent( sm ), mDaemon( 0 ) +{ +} + +SensorShellAgent::~SensorShellAgent() +{ + if ( mDaemon ) { + mDaemon->writeStdin( "quit\n", strlen( "quit\n" ) ); + delete mDaemon; + mDaemon = 0; + } +} + +bool SensorShellAgent::start( const TQString &host, const TQString &shell, + const TQString &command, int ) +{ + mRetryCount = 3; + mDaemon = new TDEProcess; + mDaemon->setUseShell(true); + setHostName( host ); + mShell = shell; + mCommand = command; + + connect( mDaemon, TQT_SIGNAL( processExited( TDEProcess* ) ), + TQT_SLOT( daemonExited( TDEProcess* ) ) ); + connect( mDaemon, TQT_SIGNAL( receivedStdout( TDEProcess*, char*, int ) ), + TQT_SLOT( msgRcvd( TDEProcess*, char*, int ) ) ); + connect( mDaemon, TQT_SIGNAL( receivedStderr( TDEProcess*, char*, int ) ), + TQT_SLOT( errMsgRcvd( TDEProcess*, char*, int ) ) ); + connect( mDaemon, TQT_SIGNAL( wroteStdin( TDEProcess* ) ), + TQT_SLOT( msgSent( TDEProcess* ) ) ); + + TQString cmd; + if ( !command.isEmpty() ) + cmd = command; + else + cmd = mShell + " " + hostName() + " ksysguardd"; + *mDaemon << cmd; + + if ( !mDaemon->start( TDEProcess::NotifyOnExit, TDEProcess::All ) ) { + sensorManager()->hostLost( this ); + kdDebug (1215) << "Command '" << cmd << "' failed" << endl; + return false; + } + + return true; +} + +void SensorShellAgent::hostInfo( TQString &shell, TQString &command, + int &port) const +{ + shell = mShell; + command = mCommand; + port = -1; +} + +void SensorShellAgent::msgSent( TDEProcess* ) +{ + setTransmitting( false ); + + // Try to send next request if available. + executeCommand(); +} + +void SensorShellAgent::msgRcvd( TDEProcess*, char *buffer, int buflen ) +{ + if ( !buffer || buflen == 0 ) + return; + mRetryCount = 3; //we recieved an answer, so reset our retry count back to 3 + TQString aux = TQString::fromLocal8Bit( buffer, buflen ); + + processAnswer( aux ); +} + +void SensorShellAgent::errMsgRcvd( TDEProcess*, char *buffer, int buflen ) +{ + if ( !buffer || buflen == 0 ) + return; + + TQString buf = TQString::fromLocal8Bit( buffer, buflen ); + + kdDebug(1215) << "SensorShellAgent: Warning, received text over stderr!" + << endl << buf << endl; +} + +void SensorShellAgent::daemonExited( TDEProcess *process ) +{ + kdDebug() << "daemonExited" << endl; + if ( mRetryCount-- <= 0 || !mDaemon->start( TDEProcess::NotifyOnExit, TDEProcess::All ) ) { + kdDebug() << "daemon could not be restart" << endl; + setDaemonOnLine( false ); + sensorManager()->hostLost( this ); + sensorManager()->requestDisengage( this ); + } +} + +bool SensorShellAgent::writeMsg( const char *msg, int len ) +{ + return mDaemon->writeStdin( msg, len ); +} + +bool SensorShellAgent::txReady() +{ + return !transmitting(); +} + +#include "SensorShellAgent.moc" diff --git a/ksysguard/gui/ksgrd/SensorShellAgent.h b/ksysguard/gui/ksgrd/SensorShellAgent.h new file mode 100644 index 000000000..2befd346b --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorShellAgent.h @@ -0,0 +1,77 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef KSG_SENSORSHELLAGENT_H +#define KSG_SENSORSHELLAGENT_H + +#include <tqobject.h> +#include <tqptrlist.h> +#include <tqguardedptr.h> + +#include <SensorAgent.h> + +class TQString; + +class TDEProcess; + +namespace KSGRD { + +class SensorClient; +class SensorManager; + +/** + The SensorShellAgent starts a ksysguardd process and handles the + asynchronous communication. It keeps a list of pending requests + that have not been answered yet by ksysguard. The current + implementation only allowes one pending requests. Incoming requests + are queued in an input FIFO. + */ +class SensorShellAgent : public SensorAgent +{ + Q_OBJECT + + public: + SensorShellAgent( SensorManager *sm ); + ~SensorShellAgent(); + + bool start( const TQString &host, const TQString &shell, + const TQString &command = "", int port = -1 ); + + void hostInfo( TQString &shell, TQString &command, int &port) const; + + private slots: + void msgSent( TDEProcess* ); + void msgRcvd( TDEProcess*, char *buffer, int buflen ); + void errMsgRcvd( TDEProcess*, char *buffer, int buflen ); + void daemonExited( TDEProcess* ); + + private: + bool writeMsg( const char *msg, int len ); + bool txReady(); + + TQGuardedPtr<TDEProcess> mDaemon; + TQString mShell; + TQString mCommand; + int mRetryCount; +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/SensorSocketAgent.cc b/ksysguard/gui/ksgrd/SensorSocketAgent.cc new file mode 100644 index 000000000..30c0cc7e9 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorSocketAgent.cc @@ -0,0 +1,137 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#include <stdlib.h> + +#include <kdebug.h> +#include <tdelocale.h> +#include <kpassdlg.h> + +#include "SensorClient.h" +#include "SensorManager.h" + +#include "SensorSocketAgent.h" + +using namespace KSGRD; + +SensorSocketAgent::SensorSocketAgent( SensorManager *sm ) + : SensorAgent( sm ) +{ + connect( &mSocket, TQT_SIGNAL( gotError( int ) ), TQT_SLOT( error( int ) ) ); + connect( &mSocket, TQT_SIGNAL( bytesWritten( int ) ), TQT_SLOT( msgSent( int ) ) ); + connect( &mSocket, TQT_SIGNAL( readyRead() ), TQT_SLOT( msgRcvd() ) ); + connect( &mSocket, TQT_SIGNAL( closed() ), TQT_SLOT( connectionClosed() ) ); +} + +SensorSocketAgent::~SensorSocketAgent() +{ + mSocket.writeBlock( "quit\n", strlen( "quit\n" ) ); + mSocket.flush(); +} + +bool SensorSocketAgent::start( const TQString &host, const TQString&, + const TQString&, int port ) +{ + if ( port <= 0 ) + kdDebug(1215) << "SensorSocketAgent::start: Illegal port " << port << endl; + + setHostName( host ); + mPort = port; + + mSocket.connect( hostName(), TQString::number(mPort) ); + + return true; +} + +void SensorSocketAgent::hostInfo( TQString &shell, TQString &command, int &port ) const +{ + shell = TQString::null; + command = TQString::null; + port = mPort; +} + +void SensorSocketAgent::msgSent( int ) +{ + if ( mSocket.bytesToWrite() != 0 ) + return; + + setTransmitting( false ); + + // Try to send next request if available. + executeCommand(); +} + +void SensorSocketAgent::msgRcvd() +{ + int buflen = mSocket.bytesAvailable(); + char* buffer = new char[ buflen ]; + + mSocket.readBlock( buffer, buflen ); + TQString buf = TQString::fromLocal8Bit( buffer, buflen ); + delete [] buffer; + + processAnswer( buf ); +} + +void SensorSocketAgent::connectionClosed() +{ + setDaemonOnLine( false ); + sensorManager()->hostLost( this ); + sensorManager()->requestDisengage( this ); +} + +void SensorSocketAgent::error( int id ) +{ + switch ( id ) { + case KNetwork::TDESocketBase::ConnectionRefused: + SensorMgr->notify( i18n( "Connection to %1 refused" ) + .arg( hostName() ) ); + break; + case KNetwork::TDESocketBase::LookupFailure: + SensorMgr->notify( i18n( "Host %1 not found" ) + .arg( hostName() ) ); + break; + case KNetwork::TDESocketBase::Timeout: + SensorMgr->notify( i18n( "Timeout at host %1") + .arg( hostName() ) ); + break; + case KNetwork::TDESocketBase::NetFailure: + SensorMgr->notify( i18n( "Network failure host %1") + .arg( hostName() ) ); + break; + default: + kdDebug(1215) << "SensorSocketAgent::error() unknown error " << id << endl; + } + + setDaemonOnLine( false ); + sensorManager()->requestDisengage( this ); +} + +bool SensorSocketAgent::writeMsg( const char *msg, int len ) +{ + return ( mSocket.writeBlock( msg, len ) == len ); +} + +bool SensorSocketAgent::txReady() +{ + return !transmitting(); +} + +#include "SensorSocketAgent.moc" diff --git a/ksysguard/gui/ksgrd/SensorSocketAgent.h b/ksysguard/gui/ksgrd/SensorSocketAgent.h new file mode 100644 index 000000000..7b9062f17 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorSocketAgent.h @@ -0,0 +1,71 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef KSG_SENSORSOCKETAGENT_H +#define KSG_SENSORSOCKETAGENT_H + +#include <tqptrlist.h> +#include <kbufferedsocket.h> + +#include <SensorAgent.h> + +class TQString; + +namespace KSGRD { + +class SensorClient; + +/** + The SensorSocketAgent connects to a ksysguardd via a TCP + connection. It keeps a list of pending requests that have not been + answered yet by ksysguard. The current implementation only allowes + one pending requests. Incoming requests are queued in an input + FIFO. + */ +class SensorSocketAgent : public SensorAgent +{ + Q_OBJECT + + public: + SensorSocketAgent( SensorManager *sm ); + ~SensorSocketAgent(); + + bool start( const TQString &host, const TQString &shell, + const TQString &command = "", int port = -1 ); + + void hostInfo( TQString &shell, TQString &command, int &port ) const; + + private slots: + void connectionClosed(); + void msgSent( int ); + void msgRcvd(); + void error( int ); + + private: + bool writeMsg( const char *msg, int len ); + bool txReady(); + + KNetwork::TDEBufferedSocket mSocket; + int mPort; +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/StyleEngine.cc b/ksysguard/gui/ksgrd/StyleEngine.cc new file mode 100644 index 000000000..ce3e3bd6b --- /dev/null +++ b/ksysguard/gui/ksgrd/StyleEngine.cc @@ -0,0 +1,176 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <tqimage.h> +#include <tqpushbutton.h> +#include <tqspinbox.h> + +#include <tdeconfig.h> +#include <tdelocale.h> + +#include "StyleSettings.h" + +#include "StyleEngine.h" + +using namespace KSGRD; + +StyleEngine* KSGRD::Style; + +StyleEngine::StyleEngine() +{ + mFirstForegroundColor = TQColor( 0x6894c9 ); // light blue + mSecondForegroundColor = TQColor( 0x6894c9 ); // light blue + mAlarmColor = TQColor( 255, 0, 0 ); + mBackgroundColor = TQColor( 0x313031 ); // almost black + mFontSize = 9; + + mSensorColors.append( TQColor( 0x1889ff ) ); // soft blue + mSensorColors.append( TQColor( 0xff7f08 ) ); // reddish + mSensorColors.append( TQColor( 0xffeb14 ) ); // bright yellow + + uint v = 0x00ff00; + for ( uint i = mSensorColors.count(); i < 32; ++i ) { + v = ( ( ( v + 82 ) & 0xff ) << 23 ) | ( v >> 8 ); + mSensorColors.append( TQColor( v & 0xff, ( v >> 16 ) & 0xff, ( v >> 8 ) & 0xff ) ); + } +} + +StyleEngine::~StyleEngine() +{ +} + +void StyleEngine::readProperties( TDEConfig *cfg ) +{ + mFirstForegroundColor = cfg->readColorEntry( "fgColor1", &mFirstForegroundColor ); + mSecondForegroundColor = cfg->readColorEntry( "fgColor2", &mSecondForegroundColor ); + mAlarmColor = cfg->readColorEntry( "alarmColor", &mAlarmColor ); + mBackgroundColor = cfg->readColorEntry( "backgroundColor", &mBackgroundColor ); + mFontSize = cfg->readNumEntry( "fontSize", mFontSize ); + + TQStringList list = cfg->readListEntry( "sensorColors" ); + if ( !list.isEmpty() ) { + mSensorColors.clear(); + TQStringList::Iterator it; + for ( it = list.begin(); it != list.end(); ++it ) + mSensorColors.append( TQColor( *it ) ); + } +} + +void StyleEngine::saveProperties( TDEConfig *cfg ) +{ + cfg->writeEntry( "fgColor1", mFirstForegroundColor ); + cfg->writeEntry( "fgColor2", mSecondForegroundColor ); + cfg->writeEntry( "alarmColor", mAlarmColor ); + cfg->writeEntry( "backgroundColor", mBackgroundColor ); + cfg->writeEntry( "fontSize", mFontSize ); + + TQStringList list; + TQValueList<TQColor>::Iterator it; + for ( it = mSensorColors.begin(); it != mSensorColors.end(); ++it ) + list.append( (*it).name() ); + + cfg->writeEntry( "sensorColors", list ); +} + +const TQColor &StyleEngine::firstForegroundColor() const +{ + return mFirstForegroundColor; +} + +const TQColor &StyleEngine::secondForegroundColor() const +{ + return mSecondForegroundColor; +} + +const TQColor &StyleEngine::alarmColor() const +{ + return mAlarmColor; +} + +const TQColor &StyleEngine::backgroundColor() const +{ + return mBackgroundColor; +} + +uint StyleEngine::fontSize() const +{ + return mFontSize; +} + +const TQColor& StyleEngine::sensorColor( uint pos ) +{ + static TQColor dummy; + + if ( pos < mSensorColors.count() ) + return *mSensorColors.at( pos ); + else + return dummy; +} + +uint StyleEngine::numSensorColors() const +{ + return mSensorColors.count(); +} + +void StyleEngine::configure() +{ + mSettingsDialog = new StyleSettings( 0 ); + + mSettingsDialog->setFirstForegroundColor( mFirstForegroundColor ); + mSettingsDialog->setSecondForegroundColor( mSecondForegroundColor ); + mSettingsDialog->setAlarmColor( mAlarmColor ); + mSettingsDialog->setBackgroundColor( mBackgroundColor ); + mSettingsDialog->setFontSize( mFontSize ); + mSettingsDialog->setSensorColors( mSensorColors ); + + connect( mSettingsDialog, TQT_SIGNAL( applyClicked() ), + this, TQT_SLOT( applyToWorksheet() ) ); + + if ( mSettingsDialog->exec() ) + apply(); + + delete mSettingsDialog; + mSettingsDialog = 0; +} + +void StyleEngine::applyToWorksheet() +{ + apply(); + emit applyStyleToWorksheet(); +} + +void StyleEngine::apply() +{ + if ( !mSettingsDialog ) + return; + + mFirstForegroundColor = mSettingsDialog->firstForegroundColor(); + mSecondForegroundColor = mSettingsDialog->secondForegroundColor(); + mAlarmColor = mSettingsDialog->alarmColor(); + mBackgroundColor = mSettingsDialog->backgroundColor(); + mFontSize = mSettingsDialog->fontSize(); + + mSensorColors = mSettingsDialog->sensorColors(); +} + +#include "StyleEngine.moc" diff --git a/ksysguard/gui/ksgrd/StyleEngine.h b/ksysguard/gui/ksgrd/StyleEngine.h new file mode 100644 index 000000000..50ec06e0b --- /dev/null +++ b/ksysguard/gui/ksgrd/StyleEngine.h @@ -0,0 +1,86 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_STYLEENGINE_H +#define KSG_STYLEENGINE_H + +#include <tqcolor.h> +#include <tqobject.h> +#include <tqptrlist.h> + +#include <kdemacros.h> + +class TDEConfig; + +class TQListBoxItem; + +class StyleSettings; + +namespace KSGRD { + +class KDE_EXPORT StyleEngine : public QObject +{ + Q_OBJECT + + public: + StyleEngine(); + ~StyleEngine(); + + void readProperties( TDEConfig* ); + void saveProperties( TDEConfig* ); + + const TQColor& firstForegroundColor() const; + const TQColor& secondForegroundColor() const; + const TQColor& alarmColor() const; + const TQColor& backgroundColor() const; + + uint fontSize() const; + + const TQColor& sensorColor( uint pos ); + uint numSensorColors() const; + + public slots: + void configure(); + void applyToWorksheet(); + + signals: + void applyStyleToWorksheet(); + + private: + void apply(); + + TQColor mFirstForegroundColor; + TQColor mSecondForegroundColor; + TQColor mAlarmColor; + TQColor mBackgroundColor; + uint mFontSize; + TQValueList<TQColor> mSensorColors; + + StyleSettings *mSettingsDialog; +}; + +KDE_EXPORT extern StyleEngine* Style; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/StyleSettings.cc b/ksysguard/gui/ksgrd/StyleSettings.cc new file mode 100644 index 000000000..b84d3e407 --- /dev/null +++ b/ksysguard/gui/ksgrd/StyleSettings.cc @@ -0,0 +1,201 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <tqimage.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqlistbox.h> +#include <tqpixmap.h> +#include <tqpushbutton.h> +#include <tqspinbox.h> +#include <tqtabwidget.h> + +#include <tdeaccelmanager.h> +#include <kcolorbutton.h> +#include <kcolordialog.h> +#include <tdelocale.h> + +#include "StyleSettings.h" + +StyleSettings::StyleSettings( TQWidget *parent, const char *name ) + : KDialogBase( Tabbed, i18n( "Global Style Settings" ), Help | Ok | Apply | + Cancel, Ok, parent, name, true, true ) +{ + TQFrame *page = addPage( i18n( "Display Style" ) ); + TQGridLayout *layout = new TQGridLayout( page, 6, 2, 0, spacingHint() ); + + TQLabel *label = new TQLabel( i18n( "First foreground color:" ), page ); + layout->addWidget( label, 0, 0 ); + + mFirstForegroundColor = new KColorButton( page ); + layout->addWidget( mFirstForegroundColor, 0, 1 ); + label->setBuddy( mFirstForegroundColor ); + + label = new TQLabel( i18n( "Second foreground color:" ), page ); + layout->addWidget( label, 1, 0 ); + + mSecondForegroundColor = new KColorButton( page ); + layout->addWidget( mSecondForegroundColor, 1, 1 ); + label->setBuddy( mSecondForegroundColor ); + + label = new TQLabel( i18n( "Alarm color:" ), page ); + layout->addWidget( label, 2, 0 ); + + mAlarmColor = new KColorButton( page ); + layout->addWidget( mAlarmColor, 2, 1 ); + label->setBuddy( mAlarmColor ); + + label = new TQLabel( i18n( "Background color:" ), page ); + layout->addWidget( label, 3, 0 ); + + mBackgroundColor = new KColorButton( page ); + layout->addWidget( mBackgroundColor, 3, 1 ); + label->setBuddy( mBackgroundColor ); + + label = new TQLabel( i18n( "Font size:" ), page ); + layout->addWidget( label, 4, 0 ); + + mFontSize = new TQSpinBox( 7, 48, 1, page ); + mFontSize->setValue( 8 ); + layout->addWidget( mFontSize, 4, 1 ); + label->setBuddy( mFontSize ); + + layout->setRowStretch( 5, 1 ); + + page = addPage( i18n( "Sensor Colors" ) ); + layout = new TQGridLayout( page, 1, 2, 0, spacingHint() ); + + mColorListBox = new TQListBox( page ); + layout->addWidget( mColorListBox, 0, 0 ); + + mEditColorButton = new TQPushButton( i18n( "Change Color..." ), page ); + mEditColorButton->setEnabled( false ); + layout->addWidget( mEditColorButton, 0, 1, Qt::AlignTop ); + + connect( mColorListBox, TQT_SIGNAL( selectionChanged( TQListBoxItem* ) ), + TQT_SLOT( selectionChanged( TQListBoxItem* ) ) ); + connect( mColorListBox, TQT_SIGNAL( doubleClicked( TQListBoxItem* ) ), + TQT_SLOT( editSensorColor() ) ); + connect( mEditColorButton, TQT_SIGNAL( clicked() ), + TQT_SLOT( editSensorColor() ) ); + + TDEAcceleratorManager::manage( this ); +} + +StyleSettings::~StyleSettings() +{ +} + +void StyleSettings::setFirstForegroundColor( const TQColor &color ) +{ + mFirstForegroundColor->setColor( color ); +} + +TQColor StyleSettings::firstForegroundColor() const +{ + return mFirstForegroundColor->color(); +} + +void StyleSettings::setSecondForegroundColor( const TQColor &color ) +{ + mSecondForegroundColor->setColor( color ); +} + +TQColor StyleSettings::secondForegroundColor() const +{ + return mSecondForegroundColor->color(); +} + +void StyleSettings::setAlarmColor( const TQColor &color ) +{ + mAlarmColor->setColor( color ); +} + +TQColor StyleSettings::alarmColor() const +{ + return mAlarmColor->color(); +} + +void StyleSettings::setBackgroundColor( const TQColor &color ) +{ + mBackgroundColor->setColor( color ); +} + +TQColor StyleSettings::backgroundColor() const +{ + return mBackgroundColor->color(); +} + +void StyleSettings::setFontSize( uint size ) +{ + mFontSize->setValue( size ); +} + +uint StyleSettings::fontSize() const +{ + return mFontSize->value(); +} + +void StyleSettings::setSensorColors( const TQValueList<TQColor> &list ) +{ + mColorListBox->clear(); + + for ( uint i = 0; i < list.count(); ++i ) { + TQPixmap pm( 12, 12 ); + pm.fill( *list.at( i ) ); + mColorListBox->insertItem( pm, i18n( "Color %1" ).arg( i ) ); + } +} + +TQValueList<TQColor> StyleSettings::sensorColors() +{ + TQValueList<TQColor> list; + + for ( uint i = 0; i < mColorListBox->count(); ++i ) + list.append( TQColor( mColorListBox->pixmap( i )->convertToImage().pixel( 1, 1 ) ) ); + + return list; +} + +void StyleSettings::editSensorColor() +{ + int pos = mColorListBox->currentItem(); + + if ( pos < 0 ) + return; + + TQColor color = mColorListBox->pixmap( pos )->convertToImage().pixel( 1, 1 ); + + if ( KColorDialog::getColor( color ) == KColorDialog::Accepted ) { + TQPixmap pm( 12, 12 ); + pm.fill( color ); + mColorListBox->changeItem( pm, mColorListBox->text( pos ), pos ); + } +} + +void StyleSettings::selectionChanged( TQListBoxItem *item ) +{ + mEditColorButton->setEnabled( item != 0 ); +} + +#include "StyleSettings.moc" diff --git a/ksysguard/gui/ksgrd/StyleSettings.h b/ksysguard/gui/ksgrd/StyleSettings.h new file mode 100644 index 000000000..c3b3d362c --- /dev/null +++ b/ksysguard/gui/ksgrd/StyleSettings.h @@ -0,0 +1,78 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_STYLESETTINGS_H +#define KSG_STYLESETTINGS_H + +#include <kdialogbase.h> + +#include <tqcolor.h> + +class KColorButton; + +class TQListBoxItem; +class TQPushButton; + +class StyleSettings : public KDialogBase +{ + Q_OBJECT + + public: + StyleSettings( TQWidget *parent = 0, const char *name = 0 ); + ~StyleSettings(); + + void setFirstForegroundColor( const TQColor &color ); + TQColor firstForegroundColor() const; + + void setSecondForegroundColor( const TQColor &color ); + TQColor secondForegroundColor() const; + + void setAlarmColor( const TQColor &color ); + TQColor alarmColor() const; + + void setBackgroundColor( const TQColor &color ); + TQColor backgroundColor() const; + + void setFontSize( uint size ); + uint fontSize() const; + + void setSensorColors( const TQValueList<TQColor> &list ); + TQValueList<TQColor> sensorColors(); + + private slots: + void editSensorColor(); + void selectionChanged( TQListBoxItem* ); + + private: + KColorButton *mFirstForegroundColor; + KColorButton *mSecondForegroundColor; + KColorButton *mAlarmColor; + KColorButton *mBackgroundColor; + + TQSpinBox *mFontSize; + + TQListBox *mColorListBox; + TQPushButton *mEditColorButton; +}; + +#endif diff --git a/ksysguard/gui/ksgrd/TimerSettings.cc b/ksysguard/gui/ksgrd/TimerSettings.cc new file mode 100644 index 000000000..43e73ab90 --- /dev/null +++ b/ksysguard/gui/ksgrd/TimerSettings.cc @@ -0,0 +1,94 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <tdeaccelmanager.h> +#include <tdelocale.h> + +#include <tqcheckbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqspinbox.h> +#include <tqwhatsthis.h> + +#include "TimerSettings.h" + +TimerSettings::TimerSettings( TQWidget *parent, const char *name ) + : KDialogBase( Plain, i18n( "Timer Settings" ), Ok | Cancel, + Ok, parent, name, true, true ) +{ + TQFrame *page = plainPage(); + + TQGridLayout *layout = new TQGridLayout( page, 2, 2, 0, spacingHint() ); + + mUseGlobalUpdate = new TQCheckBox( i18n( "Use update interval of worksheet" ), page ); + layout->addMultiCellWidget( mUseGlobalUpdate, 0, 0, 0, 1 ); + + mLabel = new TQLabel( i18n( "Update interval:" ), page ); + layout->addWidget( mLabel, 1, 0 ); + + mInterval = new TQSpinBox( 1, 300, 1, page ); + mInterval->setValue( 2 ); + mInterval->setSuffix( i18n( " sec" ) ); + layout->addWidget( mInterval, 1, 1 ); + mLabel->setBuddy( mInterval ); + TQWhatsThis::add( mInterval, i18n( "All displays of the sheet are updated at the rate specified here." ) ); + + connect( mUseGlobalUpdate, TQT_SIGNAL( toggled( bool ) ), + TQT_SLOT( globalUpdateChanged( bool ) ) ); + + mUseGlobalUpdate->setChecked( true ); + + TDEAcceleratorManager::manage( this ); +} + +TimerSettings::~TimerSettings() +{ +} + +void TimerSettings::setUseGlobalUpdate( bool value ) +{ + mUseGlobalUpdate->setChecked( value ); +} + +bool TimerSettings::useGlobalUpdate() const +{ + return mUseGlobalUpdate->isChecked(); +} + +void TimerSettings::setInterval( int interval ) +{ + mInterval->setValue( interval ); +} + +int TimerSettings::interval() const +{ + return mInterval->value(); +} + +void TimerSettings::globalUpdateChanged( bool value ) +{ + mInterval->setEnabled( !value ); + mLabel->setEnabled( !value ); +} + +#include "TimerSettings.moc" diff --git a/ksysguard/gui/ksgrd/TimerSettings.h b/ksysguard/gui/ksgrd/TimerSettings.h new file mode 100644 index 000000000..64c49959b --- /dev/null +++ b/ksysguard/gui/ksgrd/TimerSettings.h @@ -0,0 +1,56 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_TIMERSETTINGS_H +#define KSG_TIMERSETTINGS_H + +#include <kdialogbase.h> + +class TQCheckBox; +class TQLabel; +class TQSpinBox; + +class KDE_EXPORT TimerSettings : public KDialogBase +{ + Q_OBJECT + + public: + TimerSettings( TQWidget *parent, const char *name = 0 ); + ~TimerSettings(); + + void setUseGlobalUpdate( bool value ); + bool useGlobalUpdate() const; + + void setInterval( int interval ); + int interval() const; + + private slots: + void globalUpdateChanged( bool ); + + private: + TQCheckBox* mUseGlobalUpdate; + TQLabel* mLabel; + TQSpinBox* mInterval; +}; + +#endif diff --git a/ksysguard/gui/ksysguard.cc b/ksysguard/gui/ksysguard.cc new file mode 100644 index 000000000..b08763b2f --- /dev/null +++ b/ksysguard/gui/ksysguard.cc @@ -0,0 +1,650 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger + <[email protected]>. Please do not commit any changes without consulting + me first. Thanks! + + KSysGuard has been written with some source code and ideas from + ktop (<1.0). Early versions of ktop have been written by Bernd + Johannes Wuebben <[email protected]> and Nicolas Leclercq + <[email protected]>. + +*/ + +#include <assert.h> +#include <ctype.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <tdeaboutdata.h> +#include <tdeaction.h> +#include <tdeapplication.h> +#include <tdecmdlineargs.h> +#include <kdebug.h> +#include <kedittoolbar.h> +#include <tdeglobal.h> +#include <tdeglobalsettings.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <ksgrd/SensorAgent.h> +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> +#include <kstandarddirs.h> +#include <kstatusbar.h> +#include <kstdaction.h> +#include <twin.h> +#include <twinmodule.h> +#include <dnssd/remoteservice.h> + + +#include "../version.h" +#include "SensorBrowser.h" +#include "Workspace.h" + +#include "ksysguard.h" + +static const char Description[] = I18N_NOOP( "TDE system guard" ); +TopLevel* topLevel; + +/** + This is the constructor for the main widget. It sets up the menu and the + TaskMan widget. + */ +TopLevel::TopLevel( const char *name ) + : TDEMainWindow( 0, name ), DCOPObject( "KSysGuardIface" ) +{ + setPlainCaption( i18n( "TDE System Guard" ) ); + mDontSaveSession = false; + mTimerId = -1; + + mSplitter = new TQSplitter( this ); + mSplitter->setOrientation( Qt::Horizontal ); + mSplitter->setOpaqueResize( TDEGlobalSettings::opaqueResize() ); + setCentralWidget( mSplitter ); + + mSensorBrowser = new SensorBrowser( mSplitter, KSGRD::SensorMgr ); + + mServiceBrowser = new DNSSD::ServiceBrowser("_ksysguard._tcp", 0, true); + connect(mServiceBrowser,TQT_SIGNAL(serviceAdded(DNSSD::RemoteService::Ptr)),this, + TQT_SLOT(serviceAdded(DNSSD::RemoteService::Ptr))); + + mWorkSpace = new Workspace( mSplitter ); + connect( mWorkSpace, TQT_SIGNAL( announceRecentURL( const KURL& ) ), + TQT_SLOT( registerRecentURL( const KURL& ) ) ); + connect( mWorkSpace, TQT_SIGNAL( setCaption( const TQString&, bool ) ), + TQT_SLOT( setCaption( const TQString&, bool ) ) ); + connect( KSGRD::Style, TQT_SIGNAL( applyStyleToWorksheet() ), mWorkSpace, + TQT_SLOT( applyStyle() ) ); + + /* Create the status bar. It displays some information about the + * number of processes and the memory consumption of the local + * host. */ + statusBar()->insertFixedItem( i18n( "88888 Processes" ), 0 ); + statusBar()->insertFixedItem( i18n( "Memory: 88888888888 kB used, " + "88888888888 kB free" ), 1 ); + statusBar()->insertFixedItem( i18n( "Swap: 888888888 kB used, " + "888888888 kB free" ), 2 ); + statusBar()->hide(); + + // create actions for menue entries + new TDEAction( i18n( "&New Worksheet..." ), "tab_new", 0, TQT_TQOBJECT(mWorkSpace), + TQT_SLOT( newWorkSheet() ), actionCollection(), "new_worksheet" ); + + new TDEAction( i18n( "Import Worksheet..." ), "document-open", 0, TQT_TQOBJECT(mWorkSpace), + TQT_SLOT( loadWorkSheet() ), actionCollection(), "import_worksheet" ); + + mActionOpenRecent = new TDERecentFilesAction( i18n( "&Import Recent Worksheet" ),"document-open", 0, + TQT_TQOBJECT(mWorkSpace), TQT_SLOT( loadWorkSheet( const KURL& ) ), actionCollection(), "recent_import_worksheet" ); + + new TDEAction( i18n( "&Remove Worksheet" ), "tab_remove", 0, TQT_TQOBJECT(mWorkSpace), + TQT_SLOT( deleteWorkSheet() ), actionCollection(), "remove_worksheet" ); + + new TDEAction( i18n( "&Export Worksheet..." ), "document-save-as", 0, TQT_TQOBJECT(mWorkSpace), + TQT_SLOT( saveWorkSheetAs() ), actionCollection(), "export_worksheet" ); + + KStdAction::quit( TQT_TQOBJECT(this), TQT_SLOT( close() ), actionCollection() ); + + new TDEAction( i18n( "C&onnect Host..." ), "connect_established", 0, TQT_TQOBJECT(this), + TQT_SLOT( connectHost() ), actionCollection(), "connect_host" ); + new TDEAction( i18n( "D&isconnect Host" ), "connect_no", 0, TQT_TQOBJECT(this), + TQT_SLOT( disconnectHost() ), actionCollection(), "disconnect_host" ); + +// KStdAction::cut( mWorkSpace, TQT_SLOT( cut() ), actionCollection() ); +// KStdAction::copy( mWorkSpace, TQT_SLOT( copy() ), actionCollection() ); +// KStdAction::paste( mWorkSpace, TQT_SLOT( paste() ), actionCollection() ); + new TDEAction( i18n( "&Worksheet Properties" ), "configure", 0, TQT_TQOBJECT(mWorkSpace), + TQT_SLOT( configure() ), actionCollection(), "configure_sheet" ); + + new TDEAction( i18n( "Load Standard Sheets" ), "document-revert", + 0, TQT_TQOBJECT(this), TQT_SLOT( resetWorkSheets() ), + actionCollection(), "revert_all_worksheets" ); + + new TDEAction( i18n( "Configure &Style..." ), "colorize", 0, TQT_TQOBJECT(this), + TQT_SLOT( editStyle() ), actionCollection(), "configure_style" ); + + // TODO remove resize and fix so sizeHints() determines default size. + if (!initialGeometrySet()) + resize( 640, 480 ); + setupGUI(ToolBar | Keys | StatusBar | Create); + setAutoSaveSettings(); +} + + +/* + * DCOP Interface functions + */ +void TopLevel::resetWorkSheets() +{ + if ( KMessageBox::warningContinueCancel( this, + i18n( "Do you really want to restore the default worksheets?" ), + i18n( "Reset All Worksheets" ), + i18n("Reset"), + "AskResetWorkSheets") == KMessageBox::Cancel ) + return; + + mWorkSpace->removeAllWorkSheets(); + + TDEStandardDirs* kstd = TDEGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + + TQString workDir = kstd->saveLocation( "data", "ksysguard" ); + + TQString file = kstd->findResource( "data", "SystemLoad.sgrd" ); + TQString newFile = workDir + "/" + i18n( "System Load" ) + ".sgrd"; + if ( !file.isEmpty() ) + mWorkSpace->restoreWorkSheet( file, newFile ); + + file = kstd->findResource( "data", "ProcessTable.sgrd" ); + newFile = workDir + "/" + i18n( "Process Table" ) + ".sgrd"; + if ( !file.isEmpty() ) + mWorkSpace->restoreWorkSheet( file, newFile ); +} + +void TopLevel::showProcesses() +{ + mWorkSpace->showProcesses(); +} + +void TopLevel::showOnCurrentDesktop() +{ + KWin::setOnDesktop( winId(), KWin::currentDesktop() ); + kapp->updateUserTimestamp(); + KWin::forceActiveWindow( winId() ); +} + +void TopLevel::loadWorkSheet( const TQString &fileName ) +{ + mWorkSpace->loadWorkSheet( KURL( fileName ) ); +} + +void TopLevel::removeWorkSheet( const TQString &fileName ) +{ + mWorkSpace->deleteWorkSheet( fileName ); +} + +TQStringList TopLevel::listSensors( const TQString &hostName ) +{ + return mSensorBrowser->listSensors( hostName ); +} + +TQStringList TopLevel::listHosts() +{ + return mSensorBrowser->listHosts(); +} + +TQString TopLevel::readIntegerSensor( const TQString &sensorLocator ) +{ + TQString host = sensorLocator.left( sensorLocator.find( ':' ) ); + TQString sensor = sensorLocator.right( sensorLocator.length() - + sensorLocator.find( ':' ) - 1 ); + + DCOPClientTransaction *dcopTransaction = kapp->dcopClient()->beginTransaction(); + mDCopFIFO.prepend( dcopTransaction ); + + KSGRD::SensorMgr->engage( host, "", "ksysguardd" ); + KSGRD::SensorMgr->sendRequest( host, sensor, (KSGRD::SensorClient*)this, 133 ); + + return TQString::null; +} + +TQStringList TopLevel::readListSensor( const TQString& sensorLocator ) +{ + TQStringList retval; + + TQString host = sensorLocator.left( sensorLocator.find( ':' ) ); + TQString sensor = sensorLocator.right( sensorLocator.length() - + sensorLocator.find( ':' ) - 1 ); + + DCOPClientTransaction *dcopTransaction = kapp->dcopClient()->beginTransaction(); + mDCopFIFO.prepend( dcopTransaction ); + + KSGRD::SensorMgr->engage( host, "", "ksysguardd" ); + KSGRD::SensorMgr->sendRequest( host, sensor, (KSGRD::SensorClient*)this, 134 ); + + return retval; +} +/* + * End of DCOP Interface section + */ + +void TopLevel::serviceAdded(DNSSD::RemoteService::Ptr srv) +{ + KSGRD::SensorMgr->engage( srv->hostName(), "", "", srv->port() ); +} + +void TopLevel::registerRecentURL( const KURL &url ) +{ + mActionOpenRecent->addURL( url ); +} + +void TopLevel::beATaskManager() +{ + mWorkSpace->showProcesses(); + + // Avoid displaying splitter widget + mSensorBrowser->hide(); + + // No toolbar and status bar in taskmanager mode. + toolBar( "mainToolBar" )->hide(); + + mDontSaveSession = true; + + stateChanged( "showProcessState" ); +} + +void TopLevel::showRequestedSheets() +{ + toolBar( "mainToolBar" )->hide(); + + TQValueList<int> sizes; + sizes.append( 0 ); + sizes.append( 100 ); + mSplitter->setSizes( sizes ); +} + +void TopLevel::initStatusBar() +{ + KSGRD::SensorMgr->engage( "localhost", "", "ksysguardd" ); + /* Request info about the swap space size and the units it is + * measured in. The requested info will be received by + * answerReceived(). */ + KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/used?", + (KSGRD::SensorClient*)this, 5 ); + updateStatusBar(); + mServiceBrowser->startBrowse(); + + TDEToggleAction *sb = dynamic_cast<TDEToggleAction*>(action("options_show_statusbar")); + if (sb) + connect(sb, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(updateStatusBar())); +} + +void TopLevel::updateStatusBar() +{ + if ( mTimerId == -1 ) + mTimerId = startTimer( 2000 ); + + // call timerEvent to fill the status bar with real values + timerEvent( 0 ); +} + +void TopLevel::connectHost() +{ + KSGRD::SensorMgr->engageHost( "" ); +} + +void TopLevel::disconnectHost() +{ + mSensorBrowser->disconnect(); +} + +void TopLevel::editToolbars() +{ + saveMainWindowSettings( kapp->config() ); + KEditToolbar dlg( actionCollection() ); + connect( &dlg, TQT_SIGNAL( newToolbarConfig() ), this, + TQT_SLOT( slotNewToolbarConfig() ) ); + + dlg.exec(); +} + +void TopLevel::slotNewToolbarConfig() +{ + createGUI(); + applyMainWindowSettings( kapp->config() ); +} + +void TopLevel::editStyle() +{ + KSGRD::Style->configure(); +} + +void TopLevel::customEvent( TQCustomEvent *e ) +{ + if ( e->type() == TQEvent::User ) { + /* Due to the asynchronous communication between ksysguard and its + * back-ends, we sometimes need to show message boxes that were + * triggered by objects that have died already. */ + KMessageBox::error( this, *((TQString*)e->data()) ); + delete (TQString*)e->data(); + } +} + +void TopLevel::timerEvent( TQTimerEvent* ) +{ + if ( statusBar()->isVisibleTo( this ) ) { + /* Request some info about the memory status. The requested + * information will be received by answerReceived(). */ + KSGRD::SensorMgr->sendRequest( "localhost", "pscount", + (KSGRD::SensorClient*)this, 0 ); + KSGRD::SensorMgr->sendRequest( "localhost", "mem/physical/free", + (KSGRD::SensorClient*)this, 1 ); + KSGRD::SensorMgr->sendRequest( "localhost", "mem/physical/used", + (KSGRD::SensorClient*)this, 2 ); + KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/free", + (KSGRD::SensorClient*)this, 3 ); + KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/used", + (KSGRD::SensorClient*)this, 4 ); + } +} + +bool TopLevel::queryClose() +{ + if ( !mDontSaveSession ) { + if ( !mWorkSpace->saveOnQuit() ) + return false; + + saveProperties( kapp->config() ); + kapp->config()->sync(); + } + + return true; +} + +void TopLevel::readProperties( TDEConfig *cfg ) +{ + /* we can ignore 'isMaximized' because we can't set the window + maximized, so we save the coordinates instead */ + if ( cfg->readBoolEntry( "isMinimized" ) == true ) + showMinimized(); + + TQValueList<int> sizes = cfg->readIntListEntry( "SplitterSizeList" ); + if ( sizes.isEmpty() ) { + // start with a 30/70 ratio + sizes.append( 30 ); + sizes.append( 70 ); + } + mSplitter->setSizes( sizes ); + + KSGRD::SensorMgr->readProperties( cfg ); + KSGRD::Style->readProperties( cfg ); + + mWorkSpace->readProperties( cfg ); + + mActionOpenRecent->loadEntries( cfg ); + + applyMainWindowSettings( cfg ); +} + +void TopLevel::saveProperties( TDEConfig *cfg ) +{ + mActionOpenRecent->saveEntries( cfg ); + + cfg->writeEntry( "isMinimized", isMinimized() ); + cfg->writeEntry( "SplitterSizeList", mSplitter->sizes() ); + + KSGRD::Style->saveProperties( cfg ); + KSGRD::SensorMgr->saveProperties( cfg ); + + saveMainWindowSettings( cfg ); + mWorkSpace->saveProperties( cfg ); +} + +void TopLevel::answerReceived( int id, const TQString &answer ) +{ + TQString s; + static TQString unit; + static long mUsed = 0; + static long mFree = 0; + static long sUsed = 0; + static long sFree = 0; + + switch ( id ) { + case 0: + // yes, I know there is never 1 process, but that's the way + // singular vs. plural works :/ + // + // To use pluralForms, though, you need to convert to + // an integer, not use the TQString straight. + s = i18n( "1 Process", "%n Processes", answer.toInt() ); + statusBar()->changeItem( s, 0 ); + break; + + case 1: + mFree = answer.toLong(); + break; + + case 2: + mUsed = answer.toLong(); + s = i18n( "Memory: %1 %2 used, %3 %4 free" ) + .arg( TDEGlobal::locale()->formatNumber( mUsed, 0 ) ).arg( unit ) + .arg( TDEGlobal::locale()->formatNumber( mFree, 0 ) ).arg( unit ); + statusBar()->changeItem( s, 1 ); + break; + + case 3: + sFree = answer.toLong(); + setSwapInfo( sUsed, sFree, unit ); + break; + + case 4: + sUsed = answer.toLong(); + setSwapInfo( sUsed, sFree, unit ); + break; + + case 5: { + KSGRD::SensorIntegerInfo info( answer ); + unit = KSGRD::SensorMgr->translateUnit( info.unit() ); + } + + case 133: { + TQCString replyType = "TQString"; + TQByteArray replyData; + TQDataStream reply( replyData, IO_WriteOnly ); + reply << answer; + + DCOPClientTransaction *dcopTransaction = mDCopFIFO.last(); + kapp->dcopClient()->endTransaction( dcopTransaction, replyType, replyData ); + mDCopFIFO.removeLast(); + break; + } + + case 134: { + TQStringList resultList; + TQCString replyType = "TQStringList"; + TQByteArray replyData; + TQDataStream reply( replyData, IO_WriteOnly ); + + KSGRD::SensorTokenizer lines( answer, '\n' ); + + for ( unsigned int i = 0; i < lines.count(); i++ ) + resultList.append( lines[ i ] ); + + reply << resultList; + + DCOPClientTransaction *dcopTransaction = mDCopFIFO.last(); + kapp->dcopClient()->endTransaction( dcopTransaction, replyType, replyData ); + mDCopFIFO.removeLast(); + break; + } + } +} + +void TopLevel::setSwapInfo( long used, long free, const TQString &unit ) +{ + TQString msg; + if ( used == 0 && free == 0 ) // no swap available + msg = i18n( "No swap space available" ); + else { + msg = i18n( "Swap: %1 %2 used, %3 %4 free" ) + .arg( TDEGlobal::locale()->formatNumber( used, 0 ) ).arg( unit ) + .arg( TDEGlobal::locale()->formatNumber( free, 0 ) ).arg( unit ); + } + + statusBar()->changeItem( msg, 2 ); +} + +static const TDECmdLineOptions options[] = { + { "showprocesses", I18N_NOOP( "Show only process list of local host" ), 0 }, + { "+[worksheet]", I18N_NOOP( "Optional worksheet files to load" ), 0 }, + TDECmdLineLastOption +}; + +/* + * Once upon a time... + */ +int main( int argc, char** argv ) +{ + // initpipe is used to keep the parent process around till the child + // has registered with dcop. + int initpipe[ 2 ]; + pipe( initpipe ); + + /* This forking will put ksysguard in it's on session not having a + * controlling terminal attached to it. This prevents ssh from + * using this terminal for password requests. Unfortunately you + * now need a ssh with ssh-askpass support to popup an X dialog to + * enter the password. Currently only the original ssh provides this + * but not open-ssh. */ + + pid_t pid; + if ( ( pid = fork() ) < 0 ) + return -1; + else + if ( pid != 0 ) { + close( initpipe[ 1 ] ); + + // wait till init is complete + char c; + while( read( initpipe[ 0 ], &c, 1 ) < 0 ); + + // then exit + close( initpipe[ 0 ] ); + exit( 0 ); + } + + close( initpipe[ 0 ] ); + setsid(); + + TDEAboutData aboutData( "ksysguard", I18N_NOOP( "TDE System Guard" ), + KSYSGUARD_VERSION, Description, TDEAboutData::License_GPL, + I18N_NOOP( "(c) 1996-2002 The KSysGuard Developers" ) ); + aboutData.addAuthor( "Chris Schlaeger", "Current Maintainer", "[email protected]" ); + aboutData.addAuthor( "Tobias Koenig", 0, "[email protected]" ); + aboutData.addAuthor( "Nicolas Leclercq", 0, "[email protected]" ); + aboutData.addAuthor( "Alex Sanda", 0, "[email protected]" ); + aboutData.addAuthor( "Bernd Johannes Wuebben", 0, "[email protected]" ); + aboutData.addAuthor( "Ralf Mueller", 0, "[email protected]" ); + aboutData.addAuthor( "Hamish Rodda", 0, "[email protected]" ); + aboutData.addAuthor( "Torsten Kasch", I18N_NOOP( "Solaris Support\n" + "Parts derived (by permission) from the sunos5\n" + "module of William LeFebvre's \"top\" utility." ), + "[email protected]" ); + + TDECmdLineArgs::init( argc, argv, &aboutData ); + TDECmdLineArgs::addCmdLineOptions( options ); + + TDEApplication::disableAutoDcopRegistration(); + // initialize KDE application + TDEApplication *app = new TDEApplication; + + KSGRD::SensorMgr = new KSGRD::SensorManager(); + KSGRD::Style = new KSGRD::StyleEngine(); + + TDECmdLineArgs* args = TDECmdLineArgs::parsedArgs(); + + int result = 0; + + if ( args->isSet( "showprocesses" ) ) { + /* To avoid having multiple instances of ksysguard in + * taskmanager mode we check if another taskmanager is running + * already. If so, we terminate this one immediately. */ + if ( app->dcopClient()->registerAs( "ksysguard_taskmanager", false ) == + "ksysguard_taskmanager" ) { + // We have registered with DCOP, our parent can exit now. + char c = 0; + write( initpipe[ 1 ], &c, 1 ); + close( initpipe[ 1 ] ); + + topLevel = new TopLevel( "KSysGuard" ); + topLevel->beATaskManager(); + topLevel->initStatusBar(); + topLevel->show(); + KSGRD::SensorMgr->setBroadcaster( topLevel ); + + // run the application + result = app->exec(); + } else { + TQByteArray data; + app->dcopClient()->send( "ksysguard_taskmanager", "KSysGuardIface", + "showOnCurrentDesktop()", data ); + } + } else { + app->dcopClient()->registerAs( "ksysguard" ); + app->dcopClient()->setDefaultObject( "KSysGuardIface" ); + + // We have registered with DCOP, our parent can exit now. + char c = 0; + write( initpipe[ 1 ], &c, 1 ); + close( initpipe[ 1 ] ); + + topLevel = new TopLevel( "KSysGuard" ); + + // create top-level widget + if ( args->count() > 0 ) { + /* The user has specified a list of worksheets to load. In this + * case we do not restore any previous settings but load all the + * requested worksheets. */ + topLevel->showRequestedSheets(); + for ( int i = 0; i < args->count(); ++i ) + topLevel->loadWorkSheet( args->arg( i ) ); + } else { + if ( app->isRestored() ) + topLevel->restore( 1 ); + else + topLevel->readProperties( app->config() ); + } + + topLevel->initStatusBar(); + topLevel->show(); + KSGRD::SensorMgr->setBroadcaster( topLevel ); + + // run the application + result = app->exec(); + } + + delete KSGRD::Style; + delete KSGRD::SensorMgr; + delete app; + + return result; +} + +#include "ksysguard.moc" diff --git a/ksysguard/gui/ksysguard.desktop b/ksysguard/gui/ksysguard.desktop new file mode 100644 index 000000000..cfffc7d9f --- /dev/null +++ b/ksysguard/gui/ksysguard.desktop @@ -0,0 +1,102 @@ +[Desktop Entry] +Name=KSysGuard +Name[af]=Ksysguard +Name[ar]=حارس النظام +Name[bg]=Системна защита +Name[csb]=TDE Wachtôrz Systemë +Name[de]=Systemüberwachung +Name[eo]=KSistemGardilo +Name[et]=Süsteemi valvur +Name[fr]=Surveillance du système +Name[he]=משמר המערכת +Name[hi]=के-सिस-गार्ड +Name[hr]=TDE zaštitnik sustava +Name[is]=TDE álagsmælir +Name[ja]=TDE システムガード +Name[lo]=ກວດສອບແລະປ້ອງກັນລະບົບ - K +Name[mn]=Системийн хяналт +Name[nb]=TDE Systemvakt +Name[ne]=KSys रक्षक +Name[nn]=TDE Systemvakt +Name[nso]=Thlokomelo ya KSys +Name[pl]=TDE Strażnik Systemu +Name[sk]=TDE Strážca systému +Name[sv]=Systemövervakare +Name[tg]=Муҳофизати системаи-K +Name[th]=ตรวจสอบและป้องกันระบบ +Name[uz]=TDE tizim nazoratchisi +Name[uz@cyrillic]=TDE тизим назоратчиси +Name[vi]=Bảo vệ Hệ thống TDE +Name[wa]=KSisGåde +GenericName=Performance Monitor +GenericName[af]=Werkverrigting Monitor +GenericName[ar]=مراقب الإداء +GenericName[be]=Сістэмны назіральнік +GenericName[bg]=Мониторинг на системата +GenericName[bs]=Monitor performansi +GenericName[ca]=Monitor de rendiment +GenericName[cs]=Monitor výkonu +GenericName[csb]=Mònitor spòroscë +GenericName[da]=Overvågning af ydelse +GenericName[de]=Performancemonitor +GenericName[el]=Επόπτης συστήματος +GenericName[eo]=Rendimento Monitoro +GenericName[es]=Monitor de rendimiento +GenericName[et]=Jõudluse monitor +GenericName[eu]=Sistemaren errendimenduaren monitorea +GenericName[fa]=نمایشگر کارایی +GenericName[fi]=Järjestelmän suorituskyvyn monitori +GenericName[fr]=Indicateurs de performance +GenericName[fy]=Prestaasjemonitor +GenericName[gl]=Monitor de Rendemento +GenericName[he]=צג מערכת +GenericName[hr]=Nadzor performansi +GenericName[hu]=Teljesítményfigyelő +GenericName[is]=Afkasta eftirlit +GenericName[it]=Monitor delle prestazioni +GenericName[ja]=パフォーマンスモニター +GenericName[ka]=წარმადობის მონიტორი +GenericName[kk]=Жылдамдылық бақылаушысы +GenericName[km]=កម្មវិធីត្រួតពិនិត្យដំណើរការ +GenericName[lt]=Veiksenos monitorius +GenericName[mk]=Монитор на перформанси +GenericName[ms]=Pemantau Prestasi +GenericName[nb]=Ytelsesovervåker +GenericName[nds]=Leisten-Kieker +GenericName[ne]=सम्पादन मनिटर +GenericName[nl]=Prestatiemonitor +GenericName[nn]=Ytelsesovervakar +GenericName[pa]=ਪਰਦਰਸ਼ਨ ਨਿਗਰਾਨ +GenericName[pl]=Monitor wydajności +GenericName[pt]=Monitor de Performance +GenericName[pt_BR]=Monitor de Performance +GenericName[ro]=Monitor de performanță +GenericName[ru]=Монитор производительности +GenericName[rw]=Mugaragaza y'Imikorere +GenericName[se]=Buvttogoziheaddji +GenericName[sk]=Sledovač výkonu +GenericName[sl]=Nadzor delovanja +GenericName[sr]=Монитор перформанси +GenericName[sr@Latn]=Monitor performansi +GenericName[sv]=Prestandaövervakare +GenericName[ta]=செயல்திறன் திரை +GenericName[th]=สอดส่องประสิทธิภาพการทำงานของระบบ +GenericName[tr]=Sistem İzleyici +GenericName[tt]=Citezlek Küzätüçese +GenericName[uk]=Монітор швидкодії +GenericName[uz]=Tizimni nazorat qilish +GenericName[uz@cyrillic]=Тизимни назорат қилиш +GenericName[vi]=Theo dõi Hiệu năng +GenericName[wa]=Corwaitoe di ç' ki va bén +GenericName[zh_CN]=性能监视器 +GenericName[zh_TW]=效能監視器 +Exec=ksysguard %U +Icon=ksysguard +Type=Application +MimeType=application/x-ksysguard; +X-DocPath=ksysguard/index.html +Terminal=false +Path= +X-TDE-StartupNotify=true +X-DCOP-ServiceType=Multi +Categories=Qt;TDE;System; diff --git a/ksysguard/gui/ksysguard.h b/ksysguard/gui/ksysguard.h new file mode 100644 index 000000000..df1c2e0c5 --- /dev/null +++ b/ksysguard/gui/ksysguard.h @@ -0,0 +1,124 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + KSysGuard is currently maintained by Chris Schlaeger <[email protected]>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_KSYSGUARD_H +#define KSG_KSYSGUARD_H + +#include <tqevent.h> + +#include <dcopclient.h> +#include <dcopobject.h> +#include <tdeapplication.h> +#include <tdemainwindow.h> +#include <dnssd/servicebrowser.h> + +#include <ksgrd/SensorClient.h> + +class TDERecentFilesAction; +class TDEToggleAction; + +class TQSplitter; +class SensorBrowser; +class Workspace; + +class TopLevel : public TDEMainWindow, public KSGRD::SensorClient, public DCOPObject +{ + Q_OBJECT + K_DCOP + + public: + TopLevel( const char *name = 0 ); + + virtual void saveProperties( TDEConfig* ); + virtual void readProperties( TDEConfig* ); + + virtual void answerReceived( int id, const TQString& ); + + void beATaskManager(); + void showRequestedSheets(); + void initStatusBar(); + + k_dcop: + // calling ksysguard with twin/kicker hot-key + ASYNC showProcesses(); + ASYNC showOnCurrentDesktop(); + ASYNC loadWorkSheet( const TQString &fileName ); + ASYNC removeWorkSheet( const TQString &fileName ); + TQStringList listHosts(); + TQStringList listSensors( const TQString &hostName ); + TQString readIntegerSensor( const TQString &sensorLocator ); + TQStringList readListSensor( const TQString &sensorLocator ); + + public slots: + void registerRecentURL( const KURL &url ); + void resetWorkSheets(); + + protected: + virtual void customEvent( TQCustomEvent* ); + virtual void timerEvent( TQTimerEvent* ); + virtual bool queryClose(); + + protected slots: + void connectHost(); + void disconnectHost(); + void updateStatusBar(); + void editToolbars(); + void editStyle(); + void slotNewToolbarConfig(); + void serviceAdded(DNSSD::RemoteService::Ptr srv); + + private: + void setSwapInfo( long, long, const TQString& ); + + TQPtrList<DCOPClientTransaction> mDCopFIFO; + + TQSplitter* mSplitter; + TDERecentFilesAction* mActionOpenRecent; + + SensorBrowser* mSensorBrowser; + Workspace* mWorkSpace; + + DNSSD::ServiceBrowser* mServiceBrowser; + + bool mDontSaveSession; + int mTimerId; +}; + +extern TopLevel* Toplevel; + +/* + since there is only a forward declaration of DCOPClientTransaction + in dcopclient.h we have to redefine it here, otherwise QPtrList + causes errors +*/ +typedef unsigned long CARD32; + +class DCOPClientTransaction +{ + public: + TQ_INT32 id; + CARD32 key; + TQCString senderId; +}; + +#endif diff --git a/ksysguard/gui/ksysguardapplet.desktop b/ksysguard/gui/ksysguardapplet.desktop new file mode 100644 index 000000000..9eebf5381 --- /dev/null +++ b/ksysguard/gui/ksysguardapplet.desktop @@ -0,0 +1,120 @@ +[Desktop Entry] +Type=Plugin +Name=System Guard +Name[af]=Stelsel Wag +Name[ar]=حارس النظام +Name[be]=Сістэмны ахоўнік +Name[bg]=Системен монитор +Name[bn]=সিস্টেম প্রহরী +Name[br]=Gward Reizhiad +Name[bs]=Nadzor sistema +Name[ca]=Vigilant del sistema +Name[cs]=Strážce systému +Name[csb]=Wachtôrz Systemë +Name[da]=Systemvagt +Name[de]=Systemüberwachung +Name[el]=Φρουρός συστήματος +Name[eo]=Sistemo Gardilo +Name[es]=Guardián del sistema +Name[et]=Süsteemi valvur +Name[eu]=Sistemaren zaintzailea +Name[fa]=محافظ سیستم +Name[fi]=Järjestelmän valvonta +Name[fr]=Surveillance du système +Name[fy]=Systeemwarder +Name[gl]=Vixiante do Sistema +Name[he]=משמר המערכת +Name[hr]=Zaštitnik sustava +Name[hu]=Rendszermonitor +Name[is]=Kerfiseftirlit +Name[it]=Controllo del sistema +Name[ja]=システムガード +Name[ka]=სისტემის მცველი +Name[kk]=Жүйе бақылаушысы +Name[km]=ឆ្មាំប្រព័ន្ធ +Name[ko]=TDE 시스템 지킴이 +Name[lt]=Sistemos apsauga +Name[mk]=Чувар на системот +Name[nb]=Systemvakt +Name[nds]=Systeemwachter +Name[ne]=प्रणाली रक्षक +Name[nl]=Systeembewaking +Name[nn]=Systemvakt +Name[pa]=ਸਿਸਟਮ ਗਾਰਡ +Name[pl]=Strażnik Systemu +Name[pt]=Vigilante do Sistema +Name[pt_BR]=Guarda do Sistema +Name[ro]=Sistem de gardă +Name[ru]=Системный монитор +Name[se]=Vuogádatfákta +Name[sk]=Strážca systému +Name[sl]=Sistemski varuh +Name[sr]=Заштита система +Name[sr@Latn]=Zaštita sistema +Name[sv]=Systemövervakare +Name[th]=ป้องกันระบบ +Name[tr]=Sistem İzleyici +Name[uk]=Системний вартовий +Name[uz]=Kengaytirilgan tizim nazoratchisi +Name[uz@cyrillic]=Кенгайтирилган тизим назоратчиси +Name[vi]=Bảo vệ Hệ thống +Name[wa]=Gåde do sistinme +Name[zh_CN]=系统卫士 +Name[zh_TW]=系統守衛 +Comment=An advanced system monitor which allows TDE system guard displays +Comment[af]='n Gevorderde stelsel monitor wat TDE se stelsel wag skerms insluit +Comment[be]=Адмысловы сістэмны назіральнік, які "праглынае" дысплеі сістэмнага ахоўніка TDE +Comment[bg]=Системен монитор, който следи за състоянието на системата +Comment[bs]=Napredni program za nadzor sistema koji obuhvata više drugih prozora +Comment[ca]=Un monitor del sistema avançat que inclou pantalles del vigilant del sistema TDE +Comment[cs]=Pokročilý monitor systému, který pohlcuje displeje strážce TDE +Comment[csb]=Awansowóny mònitor systemë jaczi pòkazywô wskôzywôcze TDE Wachtôrza Systemë +Comment[da]=En avanceret systemovervåger som svælger skærme fra TDE's systemovervågning +Comment[de]=Erweiterte Systemüberwachung für die Kontrollleiste +Comment[el]=Ένας προχωρημένος επόπτης του συστήματος ο οποίος ενσωματώνει προβολές του φρουρού συστήματος του TDE +Comment[eo]=Malbaza sistemomonitoro kiu glutas TDE-sistemogardilo-ekranojn. +Comment[es]=Un monitor avanzado del sistema que integra los gráficos del guardián del sistema de TDE +Comment[et]=Võimas süsteemi monitor TDE süsteemi valvuri sensoritele +Comment[eu]=Sistema monitore aurreratua, TDE sistemaren zaintzailearen pantailak bistaratzen dituena +Comment[fa]=یک نمایشگر پیشرفتۀ سیستم که نمایشهای محافظ سیستم TDE را از بین میبرد +Comment[fi]=Edistynyt järjestelmän valvonta, johon sisältyy TDE järjestelmänvalvonnan näytöt +Comment[fr]=Un surveillant avancé affichant l'état du système +Comment[fy]=In avansearre systeemmonitor mei systeemwardings werjefte +Comment[gl]=Un monitor do sistema que incorpora os resultados do vixiante do sistema de TDE +Comment[he]=מנטר מערכת מתקדם המאפשר המטעה של תצוגות של משמר המערכת של TDE +Comment[hr]=Napredan sistemski nadzor koji "guta" prikaze TDE zaštitnika sustava +Comment[hu]=Rendszermonitor kijelzőkkel +Comment[is]=Þróað kerfiseftirlit sem gleypir TDE álagsmæla +Comment[it]=Un sistema di controllo del sistema avanzato che ingloba i controlli di sistema di TDE +Comment[ja]=TDE システムガードを表示する高度なシステムモニター +Comment[kk]=Жетілдірілген жүйе бақылаушысы +Comment[km]=កម្មវិធីត្រួតពិនិត្យប្រព័ន្ធកម្រិតខ្ពស់ដែលអនុញ្ញាតឲ្យប្រព័ន្ធ TDE ត្រួតពិនិត្យការបង្ហាញ +Comment[lt]=Sudėtingesnė sistemos stebėjimo priemonė, įtraukianti TDE sistemos apsaugos stebėjimo priemones +Comment[mk]=Напреден монитор на системот кој ги врамува приказите на чуварите на системот на TDE +Comment[nb]=En avansert systemovervåker som svelger visninger av TDEs systemovervåker +Comment[nds]=En verwiedert Systeemkieker, mit inbett Diagrammen vun TDE System Guard +Comment[ne]=उन्नत प्रणाली मनिटर जसले अन्त्य गर्ने TDE प्रणाली रक्षक प्रदर्शन गर्छ +Comment[nl]=Een geavanceerde systeemmonitor met systeembewakingsdisplays +Comment[nn]=Ein avansert systemovervakar som svelgjer visingar av TDE-systemovervakaren +Comment[pl]=Zaawansowany monitor systemu pokazujący wskaźniki Strażnika systemu TDE +Comment[pt]=Um monitor de sistema avançado que engloba folhas de monitorização do sistema TDE +Comment[pt_BR]=Um monitor avançado de sistema que permite monitorar o que a guarda do sistema do TDE exibe +Comment[ro]=Un monitor de sistem avansat care înghite ecranele sistemului de gardă TDE +Comment[ru]=Системный монитор +Comment[sk]=Sledovač systému, ktorý obsahuje systémových strážcov TDE +Comment[sl]=Napreden nadzor sistema, ki uporablja prikazovalnike iz Sistemskega varuha TDE +Comment[sr]=Напредни монитор који гута приказе TDE-ове заштите система +Comment[sr@Latn]=Napredni monitor koji guta prikaze TDE-ove zaštite sistema +Comment[sv]=En avancerad systemövervakare som sväljer skärmar från TDE:s systemövervakare +Comment[th]=ตัวเฝ้าตรวจสอบระบบขั้นก้าวหน้า ซึ่งกลืนหน้าจอของตัวป้องกันระบบ TDE +Comment[tr]=Gelişmiş bir sistem izleyici +Comment[uk]=Додатковий системний монітор, який поглинає показ системного вартового TDE +Comment[uz]=Tizimning protsessor, xotira, tarmoq kabi qisimlarini kuzatib turadigan kengaytirilgan tizim nazoratchisi +Comment[uz@cyrillic]=Тизимнинг процессор, хотира, тармоқ каби қисимларини кузатиб турадиган кенгайтирилган тизим назоратчиси +Comment[vi]=Một trình theo dõi hệ thống nâng cao thế chỗ cho hiển thị bảo vệ hệ thống TDE +Comment[wa]=On corwaitoe po les spepieus k' avale li håynaedje so gåde do sistinme di TDE +Comment[zh_CN]=可显示 TDE 系统卫士效果的高级系统监视器 +Comment[zh_TW]=包含 TDE 系統守衛顯示的進階系統監視器 +Icon=ksysguard +X-TDE-Library=sysguard_panelapplet +X-TDE-UniqueApplet=true diff --git a/ksysguard/gui/ksysguardui.rc b/ksysguard/gui/ksysguardui.rc new file mode 100644 index 000000000..912894ed3 --- /dev/null +++ b/ksysguard/gui/ksysguardui.rc @@ -0,0 +1,50 @@ +<!DOCTYPE kpartgui> +<kpartgui name="ksysguard" version="5"> +<State name="showProcessState"> + <Disable> + <Action name="new_worksheet"/> + <Action name="import_worksheet"/> + <Action name="recent_import_worksheet"/> + <Action name="export_worksheet"/> + <Action name="remove_worksheet"/> + <Action name="revert_all_worksheets"/> + <Action name="connect_host"/> + <Action name="disconnect_host"/> + <Action name="configure_sheet"/> + <Action name="configure_style"/> + </Disable> +</State> +<MenuBar> + <Menu name="file"><text>&File</text> + <Action name="new_worksheet"/> + <Action name="recent_import_worksheet"/> + <Action name="import_worksheet"/> + <Separator/> + <Action name="export_worksheet"/> + <Separator/> + <Action name="remove_worksheet"/> + <Action name="revert_all_worksheets"/> + <Separator/> + <Action name="connect_host"/> + <Action name="disconnect_host"/> + </Menu> + <Menu name="edit"><text>&Edit</text> + <Action name="configure_sheet"/> + </Menu> + <Menu name="settings"><text>&Settings</text> + <Action name="configure_style"/> + </Menu> +</MenuBar> +<ToolBar name="mainToolBar" noMerge="1"><text>Main Toolbar</text> + <Action name="new_worksheet"/> + <Action name="import_worksheet"/> + <Action name="export_worksheet"/> + <Separator/> + <Action name="connect_host"/> + <Action name="disconnect_host"/> + <Separator/> + <Action name="configure_sheet"/> + <Action name="configure_style"/> +</ToolBar> +</kpartgui> + diff --git a/ksysguard/gui/x-ksysguard.desktop b/ksysguard/gui/x-ksysguard.desktop new file mode 100644 index 000000000..2e96b62c0 --- /dev/null +++ b/ksysguard/gui/x-ksysguard.desktop @@ -0,0 +1,85 @@ +[Desktop Entry] +OnlyShowIn=TDE; +MimeType=application/x-ksysguard +Comment=TDE System Guard +Comment[af]=TDE Stelsel Wag +Comment[ar]=حارس النظام TDE +Comment[az]=TDE Sistem Cangüdəni +Comment[be]=Ахоўнік сістэмы TDE +Comment[bg]=Системна защита +Comment[bn]=কে.ডি.ই. সিস্টেম গার্ড +Comment[br]=Gward Reizhiad TDE +Comment[bs]=TDE zaštita sistema +Comment[ca]=Vigilant del sistema TDE +Comment[cs]=Správce systému TDE +Comment[csb]=TDE Wachtôrz Systemë +Comment[cy]=Gwarchodwr Cysawd TDE +Comment[da]=TDE Systemvagt +Comment[de]=TDE-Systemüberwachung +Comment[el]=Φρουρός συστήματος του TDE +Comment[eo]=TDE-Sistemobservilo +Comment[es]=Guardián del sistema de TDE +Comment[et]=TDE süsteemi valvur +Comment[eu]=TDEren sistemaren kontrola +Comment[fa]=محافظ سیستم TDE +Comment[fi]=TDE:n järjestelmänvalvonta +Comment[fr]=Surveillance du système +Comment[fy]=TDE systeembefeiliging +Comment[ga]=Garda an Chórais TDE +Comment[gl]=Vixiante do Sistema de TDE +Comment[he]=משמר המערכת של TDE +Comment[hi]=केडीई तंत्र गार्ड +Comment[hr]=TDE zaštitnik sustava +Comment[hu]=TDE rendszermonitor +Comment[is]=TDE kerfisvörður +Comment[it]=Controllo di sistema di TDE +Comment[ja]=TDE システムガード +Comment[ka]=TDE სისტემური მონიტორი +Comment[kk]=TDE жүйелік бақылаушысы +Comment[km]=ការពារប្រព័ន្ធ TDE +Comment[ko]=TDE 시스템 지킴이 +Comment[lo]=ເຄື່ອງມືຶປ້ອງກັນລະບົບຂອງ TDE +Comment[lt]=TDE sistemos apsauga +Comment[lv]=TDE Sistēmas Sargs +Comment[mk]=TDE Системски чувар +Comment[mn]=КДЭ-Системийн хяналт +Comment[ms]=Pengawas Sistem TDE +Comment[mt]=Gwardja tas-Sistema TDE +Comment[nb]=TDE Systemovervåker +Comment[nds]=TDE-Systeemwachter +Comment[ne]=TDE प्रणाली रक्षक +Comment[nl]=TDE systeembewaking +Comment[nn]=TDE Systemvakt +Comment[nso]=Thlokomelo ya System ya TDE +Comment[pa]=TDE ਸਿਸਟਮ ਗਾਰਡ +Comment[pl]=TDE Strażnik Systemu +Comment[pt]=Vigilante do sistema do TDE +Comment[pt_BR]=Sistema de Guarda do TDE +Comment[ro]=Sistem de gardă TDE +Comment[ru]=Системный монитор +Comment[rw]=Umurinzi Sisitemu TDE +Comment[se]=TDE vuogádatfákta +Comment[sk]=TDE Strážca systému +Comment[sl]=Sistemski varuh TDE +Comment[sr]=TDE чувар система +Comment[sr@Latn]=TDE čuvar sistema +Comment[sv]=TDE:s systemövervakare +Comment[ta]=TDE கணினி காவலன் +Comment[tg]=Муҳофизи системаи TDE +Comment[th]=เครื่องมือป้องกันระบบ TDE +Comment[tr]=TDE Sistem Koruyucu +Comment[tt]=TDE'nıñ Sistem Saqçısı +Comment[uk]=Системний вартовий TDE +Comment[uz]=TDE tizim nazoratchisi +Comment[uz@cyrillic]=TDE тизим назоратчиси +Comment[ven]=Mulindi wa maitele a TDE +Comment[vi]=Trình bảo vệ Hệ thống TDE +Comment[wa]=Gåre sistinme TDE +Comment[xh]=TDE Ukhuselo lendlela yokusebenza +Comment[zh_CN]=TDE 系统卫士 +Comment[zh_TW]=TDE 系統守衛 +Comment[zu]=Unogada Wesistimu ye-TDE +Icon=ksysguard +Type=MimeType +Patterns=*.sgrd; +X-TDE-AutoEmbed=false |