dtor first
[personal-kdebase.git] / workspace / ksysguard / gui / SensorBrowser.cc
blob3b4c284ef3b64823d98bcad7a8b160e04fbafe69
1 /*
2 KSysGuard, the KDE System Guard
4 Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org>
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public
8 License version 2 or at your option version 3 as published by
9 the Free Software Foundation.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include <QtGui/QDrag>
23 #include <QtGui/QLabel>
24 #include <QtGui/QMouseEvent>
25 #include <QtGui/QPainter>
26 #include <QtGui/QPixmap>
27 #include <QMimeData>
29 #include <kdebug.h>
30 #include <kicon.h>
31 #include <klocale.h>
32 #include <kmessagebox.h>
33 #include <ksgrd/SensorManager.h>
35 #include "SensorBrowser.h"
36 //#define SENSOR_MODEL_DO_TEST
37 //uncomment the above to test the model
38 #ifdef SENSOR_MODEL_DO_TEST
39 #include "modeltest.h"
40 #endif
42 SensorBrowserModel::SensorBrowserModel()
44 #ifdef SENSOR_MODEL_DO_TEST
45 new ModelTest(this);
46 #endif
47 mIdCount=1;
49 SensorBrowserModel::~SensorBrowserModel()
52 qDeleteAll( mHostInfoMap );
53 mHostInfoMap.clear();
54 qDeleteAll( mSensorInfoMap );
55 mSensorInfoMap.clear();
58 int SensorBrowserModel::columnCount( const QModelIndex &) const { //virtual
59 return 1;
62 QVariant SensorBrowserModel::data( const QModelIndex & index, int role) const { //virtual
63 if(!index.isValid()) return QVariant();
64 switch(role) {
65 case Qt::DisplayRole: {
66 if(index.column()==0) {
67 uint id = index.internalId();
68 if(mSensorInfoMap.contains(id)) {
69 Q_ASSERT(mSensorInfoMap.value(id));
70 SensorInfo *sensorInfo = mSensorInfoMap.value(id);
71 return sensorInfo->description() + " (" +sensorInfo->type() +')' ;
73 if(mTreeNodeNames.contains(id)) return mTreeNodeNames.value(id);
74 if(mHostInfoMap.contains(id)) {
75 Q_ASSERT(mHostInfoMap.value(id));
76 return mHostInfoMap.value(id)->hostName();
79 return QString();
81 case Qt::DecorationRole: {
82 if(index.column() == 0) {
83 HostInfo *host = getHostInfo(index.internalId());
84 KSGRD::SensorAgent *agent;
85 if(host != NULL && (agent = host->sensorAgent())) {
86 if(agent->daemonOnLine())
87 return KIcon("computer");
88 else
89 return KIcon("dialog-warning");
90 } else
91 return QIcon();
92 } else
93 return QIcon();
94 break;
96 case Qt::ToolTipRole: {
97 if(index.column() == 0) {
98 HostInfo *host = getHostInfo(index.internalId());
99 KSGRD::SensorAgent *agent;
100 if(host != NULL && (agent = host->sensorAgent())) {
101 if(agent->daemonOnLine())
102 return agent->hostName();
103 else
104 return agent->reasonForOffline();
107 break;
110 } //switch
111 return QVariant();
114 QVariant SensorBrowserModel::headerData ( int section, Qt::Orientation , int role) const { //virtual
115 if(role != Qt::DisplayRole) return QVariant();
116 if(section==0) return i18n("Sensor Browser");
117 return QVariant();
120 void SensorBrowserModel::retranslate() {
121 emit headerDataChanged(Qt::Horizontal, 0,0);
124 QModelIndex SensorBrowserModel::index ( int row, int column, const QModelIndex & parent) const { //virtual
125 if(column != 0) return QModelIndex();
126 QList<int> ids;
127 if(!parent.isValid()) {
128 ids = mHostInfoMap.keys();
130 else {
131 ids = mTreeMap.value(parent.internalId());
133 if( row >= ids.size() || row< 0) {
134 return QModelIndex();
136 QModelIndex index = createIndex(row, column, ids[row]);
137 Q_ASSERT(index.isValid());
138 return index;
141 QStringList SensorBrowserModel::listHosts() const
143 QStringList hostList;
145 QMapIterator<int, HostInfo*> it( mHostInfoMap );
146 while ( it.hasNext() ) {
147 it.next();
148 Q_ASSERT(it.value());
149 hostList.append( it.value()->hostName() );
152 return hostList;
155 QStringList SensorBrowserModel::listSensors( const QString &hostName ) const
157 QMapIterator<int, HostInfo*> it( mHostInfoMap );
158 while ( it.hasNext() ) {
159 it.next();
160 Q_ASSERT(it.value());
161 if ( it.value()->hostName() == hostName ) {
162 Q_ASSERT(mSensorInfoMap.contains(it.key()));
163 return listSensors( it.key() );
166 return QStringList();
169 QStringList SensorBrowserModel::listSensors( int parentId) const
171 SensorInfo *sensor=mSensorInfoMap.value(parentId);
172 if(sensor) return QStringList(sensor->name());
174 QStringList childSensors;
175 QList<int> children = mTreeMap.value(parentId);
176 for(int i=0; i < children.size(); i++) {
177 childSensors+= listSensors(children[i]);
179 return childSensors;
181 SensorInfo *SensorBrowserModel::getSensorInfo(QModelIndex index) const
183 if(!index.isValid()) return NULL;
184 return mSensorInfoMap.value(index.internalId());
186 int SensorBrowserModel::makeSensor(HostInfo *hostInfo, int parentId, const QString &sensorName, const QString &name, const QString &sensorType) {
187 //sensorName is the full version. e.g. mem/free
188 //name is the short version. e.g. free
189 //sensortype is e.g. Integer
190 QList<int> children = mTreeMap.value(parentId);
191 for(int i=0; i<children.size(); i++)
192 if(mSensorInfoMap.contains(children[i])) {
193 Q_ASSERT(mSensorInfoMap.value(children[i]));
194 if(mSensorInfoMap.value(children[i])->name() == sensorName)
195 return children[i];
198 QModelIndex parentModelIndex;
199 if(hostInfo->id() == parentId) {
200 parentModelIndex = createIndex(mHostInfoMap.keys().indexOf(parentId), 0 , parentId);
201 } else {
202 int parentsParentId = mParentsTreeMap.value(parentId);
203 parentModelIndex = createIndex(mTreeMap.value(parentsParentId).indexOf(parentId), 0, parentId);
205 Q_ASSERT(parentModelIndex.isValid());
206 QList<int> &parentTreemap = mTreeMap[parentId];
207 SensorInfo *sensorInfo = new SensorInfo(hostInfo, sensorName, name, sensorType);
208 beginInsertRows( parentModelIndex , parentTreemap.size(), parentTreemap.size() );
209 parentTreemap << mIdCount;
210 mParentsTreeMap.insert( mIdCount, parentId );
211 mSensorInfoMap.insert(mIdCount, sensorInfo);
212 mHostSensorsMap[hostInfo->id()].insert(sensorName, true);
213 mIdCount++;
214 endInsertRows();
215 return mIdCount-1; //NOTE mIdCount is next available number. Se we use it, then increment it, but return the number of the one that we use
218 void SensorBrowserModel::removeSensor(HostInfo *hostInfo, int parentId, const QString &sensorName) {
219 //sensorName is the full version. e.g. mem/free
220 QList<int> children = mTreeMap.value(parentId);
221 int idCount = -1;
222 int index;
223 for(index=0; index<children.size(); index++)
224 if(mSensorInfoMap.contains(children[index])) {
225 Q_ASSERT(mSensorInfoMap.value(children[index]));
226 if(mSensorInfoMap.value(children[index])->name() == sensorName) {
227 idCount = children[index];
228 break;
231 if(idCount == -1) {
232 kDebug(1215) << "removeSensor called for sensor that doesn't exist in the tree: " << sensorName ;
233 return;
235 QModelIndex parentModelIndex;
236 int parentsParentId = -1;
237 if(hostInfo->id() == parentId) {
238 parentModelIndex = createIndex(mHostInfoMap.keys().indexOf(parentId), 0 , parentId);
239 } else {
240 parentsParentId = mParentsTreeMap.value(parentId);
241 parentModelIndex = createIndex(mTreeMap.value(parentsParentId).indexOf(parentId), 0, parentId);
243 Q_ASSERT(parentModelIndex.isValid());
244 QList<int> &parentTreemap = mTreeMap[parentId];
245 beginRemoveRows( parentModelIndex, index, index );
246 parentTreemap.removeAll(idCount);
247 mParentsTreeMap.remove(idCount);
248 SensorInfo *sensorInfo = mSensorInfoMap.take(idCount);
249 delete sensorInfo;
250 mHostSensorsMap[hostInfo->id()].remove(sensorName);
251 endRemoveRows();
253 if(parentsParentId != -1)
254 removeEmptyParentTreeBranches(hostInfo->id(), parentId, parentsParentId);
256 void SensorBrowserModel::removeEmptyParentTreeBranches(int hostId, int id, int parentId) {
257 if(hostId == id)
258 return; //We don't want to remove hosts
260 if(!mTreeMap.value(id).isEmpty()) return; // We should have no children
262 QModelIndex parentModelIndex;
263 int parentsParentId = -1;
264 if(hostId == parentId) {
265 parentModelIndex = createIndex(mHostInfoMap.keys().indexOf(parentId), 0 , parentId);
266 } else {
267 parentsParentId = mParentsTreeMap.value(parentId);
268 parentModelIndex = createIndex(mTreeMap.value(parentsParentId).indexOf(parentId), 0, parentId);
271 int index = mTreeMap.value(parentId).indexOf(id);
272 int idCount = mTreeMap.value(parentId).at(index);
274 QList<int> &parentTreemap = mTreeMap[parentId];
275 beginRemoveRows( parentModelIndex, index, index );
276 parentTreemap.removeAll(idCount);
277 mParentsTreeMap.remove(idCount);
278 mTreeMap.remove(idCount);
279 mTreeNodeNames.remove(idCount);
280 endRemoveRows();
282 if(parentsParentId != -1)
283 removeEmptyParentTreeBranches(hostId, parentId, parentsParentId);
285 int SensorBrowserModel::makeTreeBranch(int parentId, const QString &name) {
286 QList<int> children = mTreeMap.value(parentId);
287 for(int i=0; i<children.size(); i++)
288 if(mTreeNodeNames.value(children[i]) == name) return children[i];
290 QModelIndex parentModelIndex;
291 if(mHostInfoMap.contains(parentId)) {
292 parentModelIndex = createIndex(mHostInfoMap.keys().indexOf(parentId), 0 , parentId);
293 } else {
294 int parentsParentId = mParentsTreeMap.value(parentId);
295 parentModelIndex = createIndex(mTreeMap.value(parentsParentId).indexOf(parentId), 0, parentId);
297 Q_ASSERT(parentModelIndex.isValid());
298 QList<int> &parentTreemap = mTreeMap[parentId];
299 beginInsertRows( parentModelIndex , parentTreemap.size(), parentTreemap.size() );
300 parentTreemap << mIdCount;
301 mParentsTreeMap.insert( mIdCount, parentId );
302 mTreeMap[mIdCount]; //create with empty qlist
303 mTreeNodeNames.insert(mIdCount, name);
304 mIdCount++;
305 endInsertRows();
307 return mIdCount-1;
310 void SensorBrowserModel::answerReceived( int hostId, const QList<QByteArray>&answer )
312 /* An answer has the following example format:
314 cpu/system/idle integer
315 cpu/system/sys integer
316 cpu/system/nice integer
317 cpu/system/user integer
318 ps table
320 HostInfo *hostInfo = getHostInfo(hostId);
321 if(!hostInfo) {
322 kDebug(1215) << "Invalid hostId " << hostId ;
323 return;
325 /* We keep a copy of the previous sensor names so that we can detect what sensors have been removed */
326 QHash<QString,bool> oldSensorNames = mHostSensorsMap.value(hostId);
327 for ( int i = 0; i < answer.count(); ++i ) {
328 if ( answer[ i ].isEmpty() )
329 continue;
331 QList<QByteArray> words = answer[ i ].split('\t');
332 if(words.size() != 2) {
333 kDebug(1215) << "Invalid data " << answer[i];
334 continue; /* Something wrong with this line of data */
336 QString sensorName = QString::fromUtf8(words[ 0 ]);
337 QString sensorType = QString::fromUtf8(words[ 1 ]);
338 oldSensorNames.remove(sensorName); /* This sensor has not been removed */
339 if ( hasSensor(hostId, sensorName)) {
340 continue;
342 if(sensorName.isEmpty()) continue;
344 if(sensorType == "string") continue;
346 /* The sensor browser can display sensors in a hierarchical order.
347 * Sensors can be grouped into nodes by seperating the hierarchical
348 * nodes through slashes in the sensor name. E. g. cpu/system/user is
349 * the sensor user in the cpu node. There is no limit for the
350 * depth of nodes. */
351 int currentNodeId = hostId; //Start from the host branch and work our way down the tree
352 QStringList absolutePath = sensorName.split( '/' );
353 for ( int j = 0; j < absolutePath.count()-1; ++j ) {
354 // Localize the sensor name part by part.
355 QString name = KSGRD::SensorMgr->translateSensorPath( absolutePath[ j ] );
356 currentNodeId = makeTreeBranch(currentNodeId, name);
358 QString name = KSGRD::SensorMgr->translateSensorPath( absolutePath[ absolutePath.size()-1] );
359 makeSensor(hostInfo, currentNodeId, sensorName, name, sensorType);
361 /* Now we have to remove sensors that were not found */
362 QHashIterator<QString, bool> it( oldSensorNames );
363 while ( it.hasNext() ) {
364 it.next();
366 int currentNodeId = hostId; //Start from the host branch and work our way down the tree
367 QStringList absolutePath = it.key().split( '/' );
368 for ( int j = 0; j < absolutePath.count()-1; ++j ) {
369 // Localize the sensor name part by part.
370 QString name = KSGRD::SensorMgr->translateSensorPath( absolutePath[ j ] );
371 currentNodeId = makeTreeBranch(currentNodeId, name);
373 removeSensor(hostInfo, currentNodeId, it.key());
375 emit sensorsAddedToHost( createIndex( mHostInfoMap.keys().indexOf(hostId), 0, hostId ) );
378 QModelIndex SensorBrowserModel::parent ( const QModelIndex & index ) const { //virtual
379 if(!index.isValid() || index.column() != 0)
380 return QModelIndex();
381 if(mHostInfoMap.contains(index.internalId())) return QModelIndex();
382 if(!mParentsTreeMap.contains(index.internalId())) {
383 kDebug(1215) << "Something is wrong with the model. Doesn't contain " << index.internalId();
384 return QModelIndex();
386 int parentId = mParentsTreeMap.value(index.internalId());
388 QModelIndex parentModelIndex;
389 if(mHostInfoMap.contains(parentId)) {
390 parentModelIndex = createIndex(mHostInfoMap.keys().indexOf(parentId), 0 , parentId);
391 } else {
392 int parentsParentId = mParentsTreeMap.value(parentId);
393 parentModelIndex = createIndex(mTreeMap.value(parentsParentId).indexOf(parentId), 0, parentId);
395 Q_ASSERT(parentModelIndex.isValid());
396 return parentModelIndex;
398 int SensorBrowserModel::rowCount ( const QModelIndex & parent ) const { //virtual
399 if(!parent.isValid()) return mHostInfoMap.size();
400 if(parent.column() != 0) return 0;
401 return mTreeMap.value(parent.internalId()).size();
403 Qt::ItemFlags SensorBrowserModel::flags ( const QModelIndex & index ) const { //virtual
404 if(!index.isValid()) return 0;
405 if(mSensorInfoMap.contains(index.internalId())) return Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled;
406 else return Qt::ItemIsEnabled;
409 SensorBrowserWidget::SensorBrowserWidget( QWidget* parent, KSGRD::SensorManager* sm )
410 : QTreeView( parent ), mSensorManager( sm )
412 setModel(&mSensorBrowserModel);
413 connect( mSensorManager, SIGNAL( update() ), &mSensorBrowserModel, SLOT( update() ) );
415 // setRootIsDecorated( false );
416 setDragDropMode(QAbstractItemView::DragOnly);
418 //setMinimumWidth( 1 );
419 retranslateUi();
420 connect( &mSensorBrowserModel, SIGNAL(sensorsAddedToHost(const QModelIndex&)), this, SLOT(expand(const QModelIndex&)));
422 KSGRD::SensorManagerIterator it( mSensorManager );
423 while ( it.hasNext() ) {
424 KSGRD::SensorAgent* sensorAgent = it.next().value();
425 QString hostName = mSensorManager->hostName( sensorAgent );
426 mSensorBrowserModel.addHost(sensorAgent, hostName);
427 kDebug() << "Adding host " << hostName;
431 SensorBrowserWidget::~SensorBrowserWidget()
435 void SensorBrowserWidget::retranslateUi() {
437 this->setToolTip( i18n( "Drag sensors to empty cells of a worksheet "
438 "or the panel applet." ) );
439 this->setWhatsThis( i18n( "The sensor browser lists the connected hosts and the sensors "
440 "that they provide. Click and drag sensors into drop zones "
441 "of a worksheet or the panel applet. A display will appear "
442 "that visualizes the "
443 "values provided by the sensor. Some sensor displays can "
444 "display values of multiple sensors. Simply drag other "
445 "sensors on to the display to add more sensors." ) );
448 void SensorBrowserWidget::changeEvent( QEvent * event )
450 if (event->type() == QEvent::LanguageChange) {
451 retranslateUi();
452 mSensorBrowserModel.retranslate();
453 mSensorBrowserModel.update();
455 QWidget::changeEvent(event);
458 void SensorBrowserWidget::disconnect()
460 QModelIndexList indexlist = selectionModel()->selectedRows();
461 for(int i=0; i < indexlist.size(); i++)
463 mSensorBrowserModel.disconnectHost(indexlist.value(i).internalId());
467 void SensorBrowserWidget::hostReconfigured( const QString& )
469 // TODO: not yet implemented.
472 void SensorBrowserModel::clear() {
473 qDeleteAll(mHostInfoMap);
474 mHostInfoMap.clear();
478 void SensorBrowserModel::disconnectHost(uint id)
480 disconnectHost(mHostInfoMap.value(id));
482 void SensorBrowserModel::disconnectHost(const HostInfo *hostInfo)
484 KSGRD::SensorMgr->disengage( hostInfo->sensorAgent() );
486 void SensorBrowserModel::disconnectHost(const QString &hostname)
488 QMapIterator<int, HostInfo*> it( mHostInfoMap );
489 while ( it.hasNext() ) {
490 it.next();
491 if(it.value()->hostName() == hostname) {
492 disconnectHost(it.value());
493 return;
498 void SensorBrowserModel::addHost(KSGRD::SensorAgent *sensorAgent, const QString &hostName)
500 beginInsertRows( QModelIndex() , mHostInfoMap.size(), mHostInfoMap.size() );
501 HostInfo* hostInfo = new HostInfo( mIdCount, sensorAgent, hostName);
502 mHostInfoMap.insert(mIdCount, hostInfo);
503 mTreeMap.insert(mIdCount, QList<int>());
504 mHostSensorsMap.insert(mIdCount, QHash<QString, bool>());
505 mIdCount++;
506 endInsertRows();
507 kDebug() << "Adding host " << hostName << "and sending monitors";
508 hostInfo->sensorAgent()->sendRequest( "monitors", this, mIdCount-1 );
511 void SensorBrowserModel::update()
513 kDebug() << "Updating";
514 QMapIterator<int, HostInfo*> it( mHostInfoMap );
515 while ( it.hasNext() ) {
516 it.next();
517 KSGRD::SensorAgent* sensorAgent = it.value()->sensorAgent();
518 int id = it.key();
519 sensorAgent->sendRequest( "monitors", this, id );
522 QMimeData * SensorBrowserModel::mimeData ( const QModelIndexList & indexes ) const { //virtual
523 QMimeData *mimeData = new QMimeData();
524 if(indexes.size() != 1) return mimeData;
525 SensorInfo *sensor = getSensorInfo(indexes[0]);
526 if(!sensor) return mimeData;
527 // Create text drag object as
528 // "<hostname> <sensorname> <sensortype> <sensordescription>".
529 // Only the description may contain blanks.
530 Q_ASSERT(sensor);
531 Q_ASSERT(sensor->hostInfo());
532 QString mDragText = sensor->hostInfo()->hostName() + ' ' +
533 sensor->name() + ' ' +
534 sensor->type()+ ' ' +
535 sensor->description();
538 mimeData->setData( "application/x-ksysguard", mDragText.toUtf8() );
539 return mimeData;
542 SensorInfo::SensorInfo( HostInfo *hostInfo, const QString &name,
543 const QString &desc, const QString &type )
544 : mName( name ), mDesc( desc ), mType( type ), mHostInfo( hostInfo )
546 Q_ASSERT(mHostInfo);
549 QString SensorInfo::name() const
551 return mName;
554 QString SensorInfo::type() const
556 return mType;
559 QString SensorInfo::description() const
561 return mDesc;
564 HostInfo *SensorInfo::hostInfo() const
566 return mHostInfo;
571 #include "SensorBrowser.moc"