|
|
|
/*
|
|
|
|
KSysGuard, the KDE System Guard
|
|
|
|
|
|
|
|
Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of version 2 of the GNU General Public
|
|
|
|
License as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
|
|
|
KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>.
|
|
|
|
Please do not commit any changes without consulting me first. Thanks!
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <tqclipboard.h>
|
|
|
|
#include <tqcursor.h>
|
|
|
|
#include <tqdragobject.h>
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqlayout.h>
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <kpopupmenu.h>
|
|
|
|
|
|
|
|
#include <SensorManager.h>
|
|
|
|
|
|
|
|
#include "DancingBars.h"
|
|
|
|
#include "DummyDisplay.h"
|
|
|
|
#include "FancyPlotter.h"
|
|
|
|
#include "ListView.h"
|
|
|
|
#include "LogFile.h"
|
|
|
|
#include "MultiMeter.h"
|
|
|
|
#include "ProcessController.h"
|
|
|
|
#include "SensorLogger.h"
|
|
|
|
#include "WorkSheet.h"
|
|
|
|
#include "WorkSheetSettings.h"
|
|
|
|
|
|
|
|
WorkSheet::WorkSheet( 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;
|
|
|
|
|
|
|
|
QClipboard* clip = TQApplication::clipboard();
|
|
|
|
|
|
|
|
clip->setText( currentDisplayAsXML() );
|
|
|
|
|
|
|
|
removeDisplay( currentDisplay() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void WorkSheet::copy()
|
|
|
|
{
|
|
|
|
if ( !currentDisplay() || currentDisplay()->isA( "DummyDisplay" ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
QClipboard* clip = TQApplication::clipboard();
|
|
|
|
|
|
|
|
clip->setText( currentDisplayAsXML() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void WorkSheet::paste()
|
|
|
|
{
|
|
|
|
uint row, column;
|
|
|
|
if ( !currentDisplay( &row, &column ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
QClipboard* 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" ) {
|
|
|
|
KPopupMenu pm;
|
|
|
|
pm.insertTitle( i18n( "Select Display Type" ) );
|
|
|
|
pm.insertItem( i18n( "&Signal Plotter" ), 1 );
|
|
|
|
pm.insertItem( i18n( "&Multimeter" ), 2 );
|
|
|
|
pm.insertItem( i18n( "&BarGraph" ), 3 );
|
|
|
|
pm.insertItem( i18n( "S&ensorLogger" ), 4 );
|
|
|
|
switch ( pm.exec( 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"
|