1 /*
2     KSysGuard, the KDE System Guard
3 
4     Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org>
5 
6  This program is free software; you can redistribute it and/or
7  modify it under the terms of the GNU General Public License as
8  published by the Free Software Foundation; either version 2 of
9  the License or (at your option) version 3 or any later version
10  accepted by the membership of KDE e.V. (or its successor approved
11  by the membership of KDE e.V.), which shall act as a proxy
12  defined in Section 14 of version 3 of the license.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 
23 #include <QDebug>
24 #include <QIcon>
25 #include <QLineEdit>
26 #include <QMimeData>
27 #include <QVBoxLayout>
28 
29 #include <KLocalizedString>
30 #include <KMessageBox>
31 #include <ksgrd/SensorManager.h>
32 
33 #include "SensorBrowser.h"
34 //#define SENSOR_MODEL_DO_TEST
35 //uncomment the above to test the model
36 #ifdef SENSOR_MODEL_DO_TEST
37 #include "modeltest.h"
38 #endif
39 
SensorBrowserModel()40 SensorBrowserModel::SensorBrowserModel()
41 {
42 #ifdef SENSOR_MODEL_DO_TEST
43     new ModelTest(this);
44 #endif
45     mIdCount=1;
46 }
~SensorBrowserModel()47 SensorBrowserModel::~SensorBrowserModel()
48 {
49     qDeleteAll( mHostInfoMap );
50     mHostInfoMap.clear();
51     qDeleteAll( mSensorInfoMap );
52     mSensorInfoMap.clear();
53 }
54 
columnCount(const QModelIndex &) const55 int SensorBrowserModel::columnCount( const QModelIndex &) const { //virtual
56     return 1;
57 }
58 
data(const QModelIndex & index,int role) const59 QVariant SensorBrowserModel::data( const QModelIndex & index, int role) const { //virtual
60     if(!index.isValid()) return QVariant();
61     switch(role) {
62         case Qt::DisplayRole: {
63             if(index.column()==0) {
64                 uint id = index.internalId();
65                 if(mSensorInfoMap.contains(id)) {
66                     Q_ASSERT(mSensorInfoMap.value(id));
67                     SensorInfo *sensorInfo = mSensorInfoMap.value(id);
68                     return QString(sensorInfo->description() + " (" + KSGRD::SensorMgr->translateSensorType(sensorInfo->type()) + ')' );
69                 }
70                 if(mTreeNodeNames.contains(id)) return mTreeNodeNames.value(id);
71                 if(mHostInfoMap.contains(id)) {
72                     Q_ASSERT(mHostInfoMap.value(id));
73                     return mHostInfoMap.value(id)->hostName();
74                 }
75             }
76             return QString();
77         }
78         case Qt::DecorationRole: {
79             if(index.column() == 0) {
80                 HostInfo *host = getHostInfo(index.internalId());
81                 KSGRD::SensorAgent *agent;
82                 if(host != nullptr && (agent = host->sensorAgent())) {
83                     if(agent->daemonOnLine())
84                         return QIcon::fromTheme(QStringLiteral("computer"));
85                     else
86                         return QIcon::fromTheme(QStringLiteral("dialog-warning"));
87                 } else
88                     return QIcon();
89             } else
90                 return QIcon();
91             break;
92         }
93         case Qt::ToolTipRole: {
94             if(index.column() == 0) {
95                 HostInfo *host = getHostInfo(index.internalId());
96                 KSGRD::SensorAgent *agent;
97                 if(host != nullptr && (agent = host->sensorAgent())) {
98                     if(agent->daemonOnLine())
99                         return agent->hostName();
100                     else
101                         return agent->reasonForOffline();
102                 }
103             }
104             break;
105         }
106 
107     } //switch
108     return QVariant();
109 }
110 
headerData(int section,Qt::Orientation,int role) const111 QVariant SensorBrowserModel::headerData ( int section, Qt::Orientation , int role) const { //virtual
112     if(role != Qt::DisplayRole) return QVariant();
113     if(section==0) return i18n("Sensor Browser");
114     return QVariant();
115 }
116 
retranslate()117 void  SensorBrowserModel::retranslate() {
118     emit headerDataChanged(Qt::Horizontal, 0,0);
119 }
120 
index(int row,int column,const QModelIndex & parent) const121 QModelIndex SensorBrowserModel::index ( int row, int column, const QModelIndex & parent) const { //virtual
122     if(column != 0) return QModelIndex();
123     QList<int> ids;
124     if(!parent.isValid()) {
125         ids = mHostInfoMap.keys();
126     }
127     else {
128         ids = mTreeMap.value(parent.internalId());
129     }
130     if( row >= ids.size() || row< 0) {
131         return QModelIndex();
132     }
133     QModelIndex index = createIndex(row, column, ids[row]);
134     Q_ASSERT(index.isValid());
135     return index;
136 }
137 
listHosts() const138 QStringList SensorBrowserModel::listHosts() const
139 {
140     QStringList hostList;
141 
142     QMapIterator<int, HostInfo*> it( mHostInfoMap );
143     while ( it.hasNext() ) {
144         it.next();
145         Q_ASSERT(it.value());
146         hostList.append( it.value()->hostName() );
147     }
148 
149     return hostList;
150 }
151 
listSensors(const QString & hostName) const152 QStringList SensorBrowserModel::listSensors( const QString &hostName ) const
153 {
154     QMapIterator<int, HostInfo*> it( mHostInfoMap );
155     while ( it.hasNext() ) {
156         it.next();
157         Q_ASSERT(it.value());
158         if ( it.value()->hostName() == hostName ) {
159             Q_ASSERT(mSensorInfoMap.contains(it.key()));
160             return listSensors( it.key() );
161         }
162     }
163     return QStringList();
164 }
165 
listSensors(int parentId) const166 QStringList SensorBrowserModel::listSensors( int parentId) const
167 {
168     SensorInfo *sensor=mSensorInfoMap.value(parentId);
169     if(sensor) return QStringList(sensor->name());
170 
171     QStringList childSensors;
172     QList<int> children = mTreeMap.value(parentId);
173     for(int i=0; i < children.size(); i++) {
174         childSensors+= listSensors(children[i]);
175     }
176     return childSensors;
177 }
getSensorInfo(QModelIndex index) const178 SensorInfo *SensorBrowserModel::getSensorInfo(QModelIndex index) const
179 {
180     if(!index.isValid()) return nullptr;
181     return mSensorInfoMap.value(index.internalId());
182 }
makeSensor(HostInfo * hostInfo,int parentId,const QString & sensorName,const QString & name,const QString & sensorType)183 int SensorBrowserModel::makeSensor(HostInfo *hostInfo, int parentId, const QString &sensorName, const QString &name, const QString &sensorType) {
184     //sensorName is the full version.  e.g.  mem/free
185     //name is the short version. e.g. free
186     //sensortype is e.g. Integer
187     QList<int> children = mTreeMap.value(parentId);
188     for(int i=0; i<children.size(); i++)
189         if(mSensorInfoMap.contains(children[i])) {
190             Q_ASSERT(mSensorInfoMap.value(children[i]));
191             if(mSensorInfoMap.value(children[i])->name() == sensorName)
192                 return children[i];
193         }
194 
195     QModelIndex parentModelIndex;
196     if(hostInfo->id() == parentId) {
197         parentModelIndex = createIndex(mHostInfoMap.keys().indexOf(parentId), 0 , parentId);
198     } else {
199         int parentsParentId = mParentsTreeMap.value(parentId);
200         parentModelIndex = createIndex(mTreeMap.value(parentsParentId).indexOf(parentId), 0, parentId);
201     }
202     Q_ASSERT(parentModelIndex.isValid());
203     QList<int> &parentTreemap = mTreeMap[parentId];
204     SensorInfo *sensorInfo = new SensorInfo(hostInfo, sensorName, name, sensorType);
205     beginInsertRows( parentModelIndex , parentTreemap.size(), parentTreemap.size() );
206     parentTreemap << mIdCount;
207     mParentsTreeMap.insert( mIdCount, parentId );
208     mSensorInfoMap.insert(mIdCount, sensorInfo);
209     mHostSensorsMap[hostInfo->id()].insert(sensorName, true);
210     mIdCount++;
211     endInsertRows();
212     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
213 }
214 
removeSensor(HostInfo * hostInfo,int parentId,const QString & sensorName)215 void SensorBrowserModel::removeSensor(HostInfo *hostInfo, int parentId, const QString &sensorName) {
216     //sensorName is the full version.  e.g.  mem/free
217     QList<int> children = mTreeMap.value(parentId);
218     int idCount = -1;
219     int index;
220     for(index=0; index<children.size(); index++)
221         if(mSensorInfoMap.contains(children[index])) {
222             Q_ASSERT(mSensorInfoMap.value(children[index]));
223             if(mSensorInfoMap.value(children[index])->name() == sensorName) {
224                 idCount = children[index];
225                 break;
226             }
227         }
228     if(idCount == -1) {
229         qDebug() << "removeSensor called for sensor that doesn't exist in the tree: " << sensorName ;
230         return;
231     }
232     QModelIndex parentModelIndex;
233     int parentsParentId = -1;
234     if(hostInfo->id() == parentId) {
235         parentModelIndex = createIndex(mHostInfoMap.keys().indexOf(parentId), 0 , parentId);
236     } else {
237         parentsParentId = mParentsTreeMap.value(parentId);
238         parentModelIndex = createIndex(mTreeMap.value(parentsParentId).indexOf(parentId), 0, parentId);
239     }
240     Q_ASSERT(parentModelIndex.isValid());
241     QList<int> &parentTreemap = mTreeMap[parentId];
242     beginRemoveRows( parentModelIndex, index, index );
243     parentTreemap.removeAll(idCount);
244     mParentsTreeMap.remove(idCount);
245     SensorInfo *sensorInfo = mSensorInfoMap.take(idCount);
246     delete sensorInfo;
247     mHostSensorsMap[hostInfo->id()].remove(sensorName);
248     endRemoveRows();
249 
250     if(parentsParentId != -1)
251         removeEmptyParentTreeBranches(hostInfo->id(), parentId, parentsParentId);
252 }
removeEmptyParentTreeBranches(int hostId,int id,int parentId)253 void SensorBrowserModel::removeEmptyParentTreeBranches(int hostId, int id, int parentId) {
254     if(hostId == id)
255         return;  //We don't want to remove hosts
256 
257     if(!mTreeMap.value(id).isEmpty()) return; // We should have no children
258 
259     QModelIndex parentModelIndex;
260     int parentsParentId = -1;
261     if(hostId == parentId) {
262         parentModelIndex = createIndex(mHostInfoMap.keys().indexOf(parentId), 0 , parentId);
263     } else {
264         parentsParentId = mParentsTreeMap.value(parentId);
265         parentModelIndex = createIndex(mTreeMap.value(parentsParentId).indexOf(parentId), 0, parentId);
266     }
267 
268     int index = mTreeMap.value(parentId).indexOf(id);
269     int idCount = mTreeMap.value(parentId).at(index);
270 
271     QList<int> &parentTreemap = mTreeMap[parentId];
272     beginRemoveRows( parentModelIndex, index, index );
273     parentTreemap.removeAll(idCount);
274     mParentsTreeMap.remove(idCount);
275     mTreeMap.remove(idCount);
276     mTreeNodeNames.remove(idCount);
277     endRemoveRows();
278 
279     if(parentsParentId != -1)
280         removeEmptyParentTreeBranches(hostId, parentId, parentsParentId);
281 }
makeTreeBranch(int parentId,const QString & name)282 int SensorBrowserModel::makeTreeBranch(int parentId, const QString &name) {
283     QList<int> children = mTreeMap.value(parentId);
284     for(int i=0; i<children.size(); i++)
285         if(mTreeNodeNames.value(children[i]) == name) return children[i];
286 
287     QModelIndex parentModelIndex;
288     if(mHostInfoMap.contains(parentId)) {
289         parentModelIndex = createIndex(mHostInfoMap.keys().indexOf(parentId), 0 , parentId);
290     } else {
291         int parentsParentId = mParentsTreeMap.value(parentId);
292         parentModelIndex = createIndex(mTreeMap.value(parentsParentId).indexOf(parentId), 0, parentId);
293     }
294     Q_ASSERT(parentModelIndex.isValid());
295     QList<int> &parentTreemap = mTreeMap[parentId];
296     beginInsertRows( parentModelIndex , parentTreemap.size(), parentTreemap.size() );
297     parentTreemap << mIdCount;
298     mParentsTreeMap.insert( mIdCount, parentId );
299     mTreeMap[mIdCount];  //create with empty qlist
300     mTreeNodeNames.insert(mIdCount, name);
301     mIdCount++;
302     endInsertRows();
303 
304     return mIdCount-1;
305 }
306 
answerReceived(int hostId,const QList<QByteArray> & answer)307 void SensorBrowserModel::answerReceived( int hostId,  const QList<QByteArray>&answer )
308 {
309     /* An answer has the following example format:
310 
311        cpu/system/idle integer
312        cpu/system/sys  integer
313        cpu/system/nice integer
314        cpu/system/user integer
315        ps       table
316        */
317     HostInfo *hostInfo = getHostInfo(hostId);
318     if(!hostInfo) {
319         qDebug() << "Invalid hostId " << hostId ;
320         return;
321     }
322     /* We keep a copy of the previous sensor names so that we can detect what sensors have been removed */
323     QHash<QString,bool> oldSensorNames = mHostSensorsMap.value(hostId);
324     for ( int i = 0; i < answer.count(); ++i ) {
325         if ( answer[ i ].isEmpty() )
326             continue;
327 
328         QList<QByteArray> words = answer[ i ].split('\t');
329         if(words.size() != 2) {
330             qDebug() << "Invalid data " << answer[i];
331             continue;  /* Something wrong with this line of data */
332         }
333         QString sensorName = QString::fromUtf8(words[ 0 ]);
334         QString sensorType = QString::fromUtf8(words[ 1 ]);
335         oldSensorNames.remove(sensorName);  /* This sensor has not been removed */
336         if ( hasSensor(hostId, sensorName)) {
337             continue;
338         }
339         if(sensorName.isEmpty()) continue;
340 
341         if(sensorType == QLatin1String("string")) continue;
342 
343         /* The sensor browser can display sensors in a hierarchical order.
344          * Sensors can be grouped into nodes by separating the hierarchical
345          * nodes through slashes in the sensor name. E. g. cpu/system/user is
346          * the sensor user in the cpu node. There is no limit for the
347          * depth of nodes. */
348         int currentNodeId = hostId;  //Start from the host branch and work our way down the tree
349         QStringList absolutePath = sensorName.split( '/' );
350         for ( int j = 0; j < absolutePath.count()-1; ++j ) {
351             // Localize the sensor name part by part.
352             QString name = KSGRD::SensorMgr->translateSensorPath( absolutePath[ j ] );
353             currentNodeId = makeTreeBranch(currentNodeId, name);
354         }
355         QString name = KSGRD::SensorMgr->translateSensorPath( absolutePath[ absolutePath.size()-1] );
356         makeSensor(hostInfo, currentNodeId, sensorName, name, sensorType);
357     }
358     /* Now we have to remove sensors that were not found */
359     QHashIterator<QString, bool> it( oldSensorNames );
360     while ( it.hasNext() ) {
361         it.next();
362 
363         int currentNodeId = hostId;  //Start from the host branch and work our way down the tree
364         QStringList absolutePath = it.key().split( '/' );
365         for ( int j = 0; j < absolutePath.count()-1; ++j ) {
366             // Localize the sensor name part by part.
367             QString name = KSGRD::SensorMgr->translateSensorPath( absolutePath[ j ] );
368             currentNodeId = makeTreeBranch(currentNodeId, name);
369         }
370         removeSensor(hostInfo, currentNodeId, it.key());
371     }
372     emit sensorsAddedToHost( createIndex( mHostInfoMap.keys().indexOf(hostId), 0, hostId ) );
373 }
374 
375 //virtual
parent(const QModelIndex & index) const376 QModelIndex SensorBrowserModel::parent ( const QModelIndex & index ) const {
377     if(!index.isValid() || index.column() != 0)
378         return QModelIndex();
379     if(mHostInfoMap.contains(index.internalId())) return QModelIndex();
380     if(!mParentsTreeMap.contains(index.internalId())) {
381         qDebug() << "Something is wrong with the model.  Doesn't contain " << index.internalId();
382         return QModelIndex();
383     }
384     int parentId = mParentsTreeMap.value(index.internalId());
385 
386     QModelIndex parentModelIndex;
387     if(mHostInfoMap.contains(parentId)) {
388         parentModelIndex = createIndex(mHostInfoMap.keys().indexOf(parentId), 0 , parentId);
389     } else {
390         int parentsParentId = mParentsTreeMap.value(parentId);
391         parentModelIndex = createIndex(mTreeMap.value(parentsParentId).indexOf(parentId), 0, parentId);
392     }
393     Q_ASSERT(parentModelIndex.isValid());
394     return parentModelIndex;
395 }
396 //virtual
rowCount(const QModelIndex & parent) const397 int SensorBrowserModel::rowCount ( const QModelIndex & parent ) const {
398     if(!parent.isValid()) return mHostInfoMap.size();
399     if(parent.column() != 0) return 0;
400     return mTreeMap.value(parent.internalId()).size();
401 }
402 //virtual
flags(const QModelIndex & index) const403 Qt::ItemFlags SensorBrowserModel::flags ( const QModelIndex & index ) const {
404     if(!index.isValid()) return Qt::NoItemFlags;
405     if(mSensorInfoMap.contains(index.internalId())) return Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled;
406     else return Qt::ItemIsEnabled;
407 }
408 
SensorBrowserWidget(QWidget * parent,KSGRD::SensorManager * sm)409 SensorBrowserWidget::SensorBrowserWidget( QWidget* parent, KSGRD::SensorManager* sm ) : QWidget( parent )
410 {
411     QVBoxLayout *layout = new QVBoxLayout;
412     m_treeWidget = new SensorBrowserTreeWidget(this, sm);
413     QLineEdit * search_line = new QLineEdit(this);
414     connect(search_line, &QLineEdit::textChanged, this, [this](const QString &text) {
415         m_treeWidget->model().setFilterFixedString(text);
416     });
417     layout->addWidget(search_line);
418     layout->addWidget(m_treeWidget);
419     setLayout(layout);
420 }
~SensorBrowserWidget()421 SensorBrowserWidget::~SensorBrowserWidget()
422 {
423 }
SensorBrowserTreeWidget(QWidget * parent,KSGRD::SensorManager * sm)424 SensorBrowserTreeWidget::SensorBrowserTreeWidget( QWidget* parent, KSGRD::SensorManager* sm ) : QTreeView( parent ), mSensorManager( sm )
425 {
426     mSortFilterProxyModel.setSourceModel(&mSensorBrowserModel);
427     mSortFilterProxyModel.setRecursiveFilteringEnabled(true);
428     mSortFilterProxyModel.setFilterCaseSensitivity(Qt::CaseInsensitive);
429     setModel(&mSortFilterProxyModel);
430     connect(mSensorManager, &KSGRD::SensorManager::update, &mSensorBrowserModel, &SensorBrowserModel::update);
431     connect(mSensorManager, &KSGRD::SensorManager::hostAdded, &mSensorBrowserModel, &SensorBrowserModel::hostAdded);
432     connect(mSensorManager, &KSGRD::SensorManager::hostConnectionLost, &mSensorBrowserModel, &SensorBrowserModel::hostRemoved);
433 //  connect( mSensorManager, SIGNAL(hostAdded(KSGRD::SensorAgent*,QString)), SLOT(updateView()) );
434 //  connect( mSensorManager, SIGNAL(hostConnectionLost(QString)), SLOT(updateView()) );
435     connect(&mSortFilterProxyModel, &QSortFilterProxyModel::rowsInserted, this, &SensorBrowserTreeWidget::updateView);
436 
437     setDragDropMode(QAbstractItemView::DragOnly);
438     setUniformRowHeights(true);
439 
440     //setMinimumWidth( 1 );
441     retranslateUi();
442     connect(&mSensorBrowserModel, &SensorBrowserModel::sensorsAddedToHost, this, &SensorBrowserTreeWidget::expandItem);
443 
444     KSGRD::SensorManagerIterator it( mSensorManager );
445     while ( it.hasNext() ) {
446         KSGRD::SensorAgent* sensorAgent = it.next().value();
447         QString hostName = mSensorManager->hostName( sensorAgent );
448         mSensorBrowserModel.addHost(sensorAgent, hostName);
449     }
450     updateView();
451 }
452 
~SensorBrowserTreeWidget()453 SensorBrowserTreeWidget::~SensorBrowserTreeWidget()
454 {
455 }
456 
updateView()457 void SensorBrowserTreeWidget::updateView()
458 {
459     if(mSensorManager->count() == 1) {
460         setRootIsDecorated( false );
461         //expand the top level
462         for(int i = 0; i < mSortFilterProxyModel.rowCount(); i++)
463             expand(mSortFilterProxyModel.index(i,0));
464     } else
465         setRootIsDecorated( true );
466 }
expandItem(const QModelIndex & model_index)467 void SensorBrowserTreeWidget::expandItem(const QModelIndex &model_index)
468 {
469     expand(mSortFilterProxyModel.mapFromSource(model_index));
470 }
retranslateUi()471 void SensorBrowserTreeWidget::retranslateUi() {
472 
473     this->setToolTip( i18n( "Drag sensors to empty cells of a worksheet "));
474     this->setWhatsThis( i18n( "The sensor browser lists the connected hosts and the sensors "
475                 "that they provide. Click and drag sensors into drop zones "
476                 "of a worksheet. A display will appear "
477                 "that visualizes the "
478                 "values provided by the sensor. Some sensor displays can "
479                 "display values of multiple sensors. Simply drag other "
480                 "sensors on to the display to add more sensors." ) );
481 }
482 
changeEvent(QEvent * event)483 void SensorBrowserTreeWidget::changeEvent( QEvent * event )
484 {
485     if (event->type() == QEvent::LanguageChange) {
486         retranslateUi();
487         mSensorBrowserModel.retranslate();
488         mSensorBrowserModel.update();
489     }
490     QWidget::changeEvent(event);
491 }
492 
disconnect()493 void SensorBrowserTreeWidget::disconnect()
494 {
495     QModelIndexList indexlist = selectionModel()->selectedRows();
496     for(int i=0; i < indexlist.size(); i++)
497     {
498         mSensorBrowserModel.disconnectHost(indexlist.value(i).internalId());
499     }
500 }
501 
hostReconfigured(const QString &)502 void SensorBrowserTreeWidget::hostReconfigured( const QString& )
503 {
504     // TODO: not yet implemented.
505 }
506 
clear()507 void SensorBrowserModel::clear() {
508     qDeleteAll(mHostInfoMap);
509     mHostInfoMap.clear();
510 
511 }
512 
disconnectHost(uint id)513 void SensorBrowserModel::disconnectHost(uint id)
514 {
515     disconnectHost(mHostInfoMap.value(id));
516 }
disconnectHost(const HostInfo * hostInfo)517 void SensorBrowserModel::disconnectHost(const HostInfo *hostInfo)
518 {
519     KSGRD::SensorMgr->disengage( hostInfo->sensorAgent() );
520 }
disconnectHost(const QString & hostname)521 void SensorBrowserModel::disconnectHost(const QString &hostname)
522 {
523     HostInfo* toDelete = findHostInfoByHostName(hostname);
524     if (toDelete != nullptr)
525         disconnectHost(toDelete);
526 }
findHostInfoByHostName(const QString & hostName) const527 HostInfo* SensorBrowserModel::findHostInfoByHostName(const QString &hostName) const {
528     HostInfo* toReturn = nullptr;
529     QMapIterator<int, HostInfo*> it( mHostInfoMap );
530     while (it.hasNext() && toReturn == nullptr) {
531         it.next();
532         if (it.value()->hostName() == hostName) {
533             toReturn = it.value();
534         }
535     }
536     return toReturn;
537 }
hostAdded(KSGRD::SensorAgent * sensorAgent,const QString & hostName)538 void SensorBrowserModel::hostAdded(KSGRD::SensorAgent *sensorAgent, const QString &hostName)  {
539     addHost(sensorAgent,hostName);
540     update();
541 }
542 
hostRemoved(const QString & hostName)543 void SensorBrowserModel::hostRemoved(const QString &hostName)  {
544     HostInfo* toRemove = findHostInfoByHostName(hostName);
545     if (toRemove != nullptr)  {
546         beginResetModel();
547         int hostId = toRemove->id();
548         removeAllSensorUnderBranch(toRemove,hostId);
549         removeEmptyParentTreeBranches(hostId,hostId,hostId);
550 
551         delete mHostInfoMap.take(hostId);
552         mTreeMap.take(hostId);
553         mHostSensorsMap.take(hostId);
554         endResetModel();
555     }
556     update();
557 }
558 
removeAllSensorUnderBranch(HostInfo * hostInfo,int parentId)559 void SensorBrowserModel::removeAllSensorUnderBranch(HostInfo* hostInfo, int parentId)  {
560 
561     QList<int> children = mTreeMap.value(parentId);
562 
563     for (int i = 0; i < children.size(); i++) {
564 
565         if (mTreeMap.contains(children[i]))  {
566             //well our children is not a sensor so remove what is under him
567             removeAllSensorUnderBranch(hostInfo,children[i]);
568 
569         } else  {
570             //well this should be a sensor so remove it
571             if (mSensorInfoMap.contains(children[i])) {
572                 SensorInfo* sensorToRemove = mSensorInfoMap.value(children[i]);
573                 Q_ASSERT(sensorToRemove);
574                 removeSensor(hostInfo, parentId, sensorToRemove->name());
575             }
576         }
577     }
578 
579 
580 }
addHost(KSGRD::SensorAgent * sensorAgent,const QString & hostName)581 void SensorBrowserModel::addHost(KSGRD::SensorAgent *sensorAgent, const QString &hostName)
582 {
583     beginInsertRows( QModelIndex() , mHostInfoMap.size(), mHostInfoMap.size() );
584     HostInfo* hostInfo = new HostInfo( mIdCount, sensorAgent, hostName);
585     mHostInfoMap.insert(mIdCount, hostInfo);
586     mTreeMap.insert(mIdCount, QList<int>());
587     mHostSensorsMap.insert(mIdCount, QHash<QString, bool>());
588     mIdCount++;
589     endInsertRows();
590     hostInfo->sensorAgent()->sendRequest( QStringLiteral("monitors"), this, mIdCount-1 );
591 }
592 
update()593 void SensorBrowserModel::update()
594 {
595     QMapIterator<int, HostInfo*> it( mHostInfoMap );
596     while ( it.hasNext() ) {
597         it.next();
598         KSGRD::SensorAgent* sensorAgent = it.value()->sensorAgent();
599         int id = it.key();
600         sensorAgent->sendRequest( QStringLiteral("monitors"), this, id );
601     }
602 }
mimeData(const QModelIndexList & indexes) const603 QMimeData * SensorBrowserModel::mimeData ( const QModelIndexList & indexes ) const { //virtual
604     QMimeData *mimeData = new QMimeData();
605     if(indexes.size() != 1) return mimeData;
606     SensorInfo *sensor = getSensorInfo(indexes[0]);
607     if(!sensor) return mimeData;
608     // Create text drag object as
609     // "<hostname> <sensorname> <sensortype> <sensordescription>".
610     // Only the description may contain blanks.
611     Q_ASSERT(sensor);
612     Q_ASSERT(sensor->hostInfo());
613     QString mDragText = sensor->hostInfo()->hostName() + ' ' +
614         sensor->name() + ' ' +
615         sensor->type()+ ' ' +
616         sensor->description();
617 
618 
619     mimeData->setData( QStringLiteral("application/x-ksysguard"), mDragText.toUtf8() );
620     return mimeData;
621 }
622 
SensorInfo(HostInfo * hostInfo,const QString & name,const QString & desc,const QString & type)623 SensorInfo::SensorInfo( HostInfo *hostInfo, const QString &name,
624         const QString &desc, const QString &type )
625   : mName( name ), mDesc( desc ), mType( type ), mHostInfo( hostInfo )
626 {
627     Q_ASSERT(mHostInfo);
628 }
629 
name() const630 QString SensorInfo::name() const
631 {
632     return mName;
633 }
634 
type() const635 QString SensorInfo::type() const
636 {
637     return mType;
638 }
639 
description() const640 QString SensorInfo::description() const
641 {
642     return mDesc;
643 }
644 
hostInfo() const645 HostInfo *SensorInfo::hostInfo() const
646 {
647     return mHostInfo;
648 }
649 
650 
651 
652 
653