DancingBars.cpp 10.6 KB
Newer Older
1
2
/*
    KSysGuard, the KDE System Guard
3
   
4
    Copyright (c) 1999, 2000, 2001 Chris Schlaeger <cs@kde.org>
5
    
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 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) version 3 or any later version
 accepted by the membership of KDE e.V. (or its successor approved
 by the membership of KDE e.V.), which shall act as a proxy 
 defined in Section 14 of version 3 of the license.

 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, see <http://www.gnu.org/licenses/>.
21
22
23
*/

#include <QCheckBox>
Ragnar Thomsen's avatar
Ragnar Thomsen committed
24
#include <QDebug>
25
#include <QDomElement>
26
#include <QPushButton>
27
#include <QHBoxLayout>
Laurent Montel's avatar
Laurent Montel committed
28

Martin Flöser's avatar
Martin Flöser committed
29
#include <KLocalizedString>
30
#include <ksgrd/SensorManager.h>
31
#include "StyleEngine.h"
32
33
34
35
36
37

#include "BarGraph.h"
#include "DancingBarsSettings.h"

#include "DancingBars.h"

38
39
DancingBars::DancingBars( QWidget *parent, const QString &title, SharedSettings *workSheetSettings)
  : KSGRD::SensorDisplay( parent, title, workSheetSettings)
40
41
42
43
44
{
  mBars = 0;
  mFlags = QBitArray( 100 );
  mFlags.fill( false );

45
  QLayout *layout = new QHBoxLayout(this);
46
  mPlotter = new BarGraph( this );
47
  layout->addWidget(mPlotter);
48
49
50

  setMinimumSize( sizeHint() );

51
  /* All RMB clicks to the mPlotter widget will be handled by 
52
53
54
55
56
57
58
59
60
61
62
63
64
   * SensorDisplay::eventFilter. */
  mPlotter->installEventFilter( this );

  setPlotterWidget( mPlotter );

}

DancingBars::~DancingBars()
{
}

void DancingBars::configureSettings()
{
65
  DancingBarsSettings dlg( this );
66

67
68
69
  dlg.setTitle( title() );
  dlg.setMinValue( mPlotter->getMin() );
  dlg.setMaxValue( mPlotter->getMax() );
70
71
72
73
74

  double l, u;
  bool la, ua;
  mPlotter->getLimits( l, la, u, ua );

75
76
  dlg.setUseUpperLimit( ua );
  dlg.setUpperLimit( u );
77

78
79
  dlg.setUseLowerLimit( la );
  dlg.setLowerLimit( l );
80

81
82
83
84
  dlg.setForegroundColor( mPlotter->normalColor );
  dlg.setAlarmColor( mPlotter->alarmColor );
  dlg.setBackgroundColor( mPlotter->mBackgroundColor );
  dlg.setFontSize( mPlotter->fontSize );
85

86
  SensorModelEntry::List list;
Laurent Montel's avatar
Laurent Montel committed
87
  for(int i = 0; i < mBars; i++){
88
    SensorModelEntry entry;
89
    auto sensor = sensors().at( i );
90
    entry.setId( i );
91
92
    entry.setHostName( sensor->hostName() );
    entry.setSensorName( KSGRD::SensorMgr->translateSensor( sensor->name() ) );
93
    entry.setLabel( mPlotter->footers[ i ] );
94
95
    entry.setUnit( KSGRD::SensorMgr->translateUnit( sensor->unit() ) );
    entry.setStatus( sensor->isOk() ? i18n( "OK" ) : i18n( "Error" ) );
96
97
98

    list.append( entry );
  }
99
  dlg.setSensors( list );
100

101
102
  if ( !dlg.exec() )
    return;
103

104
105
106
107
108
109
110
111
  setTitle( dlg.title() );
  mPlotter->changeRange( dlg.minValue(), dlg.maxValue() );
  mPlotter->setLimits( dlg.useLowerLimit() ?
                       dlg.lowerLimit() : 0,
                       dlg.useLowerLimit(),
                       dlg.useUpperLimit() ?
                       dlg.upperLimit() : 0,
                       dlg.useUpperLimit() );
112

113
114
115
116
  mPlotter->normalColor = dlg.foregroundColor();
  mPlotter->alarmColor = dlg.alarmColor();
  mPlotter->mBackgroundColor = dlg.backgroundColor();
  mPlotter->fontSize = dlg.fontSize();
117

118
119
120
  QList<uint> deletedIds = dlg.getDeletedIds();
  for(int i = 0; i<deletedIds.count(); i++){
	  removeSensor(deletedIds[i]);
121
122
  }

123
124
125
126
127
128
129
130
  // If the range has reset to "auto-range" then we need to ask for
  // sensor info to re-calibrate. In answerReceived() there's a special-
  // case recalibrating on sensor 0 (with id 100), so ask for that one.
  if ( mPlotter->getMin() == 0.0 && mPlotter->getMax() == 0.0 && mBars > 0 ) {
      const auto& sensor = sensors().at( 0 );
      // The 100 is magic in answerReceived()
      sendRequest( sensor->hostName(), sensor->name() + QLatin1Char('?'), 100 );
  }
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  repaint();
}

void DancingBars::applyStyle()
{
  mPlotter->normalColor = KSGRD::Style->firstForegroundColor();
  mPlotter->alarmColor = KSGRD::Style->alarmColor();
  mPlotter->mBackgroundColor = KSGRD::Style->backgroundColor();
  mPlotter->fontSize = KSGRD::Style->fontSize();

  repaint();
}

bool DancingBars::addSensor( const QString &hostName, const QString &name,
                             const QString &type, const QString &title )
{
147
  if ( type != QLatin1String("integer") && type != QLatin1String("float") )
148
149
150
151
152
153
154
155
    return false;

  if ( mBars >= 32 )
    return false;

  if ( !mPlotter->addBar( title ) )
    return false;

156
  registerSensor( new KSGRD::SensorProperties( hostName, name, type, title ) );
157
158
159

  /* To differentiate between answers from value requests and info
   * requests we add 100 to the beam index for info requests. */
160
  sendRequest( hostName, name + QLatin1Char('?'), mBars + 100 );
161
162
163
  ++mBars;
  mSampleBuffer.resize( mBars );

164
  QString tooltip;
Laurent Montel's avatar
Laurent Montel committed
165
  for ( int i = 0; i < mBars; ++i ) {
Laurent Montel's avatar
Laurent Montel committed
166
    tooltip += QStringLiteral( "%1%2:%3" ).arg( i != 0 ? QStringLiteral("\n") : QString() )
167
168
169
170
                                   .arg( sensors().at( i )->hostName() )
                                   .arg( sensors().at( i )->name() );
  }
  mPlotter->setToolTip( tooltip );
171
172
173
174
175
176
177

  return true;
}

bool DancingBars::removeSensor( uint pos )
{
  if ( pos >= mBars ) {
Ragnar Thomsen's avatar
Ragnar Thomsen committed
178
    qDebug() << "DancingBars::removeSensor: idx out of range ("
179
                  << pos << ")";
180
181
182
183
184
185
186
    return false;
  }

  mPlotter->removeBar( pos );
  mBars--;
  KSGRD::SensorDisplay::removeSensor( pos );

187
  QString tooltip;
Laurent Montel's avatar
Laurent Montel committed
188
  for ( int i = 0; i < mBars; ++i ) {
189
    tooltip += QStringLiteral( "%1%2:%3" ).arg( i != 0 ? QStringLiteral("\n") : QString() )
190
191
192
193
                                   .arg( sensors().at( i )->hostName() )
                                   .arg( sensors().at( i )->name() );
  }
  mPlotter->setToolTip( tooltip );
194
195
196
197
198
199
200
201
202

  return true;
}

void DancingBars::updateSamples( const QVector<double> &samples )
{
  mPlotter->updateSamples( samples );
}

203
void DancingBars::answerReceived( int id, const QList<QByteArray> &answerlist )
204
205
206
{
  /* We received something, so the sensor is probably ok. */
  sensorError( id, false );
207
  QByteArray answer;
208
209
  if(!answerlist.isEmpty()) answer = answerlist[0];
  if ( id < 100 ) {
210
    if(id >= mSampleBuffer.count()) {
Ragnar Thomsen's avatar
Ragnar Thomsen committed
211
      qDebug() << "ERROR: DancingBars received invalid data";
212
213
214
      sensorError(id, true);
      return;
    }
215
216
    mSampleBuffer[ id ] = answer.toDouble();
    if ( mFlags.testBit( id ) == true ) {
Ragnar Thomsen's avatar
Ragnar Thomsen committed
217
      qDebug() << "ERROR: DancingBars lost sample (" << mFlags
218
                    << ", " << mBars << ")";
219
      sensorError( id, true );
220
      return;
221
222
223
    }
    mFlags.setBit( id, true );

224
    bool allBitsAvailable = true;
Laurent Montel's avatar
Laurent Montel committed
225
    for ( int i = 0; i < mBars; ++i )
226
227
228
      allBitsAvailable &= mFlags.testBit( i );

    if ( allBitsAvailable ) {
229
      mPlotter->updateSamples( mSampleBuffer );
230
      mFlags.fill( false );
231
232
233
234
235
236
237
238
239
240
    }
  } 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() );
241
      }
242

243
    sensors().at( id - 100 )->setUnit( info.unit() );
244
  }
245
246
247
248
249
250
}

bool DancingBars::restoreSettings( QDomElement &element )
{
  SensorDisplay::restoreSettings( element );

251
252
  mPlotter->changeRange( element.attribute( QStringLiteral("min"), QStringLiteral("0") ).toDouble(),
                         element.attribute( QStringLiteral("max"), QStringLiteral("0") ).toDouble() );
253

254
255
256
257
  mPlotter->setLimits( element.attribute( QStringLiteral("lowlimit"), QStringLiteral("0") ).toDouble(),
                       element.attribute( QStringLiteral("lowlimitactive"), QStringLiteral("0") ).toInt(),
                       element.attribute( QStringLiteral("uplimit"), QStringLiteral("0") ).toDouble(),
                       element.attribute( QStringLiteral("uplimitactive"), QStringLiteral("0") ).toInt() );
258

259
  mPlotter->normalColor = restoreColor( element, QStringLiteral("normalColor"),
260
                                        KSGRD::Style->firstForegroundColor() );
261
  mPlotter->alarmColor = restoreColor( element, QStringLiteral("alarmColor"),
262
                                       KSGRD::Style->alarmColor() );
263
  mPlotter->mBackgroundColor = restoreColor( element, QStringLiteral("backgroundColor"),
264
                                            KSGRD::Style->backgroundColor() );
265
  mPlotter->fontSize = element.attribute( QStringLiteral("fontSize"), QStringLiteral( "%1" ).arg(
266
267
                                          KSGRD::Style->fontSize() ) ).toInt();

268
  QDomNodeList dnList = element.elementsByTagName( QStringLiteral("beam") );
269
270
  for ( int i = 0; i < dnList.count(); ++i ) {
    QDomElement el = dnList.item( i ).toElement();
271
272
273
    addSensor( el.attribute( QStringLiteral("hostName") ), el.attribute( QStringLiteral("sensorName") ),
               ( el.attribute( QStringLiteral("sensorType") ).isEmpty() ? QStringLiteral("integer") :
               el.attribute( QStringLiteral("sensorType") ) ), el.attribute( QStringLiteral("sensorDescr") ) );
274
275
276
277
278
279
  }


  return true;
}

280
bool DancingBars::saveSettings( QDomDocument &doc, QDomElement &element)
281
{
282
283
  element.setAttribute( QStringLiteral("min"), mPlotter->getMin() );
  element.setAttribute( QStringLiteral("max"), mPlotter->getMax() );
284
285
286
  double l, u;
  bool la, ua;
  mPlotter->getLimits( l, la, u, ua );
287
288
289
290
  element.setAttribute( QStringLiteral("lowlimit"), l );
  element.setAttribute( QStringLiteral("lowlimitactive"), la );
  element.setAttribute( QStringLiteral("uplimit"), u );
  element.setAttribute( QStringLiteral("uplimitactive"), ua );
291

292
293
294
295
  saveColor( element, QStringLiteral("normalColor"), mPlotter->normalColor );
  saveColor( element, QStringLiteral("alarmColor"), mPlotter->alarmColor );
	saveColor( element, QStringLiteral("backgroundColor"), mPlotter->mBackgroundColor );
  element.setAttribute( QStringLiteral("fontSize"), mPlotter->fontSize );
296

Laurent Montel's avatar
Laurent Montel committed
297
  for ( int i = 0; i < mBars; ++i ) {
298
    QDomElement beam = doc.createElement( QStringLiteral("beam") );
299
    element.appendChild( beam );
300
301
302
303
    beam.setAttribute( QStringLiteral("hostName"), sensors().at( i )->hostName() );
    beam.setAttribute( QStringLiteral("sensorName"), sensors().at( i )->name() );
    beam.setAttribute( QStringLiteral("sensorType"), sensors().at( i )->type() );
    beam.setAttribute( QStringLiteral("sensorDescr"), mPlotter->footers[ i ] );
304
305
306
307
308
309
310
311
312
313
314
315
  }

  SensorDisplay::saveSettings( doc, element );

  return true;
}

bool DancingBars::hasSettingsDialog() const
{
  return true;
}

316