diff --git a/gui/SensorBrowser.cpp b/gui/SensorBrowser.cpp index 195a0779..fcc942ab 100644 --- a/gui/SensorBrowser.cpp +++ b/gui/SensorBrowser.cpp @@ -1,649 +1,649 @@ /* KSysGuard, the KDE System Guard Copyright (c) 1999, 2000 Chris Schlaeger 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 . */ #include #include #include #include #include #include #include #include #include "SensorBrowser.h" //#define SENSOR_MODEL_DO_TEST //uncomment the above to test the model #ifdef SENSOR_MODEL_DO_TEST #include "modeltest.h" #endif SensorBrowserModel::SensorBrowserModel() { #ifdef SENSOR_MODEL_DO_TEST new ModelTest(this); #endif mIdCount=1; } SensorBrowserModel::~SensorBrowserModel() { qDeleteAll( mHostInfoMap ); mHostInfoMap.clear(); qDeleteAll( mSensorInfoMap ); mSensorInfoMap.clear(); } int SensorBrowserModel::columnCount( const QModelIndex &) const { //virtual return 1; } QVariant SensorBrowserModel::data( const QModelIndex & index, int role) const { //virtual if(!index.isValid()) return QVariant(); switch(role) { case Qt::DisplayRole: { if(index.column()==0) { uint id = index.internalId(); if(mSensorInfoMap.contains(id)) { Q_ASSERT(mSensorInfoMap.value(id)); SensorInfo *sensorInfo = mSensorInfoMap.value(id); return QString(sensorInfo->description() + " (" + KSGRD::SensorMgr->translateSensorType(sensorInfo->type()) + ')' ); } if(mTreeNodeNames.contains(id)) return mTreeNodeNames.value(id); if(mHostInfoMap.contains(id)) { Q_ASSERT(mHostInfoMap.value(id)); return mHostInfoMap.value(id)->hostName(); } } return QString(); } case Qt::DecorationRole: { if(index.column() == 0) { HostInfo *host = getHostInfo(index.internalId()); KSGRD::SensorAgent *agent; - if(host != NULL && (agent = host->sensorAgent())) { + if(host != nullptr && (agent = host->sensorAgent())) { if(agent->daemonOnLine()) return QIcon::fromTheme(QStringLiteral("computer")); else return QIcon::fromTheme(QStringLiteral("dialog-warning")); } else return QIcon(); } else return QIcon(); break; } case Qt::ToolTipRole: { if(index.column() == 0) { HostInfo *host = getHostInfo(index.internalId()); KSGRD::SensorAgent *agent; - if(host != NULL && (agent = host->sensorAgent())) { + if(host != nullptr && (agent = host->sensorAgent())) { if(agent->daemonOnLine()) return agent->hostName(); else return agent->reasonForOffline(); } } break; } } //switch return QVariant(); } QVariant SensorBrowserModel::headerData ( int section, Qt::Orientation , int role) const { //virtual if(role != Qt::DisplayRole) return QVariant(); if(section==0) return i18n("Sensor Browser"); return QVariant(); } void SensorBrowserModel::retranslate() { emit headerDataChanged(Qt::Horizontal, 0,0); } QModelIndex SensorBrowserModel::index ( int row, int column, const QModelIndex & parent) const { //virtual if(column != 0) return QModelIndex(); QList ids; if(!parent.isValid()) { ids = mHostInfoMap.keys(); } else { ids = mTreeMap.value(parent.internalId()); } if( row >= ids.size() || row< 0) { return QModelIndex(); } QModelIndex index = createIndex(row, column, ids[row]); Q_ASSERT(index.isValid()); return index; } QStringList SensorBrowserModel::listHosts() const { QStringList hostList; QMapIterator it( mHostInfoMap ); while ( it.hasNext() ) { it.next(); Q_ASSERT(it.value()); hostList.append( it.value()->hostName() ); } return hostList; } QStringList SensorBrowserModel::listSensors( const QString &hostName ) const { QMapIterator it( mHostInfoMap ); while ( it.hasNext() ) { it.next(); Q_ASSERT(it.value()); if ( it.value()->hostName() == hostName ) { Q_ASSERT(mSensorInfoMap.contains(it.key())); return listSensors( it.key() ); } } return QStringList(); } QStringList SensorBrowserModel::listSensors( int parentId) const { SensorInfo *sensor=mSensorInfoMap.value(parentId); if(sensor) return QStringList(sensor->name()); QStringList childSensors; QList children = mTreeMap.value(parentId); for(int i=0; i < children.size(); i++) { childSensors+= listSensors(children[i]); } return childSensors; } SensorInfo *SensorBrowserModel::getSensorInfo(QModelIndex index) const { - if(!index.isValid()) return NULL; + if(!index.isValid()) return nullptr; return mSensorInfoMap.value(index.internalId()); } int SensorBrowserModel::makeSensor(HostInfo *hostInfo, int parentId, const QString &sensorName, const QString &name, const QString &sensorType) { //sensorName is the full version. e.g. mem/free //name is the short version. e.g. free //sensortype is e.g. Integer QList children = mTreeMap.value(parentId); for(int i=0; iname() == sensorName) return children[i]; } QModelIndex parentModelIndex; if(hostInfo->id() == parentId) { parentModelIndex = createIndex(mHostInfoMap.keys().indexOf(parentId), 0 , parentId); } else { int parentsParentId = mParentsTreeMap.value(parentId); parentModelIndex = createIndex(mTreeMap.value(parentsParentId).indexOf(parentId), 0, parentId); } Q_ASSERT(parentModelIndex.isValid()); QList &parentTreemap = mTreeMap[parentId]; SensorInfo *sensorInfo = new SensorInfo(hostInfo, sensorName, name, sensorType); beginInsertRows( parentModelIndex , parentTreemap.size(), parentTreemap.size() ); parentTreemap << mIdCount; mParentsTreeMap.insert( mIdCount, parentId ); mSensorInfoMap.insert(mIdCount, sensorInfo); mHostSensorsMap[hostInfo->id()].insert(sensorName, true); mIdCount++; endInsertRows(); 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 } void SensorBrowserModel::removeSensor(HostInfo *hostInfo, int parentId, const QString &sensorName) { //sensorName is the full version. e.g. mem/free QList children = mTreeMap.value(parentId); int idCount = -1; int index; for(index=0; indexname() == sensorName) { idCount = children[index]; break; } } if(idCount == -1) { qDebug() << "removeSensor called for sensor that doesn't exist in the tree: " << sensorName ; return; } QModelIndex parentModelIndex; int parentsParentId = -1; if(hostInfo->id() == parentId) { parentModelIndex = createIndex(mHostInfoMap.keys().indexOf(parentId), 0 , parentId); } else { parentsParentId = mParentsTreeMap.value(parentId); parentModelIndex = createIndex(mTreeMap.value(parentsParentId).indexOf(parentId), 0, parentId); } Q_ASSERT(parentModelIndex.isValid()); QList &parentTreemap = mTreeMap[parentId]; beginRemoveRows( parentModelIndex, index, index ); parentTreemap.removeAll(idCount); mParentsTreeMap.remove(idCount); SensorInfo *sensorInfo = mSensorInfoMap.take(idCount); delete sensorInfo; mHostSensorsMap[hostInfo->id()].remove(sensorName); endRemoveRows(); if(parentsParentId != -1) removeEmptyParentTreeBranches(hostInfo->id(), parentId, parentsParentId); } void SensorBrowserModel::removeEmptyParentTreeBranches(int hostId, int id, int parentId) { if(hostId == id) return; //We don't want to remove hosts if(!mTreeMap.value(id).isEmpty()) return; // We should have no children QModelIndex parentModelIndex; int parentsParentId = -1; if(hostId == parentId) { parentModelIndex = createIndex(mHostInfoMap.keys().indexOf(parentId), 0 , parentId); } else { parentsParentId = mParentsTreeMap.value(parentId); parentModelIndex = createIndex(mTreeMap.value(parentsParentId).indexOf(parentId), 0, parentId); } int index = mTreeMap.value(parentId).indexOf(id); int idCount = mTreeMap.value(parentId).at(index); QList &parentTreemap = mTreeMap[parentId]; beginRemoveRows( parentModelIndex, index, index ); parentTreemap.removeAll(idCount); mParentsTreeMap.remove(idCount); mTreeMap.remove(idCount); mTreeNodeNames.remove(idCount); endRemoveRows(); if(parentsParentId != -1) removeEmptyParentTreeBranches(hostId, parentId, parentsParentId); } int SensorBrowserModel::makeTreeBranch(int parentId, const QString &name) { QList children = mTreeMap.value(parentId); for(int i=0; i &parentTreemap = mTreeMap[parentId]; beginInsertRows( parentModelIndex , parentTreemap.size(), parentTreemap.size() ); parentTreemap << mIdCount; mParentsTreeMap.insert( mIdCount, parentId ); mTreeMap[mIdCount]; //create with empty qlist mTreeNodeNames.insert(mIdCount, name); mIdCount++; endInsertRows(); return mIdCount-1; } void SensorBrowserModel::answerReceived( int hostId, const QList&answer ) { /* An answer has the following example format: cpu/system/idle integer cpu/system/sys integer cpu/system/nice integer cpu/system/user integer ps table */ HostInfo *hostInfo = getHostInfo(hostId); if(!hostInfo) { qDebug() << "Invalid hostId " << hostId ; return; } /* We keep a copy of the previous sensor names so that we can detect what sensors have been removed */ QHash oldSensorNames = mHostSensorsMap.value(hostId); for ( int i = 0; i < answer.count(); ++i ) { if ( answer[ i ].isEmpty() ) continue; QList words = answer[ i ].split('\t'); if(words.size() != 2) { qDebug() << "Invalid data " << answer[i]; continue; /* Something wrong with this line of data */ } QString sensorName = QString::fromUtf8(words[ 0 ]); QString sensorType = QString::fromUtf8(words[ 1 ]); oldSensorNames.remove(sensorName); /* This sensor has not been removed */ if ( hasSensor(hostId, sensorName)) { continue; } if(sensorName.isEmpty()) continue; if(sensorType == QLatin1String("string")) continue; /* The sensor browser can display sensors in a hierarchical order. * Sensors can be grouped into nodes by seperating the hierarchical * nodes through slashes in the sensor name. E. g. cpu/system/user is * the sensor user in the cpu node. There is no limit for the * depth of nodes. */ int currentNodeId = hostId; //Start from the host branch and work our way down the tree QStringList absolutePath = sensorName.split( '/' ); for ( int j = 0; j < absolutePath.count()-1; ++j ) { // Localize the sensor name part by part. QString name = KSGRD::SensorMgr->translateSensorPath( absolutePath[ j ] ); currentNodeId = makeTreeBranch(currentNodeId, name); } QString name = KSGRD::SensorMgr->translateSensorPath( absolutePath[ absolutePath.size()-1] ); makeSensor(hostInfo, currentNodeId, sensorName, name, sensorType); } /* Now we have to remove sensors that were not found */ QHashIterator it( oldSensorNames ); while ( it.hasNext() ) { it.next(); int currentNodeId = hostId; //Start from the host branch and work our way down the tree QStringList absolutePath = it.key().split( '/' ); for ( int j = 0; j < absolutePath.count()-1; ++j ) { // Localize the sensor name part by part. QString name = KSGRD::SensorMgr->translateSensorPath( absolutePath[ j ] ); currentNodeId = makeTreeBranch(currentNodeId, name); } removeSensor(hostInfo, currentNodeId, it.key()); } emit sensorsAddedToHost( createIndex( mHostInfoMap.keys().indexOf(hostId), 0, hostId ) ); } //virtual QModelIndex SensorBrowserModel::parent ( const QModelIndex & index ) const { if(!index.isValid() || index.column() != 0) return QModelIndex(); if(mHostInfoMap.contains(index.internalId())) return QModelIndex(); if(!mParentsTreeMap.contains(index.internalId())) { qDebug() << "Something is wrong with the model. Doesn't contain " << index.internalId(); return QModelIndex(); } int parentId = mParentsTreeMap.value(index.internalId()); QModelIndex parentModelIndex; if(mHostInfoMap.contains(parentId)) { parentModelIndex = createIndex(mHostInfoMap.keys().indexOf(parentId), 0 , parentId); } else { int parentsParentId = mParentsTreeMap.value(parentId); parentModelIndex = createIndex(mTreeMap.value(parentsParentId).indexOf(parentId), 0, parentId); } Q_ASSERT(parentModelIndex.isValid()); return parentModelIndex; } //virtual int SensorBrowserModel::rowCount ( const QModelIndex & parent ) const { if(!parent.isValid()) return mHostInfoMap.size(); if(parent.column() != 0) return 0; return mTreeMap.value(parent.internalId()).size(); } //virtual Qt::ItemFlags SensorBrowserModel::flags ( const QModelIndex & index ) const { if(!index.isValid()) return 0; if(mSensorInfoMap.contains(index.internalId())) return Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled; else return Qt::ItemIsEnabled; } SensorBrowserWidget::SensorBrowserWidget( QWidget* parent, KSGRD::SensorManager* sm ) : QWidget( parent ) { QVBoxLayout *layout = new QVBoxLayout; m_treeWidget = new SensorBrowserTreeWidget(this, sm); KFilterProxySearchLine * search_line = new KFilterProxySearchLine(this); search_line->setProxy(&m_treeWidget->model()); layout->addWidget(search_line); layout->addWidget(m_treeWidget); setLayout(layout); } SensorBrowserWidget::~SensorBrowserWidget() { } SensorBrowserTreeWidget::SensorBrowserTreeWidget( QWidget* parent, KSGRD::SensorManager* sm ) : QTreeView( parent ), mSensorManager( sm ) { mSortFilterProxyModel.setSourceModel(&mSensorBrowserModel); mSortFilterProxyModel.setShowAllChildren(true); setModel(&mSortFilterProxyModel); connect(mSensorManager, &KSGRD::SensorManager::update, &mSensorBrowserModel, &SensorBrowserModel::update); connect(mSensorManager, &KSGRD::SensorManager::hostAdded, &mSensorBrowserModel, &SensorBrowserModel::hostAdded); connect(mSensorManager, &KSGRD::SensorManager::hostConnectionLost, &mSensorBrowserModel, &SensorBrowserModel::hostRemoved); // connect( mSensorManager, SIGNAL(hostAdded(KSGRD::SensorAgent*,QString)), SLOT(updateView()) ); // connect( mSensorManager, SIGNAL(hostConnectionLost(QString)), SLOT(updateView()) ); connect(&mSortFilterProxyModel, &KSortFilterProxyModel::rowsInserted, this, &SensorBrowserTreeWidget::updateView); setDragDropMode(QAbstractItemView::DragOnly); setUniformRowHeights(true); //setMinimumWidth( 1 ); retranslateUi(); connect(&mSensorBrowserModel, &SensorBrowserModel::sensorsAddedToHost, this, &SensorBrowserTreeWidget::expandItem); KSGRD::SensorManagerIterator it( mSensorManager ); while ( it.hasNext() ) { KSGRD::SensorAgent* sensorAgent = it.next().value(); QString hostName = mSensorManager->hostName( sensorAgent ); mSensorBrowserModel.addHost(sensorAgent, hostName); } updateView(); } SensorBrowserTreeWidget::~SensorBrowserTreeWidget() { } void SensorBrowserTreeWidget::updateView() { if(mSensorManager->count() == 1) { setRootIsDecorated( false ); //expand the top level for(int i = 0; i < mSortFilterProxyModel.rowCount(); i++) expand(mSortFilterProxyModel.index(i,0)); } else setRootIsDecorated( true ); } void SensorBrowserTreeWidget::expandItem(const QModelIndex &model_index) { expand(mSortFilterProxyModel.mapFromSource(model_index)); } void SensorBrowserTreeWidget::retranslateUi() { this->setToolTip( i18n( "Drag sensors to empty cells of a worksheet ")); this->setWhatsThis( i18n( "The sensor browser lists the connected hosts and the sensors " "that they provide. Click and drag sensors into drop zones " "of a worksheet. 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." ) ); } void SensorBrowserTreeWidget::changeEvent( QEvent * event ) { if (event->type() == QEvent::LanguageChange) { retranslateUi(); mSensorBrowserModel.retranslate(); mSensorBrowserModel.update(); } QWidget::changeEvent(event); } void SensorBrowserTreeWidget::disconnect() { QModelIndexList indexlist = selectionModel()->selectedRows(); for(int i=0; i < indexlist.size(); i++) { mSensorBrowserModel.disconnectHost(indexlist.value(i).internalId()); } } void SensorBrowserTreeWidget::hostReconfigured( const QString& ) { // TODO: not yet implemented. } void SensorBrowserModel::clear() { qDeleteAll(mHostInfoMap); mHostInfoMap.clear(); } void SensorBrowserModel::disconnectHost(uint id) { disconnectHost(mHostInfoMap.value(id)); } void SensorBrowserModel::disconnectHost(const HostInfo *hostInfo) { KSGRD::SensorMgr->disengage( hostInfo->sensorAgent() ); } void SensorBrowserModel::disconnectHost(const QString &hostname) { HostInfo* toDelete = findHostInfoByHostName(hostname); - if (toDelete != NULL) + if (toDelete != nullptr) disconnectHost(toDelete); } HostInfo* SensorBrowserModel::findHostInfoByHostName(const QString &hostName) const { - HostInfo* toReturn = NULL; + HostInfo* toReturn = nullptr; QMapIterator it( mHostInfoMap ); - while (it.hasNext() && toReturn == NULL) { + while (it.hasNext() && toReturn == nullptr) { it.next(); if (it.value()->hostName() == hostName) { toReturn = it.value(); } } return toReturn; } void SensorBrowserModel::hostAdded(KSGRD::SensorAgent *sensorAgent, const QString &hostName) { addHost(sensorAgent,hostName); update(); } void SensorBrowserModel::hostRemoved(const QString &hostName) { HostInfo* toRemove = findHostInfoByHostName(hostName); - if (toRemove != NULL) { + if (toRemove != nullptr) { beginResetModel(); int hostId = toRemove->id(); removeAllSensorUnderBranch(toRemove,hostId); removeEmptyParentTreeBranches(hostId,hostId,hostId); delete mHostInfoMap.take(hostId); mTreeMap.take(hostId); mHostSensorsMap.take(hostId); endResetModel(); } update(); } void SensorBrowserModel::removeAllSensorUnderBranch(HostInfo* hostInfo, int parentId) { QList children = mTreeMap.value(parentId); for (int i = 0; i < children.size(); i++) { if (mTreeMap.contains(children[i])) { //well our children is not a sensor so remove what is under him removeAllSensorUnderBranch(hostInfo,children[i]); } else { //well this should be a sensor so remove it if (mSensorInfoMap.contains(children[i])) { SensorInfo* sensorToRemove = mSensorInfoMap.value(children[i]); Q_ASSERT(sensorToRemove); removeSensor(hostInfo, parentId, sensorToRemove->name()); } } } } void SensorBrowserModel::addHost(KSGRD::SensorAgent *sensorAgent, const QString &hostName) { beginInsertRows( QModelIndex() , mHostInfoMap.size(), mHostInfoMap.size() ); HostInfo* hostInfo = new HostInfo( mIdCount, sensorAgent, hostName); mHostInfoMap.insert(mIdCount, hostInfo); mTreeMap.insert(mIdCount, QList()); mHostSensorsMap.insert(mIdCount, QHash()); mIdCount++; endInsertRows(); hostInfo->sensorAgent()->sendRequest( QStringLiteral("monitors"), this, mIdCount-1 ); } void SensorBrowserModel::update() { QMapIterator it( mHostInfoMap ); while ( it.hasNext() ) { it.next(); KSGRD::SensorAgent* sensorAgent = it.value()->sensorAgent(); int id = it.key(); sensorAgent->sendRequest( QStringLiteral("monitors"), this, id ); } } QMimeData * SensorBrowserModel::mimeData ( const QModelIndexList & indexes ) const { //virtual QMimeData *mimeData = new QMimeData(); if(indexes.size() != 1) return mimeData; SensorInfo *sensor = getSensorInfo(indexes[0]); if(!sensor) return mimeData; // Create text drag object as // " ". // Only the description may contain blanks. Q_ASSERT(sensor); Q_ASSERT(sensor->hostInfo()); QString mDragText = sensor->hostInfo()->hostName() + ' ' + sensor->name() + ' ' + sensor->type()+ ' ' + sensor->description(); mimeData->setData( QStringLiteral("application/x-ksysguard"), mDragText.toUtf8() ); return mimeData; } SensorInfo::SensorInfo( HostInfo *hostInfo, const QString &name, const QString &desc, const QString &type ) : mName( name ), mDesc( desc ), mType( type ), mHostInfo( hostInfo ) { Q_ASSERT(mHostInfo); } QString SensorInfo::name() const { return mName; } QString SensorInfo::type() const { return mType; } QString SensorInfo::description() const { return mDesc; } HostInfo *SensorInfo::hostInfo() const { return mHostInfo; } diff --git a/gui/SensorDisplayLib/FancyPlotter.cpp b/gui/SensorDisplayLib/FancyPlotter.cpp index 0d0a9092..02ff1b0c 100644 --- a/gui/SensorDisplayLib/FancyPlotter.cpp +++ b/gui/SensorDisplayLib/FancyPlotter.cpp @@ -1,941 +1,941 @@ /* KSysGuard, the KDE System Guard Copyright (c) 1999 - 2002 Chris Schlaeger 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "StyleEngine.h" #include "FancyPlotterSettings.h" #include "FancyPlotter.h" class SensorToAdd { public: QRegExp name; QString hostname; QString type; QList colors; QString summationName; }; class FancyPlotterLabel : public QLabel { public: FancyPlotterLabel(QWidget *parent) : QLabel(parent) { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); longHeadingWidth = 0; shortHeadingWidth = 0; textMargin = 0; setLayoutDirection(Qt::LeftToRight); //We do this because we organise the strings ourselves.. is this going to muck it up though for RTL languages? } ~FancyPlotterLabel() { } void setLabel(const QString &name, const QColor &color) { labelName = name; if(indicatorSymbol.isNull()) { if(fontMetrics().inFont(QChar(0x25CF))) indicatorSymbol = QChar(0x25CF); else indicatorSymbol = QLatin1Char('#'); } changeLabel(color); } void setValueText(const QString &value) { //value can have multiple strings, separated with the 0x9c character valueText = value.split(QChar(0x9c)); - resizeEvent(NULL); + resizeEvent(nullptr); update(); } void resizeEvent( QResizeEvent * ) Q_DECL_OVERRIDE { QFontMetrics fm = fontMetrics(); if(valueText.isEmpty()) { if(longHeadingWidth < width()) setText(longHeadingText); else setText(shortHeadingText); return; } QString value = valueText.first(); int textWidth = fm.boundingRect(value).width(); if(textWidth + longHeadingWidth < width()) setBothText(longHeadingText, value); else if(textWidth + shortHeadingWidth < width()) setBothText(shortHeadingText, value); else { int valueTextCount = valueText.count(); int i; for(i = 1; i < valueTextCount; ++i) { textWidth = fm.boundingRect(valueText.at(i)).width(); if(textWidth + shortHeadingWidth <= width()) { break; } } if(i < valueTextCount) setBothText(shortHeadingText, valueText.at(i)); else setText(noHeadingText + valueText.last()); //This just sets the color of the text } } void changeLabel(const QColor &_color) { color = _color; if ( QApplication::layoutDirection() == Qt::RightToLeft ) longHeadingText = QStringLiteral(": ") + labelName + QStringLiteral(" ") + indicatorSymbol + QStringLiteral(""); else longHeadingText = QStringLiteral("") + indicatorSymbol + QStringLiteral(" ") + labelName + QStringLiteral(" :"); shortHeadingText = QStringLiteral("") + indicatorSymbol + QStringLiteral(""); noHeadingText = QStringLiteral(""); textMargin = fontMetrics().width(QLatin1Char('x')) + margin()*2 + frameWidth()*2; longHeadingWidth = fontMetrics().boundingRect(labelName + QStringLiteral(" :") + indicatorSymbol + QStringLiteral(" x")).width() + textMargin; shortHeadingWidth = fontMetrics().boundingRect(indicatorSymbol).width() + textMargin; setMinimumWidth(shortHeadingWidth); update(); } private: void setBothText(const QString &heading, const QString & value) { if(QApplication::layoutDirection() == Qt::LeftToRight) setText(heading + QLatin1Char(' ') + value); else setText(QStringLiteral("") + value + QLatin1Char(' ') + heading); } int textMargin; QString longHeadingText; QString shortHeadingText; QString noHeadingText; int longHeadingWidth; int shortHeadingWidth; QList valueText; QString labelName; QColor color; static QChar indicatorSymbol; }; QChar FancyPlotterLabel::indicatorSymbol; FancyPlotter::FancyPlotter( QWidget* parent, const QString &title, SharedSettings *workSheetSettings) : KSGRD::SensorDisplay( parent, title, workSheetSettings ) { mBeams = 0; mSettingsDialog = 0; mSensorReportedMax = mSensorReportedMin = 0; mSensorManualMax = mSensorManualMin = 0; mUseManualRange = false; mNumAnswers = 0; - mLabelsWidget = NULL; + mLabelsWidget = nullptr; //The unicode character 0x25CF is a big filled in circle. We would prefer to use this in the tooltip. //However it's maybe possible that the font used to draw the tooltip won't have it. So we fall back to a //"#" instead. QFontMetrics fm(QToolTip::font()); if(fm.inFont(QChar(0x25CF))) mIndicatorSymbol = QChar(0x25CF); else mIndicatorSymbol = QLatin1Char('#'); QBoxLayout *layout = new QVBoxLayout(this); layout->setSpacing(0); mPlotter = new KSignalPlotter( this ); int axisTextWidth = fontMetrics().width(i18nc("Largest axis title", "99999 XXXX")); mPlotter->setMaxAxisTextWidth( axisTextWidth ); mPlotter->setUseAutoRange( true ); mHeading = new QLabel(translatedTitle(), this); QFont headingFont; headingFont.setWeight(QFont::Bold); headingFont.setPointSizeF(headingFont.pointSizeF() * 1.19); mHeading->setFont(headingFont); layout->addWidget(mHeading); layout->addWidget(mPlotter); /* Create a set of labels underneath the graph. */ mLabelsWidget = new QWidget; layout->addWidget(mLabelsWidget); QBoxLayout *outerLabelLayout = new QHBoxLayout(mLabelsWidget); outerLabelLayout->setSpacing(0); outerLabelLayout->setContentsMargins(0,0,0,0); /* create a spacer to fill up the space up to the start of the graph */ outerLabelLayout->addItem(new QSpacerItem(axisTextWidth + 10, 0, QSizePolicy::Preferred)); mLabelLayout = new QHBoxLayout; outerLabelLayout->addLayout(mLabelLayout); mLabelLayout->setContentsMargins(0,0,0,0); QFont font; font.setPointSize( KSGRD::Style->fontSize() ); mPlotter->setFont( font ); /* All RMB clicks to the mPlotter widget will be handled by * SensorDisplay::eventFilter. */ mPlotter->installEventFilter( this ); setPlotterWidget( mPlotter ); connect(mPlotter, &KSignalPlotter::axisScaleChanged, this, &FancyPlotter::plotterAxisScaleChanged); QDomElement emptyElement; restoreSettings(emptyElement); } FancyPlotter::~FancyPlotter() { } void FancyPlotter::setTitle( const QString &title ) { //virtual KSGRD::SensorDisplay::setTitle( title ); if(mHeading) mHeading->setText(translatedTitle()); } bool FancyPlotter::eventFilter( QObject* object, QEvent* event ) { //virtual if(event->type() == QEvent::ToolTip) setTooltip(); return SensorDisplay::eventFilter(object, event); } void FancyPlotter::configureSettings() { if(mSettingsDialog) return; mSettingsDialog = new FancyPlotterSettings( this, mSharedSettings->locked ); mSettingsDialog->setTitle( title() ); mSettingsDialog->setUseManualRange( mUseManualRange ); if(mUseManualRange) { mSettingsDialog->setMinValue( mSensorManualMin ); mSettingsDialog->setMaxValue( mSensorManualMax ); } else { mSettingsDialog->setMinValue( mSensorReportedMin ); mSettingsDialog->setMaxValue( mSensorReportedMax ); } mSettingsDialog->setHorizontalScale( mPlotter->horizontalScale() ); mSettingsDialog->setShowVerticalLines( mPlotter->showVerticalLines() ); mSettingsDialog->setVerticalLinesDistance( mPlotter->verticalLinesDistance() ); mSettingsDialog->setVerticalLinesScroll( mPlotter->verticalLinesScroll() ); mSettingsDialog->setShowHorizontalLines( mPlotter->showHorizontalLines() ); mSettingsDialog->setShowAxis( mPlotter->showAxis() ); mSettingsDialog->setFontSize( mPlotter->font().pointSize() ); mSettingsDialog->setRangeUnits( mUnit ); mSettingsDialog->setRangeUnits( mUnit ); mSettingsDialog->setStackBeams( mPlotter->stackGraph() ); bool hasIntegerRange = true; SensorModelEntry::List list; for ( int i = 0; i < (int)mBeams; ++i ) { - FPSensorProperties *sensor = NULL; + FPSensorProperties *sensor = nullptr; //find the first sensor for this beam, since one beam can have many sensors for ( int j = 0; j < sensors().count(); ++j ) { FPSensorProperties *sensor2 = static_cast(sensors().at(j)); if(sensor2->beamId == i) sensor = sensor2; } if(!sensor) return; SensorModelEntry entry; entry.setId( i ); entry.setHostName( sensor->hostName() ); entry.setSensorName( sensor->regExpName().isEmpty()?sensor->name():sensor->regExpName() ); entry.setUnit( sensor->unit() ); entry.setStatus( sensor->isOk() ? i18n( "OK" ) : i18n( "Error" ) ); entry.setColor( mPlotter->beamColor( i ) ); if(!sensor->isInteger) hasIntegerRange = false; list.append( entry ); } mSettingsDialog->setSensors( list ); mSettingsDialog->setHasIntegerRange( hasIntegerRange ); connect(mSettingsDialog, &FancyPlotterSettings::applyClicked, this, &FancyPlotter::applySettings); connect(mSettingsDialog, &FancyPlotterSettings::okClicked, this, &FancyPlotter::applySettings); connect(mSettingsDialog, &FancyPlotterSettings::finished, this, &FancyPlotter::settingsFinished); mSettingsDialog->open(); // open() opens the dialog modaly (ie. blocks the parent window) } void FancyPlotter::settingsFinished() { applySettings(); mSettingsDialog->hide(); mSettingsDialog->deleteLater(); mSettingsDialog = 0; } void FancyPlotter::applySettings() { if (!mSettingsDialog) { return; } setTitle( mSettingsDialog->title() ); mUseManualRange = mSettingsDialog->useManualRange(); if(mUseManualRange) { mSensorManualMin = mSettingsDialog->minValue(); mSensorManualMax = mSettingsDialog->maxValue(); mPlotter->changeRange( mSettingsDialog->minValue(), mSettingsDialog->maxValue() ); } else { mPlotter->changeRange( mSensorReportedMin, mSensorReportedMax ); } if ( mPlotter->horizontalScale() != mSettingsDialog->horizontalScale() ) { mPlotter->setHorizontalScale( mSettingsDialog->horizontalScale() ); } mPlotter->setShowVerticalLines( mSettingsDialog->showVerticalLines() ); mPlotter->setVerticalLinesDistance( mSettingsDialog->verticalLinesDistance() ); mPlotter->setVerticalLinesScroll( mSettingsDialog->verticalLinesScroll() ); mPlotter->setShowHorizontalLines( mSettingsDialog->showHorizontalLines() ); mPlotter->setShowAxis( mSettingsDialog->showAxis() ); mPlotter->setStackGraph( mSettingsDialog->stackBeams() ); QFont font; font.setPointSize( mSettingsDialog->fontSize() ); mPlotter->setFont( font ); QList deletedBeams = mSettingsDialog->deleted(); for ( int i =0; i < deletedBeams.count(); ++i) { removeBeam(deletedBeams[i]); } mSettingsDialog->clearDeleted(); //We have deleted them, so clear the deleted reorderBeams(mSettingsDialog->order()); mSettingsDialog->resetOrder(); //We have now reordered the sensors, so reset the order SensorModelEntry::List list = mSettingsDialog->sensors(); for( int i = 0; i < list.count(); i++) setBeamColor(i, list[i].color()); mPlotter->update(); } void FancyPlotter::resizeEvent( QResizeEvent* ) { bool showHeading = true;; bool showLabels = true;; if( height() < mLabelsWidget->sizeHint().height() + mHeading->sizeHint().height() + mPlotter->minimumHeight() ) showHeading = false; if( height() < mLabelsWidget->sizeHint().height() + mPlotter->minimumHeight() ) showLabels = false; mHeading->setVisible(showHeading); mLabelsWidget->setVisible(showLabels); } void FancyPlotter::reorderBeams(const QList & orderOfBeams) { //Q_ASSERT(orderOfBeams.size() == mLabelLayout.size()); Commented out because it cause compile problems in some cases?? //Reorder the graph mPlotter->reorderBeams(orderOfBeams); //Reorder the labels underneath the graph QList labelsInOldOrder; while(!mLabelLayout->isEmpty()) labelsInOldOrder.append(mLabelLayout->takeAt(0)); for(int newIndex = 0; newIndex < orderOfBeams.count(); newIndex++) { int oldIndex = orderOfBeams.at(newIndex); mLabelLayout->addItem(labelsInOldOrder.at(oldIndex)); } for ( int i = 0; i < sensors().count(); ++i ) { FPSensorProperties *sensor = static_cast(sensors().at(i)); for(int newIndex = 0; newIndex < orderOfBeams.count(); newIndex++) { int oldIndex = orderOfBeams.at(newIndex); if(oldIndex == sensor->beamId) { sensor->beamId = newIndex; break; } } } } void FancyPlotter::applyStyle() { QFont font = mPlotter->font(); font.setPointSize(KSGRD::Style->fontSize() ); mPlotter->setFont( font ); for ( int i = 0; i < mPlotter->numBeams() && (unsigned int)i < KSGRD::Style->numSensorColors(); ++i ) { setBeamColor(i, KSGRD::Style->sensorColor(i)); } mPlotter->update(); } void FancyPlotter::setBeamColor(int i, const QColor &color) { mPlotter->setBeamColor( i, color ); static_cast((static_cast(mLabelLayout->itemAt(i)))->widget())->changeLabel(color); } bool FancyPlotter::addSensor( const QString &hostName, const QString &name, const QString &type, const QString &title ) { return addSensor( hostName, name, type, title, KSGRD::Style->sensorColor( mBeams ), QString(), mBeams ); } bool FancyPlotter::addSensor( const QString &hostName, const QString &name, const QString &type, const QString &title, const QColor &color, const QString ®expName, int beamId, const QString & summationName) { if ( type != QLatin1String("integer") && type != QLatin1String("float") ) return false; registerSensor( new FPSensorProperties( hostName, name, type, title, color, regexpName, beamId, summationName ) ); /* To differentiate between answers from value requests and info * requests we add 100 to the beam index for info requests. */ sendRequest( hostName, name + QLatin1Char('?'), sensors().size() - 1 + 100 ); if((int)mBeams == beamId) { mPlotter->addBeam( color ); /* Add a label for this beam */ FancyPlotterLabel *label = new FancyPlotterLabel(this); mLabelLayout->addWidget(label); if(!summationName.isEmpty()) { label->setLabel(summationName, mPlotter->beamColor(mBeams)); } ++mBeams; } return true; } bool FancyPlotter::removeBeam( uint beamId ) { if ( beamId >= mBeams ) { qDebug() << "FancyPlotter::removeBeam: beamId out of range (" << beamId << ")" << endl; return false; } mPlotter->removeBeam( beamId ); --mBeams; QWidget *label = (static_cast(mLabelLayout->takeAt( beamId )))->widget(); mLabelLayout->removeWidget(label); delete label; mSensorReportedMax = 0; mSensorReportedMin = 0; for ( int i = sensors().count()-1; i >= 0; --i ) { FPSensorProperties *sensor = static_cast(sensors().at(i)); if(sensor->beamId == (int)beamId) removeSensor( i ); else { if(sensor->beamId > (int)beamId) sensor->beamId--; //sensor pointer is no longer valid after removing the sensor mSensorReportedMax = qMax(mSensorReportedMax, sensor->maxValue); mSensorReportedMin = qMin(mSensorReportedMin, sensor->minValue); } } //change the plotter's range to the new maximum if ( !mUseManualRange ) mPlotter->changeRange( mSensorReportedMin, mSensorReportedMax ); else mPlotter->changeRange( mSensorManualMin, mSensorManualMax ); //loop through the new sensors to find the new unit for ( int i = 0; i < sensors().count(); i++ ) { FPSensorProperties *sensor = static_cast(sensors().at(i)); if(i == 0) mUnit = sensor->unit(); else if(mUnit != sensor->unit()) { mUnit = QLatin1String(""); break; } } //adjust the scale to take into account the removed sensor plotterAxisScaleChanged(); return true; } void FancyPlotter::setTooltip() { QString tooltip = QStringLiteral("

"); QString description; QString lastValue; bool neednewline = false; bool showingSummationGroup = false; int beamId = -1; //Note that the number of beams can be less than the number of sensors, since some sensors //get added together for a beam. //For the tooltip, we show all the sensors for ( int i = 0; i < sensors().count(); ++i ) { FPSensorProperties *sensor = static_cast(sensors().at(i)); description = sensor->description(); if(description.isEmpty()) description = sensor->name(); if(sensor->isOk()) { lastValue = QLocale().toString( sensor->lastValue, (sensor->isInteger)?0:-1 ); if (sensor->unit() == QLatin1String("%")) lastValue = i18nc("units", "%1%", lastValue); else if( !sensor->unit().isEmpty() ) lastValue = i18nc("units", QString(QStringLiteral("%1 ") + sensor->unit()).toUtf8().constData(), lastValue); } else { lastValue = i18n("Error"); } if (beamId != sensor->beamId) { if (!sensor->summationName.isEmpty()) { tooltip += i18nc("%1 is what is being shown statistics for, like 'Memory', 'Swap', etc.", "

%1:
", i18n(sensor->summationName.toUtf8().constData())); showingSummationGroup = true; neednewline = false; } else if (showingSummationGroup) { //When a summation group has finished, seperate the next sensor with a newline showingSummationGroup = false; tooltip += QLatin1String("
"); } } beamId = sensor->beamId; if(sensor->isLocalhost()) { tooltip += QStringLiteral( "%1%2 %3 (%4)" ).arg( neednewline ? QStringLiteral("
") : QString()) .arg(QStringLiteral("beamColor( beamId ).name() + QStringLiteral("\">") + mIndicatorSymbol+ QStringLiteral("")) .arg( i18n(description.toUtf8().constData()) ) .arg( lastValue ); } else { tooltip += QStringLiteral( "%1%2 %3:%4 (%5)" ).arg( neednewline ? QStringLiteral("
") : QString() ) .arg(QStringLiteral("beamColor( beamId ).name() + QStringLiteral("\">") + mIndicatorSymbol+ QStringLiteral("")) .arg( sensor->hostName() ) .arg( i18n(description.toUtf8().constData()) ) .arg( lastValue ); } neednewline = true; } // tooltip += ""; mPlotter->setToolTip( tooltip ); } void FancyPlotter::sendDataToPlotter( ) { if(!mSampleBuf.isEmpty() && mBeams != 0) { if((uint)mSampleBuf.count() > mBeams) { mSampleBuf.clear(); return; //ignore invalid results - can happen if a sensor is deleted } while((uint)mSampleBuf.count() < mBeams) mSampleBuf.append(mPlotter->lastValue(mSampleBuf.count())); //we might have sensors missing so set their values to the previously known value mPlotter->addSample( mSampleBuf ); if(isVisible()) { if(QToolTip::isVisible() && (qApp->topLevelAt(QCursor::pos()) == window()) && mPlotter->geometry().contains(mPlotter->mapFromGlobal( QCursor::pos() ))) { setTooltip(); QToolTip::showText(QCursor::pos(), mPlotter->toolTip(), mPlotter); } QString lastValue; int beamId = -1; for ( int i = 0; i < sensors().size(); ++i ) { FPSensorProperties *sensor = static_cast(sensors().at(i)); if(sensor->beamId == beamId) continue; beamId = sensor->beamId; if(sensor->isOk() && mPlotter->numBeams() > beamId) { int precision; if(sensor->unit() == mUnit) { precision = (sensor->isInteger && mPlotter->scaleDownBy() == 1)?0:-1; lastValue = mPlotter->lastValueAsString(beamId, precision); } else { precision = (sensor->isInteger)?0:-1; lastValue = QLocale().toString( mPlotter->lastValue(beamId), precision ); if (sensor->unit() == QLatin1String("%")) lastValue = i18nc("units", "%1%", lastValue); else if( !sensor->unit().isEmpty() ) { lastValue = i18nc("units", QString(QStringLiteral("%1 ") + sensor->unit()).toUtf8().constData(), lastValue); } } if(sensor->maxValue != 0 && sensor->unit() != QLatin1String("%")) { //Use a multi length string incase we do not have enough room lastValue = i18n("%1 of %2" "\xc2\x9c" "%1", lastValue, mPlotter->valueAsString(sensor->maxValue, precision) ); } } else { lastValue = i18n("Error"); } static_cast((static_cast(mLabelLayout->itemAt(beamId)))->widget())->setValueText(lastValue); } } } mSampleBuf.clear(); } void FancyPlotter::timerTick() //virtual { if(mNumAnswers < sensors().count()) sendDataToPlotter(); //we haven't received enough answers yet, but plot what we do have mNumAnswers = 0; SensorDisplay::timerTick(); } void FancyPlotter::plotterAxisScaleChanged() { //Prevent this being called recursively disconnect(mPlotter, &KSignalPlotter::axisScaleChanged, this, &FancyPlotter::plotterAxisScaleChanged); KLocalizedString unit; double value = mPlotter->currentMaximumRangeValue(); if(mUnit == QLatin1String("KiB")) { if(value >= 1024*1024*1024*0.7) { //If it's over 0.7TiB, then set the scale to terabytes mPlotter->setScaleDownBy(1024*1024*1024); unit = ki18nc("units", "%1 TiB"); // the unit - terabytes } else if(value >= 1024*1024*0.7) { //If it's over 0.7GiB, then set the scale to gigabytes mPlotter->setScaleDownBy(1024*1024); unit = ki18nc("units", "%1 GiB"); // the unit - gigabytes } else if(value > 1024) { mPlotter->setScaleDownBy(1024); unit = ki18nc("units", "%1 MiB"); // the unit - megabytes } else { mPlotter->setScaleDownBy(1); unit = ki18nc("units", "%1 KiB"); // the unit - kilobytes } } else if(mUnit == QLatin1String("KiB/s")) { if(value >= 1024*1024*1024*0.7) { //If it's over 0.7TiB, then set the scale to terabytes mPlotter->setScaleDownBy(1024*1024*1024); unit = ki18nc("units", "%1 TiB/s"); // the unit - terabytes per second } else if(value >= 1024*1024*0.7) { //If it's over 0.7GiB, then set the scale to gigabytes mPlotter->setScaleDownBy(1024*1024); unit = ki18nc("units", "%1 GiB/s"); // the unit - gigabytes per second } else if(value > 1024) { mPlotter->setScaleDownBy(1024); unit = ki18nc("units", "%1 MiB/s"); // the unit - megabytes per second } else { mPlotter->setScaleDownBy(1); unit = ki18nc("units", "%1 KiB/s"); // the unit - kilobytes per second } } else if(mUnit == QLatin1String("%")) { mPlotter->setScaleDownBy(1); unit = ki18nc("units", "%1%"); //the unit - percentage } else if(mUnit.isEmpty()) { unit = ki18nc("unitless - just a number", "%1"); } else { #if 0 // the strings are here purely for translation NOOP_I18NC("units", "%1 1/s"); // the unit - 1 per second NOOP_I18NC("units", "%1 s"); // the unit - seconds NOOP_I18NC("units", "%1 MHz"); // the unit - frequency megahertz #endif mPlotter->setScaleDownBy(1); //translate any others unit = ki18nc("units", QString(QStringLiteral("%1 ") + mUnit).toUtf8().constData()); } mPlotter->setUnit(unit); //reconnect connect(mPlotter, &KSignalPlotter::axisScaleChanged, this, &FancyPlotter::plotterAxisScaleChanged); } void FancyPlotter::answerReceived( int id, const QList &answerlist ) { QByteArray answer; if(!answerlist.isEmpty()) answer = answerlist[0]; if ( (uint)id < 100 ) { //Make sure that we put the answer in the correct place. Its index in the list should be equal to the sensor index. This in turn will contain the beamId if(id >= sensors().count()) return; //just ignore if we get a result for an invalid sensor FPSensorProperties *sensor = static_cast(sensors().at(id)); int beamId = sensor->beamId; double value = answer.toDouble(); while(beamId > mSampleBuf.count()) mSampleBuf.append(0); //we might have sensors missing so set their values to zero if(beamId == mSampleBuf.count()) { mSampleBuf.append( value ); } else { mSampleBuf[beamId] += value; //If we get two answers for the same beamid, we should add them together. That's how the summation works } sensor->lastValue = value; /* We received something, so the sensor is probably ok. */ sensorError( id, false ); if(++mNumAnswers == sensors().count()) sendDataToPlotter(); //we have received all the answers so start plotting } else if ( id >= 100 && id < 200 ) { if( (id - 100) >= sensors().count()) return; //just ignore if we get a result for an invalid sensor KSGRD::SensorFloatInfo info( answer ); QString unit = info.unit(); if(unit.toUpper() == QLatin1String("KB") || unit.toUpper() == QLatin1String("KIB")) unit = QStringLiteral("KiB"); if(unit.toUpper() == QLatin1String("KB/S") || unit.toUpper() == QLatin1String("KIB/S")) unit = QStringLiteral("KiB/s"); if(id == 100) //if we are the first sensor, just use that sensors units as the global unit mUnit = unit; else if(unit != mUnit) mUnit = QLatin1String(""); //if the units don't match, then set the units on the scale to empty, to avoid any confusion mSensorReportedMax = qMax(mSensorReportedMax, info.max()); mSensorReportedMin = qMin(mSensorReportedMin, info.min()); if ( !mUseManualRange ) mPlotter->changeRange( mSensorReportedMin, mSensorReportedMax ); plotterAxisScaleChanged(); FPSensorProperties *sensor = static_cast(sensors().at(id - 100)); sensor->maxValue = info.max(); sensor->minValue = info.min(); sensor->setUnit( unit ); sensor->setDescription( info.name() ); QString summationName = sensor->summationName; int beamId = sensor->beamId; Q_ASSERT(beamId < mPlotter->numBeams()); Q_ASSERT(beamId < mLabelLayout->count()); if(summationName.isEmpty()) static_cast((static_cast(mLabelLayout->itemAt(beamId)))->widget())->setLabel(info.name(), mPlotter->beamColor(beamId)); } else if( id == 200) { /* FIXME This doesn't check the host! */ if(!mSensorsToAdd.isEmpty()) { foreach(SensorToAdd *sensor, mSensorsToAdd) { int beamId = mBeams; //Assign the next sensor to the next available beamId for ( int i = 0; i < answerlist.count(); ++i ) { if ( answerlist[ i ].isEmpty() ) continue; QString sensorName = QString::fromUtf8(answerlist[ i ].split('\t')[0]); if(sensor->name.exactMatch(sensorName)) { if(sensor->summationName.isEmpty()) beamId = mBeams; //If summationName is not empty then reuse the previous beamId. In this way we can have multiple sensors with the same beamId, which can then be summed together QColor color; if(!sensor->colors.isEmpty() ) color = sensor->colors.takeFirst(); else if(KSGRD::Style->numSensorColors() != 0) color = KSGRD::Style->sensorColor( beamId % KSGRD::Style->numSensorColors()); addSensor( sensor->hostname, sensorName, (sensor->type.isEmpty()) ? QStringLiteral("float") : sensor->type , QLatin1String(""), color, sensor->name.pattern(), beamId, sensor->summationName); } } } qDeleteAll(mSensorsToAdd); mSensorsToAdd.clear(); } } } bool FancyPlotter::restoreSettings( QDomElement &element ) { mUseManualRange = element.attribute( QStringLiteral("manualRange"), QStringLiteral("0") ).toInt(); if(mUseManualRange) { mSensorManualMax = element.attribute( QStringLiteral("max") ).toDouble(); mSensorManualMin = element.attribute( QStringLiteral("min") ).toDouble(); mPlotter->changeRange( mSensorManualMin, mSensorManualMax ); } else { mPlotter->changeRange( mSensorReportedMin, mSensorReportedMax ); } mPlotter->setUseAutoRange(element.attribute( QStringLiteral("autoRange"), QStringLiteral("1") ).toInt()); // Do not restore the color settings from a previous version int version = element.attribute(QStringLiteral("version"), QStringLiteral("0")).toInt(); mPlotter->setShowVerticalLines( element.attribute( QStringLiteral("vLines"), QStringLiteral("0") ).toUInt() ); mPlotter->setVerticalLinesDistance( element.attribute( QStringLiteral("vDistance"), QStringLiteral("30") ).toUInt() ); mPlotter->setVerticalLinesScroll( element.attribute( QStringLiteral("vScroll"), QStringLiteral("0") ).toUInt() ); mPlotter->setHorizontalScale( element.attribute( QStringLiteral("hScale"), QStringLiteral("6") ).toUInt() ); mPlotter->setShowHorizontalLines( element.attribute( QStringLiteral("hLines"), QStringLiteral("1") ).toUInt() ); mPlotter->setStackGraph( element.attribute(QStringLiteral("stacked"), QStringLiteral("0")).toInt()); QString filename = element.attribute( QStringLiteral("svgBackground")); if (!filename.isEmpty() && filename[0] == QLatin1Char('/')) { filename = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("ksysguard/") + filename); } mPlotter->setSvgBackground( filename ); if(version >= 1) { mPlotter->setShowAxis( element.attribute( QStringLiteral("labels"), QStringLiteral("1") ).toUInt() ); uint fontsize = element.attribute( QStringLiteral("fontSize"), QStringLiteral("0")).toUInt(); if(fontsize == 0) fontsize = KSGRD::Style->fontSize(); QFont font; font.setPointSize( fontsize ); mPlotter->setFont( font ); } QDomNodeList dnList = element.elementsByTagName( QStringLiteral("beam") ); for ( int i = 0; i < dnList.count(); ++i ) { QDomElement el = dnList.item( i ).toElement(); if(el.hasAttribute(QStringLiteral("regexpSensorName"))) { SensorToAdd *sensor = new SensorToAdd(); sensor->name = QRegExp(el.attribute(QStringLiteral("regexpSensorName"))); sensor->hostname = el.attribute( QStringLiteral("hostName") ); sensor->type = el.attribute( QStringLiteral("sensorType") ); sensor->summationName = el.attribute(QStringLiteral("summationName")); QStringList colors = el.attribute(QStringLiteral("color")).split(QLatin1Char(',')); bool ok; foreach(const QString &color, colors) { int c = color.toUInt( &ok, 0 ); if(ok) { QColor col( (c & 0xff0000) >> 16, (c & 0xff00) >> 8, (c & 0xff), (c & 0xff000000) >> 24); if(col.isValid()) { if(col.alpha() == 0) col.setAlpha(255); sensor->colors << col; } else sensor->colors << KSGRD::Style->sensorColor( i ); } else sensor->colors << KSGRD::Style->sensorColor( i ); } mSensorsToAdd.append(sensor); sendRequest( sensor->hostname, QStringLiteral("monitors"), 200 ); } else addSensor( el.attribute( QStringLiteral("hostName") ), el.attribute( QStringLiteral("sensorName") ), ( el.attribute( QStringLiteral("sensorType") ).isEmpty() ? QStringLiteral("float") : el.attribute( QStringLiteral("sensorType") ) ), QLatin1String(""), restoreColor( el, QStringLiteral("color"), KSGRD::Style->sensorColor( i ) ), QString(), mBeams, el.attribute(QStringLiteral("summationName")) ); } SensorDisplay::restoreSettings( element ); return true; } bool FancyPlotter::saveSettings( QDomDocument &doc, QDomElement &element) { element.setAttribute( QStringLiteral("autoRange"), mPlotter->useAutoRange() ); element.setAttribute( QStringLiteral("manualRange"), mUseManualRange ); if(mUseManualRange) { element.setAttribute( QStringLiteral("min"), mSensorManualMin ); element.setAttribute( QStringLiteral("max"), mSensorManualMax ); } element.setAttribute( QStringLiteral("vLines"), mPlotter->showVerticalLines() ); element.setAttribute( QStringLiteral("vDistance"), mPlotter->verticalLinesDistance() ); element.setAttribute( QStringLiteral("vScroll"), mPlotter->verticalLinesScroll() ); element.setAttribute( QStringLiteral("hScale"), mPlotter->horizontalScale() ); element.setAttribute( QStringLiteral("hLines"), mPlotter->showHorizontalLines() ); element.setAttribute( QStringLiteral("svgBackground"), mPlotter->svgBackground() ); element.setAttribute( QStringLiteral("stacked"), mPlotter->stackGraph() ); element.setAttribute( QStringLiteral("version"), 1 ); element.setAttribute( QStringLiteral("labels"), mPlotter->showAxis() ); element.setAttribute( QStringLiteral("fontSize"), mPlotter->font().pointSize() ); QHash hash; int beamId = -1; for ( int i = 0; i < sensors().size(); ++i ) { FPSensorProperties *sensor = static_cast(sensors().at(i)); if(sensor->beamId == beamId) continue; beamId = sensor->beamId; QString regExpName = sensor->regExpName(); if(!regExpName.isEmpty() && hash.contains( regExpName )) { QDomElement oldBeam = hash.value(regExpName); saveColorAppend( oldBeam, QStringLiteral("color"), mPlotter->beamColor( beamId ) ); } else { QDomElement beam = doc.createElement( QStringLiteral("beam") ); element.appendChild( beam ); beam.setAttribute( QStringLiteral("hostName"), sensor->hostName() ); if(regExpName.isEmpty()) beam.setAttribute( QStringLiteral("sensorName"), sensor->name() ); else { beam.setAttribute( QStringLiteral("regexpSensorName"), sensor->regExpName() ); hash[regExpName] = beam; } if(!sensor->summationName.isEmpty()) beam.setAttribute( QStringLiteral("summationName"), sensor->summationName); beam.setAttribute( QStringLiteral("sensorType"), sensor->type() ); saveColor( beam, QStringLiteral("color"), mPlotter->beamColor( beamId ) ); } } SensorDisplay::saveSettings( doc, element ); return true; } bool FancyPlotter::hasSettingsDialog() const { return true; } FPSensorProperties::FPSensorProperties() { } FPSensorProperties::FPSensorProperties( const QString &hostName, const QString &name, const QString &type, const QString &description, const QColor &color, const QString ®expName, int beamId_, const QString &summationName_ ) : KSGRD::SensorProperties( hostName, name, type, description), mColor( color ) { setRegExpName(regexpName); beamId = beamId_; summationName = summationName_; maxValue = 0; minValue = 0; lastValue = 0; isInteger = (type == QLatin1String("integer")); } FPSensorProperties::~FPSensorProperties() { } void FPSensorProperties::setColor( const QColor &color ) { mColor = color; } QColor FPSensorProperties::color() const { return mColor; } diff --git a/gui/SensorDisplayLib/ListView.cpp b/gui/SensorDisplayLib/ListView.cpp index 3962d93c..6e085e11 100644 --- a/gui/SensorDisplayLib/ListView.cpp +++ b/gui/SensorDisplayLib/ListView.cpp @@ -1,446 +1,446 @@ /* KSysGuard, the KDE System Guard Copyright (c) 2001 Tobias Koenig 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 . */ #include #include #include #include #include #include #include #include #include #include #include "StyleEngine.h" #include #include #include "ListView.h" #include "ListViewSettings.h" static QString formatByteSize(qlonglong amountInKB, int units) { enum { UnitsAuto, UnitsKB, UnitsMB, UnitsGB, UnitsTB, UnitsPB }; static QString kString = i18n("%1 K", QString::fromLatin1("%1")); static QString mString = i18n("%1 M", QString::fromLatin1("%1")); static QString gString = i18n("%1 G", QString::fromLatin1("%1")); static QString tString = i18n("%1 T", QString::fromLatin1("%1")); static QString pString = i18n("%1 P", QString::fromLatin1("%1")); double amount; if (units == UnitsAuto) { if (amountInKB < 1024.0*0.9) units = UnitsKB; // amount < 0.9 MiB == KiB else if (amountInKB < 1024.0*1024.0*0.9) units = UnitsMB; // amount < 0.9 GiB == MiB else if (amountInKB < 1024.0*1024.0*1024.0*0.9) units = UnitsGB; // amount < 0.9 TiB == GiB else if (amountInKB < 1024.0*1024.0*1024.0*1024.0*0.9) units = UnitsTB; // amount < 0.9 PiB == TiB else units = UnitsPB; } switch(units) { case UnitsKB: return kString.arg(QLocale().toString(amountInKB)); case UnitsMB: amount = amountInKB/1024.0; return mString.arg(QLocale().toString(amount, 'g', 1)); case UnitsGB: amount = amountInKB/(1024.0*1024.0); if(amount < 0.1 && amount > 0.05) amount = 0.1; return gString.arg(QLocale().toString(amount, 'g', 1)); case UnitsTB: amount = amountInKB/(1024.0*1024.0*1024.0); if(amount < 0.1 && amount > 0.05) amount = 0.1; return tString.arg(QLocale().toString(amount, 'g', 1)); case UnitsPB: amount = amountInKB/(1024.0*1024.0*1024.0*1024.0); if(amount < 0.1 && amount > 0.05) amount = 0.1; return pString.arg(QLocale().toString(amount, 'g', 1)); default: return QLatin1String(""); // error } } ListView::ListView(QWidget* parent, const QString& title, SharedSettings *workSheetSettings) : KSGRD::SensorDisplay(parent, title, workSheetSettings) { QVBoxLayout *layout = new QVBoxLayout(this); mUnits = UnitsKB; mView = new QTreeView(this); // QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this); // proxyModel->setSourceModel(&mModel); mView->setModel(&mModel); mModel.setSortRole(Qt::UserRole); layout->addWidget(mView); this->setLayout(layout); mView->setContextMenuPolicy( Qt::CustomContextMenu ); mView->header()->setContextMenuPolicy( Qt::CustomContextMenu ); connect(mView, &QTreeView::customContextMenuRequested, this, &ListView::showContextMenu); connect(mView->header(), &QWidget::customContextMenuRequested, this, &ListView::showColumnContextMenu); mView->setAlternatingRowColors(true); mView->header()->setSectionsMovable(true); mView->setSelectionMode( QAbstractItemView::NoSelection ); mView->setUniformRowHeights(true); mView->setRootIsDecorated(false); mView->header()->setSortIndicatorShown(true); mView->header()->setSectionsClickable(true); mView->setSortingEnabled(true); /* QPalette palette; palette.setColor(backgroundRole(), KSGRD::Style->backgroundColor()); setPalette(palette);*/ setMinimumSize(50, 25); setPlotterWidget(mView); setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding); mView->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding); } void ListView::showColumnContextMenu(const QPoint &point) { int index = mView->header()->logicalIndexAt(point); if (index < 0 || index >= mColumnTypes.count()) return; //Should be impossible QMenu *menu = new QMenu(); /*if(index >= 0) { //selected a column. Give the option to hide it action = new QAction(&menu); action->setData(-index-1); //We set data to be negative (and minus 1) to hide a column, and positive to show a column action->setText(i18n("Hide Column '%1'", d->mFilterModel.headerData(index, Qt::Horizontal, Qt::DisplayRole).toString())); menu.addAction(action); if(d->mUi->treeView->header()->sectionsHidden()) { menu.addSeparator(); } }*/ - QAction *actionAuto = NULL; - QAction *actionKB = NULL; - QAction *actionMB = NULL; - QAction *actionGB = NULL; - QAction *actionTB = NULL; + QAction *actionAuto = nullptr; + QAction *actionKB = nullptr; + QAction *actionMB = nullptr; + QAction *actionGB = nullptr; + QAction *actionTB = nullptr; if (mColumnTypes[index] == KByte) { menu->addSeparator()->setText(i18n("Display Units")); QActionGroup *unitsGroup = new QActionGroup(menu); /* Automatic (human readable)*/ actionAuto = new QAction(menu); actionAuto->setText(i18n("Mixed")); actionAuto->setCheckable(true); menu->addAction(actionAuto); unitsGroup->addAction(actionAuto); /* Kilobytes */ actionKB = new QAction(menu); actionKB->setText(i18n("Kilobytes")); actionKB->setCheckable(true); menu->addAction(actionKB); unitsGroup->addAction(actionKB); /* Megabytes */ actionMB = new QAction(menu); actionMB->setText(i18n("Megabytes")); actionMB->setCheckable(true); menu->addAction(actionMB); unitsGroup->addAction(actionMB); /* Gigabytes */ actionGB = new QAction(menu); actionGB->setText(i18n("Gigabytes")); actionGB->setCheckable(true); menu->addAction(actionGB); unitsGroup->addAction(actionGB); /* Terabytes */ actionTB = new QAction(menu); actionTB->setText(i18n("Terabytes")); actionTB->setCheckable(true); menu->addAction(actionTB); unitsGroup->addAction(actionTB); switch(mUnits) { case UnitsAuto: actionAuto->setChecked(true); break; case UnitsKB: actionKB->setChecked(true); break; case UnitsMB: actionMB->setChecked(true); break; case UnitsGB: actionGB->setChecked(true); break; case UnitsTB: actionTB->setChecked(true); break; default: break; } unitsGroup->setExclusive(true); } QAction *result = menu->exec(mView->header()->mapToGlobal(point)); if (result == actionAuto) mUnits = UnitsAuto; else if (result == actionKB) mUnits = UnitsKB; else if (result == actionMB) mUnits = UnitsMB; else if (result == actionGB) mUnits = UnitsGB; else if (result == actionTB) mUnits = UnitsTB; delete menu; } bool ListView::addSensor(const QString& hostName, const QString& sensorName, const QString& sensorType, const QString& title) { if (sensorType != QLatin1String("listview")) return false; if(sensorName.isEmpty()) 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); return true; } void ListView::updateList() { for(int i = 0; i < sensors().count(); i++) sendRequest(sensors().at(i)->hostName(), sensors().at(i)->name(), 19); } ListView::ColumnType ListView::convertColumnType(const QString &type) const { if ( type == QLatin1String("d") || type == QLatin1String("D") ) return Int; else if ( type == QLatin1String("f") || type == QLatin1String("F") ) return Float; else if ( type == QLatin1String("t") ) return Time; else if ( type == QLatin1String("M") ) return DiskStat; else if ( type == QLatin1String("KB") ) return KByte; else if ( type == QLatin1String("%") ) return Percentage; else return Text; } void ListView::answerReceived(int id, const QList& 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. */ if (answer.count() != 2) { qWarning() << "wrong number of lines"; return; } KSGRD::SensorTokenizer headers(answer[0], '\t'); KSGRD::SensorTokenizer colTypes(answer[1], '\t'); /* add the new columns */ mModel.clear(); QStringList translatedHeaders; translatedHeaders.reserve(headers.count()); for (uint i = 0; i < headers.count(); i++) { translatedHeaders.append( i18nc("heading from daemon", headers[i].constData()) ); } for(uint i =0 ; i < colTypes.count(); i++) { ColumnType type = convertColumnType(colTypes[i]); mColumnTypes.append(type); if (type == Text || type == DiskStat) mModel.addColumnAlignment(Qt::AlignLeft); else mModel.addColumnAlignment(Qt::AlignRight); } mModel.setHorizontalHeaderLabels(translatedHeaders); //If we have some header settings to restore, we can do so now if(!mHeaderSettings.isEmpty()) { mView->header()->restoreState(mHeaderSettings); mModel.sort( mView->header()->sortIndicatorSection(), mView->header()->sortIndicatorOrder() ); } break; } case 19: { for (int i = 0; i < answer.count(); i++) { KSGRD::SensorTokenizer records(answer[i], '\t'); for (uint j = 0; j < records.count() && j < (uint)mColumnTypes.count(); j++) { QStandardItem *item = new QStandardItem(); item->setEditable(false); switch( mColumnTypes[j] ) { case Int: item->setData(records[j].toLongLong(), Qt::UserRole); item->setText(records[j]); break; case Percentage: item->setData(records[j].toInt(), Qt::UserRole); item->setText(records[j] + QLatin1Char('%')); break; case Float: item->setData(records[j].toFloat(), Qt::DisplayRole); item->setData(records[j].toFloat(), Qt::UserRole); break; case Time: item->setData(QTime::fromString(records[j]), Qt::DisplayRole); item->setData(QTime::fromString(records[j]), Qt::UserRole); break; case KByte: { item->setData(records[j].toInt(), Qt::UserRole); item->setText(formatByteSize(records[j].toLongLong(), mUnits)); break; } case DiskStat: case Text: default: item->setText(records[j]); item->setData(records[j], Qt::UserRole); } mModel.setItem(i, j, item); } } mModel.setRowCount(answer.count()); mModel.sort( mView->header()->sortIndicatorSection(), mView->header()->sortIndicatorOrder() ); break; } } } bool ListView::restoreSettings(QDomElement& element) { addSensor(element.attribute(QStringLiteral("hostName")), element.attribute(QStringLiteral("sensorName")), (element.attribute(QStringLiteral("sensorType")).isEmpty() ? QStringLiteral("listview") : element.attribute(QStringLiteral("sensorType"))), element.attribute(QStringLiteral("title"))); //At this stage, we don't have the heading information, so we cannot setup the headers yet. //Save the info, the restore later. mHeaderSettings = QByteArray::fromBase64(element.attribute(QStringLiteral("treeViewHeader")).toLatin1()); mUnits = (ListView::Units)element.attribute(QStringLiteral("units"), QStringLiteral("0")).toInt(); /* QPalette pal = monitor->palette(); pal.setColor(QPalette::Link, restoreColor(element, "gridColor", KSGRD::Style->firstForegroundColor())); pal.setColor(QPalette::Text, restoreColor(element, "textColor", KSGRD::Style->secondForegroundColor())); pal.setColor(QPalette::Base, restoreColor(element, "backgroundColor", KSGRD::Style->backgroundColor())); monitor->setPalette( pal ); */ SensorDisplay::restoreSettings(element); return true; } bool ListView::saveSettings(QDomDocument& doc, QDomElement& element) { if(!sensors().isEmpty()) { element.setAttribute(QStringLiteral("hostName"), sensors().at(0)->hostName()); element.setAttribute(QStringLiteral("sensorName"), sensors().at(0)->name()); element.setAttribute(QStringLiteral("sensorType"), sensors().at(0)->type()); /* QPalette pal = monitor->palette(); saveColor(element, "gridColor", pal.color(QPalette::Link)); saveColor(element, "textColor", pal.color(QPalette::Text)); saveColor(element, "backgroundColor", pal.color(QPalette::Base)); */ } element.setAttribute(QStringLiteral("treeViewHeader"), QString::fromLatin1(mView->header()->saveState().toBase64())); element.setAttribute(QStringLiteral("units"), QString::number(mUnits)); SensorDisplay::saveSettings(doc, element); return true; } void ListView::configureSettings() { lvs = new ListViewSettings(this, "ListViewSettings"); Q_CHECK_PTR(lvs); /* QPalette pal = monitor->palette(); lvs->setGridColor(pal.color(QPalette::Link)); lvs->setTextColor(pal.color(QPalette::Text)); lvs->setBackgroundColor(pal.color(QPalette::Base)); lvs->setTitle(title()); */ if (lvs->exec()) applySettings(); delete lvs; lvs = 0; } void ListView::applySettings() { /* QPalette pal = monitor->palette(); pal.setColor(QPalette::Active, QPalette::Link, lvs->gridColor()); pal.setColor(QPalette::Active, QPalette::Text, lvs->textColor()); pal.setColor(QPalette::Active, QPalette::Base, lvs->backgroundColor()); pal.setColor(QPalette::Disabled, QPalette::Link, lvs->gridColor()); pal.setColor(QPalette::Disabled, QPalette::Text, lvs->textColor()); pal.setColor(QPalette::Disabled, QPalette::Base, lvs->backgroundColor()); pal.setColor(QPalette::Inactive, QPalette::Link, lvs->gridColor()); pal.setColor(QPalette::Inactive, QPalette::Text, lvs->textColor()); pal.setColor(QPalette::Inactive, QPalette::Base, lvs->backgroundColor()); monitor->setPalette( pal ); */ setTitle(lvs->title()); } void ListView::applyStyle() { /* QPalette pal = monitor->palette(); pal.setColor(QPalette::Link, KSGRD::Style->firstForegroundColor()); pal.setColor(QPalette::Text, KSGRD::Style->secondForegroundColor()); pal.setColor(QPalette::Base, KSGRD::Style->backgroundColor()); monitor->setPalette( pal );*/ } diff --git a/gui/SensorDisplayLib/LogFile.cpp b/gui/SensorDisplayLib/LogFile.cpp index 559664c0..cdc9493b 100644 --- a/gui/SensorDisplayLib/LogFile.cpp +++ b/gui/SensorDisplayLib/LogFile.cpp @@ -1,295 +1,295 @@ /* KSysGuard, the KDE System Guard Copyright (c) 2001 Tobias Koenig 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. */ #include "LogFile.h" #include #include #include #include #include #include #include #include #include #include #include #include "StyleEngine.h" #include "ui_LogFileSettings.h" LogFile::LogFile(QWidget *parent, const QString& title, SharedSettings *workSheetSettings) : KSGRD::SensorDisplay(parent, title, workSheetSettings) { qDebug() << "Making sensor logger"; logFileID= 0; - lfs = NULL; + lfs = nullptr; QLayout *layout = new QHBoxLayout(this); monitor = new QListWidget(this); layout->addWidget(monitor); setLayout(layout); setMinimumSize(50, 25); monitor->setContextMenuPolicy( Qt::CustomContextMenu ); connect(monitor, &QListWidget::customContextMenuRequested, this, &LogFile::showContextMenu); setPlotterWidget(monitor); } LogFile::~LogFile(void) { sendRequest(sensors().at(0)->hostName(), QStringLiteral("logfile_unregister %1" ).arg(logFileID), 43); } bool LogFile::addSensor(const QString& hostName, const QString& sensorName, const QString& sensorType, const QString& title) { if (sensorType != QLatin1String("logfile")) return (false); registerSensor(new KSGRD::SensorProperties(hostName, sensorName, sensorType, title)); QString sensorID = sensorName.right(sensorName.length() - (sensorName.lastIndexOf(QLatin1String("/")) + 1)); sendRequest(sensors().at(0)->hostName(), QStringLiteral("logfile_register %1" ).arg(sensorID), 42); if (title.isEmpty()) setTitle(sensors().at(0)->hostName() + ':' + sensorID); else setTitle(title); return (true); } void LogFile::configureSettings(void) { QPalette cgroup = monitor->palette(); lfs = new Ui_LogFileSettings; Q_CHECK_PTR(lfs); QDialog dlg; dlg.setWindowTitle( i18n("File logging settings") ); QWidget *mainWidget = new QWidget( this ); lfs->setupUi(mainWidget); QVBoxLayout *vlayout = new QVBoxLayout(this); vlayout->addWidget(mainWidget); dlg.setLayout(vlayout); lfs->fgColor->setColor(cgroup.color( QPalette::Text )); lfs->fgColor->setText(i18n("Foreground color:")); lfs->bgColor->setColor(cgroup.color( QPalette::Base )); lfs->bgColor->setText(i18n("Background color:")); lfs->fontRequester->setFont(monitor->font()); lfs->ruleList->addItems(filterRules); lfs->title->setText(title()); connect(lfs->buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept); connect(lfs->buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject); connect(lfs->addButton, &QPushButton::clicked, this, &LogFile::settingsAddRule); connect(lfs->deleteButton, &QPushButton::clicked, this, &LogFile::settingsDeleteRule); connect(lfs->changeButton, &QPushButton::clicked, this, &LogFile::settingsChangeRule); connect(lfs->ruleList, &QListWidget::currentRowChanged, this, &LogFile::settingsRuleListSelected); connect(lfs->ruleText, &QLineEdit::returnPressed, this, &LogFile::settingsAddRule); connect(lfs->ruleText, &QLineEdit::textChanged, this, &LogFile::settingsRuleTextChanged); settingsRuleListSelected(lfs->ruleList->currentRow()); settingsRuleTextChanged(); if (dlg.exec()) applySettings(); delete lfs; lfs = 0; } void LogFile::settingsRuleTextChanged() { lfs->addButton->setEnabled(!lfs->ruleText->text().isEmpty()); lfs->changeButton->setEnabled(!lfs->ruleText->text().isEmpty() && lfs->ruleList->currentRow() > -1); } void LogFile::settingsAddRule() { if (!lfs->ruleText->text().isEmpty()) { lfs->ruleList->addItem(lfs->ruleText->text()); lfs->ruleText->setText(QLatin1String("")); } } void LogFile::settingsDeleteRule() { delete lfs->ruleList->takeItem(lfs->ruleList->currentRow()); lfs->ruleText->setText(QLatin1String("")); } void LogFile::settingsChangeRule() { if (lfs->ruleList->currentItem() && !lfs->ruleText->text().isEmpty()) lfs->ruleList->currentItem()->setText(lfs->ruleText->text()); lfs->ruleText->setText(QLatin1String("")); } void LogFile::settingsRuleListSelected(int index) { bool anySelected = (index > -1); if (anySelected) lfs->ruleText->setText(lfs->ruleList->item(index)->text()); lfs->changeButton->setEnabled(anySelected && !lfs->ruleText->text().isEmpty()); lfs->deleteButton->setEnabled(anySelected); } void LogFile::applySettings(void) { QPalette cgroup = monitor->palette(); cgroup.setColor(QPalette::Text, lfs->fgColor->color()); cgroup.setColor(QPalette::Base, lfs->bgColor->color()); monitor->setPalette( cgroup ); monitor->setFont(lfs->fontRequester->font()); filterRules.clear(); for (int i = 0; i < lfs->ruleList->count(); i++) filterRules.append(lfs->ruleList->item(i)->text()); setTitle(lfs->title->text()); } void LogFile::applyStyle() { QPalette cgroup = monitor->palette(); cgroup.setColor(QPalette::Text, KSGRD::Style->firstForegroundColor()); cgroup.setColor(QPalette::Base, KSGRD::Style->backgroundColor()); monitor->setPalette( cgroup ); } bool LogFile::restoreSettings(QDomElement& element) { QFont font; QPalette cgroup = monitor->palette(); cgroup.setColor(QPalette::Active, QPalette::Text, restoreColor(element, QStringLiteral("textColor"), Qt::green)); cgroup.setColor(QPalette::Active, QPalette::Base, restoreColor(element, QStringLiteral("backgroundColor"), Qt::black)); cgroup.setColor(QPalette::Disabled, QPalette::Text, restoreColor(element, QStringLiteral("textColor"), Qt::green)); cgroup.setColor(QPalette::Disabled, QPalette::Base, restoreColor(element, QStringLiteral("backgroundColor"), Qt::black)); cgroup.setColor(QPalette::Inactive, QPalette::Text, restoreColor(element, QStringLiteral("textColor"), Qt::green)); cgroup.setColor(QPalette::Inactive, QPalette::Base, restoreColor(element, QStringLiteral("backgroundColor"), Qt::black)); monitor->setPalette(cgroup); addSensor(element.attribute(QStringLiteral("hostName")), element.attribute(QStringLiteral("sensorName")), (element.attribute(QStringLiteral("sensorType")).isEmpty() ? QStringLiteral("logfile") : element.attribute(QStringLiteral("sensorType"))), element.attribute(QStringLiteral("title"))); font.fromString( element.attribute( QStringLiteral("font") ) ); monitor->setFont(font); QDomNodeList dnList = element.elementsByTagName(QStringLiteral("filter")); for (int i = 0; i < dnList.count(); i++) { QDomElement element = dnList.item(i).toElement(); filterRules.append(element.attribute(QStringLiteral("rule"))); } SensorDisplay::restoreSettings(element); return true; } bool LogFile::saveSettings(QDomDocument& doc, QDomElement& element) { element.setAttribute(QStringLiteral("hostName"), sensors().at(0)->hostName()); element.setAttribute(QStringLiteral("sensorName"), sensors().at(0)->name()); element.setAttribute(QStringLiteral("sensorType"), sensors().at(0)->type()); element.setAttribute(QStringLiteral("font"), monitor->font().toString()); saveColor(element, QStringLiteral("textColor"), monitor->palette().color( QPalette::Text ) ); saveColor(element, QStringLiteral("backgroundColor"), monitor->palette().color( QPalette::Base ) ); for (QStringList::Iterator it = filterRules.begin(); it != filterRules.end(); ++it) { QDomElement filter = doc.createElement(QStringLiteral("filter")); filter.setAttribute(QStringLiteral("rule"), (*it)); element.appendChild(filter); } SensorDisplay::saveSettings(doc, element); return true; } void LogFile::updateMonitor() { sendRequest(sensors().at(0)->hostName(), QStringLiteral("%1 %2" ).arg(sensors().at(0)->name()).arg(logFileID), 19); } void LogFile::answerReceived(int id, const QList& answer) { /* We received something, so the sensor is probably ok. */ sensorError(id, false); switch (id) { case 19: { QString s; for (int i = 0; i < answer.count(); i++) { s = QString::fromUtf8(answer[i]); if (monitor->count() == MAXLINES) monitor->takeItem(0); monitor->addItem(s); for (QStringList::Iterator it = filterRules.begin(); it != filterRules.end(); ++it) { QRegExp *expr = new QRegExp((*it).toLatin1()); if (expr->indexIn(s) != -1) { KNotification::event(QStringLiteral("pattern_match"), QStringLiteral("rule '%1' matched").arg(*it),QPixmap(),this); } delete expr; } } monitor->setCurrentRow( monitor->count() - 1 ); break; } case 42: { if(answer.isEmpty()) logFileID= 0; else logFileID = answer[0].toULong(); break; } } } diff --git a/gui/SensorDisplayLib/ProcessController.cpp b/gui/SensorDisplayLib/ProcessController.cpp index a936708c..ed95eefc 100644 --- a/gui/SensorDisplayLib/ProcessController.cpp +++ b/gui/SensorDisplayLib/ProcessController.cpp @@ -1,186 +1,186 @@ /* KSysGuard, the KDE System Guard Copyright (c) 1999 - 2001 Chris Schlaeger Copyright (c) 2006 John Tapsell 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; version 2 of the License, or (at your option) version 3. 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 . */ #include #include #include #include #include #include #include #include #include "ProcessController.h" #include "processui/ksysguardprocesslist.h" #include "processcore/processes.h" //#define DO_MODELCHECK #ifdef DO_MODELCHECK #include "modeltest.h" #endif ProcessController::ProcessController(QWidget* parent, SharedSettings *workSheetSettings) : KSGRD::SensorDisplay(parent, QString(), workSheetSettings) { - mProcessList = NULL; - mProcesses = NULL; + mProcessList = nullptr; + mProcesses = nullptr; } void ProcessController::sensorError(int, bool err) { if (err == sensors().at(0)->isOk()) { if (err) { qDebug() << "SensorError called with an error"; } /* This happens only when the sensorOk status needs to be changed. */ sensors().at(0)->setIsOk( !err ); } setSensorOk(sensors().at(0)->isOk()); } bool ProcessController::restoreSettings(QDomElement& element) { bool result = addSensor(element.attribute(QStringLiteral("hostName")), element.attribute(QStringLiteral("sensorName")), (element.attribute(QStringLiteral("sensorType")).isEmpty() ? QStringLiteral("table") : element.attribute(QStringLiteral("sensorType"))), QString()); if(!result) return false; int version = element.attribute(QStringLiteral("version"), QStringLiteral("0")).toUInt(); if(version == PROCESSHEADERVERSION) { //If the header has changed, the old settings are no longer valid. Only restore if version is the same mProcessList->restoreHeaderState(QByteArray::fromBase64(element.attribute(QStringLiteral("treeViewHeader")).toLatin1())); } bool showTotals = element.attribute(QStringLiteral("showTotals"), QStringLiteral("1")).toUInt(); mProcessList->setShowTotals(showTotals); int units = element.attribute(QStringLiteral("units"), QString::number((int)ProcessModel::UnitsKB)).toUInt(); mProcessList->setUnits((ProcessModel::Units)units); int ioUnits = element.attribute(QStringLiteral("ioUnits"), QString::number((int)ProcessModel::UnitsKB)).toUInt(); mProcessList->processModel()->setIoUnits((ProcessModel::Units)ioUnits); int ioInformation = element.attribute(QStringLiteral("ioInformation"), QString::number((int)ProcessModel::ActualBytesRate)).toUInt(); mProcessList->processModel()->setIoInformation((ProcessModel::IoInformation)ioInformation); bool showCommandLineOptions = element.attribute(QStringLiteral("showCommandLineOptions"), QStringLiteral("0")).toUInt(); mProcessList->processModel()->setShowCommandLineOptions(showCommandLineOptions); bool showTooltips = element.attribute(QStringLiteral("showTooltips"), QStringLiteral("1")).toUInt(); mProcessList->processModel()->setShowingTooltips(showTooltips); bool normalizeCPUUsage = element.attribute(QStringLiteral("normalizeCPUUsage"), QStringLiteral("1")).toUInt(); mProcessList->processModel()->setNormalizedCPUUsage(normalizeCPUUsage); int filterState = element.attribute(QStringLiteral("filterState"), QString::number((int)ProcessFilter::AllProcesses)).toUInt(); mProcessList->setState((ProcessFilter::State)filterState); SensorDisplay::restoreSettings(element); return result; } bool ProcessController::saveSettings(QDomDocument& doc, QDomElement& element) { if(!mProcessList) return false; element.setAttribute(QStringLiteral("hostName"), sensors().at(0)->hostName()); element.setAttribute(QStringLiteral("sensorName"), sensors().at(0)->name()); element.setAttribute(QStringLiteral("sensorType"), sensors().at(0)->type()); element.setAttribute(QStringLiteral("version"), QString::number(PROCESSHEADERVERSION)); element.setAttribute(QStringLiteral("treeViewHeader"), QString::fromLatin1(mProcessList->treeView()->header()->saveState().toBase64())); element.setAttribute(QStringLiteral("showTotals"), mProcessList->showTotals()?1:0); element.setAttribute(QStringLiteral("units"), (int)(mProcessList->units())); element.setAttribute(QStringLiteral("ioUnits"), (int)(mProcessList->processModel()->ioUnits())); element.setAttribute(QStringLiteral("ioInformation"), (int)(mProcessList->processModel()->ioInformation())); element.setAttribute(QStringLiteral("showCommandLineOptions"), mProcessList->processModel()->isShowCommandLineOptions()); element.setAttribute(QStringLiteral("showTooltips"), mProcessList->processModel()->isShowingTooltips()); element.setAttribute(QStringLiteral("normalizeCPUUsage"), mProcessList->processModel()->isNormalizedCPUUsage()); element.setAttribute(QStringLiteral("filterState"), (int)(mProcessList->state())); SensorDisplay::saveSettings(doc, element); return true; } void ProcessController::timerTick() { mProcessList->updateList(); } void ProcessController::answerReceived( int id, const QList& answer ) { if(mProcesses) mProcesses->answerReceived(id, answer); } bool ProcessController::addSensor(const QString& hostName, const QString& sensorName, const QString& sensorType, const QString& title) { if (sensorType != QLatin1String("table")) return false; QStackedLayout *layout = new QStackedLayout(this); mProcessList = new KSysGuardProcessList(this, hostName); mProcessList->setUpdateIntervalMSecs(0); //we will call updateList() manually mProcessList->setContentsMargins(0,0,0,0); mProcessList->setScriptingEnabled(true); addActions(mProcessList->actions()); connect(mProcessList, &KSysGuardProcessList::updated, this, &ProcessController::updated); connect(mProcessList, &KSysGuardProcessList::processListChanged, this, &ProcessController::processListChanged); mProcessList->setContextMenuPolicy( Qt::CustomContextMenu ); connect(mProcessList, &KSysGuardProcessList::customContextMenuRequested, this, &ProcessController::showContextMenu); layout->addWidget(mProcessList); /** To use a remote sensor, we need to drill down through the layers, to connect to the remote processes. Then connect to its signals and slots. * It's horrible I know :( */ if(!hostName.isEmpty() && hostName != QLatin1String("localhost")) { KSysGuard::Processes *processes = mProcessList->processModel()->processController(); mProcesses = processes; if(processes) { connect(processes, &KSysGuard::Processes::runCommand, this, &ProcessController::runCommand); } } setPlotterWidget(mProcessList); QTimer::singleShot(0, mProcessList->filterLineEdit(), SLOT(setFocus())); 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(). */ sensors().at(0)->setIsOk(true); //Assume it is okay from the start setSensorOk(sensors().at(0)->isOk()); emit processListChanged(); return true; } void ProcessController::runCommand(const QString &command, int id) { sendRequest(sensors().at(0)->hostName(), command, id); } diff --git a/gui/WorkSheet.cpp b/gui/WorkSheet.cpp index ed85e157..b4c4eac4 100644 --- a/gui/WorkSheet.cpp +++ b/gui/WorkSheet.cpp @@ -1,808 +1,808 @@ /* KSysGuard, the KDE System Guard Copyright (c) 1999 - 2001 Chris Schlaeger 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DancingBars.h" #include "DummyDisplay.h" #include "FancyPlotter.h" #include "ksysguard.h" #include "ListView.h" #include "LogFile.h" #include "MultiMeter.h" #include "ProcessController.h" #include "SensorLogger.h" #include "WorkSheet.h" #include "WorkSheetSettings.h" WorkSheet::WorkSheet( QWidget *parent ) : QWidget( parent ) { mGridLayout = 0; mRows = mColumns = 0; setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); setAcceptDrops( true ); } WorkSheet::WorkSheet( int rows, int columns, float interval, QWidget* parent ) : QWidget( parent) { mGridLayout = 0; setUpdateInterval( interval ); createGrid( rows, columns ); mGridLayout->activate(); setAcceptDrops( true ); } WorkSheet::~WorkSheet() { } bool WorkSheet::load( const QString &fileName ) { QFile file( fileName ); if ( !file.open( QIODevice::ReadOnly ) ) { KMessageBox::sorry( this, i18n( "Cannot open the file %1." , fileName ) ); return false; } QDomDocument 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." , fileName ) ); return false; } // Check for proper document type. if ( doc.doctype().name() != QLatin1String("KSysGuardWorkSheet") ) { KMessageBox::sorry( this, i18n( "The file %1 does not contain a valid worksheet " "definition, which must have a document type 'KSysGuardWorkSheet'.", fileName ) ); return false; } QDomElement element = doc.documentElement(); bool rowsOk, columnsOk; int rows = element.attribute( QStringLiteral("rows") ).toInt( &rowsOk ); int columns = element.attribute( QStringLiteral("columns") ).toInt( &columnsOk ); if ( !( rowsOk && columnsOk ) ) { KMessageBox::sorry( this, i18n("The file %1 has an invalid worksheet size.", fileName ) ); return false; } // Check for proper size. float interval = element.attribute( QStringLiteral("interval"), QStringLiteral("0.5") ).toFloat(); if( interval < 0 || interval > 100000 ) //make sure the interval is fairly sane interval = 0.5; setUpdateInterval( interval ); createGrid( rows, columns ); mGridLayout->activate(); mTitle = element.attribute( QStringLiteral("title")); mTranslatedTitle = mTitle.isEmpty() ? QLatin1String("") : i18n(mTitle.toUtf8().constData()); bool ok; mSharedSettings.locked = element.attribute( QStringLiteral("locked") ).toUInt( &ok ); if(!ok) mSharedSettings.locked = false; int i; /* Load lists of hosts that are needed for the work sheet and try * to establish a connection. */ QDomNodeList dnList = element.elementsByTagName( QStringLiteral("host") ); for ( i = 0; i < dnList.count(); ++i ) { QDomElement element = dnList.item( i ).toElement(); bool ok; int port = element.attribute( QStringLiteral("port") ).toInt( &ok ); if ( !ok ) port = -1; KSGRD::SensorMgr->engage( element.attribute( QStringLiteral("name") ), element.attribute( QStringLiteral("shell") ), element.attribute( QStringLiteral("command") ), port ); } //if no hosts are specified, at least connect to localhost if(dnList.count() == 0) KSGRD::SensorMgr->engage( QStringLiteral("localhost"), QLatin1String(""), QStringLiteral("ksysguardd"), -1); // Load the displays and place them into the work sheet. dnList = element.elementsByTagName( QStringLiteral("display") ); for ( i = 0; i < dnList.count(); ++i ) { QDomElement element = dnList.item( i ).toElement(); int row = element.attribute( QStringLiteral("row") ).toInt(); int column = element.attribute( QStringLiteral("column") ).toInt(); int rowSpan = element.attribute( QStringLiteral("rowSpan"), QStringLiteral("1") ).toInt(); int columnSpan = element.attribute( QStringLiteral("columnSpan"), QStringLiteral("1") ).toInt(); if ( row < 0 || rowSpan < 0 || (row + rowSpan - 1) >= mRows || column < 0 || columnSpan < 0 || (column + columnSpan - 1) >= mColumns) { qDebug() << "Row or Column out of range (" << row << ", " << column << ")-(" << (row + rowSpan - 1) << ", " << (column + columnSpan - 1) << ")" << endl; return false; } replaceDisplay( row, column, element, rowSpan, columnSpan ); } mFullFileName = fileName; return true; } bool WorkSheet::save( const QString &fileName ) { return exportWorkSheet(fileName); } bool WorkSheet::exportWorkSheet( const QString &fileName ) { QDomDocument doc( QStringLiteral("KSysGuardWorkSheet") ); doc.appendChild( doc.createProcessingInstruction( QStringLiteral("xml"), QStringLiteral("version=\"1.0\" encoding=\"UTF-8\"") ) ); // save work sheet information QDomElement ws = doc.createElement( QStringLiteral("WorkSheet") ); doc.appendChild( ws ); ws.setAttribute( QStringLiteral("title"), mTitle ); ws.setAttribute( QStringLiteral("locked"), mSharedSettings.locked?"1":"0" ); ws.setAttribute( QStringLiteral("interval"), updateInterval() ); ws.setAttribute( QStringLiteral("rows"), mRows ); ws.setAttribute( QStringLiteral("columns"), mColumns ); QStringList hosts; collectHosts( hosts ); // save host information (name, shell, etc.) QStringList::Iterator it; for ( it = hosts.begin(); it != hosts.end(); ++it ) { QString shell, command; int port; if ( KSGRD::SensorMgr->hostInfo( *it, shell, command, port ) ) { QDomElement host = doc.createElement( QStringLiteral("host") ); ws.appendChild( host ); host.setAttribute( QStringLiteral("name"), *it ); host.setAttribute( QStringLiteral("shell"), shell ); host.setAttribute( QStringLiteral("command"), command ); host.setAttribute( QStringLiteral("port"), port ); } } for (int i = 0; i < mGridLayout->count(); i++) { KSGRD::SensorDisplay* display = static_cast(mGridLayout->itemAt(i)->widget()); if (display->metaObject()->className() != QByteArray("DummyDisplay")) { int row, column, rowSpan, columnSpan; mGridLayout->getItemPosition(i, &row, &column, &rowSpan, &columnSpan); QDomElement element = doc.createElement(QStringLiteral("display")); ws.appendChild(element); element.setAttribute(QStringLiteral("row"), row); element.setAttribute(QStringLiteral("column"), column); element.setAttribute(QStringLiteral("rowSpan"), rowSpan); element.setAttribute(QStringLiteral("columnSpan"), columnSpan); element.setAttribute(QStringLiteral("class"), display->metaObject()->className()); display->saveSettings(doc, element); } } if (!QFileInfo::exists(QFileInfo(fileName).path())) { QDir().mkpath(QFileInfo(fileName).path()); } QFile file( fileName ); if ( !file.open( QIODevice::WriteOnly ) ) { KMessageBox::sorry( this, i18n( "Cannot save file %1" , fileName ) ); return false; } QTextStream s( &file ); s.setCodec( "UTF-8" ); s << doc; file.close(); return true; } void WorkSheet::cut() { if ( !currentDisplay() || currentDisplay()->metaObject()->className() == QByteArray("DummyDisplay" ) ) return; QClipboard* clip = QApplication::clipboard(); clip->setText( currentDisplayAsXML() ); removeDisplay( currentDisplay() ); } void WorkSheet::copy() { if ( !currentDisplay() || currentDisplay()->metaObject()->className() == QByteArray( "DummyDisplay" ) ) return; QClipboard* clip = QApplication::clipboard(); clip->setText( currentDisplayAsXML() ); } void WorkSheet::paste() { int row, column; if ( !currentDisplay( &row, &column ) ) return; QClipboard* clip = QApplication::clipboard(); QDomDocument doc; /* Get text from clipboard and check for a valid XML header and * proper document type. */ if ( !doc.setContent( clip->text() ) || doc.doctype().name() != QLatin1String("KSysGuardDisplay") ) { KMessageBox::sorry( this, i18n("The clipboard does not contain a valid display " "description." ) ); return; } QDomElement element = doc.documentElement(); replaceDisplay( row, column, element ); } void WorkSheet::setFileName( const QString &fileName ) { mFileName = fileName; } QString WorkSheet::fullFileName() const { return mFullFileName; } QString WorkSheet::fileName() const { return mFileName; } void WorkSheet::setTitle( const QString &title ) { mTitle = title; mTranslatedTitle = mTitle.isEmpty() ? QLatin1String("") : i18n(mTitle.toUtf8().constData()); emit titleChanged(this); } QString WorkSheet::translatedTitle() const { return mTranslatedTitle; } QString WorkSheet::title() const { return mTitle; } KSGRD::SensorDisplay* WorkSheet::insertDisplay( DisplayType displayType, QString displayTitle, int row, int column, int rowSpan, int columnSpan ) { KSGRD::SensorDisplay* newDisplay = 0; switch(displayType) { case DisplayDummy: newDisplay = new DummyDisplay( this, &mSharedSettings ); break; case DisplayFancyPlotter: newDisplay = new FancyPlotter( this, displayTitle, &mSharedSettings ); break; case DisplayMultiMeter: newDisplay = new MultiMeter( this, displayTitle, &mSharedSettings); break; case DisplayDancingBars: newDisplay = new DancingBars( this, displayTitle, &mSharedSettings); break; case DisplaySensorLogger: newDisplay = new SensorLogger( this, displayTitle, &mSharedSettings); break; case DisplayListView: newDisplay = new ListView( this, displayTitle, &mSharedSettings); break; case DisplayLogFile: newDisplay = new LogFile( this, displayTitle, &mSharedSettings ); break; case DisplayProcessControllerRemote: newDisplay = new ProcessController(this, &mSharedSettings); newDisplay->setObjectName(QStringLiteral("remote process controller")); break; case DisplayProcessControllerLocal: newDisplay = new ProcessController(this, &mSharedSettings); if (!Toplevel->localProcessController()) Toplevel->setLocalProcessController(static_cast(newDisplay)); break; default: Q_ASSERT(false); - return NULL; + return nullptr; } newDisplay->applyStyle(); connect(&mTimer, &QTimer::timeout, newDisplay, &KSGRD::SensorDisplay::timerTick); replaceDisplay( row, column, newDisplay, rowSpan, columnSpan ); return newDisplay; } KSGRD::SensorDisplay *WorkSheet::addDisplay( const QString &hostName, const QString &sensorName, const QString &sensorType, const QString& sensorDescr, int row, int column ) { KSGRD::SensorDisplay* display = static_cast(mGridLayout->itemAtPosition(row, column)->widget()); /* If the by 'row' and 'column' specified display is a QGroupBox dummy * display we replace the widget. Otherwise we just try to add * the new sensor to an existing display. */ if ( display->metaObject()->className() == QByteArray( "DummyDisplay" ) ) { DisplayType displayType = DisplayDummy; /* 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 == QLatin1String("integer") || sensorType == QLatin1String("float") ) { QMenu pm; pm.addSection( i18n( "Select Display Type" ) ); QAction *a1 = pm.addAction( i18n( "&Line graph" ) ); QAction *a2 = pm.addAction( i18n( "&Digital display" ) ); QAction *a3 = pm.addAction( i18n( "&Bar graph" ) ); QAction *a4 = pm.addAction( i18n( "Log to a &file" ) ); QAction *execed = pm.exec( QCursor::pos() ); if (execed == a1) displayType = DisplayFancyPlotter; else if (execed == a2) displayType = DisplayMultiMeter; else if (execed == a3) displayType = DisplayDancingBars; else if (execed == a4) displayType = DisplaySensorLogger; else return 0; } else if ( sensorType == QLatin1String("listview") ) { displayType = DisplayListView; } else if ( sensorType == QLatin1String("logfile") ) { displayType = DisplayLogFile; } else if ( sensorType == QLatin1String("sensorlogger") ) { displayType = DisplaySensorLogger; } else if ( sensorType == QLatin1String("table") ) { if(hostName.isEmpty() || hostName == QLatin1String("localhost")) displayType = DisplayProcessControllerLocal; else displayType = DisplayProcessControllerRemote; } else { qDebug() << "Unknown sensor type: " << sensorType; return 0; } display = insertDisplay(displayType, sensorDescr, row, column); } if (!display->addSensor( hostName, sensorName, sensorType, sensorDescr )) { // Failed to add sensor, so we need to remove the display that we just added removeDisplay(display); return 0; } return display; } void WorkSheet::settings() { WorkSheetSettings dlg( this, mSharedSettings.locked ); dlg.setSheetTitle( mTranslatedTitle ); dlg.setInterval( updateInterval() ); if(!mSharedSettings.locked) { dlg.setRows( mRows ); dlg.setColumns( mColumns ); } if ( dlg.exec() ) { setUpdateInterval( dlg.interval() ); if (!mSharedSettings.locked) resizeGrid( dlg.rows(), dlg.columns() ); if(mTranslatedTitle != dlg.sheetTitle()) { //Title has changed if(mRows == 1 && mColumns == 1) { static_cast(mGridLayout->itemAt(0)->widget())->setTitle(dlg.sheetTitle()); } else { setTitle(dlg.sheetTitle()); } } } } void WorkSheet::showPopupMenu( KSGRD::SensorDisplay *display ) { display->configureSettings(); } void WorkSheet::applyStyle() { for (int i = 0; i < mGridLayout->count(); i++) static_cast(mGridLayout->itemAt(i)->widget())->applyStyle(); } void WorkSheet::dragEnterEvent( QDragEnterEvent* event) { if ( !event->mimeData()->hasFormat(QStringLiteral("application/x-ksysguard")) ) return; event->accept(); } void WorkSheet::dragMoveEvent( QDragMoveEvent *event ) { /* Find the sensor display that is supposed to get the drop * event and replace or add sensor. */ const QPoint globalPos = mapToGlobal( event->pos() ); for ( int i = 0; i < mGridLayout->count(); i++ ) { KSGRD::SensorDisplay* display = static_cast(mGridLayout->itemAt(i)->widget()); const QRect widgetRect = QRect( display->mapToGlobal( QPoint( 0, 0 ) ), display->size() ); if ( widgetRect.contains( globalPos ) ) { QByteArray widgetType = display->metaObject()->className(); if(widgetType == "MultiMeter" || widgetType == "ProcessController" || widgetType == "table") event->ignore(widgetRect); else if(widgetType != "Dummy") event->accept(widgetRect); return; } } } void WorkSheet::dropEvent( QDropEvent *event ) { if ( !event->mimeData()->hasFormat(QStringLiteral("application/x-ksysguard")) ) return; const QString dragObject = QString::fromUtf8(event->mimeData()->data(QStringLiteral("application/x-ksysguard"))); // The host name, sensor name and type are separated by a ' '. QStringList parts = dragObject.split( ' '); QString hostName = parts[ 0 ]; QString sensorName = parts[ 1 ]; QString sensorType = parts[ 2 ]; QString sensorDescr = QStringList(parts.mid( 3 )).join(' '); 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. */ const QPoint globalPos = mapToGlobal( event->pos() ); for ( int i = 0; i < mGridLayout->count(); i++ ) { KSGRD::SensorDisplay* display = static_cast(mGridLayout->itemAt(i)->widget()); const QSize displaySize = display->size(); const QPoint displayPoint( displaySize.width(), displaySize.height() ); const QRect widgetRect = QRect( display->mapToGlobal( QPoint( 0, 0 ) ), display->mapToGlobal( displayPoint ) ); if ( widgetRect.contains( globalPos ) ) { int row, column, rowSpan, columnSpan; mGridLayout->getItemPosition(i, &row, &column, &rowSpan, &columnSpan); addDisplay( hostName, sensorName, sensorType, sensorDescr, row, column ); return; } } } QSize WorkSheet::sizeHint() const { return QSize( 800,600 ); } bool WorkSheet::event( QEvent *e ) { if ( e->type() == QEvent::User ) { // SensorDisplays send out this event if they want to be removed. if ( KMessageBox::warningContinueCancel( this, i18n( "Remove this display?" ), i18n("Remove Display"), KStandardGuiItem::del() ) == KMessageBox::Continue ) { KSGRD::SensorDisplay::DeleteEvent *event = static_cast( e ); removeDisplay( event->display() ); return true; } } return QWidget::event( e ); } bool WorkSheet::replaceDisplay( int row, int column, QDomElement& element, int rowSpan, int columnSpan ) { QString classType = element.attribute( QStringLiteral("class") ); QString hostName = element.attribute( QStringLiteral("hostName") ); DisplayType displayType = DisplayDummy; KSGRD::SensorDisplay* newDisplay; if ( classType == QLatin1String("FancyPlotter") ) displayType = DisplayFancyPlotter; else if ( classType == QLatin1String("MultiMeter") ) displayType = DisplayMultiMeter; else if ( classType == QLatin1String("DancingBars") ) displayType = DisplayDancingBars; else if ( classType == QLatin1String("ListView") ) displayType = DisplayListView; else if ( classType == QLatin1String("LogFile") ) displayType = DisplayLogFile; else if ( classType == QLatin1String("SensorLogger") ) displayType = DisplaySensorLogger; else if ( classType == QLatin1String("ProcessController") ) { if(hostName.isEmpty() || hostName == QLatin1String("localhost")) displayType = DisplayProcessControllerLocal; else displayType = DisplayProcessControllerRemote; } else { qDebug() << "Unknown class " << classType; return false; } newDisplay = insertDisplay(displayType, i18n("Dummy"), row, column, rowSpan, columnSpan); // load display specific settings if ( !newDisplay->restoreSettings( element ) ) return false; return true; } void WorkSheet::replaceDisplay( int row, int column, KSGRD::SensorDisplay* newDisplay, int rowSpan, int columnSpan ) { if ( !newDisplay ) newDisplay = new DummyDisplay( this, &mSharedSettings ); // remove the old display && sensor frame at this location QSet oldDisplays; for (int i = row; i < row + rowSpan; i++) for (int j = column; j < column + columnSpan; j++) { QLayoutItem* item = mGridLayout->itemAtPosition(i, j); if (item) oldDisplays.insert(item); } for (QSet::iterator iter = oldDisplays.begin(); iter != oldDisplays.end(); iter++) { QLayoutItem* item = *iter; int oldDisplayRow, oldDisplayColumn, oldDisplayRowSpan, oldDisplayColumnSpan; mGridLayout->getItemPosition(mGridLayout->indexOf(item->widget()), &oldDisplayRow, &oldDisplayColumn, &oldDisplayRowSpan, &oldDisplayColumnSpan); mGridLayout->removeItem(item); if (item->widget() != Toplevel->localProcessController()) delete item->widget(); delete item; for (int i = oldDisplayRow; i < oldDisplayRow + oldDisplayRowSpan; i++) for (int j = oldDisplayColumn; j < oldDisplayColumn + oldDisplayColumnSpan; j++) if ((i < row || i >= row + rowSpan || j < column || j >= column + columnSpan) && !mGridLayout->itemAtPosition(i, j)) mGridLayout->addWidget(new DummyDisplay(this, &mSharedSettings), i, j); } mGridLayout->addWidget(newDisplay, row, column, rowSpan, columnSpan); if (newDisplay->metaObject()->className() != QByteArray("DummyDisplay")) { connect(newDisplay, &KSGRD::SensorDisplay::showPopupMenu, this, &WorkSheet::showPopupMenu); newDisplay->setDeleteNotifier(this); } // if there's only item, the tab's title should be the widget's title if (row == 0 && mRows == rowSpan && column == 0 && mColumns == columnSpan) { connect(newDisplay, &KSGRD::SensorDisplay::titleChanged, this, &WorkSheet::setTitle); setTitle(newDisplay->title()); } if (isVisible()) newDisplay->show(); } void WorkSheet::refreshSheet() { for (int i = 0; i < mGridLayout->count(); i++) static_cast(mGridLayout->itemAt(i)->widget())->timerTick(); } void WorkSheet::removeDisplay( KSGRD::SensorDisplay *display ) { if ( !display ) return; int row, column, rowSpan, columnSpan; mGridLayout->getItemPosition(mGridLayout->indexOf(display), &row, &column, &rowSpan, &columnSpan); replaceDisplay(row, column); } void WorkSheet::collectHosts( QStringList &list ) { for (int i = 0; i < mGridLayout->count(); i++) static_cast(mGridLayout->itemAt(i)->widget())->hosts(list); } void WorkSheet::createGrid( int rows, int columns ) { mRows = rows; mColumns = columns; // create grid layout with specified dimensions mGridLayout = new QGridLayout( this ); mGridLayout->setSpacing( 5 ); /* set stretch factors for rows and columns */ for ( int r = 0; r < mRows; ++r ) mGridLayout->setRowStretch( r, 100 ); for ( int c = 0; c < mColumns; ++c ) mGridLayout->setColumnStretch( c, 100 ); for (int r = 0; r < mRows; r++) for (int c = 0; c < mColumns; c++) replaceDisplay(r, c); } void WorkSheet::resizeGrid( int newRows, int newColumns ) { int oldRows = mRows, oldColumns = mColumns; mRows = newRows; mColumns = newColumns; /* delete any excess displays */ for (int i = 0; i < mGridLayout->count(); i++) { int row, column, rowSpan, columnSpan; mGridLayout->getItemPosition(i, &row, &column, &rowSpan, &columnSpan); if (row + rowSpan - 1 >= mRows || column + columnSpan - 1 >= mColumns) { QLayoutItem* item = mGridLayout->takeAt(i); if (item->widget() != Toplevel->localProcessController()) delete item->widget(); delete item; --i; } } /* create new displays */ if (mRows > oldRows || mColumns > oldColumns) for (int i = 0; i < mRows; ++i) for (int j = 0; j < mColumns; ++j) if (i >= oldRows || j >= oldColumns) replaceDisplay(i, j); /* set stretch factors for new rows and columns (if any) */ for ( int r = oldRows; r < mRows; ++r ) mGridLayout->setRowStretch( r, 100 ); for ( int c = oldColumns; c < mColumns; ++c ) mGridLayout->setColumnStretch( 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 stretch factor of 0 and hence be * invisible. */ for ( int r = mRows; r < oldRows; ++r ) mGridLayout->setRowStretch( r, 0 ); for ( int c = mColumns; c < oldColumns; ++c ) mGridLayout->setColumnStretch( c, 0 ); fixTabOrder(); mGridLayout->activate(); } KSGRD::SensorDisplay *WorkSheet::currentDisplay( int * row, int * column ) { int dummyRow, dummyColumn, rowSpan, columnSpan; if (!row) row = &dummyRow; if (!column) column = &dummyColumn; for (int i = 0; i < mGridLayout->count(); i++) { KSGRD::SensorDisplay* display = static_cast(mGridLayout->itemAt(i)->widget()); if (display->hasFocus()) { mGridLayout->getItemPosition(i, row, column, &rowSpan, &columnSpan); return display; } } - return NULL; + return nullptr; } void WorkSheet::fixTabOrder() { QWidget* previous = 0; for (int i = 0; i < mGridLayout->count(); i++) { QWidget* current = mGridLayout->itemAt(i)->widget(); if (previous) setTabOrder(previous, current); previous = current; } } QString WorkSheet::currentDisplayAsXML() { KSGRD::SensorDisplay* display = currentDisplay(); if ( !display ) return QString(); /* We create an XML description of the current display. */ QDomDocument doc( QStringLiteral("KSysGuardDisplay") ); doc.appendChild( doc.createProcessingInstruction( QStringLiteral("xml"), QStringLiteral("version=\"1.0\" encoding=\"UTF-8\"") ) ); QDomElement element = doc.createElement( QStringLiteral("display") ); doc.appendChild( element ); element.setAttribute( QStringLiteral("class"), display->metaObject()->className() ); display->saveSettings( doc, element ); return doc.toString(); } void WorkSheet::changeEvent( QEvent * event ) { if (event->type() == QEvent::LanguageChange) { setTitle(mTitle); //retranslate } } void WorkSheet::setUpdateInterval( float secs) { if(secs == 0) mTimer.stop(); else { mTimer.setInterval(secs*1000); mTimer.start(); } } float WorkSheet::updateInterval() const { if(mTimer.isActive()) return mTimer.interval()/1000.0; else return 0; } diff --git a/gui/ksysguard.cpp b/gui/ksysguard.cpp index cb4444ff..264fa7d6 100644 --- a/gui/ksysguard.cpp +++ b/gui/ksysguard.cpp @@ -1,600 +1,600 @@ /* KSysGuard, the KDE System Guard Copyright (c) 2006 - 2008 John Tapsell Copyright (c) 1999 - 2001 Chris Schlaeger 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 . 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 and Nicolas Leclercq . */ #include "ksysguard.h" #include "config-workspace.h" #include "HostConnector.h" #include "ProcessController.h" #include "SensorBrowser.h" #include "StyleEngine.h" #include "Workspace.h" #include "WorkSheet.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //Comment out to stop ksysguard from forking. Good for debugging //#define FORK_KSYSGUARD static const char Description[] = I18N_NOOP( "KDE System Monitor" ); TopLevel* Toplevel; TopLevel::TopLevel() - : KXmlGuiWindow( NULL, Qt::WindowFlags(KDE_DEFAULT_WINDOWFLAGS) | Qt::WindowContextHelpButtonHint) + : KXmlGuiWindow( nullptr, Qt::WindowFlags(KDE_DEFAULT_WINDOWFLAGS) | Qt::WindowContextHelpButtonHint) { QDBusConnection::sessionBus().registerObject(QStringLiteral("/"), this, QDBusConnection::ExportScriptableSlots); mTimerId = -1; - mLocalProcessController = NULL; + mLocalProcessController = nullptr; mSplitter = new QSplitter( this ); mSplitter->setOrientation( Qt::Horizontal ); setCentralWidget( mSplitter ); mSensorBrowser = 0; mWorkSpace = new Workspace( mSplitter ); connect( mWorkSpace, SIGNAL(setCaption(QString)), SLOT(setCaption(QString)) ); connect( mWorkSpace, SIGNAL(currentChanged(int)), SLOT(currentTabChanged(int)) ); /* Create the status bar. It displays some information about the * number of processes and the memory consumption of the local * host. */ const int STATUSBAR_STRETCH=1; sbProcessCount = new QLabel(); statusBar()->addWidget( sbProcessCount, STATUSBAR_STRETCH ); sbCpuStat = new QLabel(); statusBar()->addWidget( sbCpuStat, STATUSBAR_STRETCH ); sbMemTotal = new QLabel(); statusBar()->addWidget( sbMemTotal, STATUSBAR_STRETCH ); sbSwapTotal = new QLabel(); statusBar()->addWidget( sbSwapTotal, STATUSBAR_STRETCH ); statusBar()->hide(); // create actions for menu entries mRefreshTabAction = KStandardAction::redisplay(mWorkSpace,SLOT(refreshActiveWorksheet()),actionCollection()); mNewWorksheetAction = actionCollection()->addAction(QStringLiteral("new_worksheet")); mNewWorksheetAction->setIcon(QIcon::fromTheme(QStringLiteral("tab-new"))); connect(mNewWorksheetAction, &QAction::triggered, mWorkSpace, &Workspace::newWorkSheet); mInsertWorksheetAction = actionCollection()->addAction(QStringLiteral("import_worksheet")); mInsertWorksheetAction->setIcon(QIcon::fromTheme(QStringLiteral("document-open")) ); connect(mInsertWorksheetAction, SIGNAL(triggered(bool)), mWorkSpace, SLOT(importWorkSheet())); mTabExportAction = actionCollection()->addAction( QStringLiteral("export_worksheet") ); mTabExportAction->setIcon( QIcon::fromTheme(QStringLiteral("document-save-as")) ); connect(mTabExportAction, SIGNAL(triggered(bool)), mWorkSpace, SLOT(exportWorkSheet())); mTabRemoveAction = actionCollection()->addAction( QStringLiteral("remove_worksheet") ); mTabRemoveAction->setIcon( QIcon::fromTheme(QStringLiteral("tab-close")) ); connect(mTabRemoveAction, SIGNAL(triggered(bool)), mWorkSpace, SLOT(removeWorkSheet())); mMonitorRemoteAction = actionCollection()->addAction( QStringLiteral("connect_host") ); mMonitorRemoteAction->setIcon( QIcon::fromTheme(QStringLiteral("network-connect")) ); connect(mMonitorRemoteAction, &QAction::triggered, this, &TopLevel::connectHost); //knewstuff2 action mHotNewWorksheetAction = actionCollection()->addAction( QStringLiteral("get_new_worksheet") ); mHotNewWorksheetAction->setIcon( QIcon::fromTheme(QStringLiteral("network-server")) ); connect(mHotNewWorksheetAction, &QAction::triggered, mWorkSpace, &Workspace::getHotNewWorksheet); mHotNewWorksheetUploadAction = actionCollection()->addAction( QStringLiteral("upload_worksheet") ); mHotNewWorksheetUploadAction->setIcon( QIcon::fromTheme(QStringLiteral("network-server")) ); connect(mHotNewWorksheetUploadAction, &QAction::triggered, mWorkSpace, &Workspace::uploadHotNewWorksheet); - mQuitAction = NULL; + mQuitAction = nullptr; mConfigureSheetAction = actionCollection()->addAction( QStringLiteral("configure_sheet") ); mConfigureSheetAction->setIcon( QIcon::fromTheme(QStringLiteral("configure")) ); connect(mConfigureSheetAction, &QAction::triggered, this, &TopLevel::configureCurrentSheet); retranslateUi(); } void TopLevel::setLocalProcessController(ProcessController * localProcessController) { Q_ASSERT(!mLocalProcessController); mLocalProcessController = localProcessController; connect( mLocalProcessController, &ProcessController::processListChanged, this, &TopLevel::updateProcessCount); for(int i = 0; i < mLocalProcessController->actions().size(); i++) { actionCollection()->addAction("processAction" + QString::number(i), mLocalProcessController->actions().at(i)); } } void TopLevel::retranslateUi() { setPlainCaption( i18n( "System Monitor" ) ); mRefreshTabAction->setText(i18n("&Refresh Tab")); mNewWorksheetAction->setText(i18n( "&New Tab..." )); mInsertWorksheetAction->setText(i18n( "Import Tab Fr&om File..." )); mTabExportAction->setText( i18n( "Save Tab &As..." ) ); mTabRemoveAction->setText( i18n( "&Close Tab" ) ); mMonitorRemoteAction->setText( i18n( "Monitor &Remote Machine..." ) ); mHotNewWorksheetAction->setText( i18n( "&Download New Tabs..." ) ); mHotNewWorksheetUploadAction->setText( i18n( "&Upload Current Tab..." ) ); mConfigureSheetAction->setText( i18n( "Tab &Properties" ) ); if(mQuitAction) { - QAction *tmpQuitAction = KStandardAction::quit( NULL, NULL, NULL ); + QAction *tmpQuitAction = KStandardAction::quit( nullptr, nullptr, nullptr ); mQuitAction->setText(tmpQuitAction->text()); mQuitAction->setWhatsThis(tmpQuitAction->whatsThis()); mQuitAction->setToolTip(tmpQuitAction->toolTip()); delete tmpQuitAction; } else mQuitAction = KStandardAction::quit( this, SLOT(close()), actionCollection() ); } void TopLevel::configureCurrentSheet() { mWorkSpace->configure(); mRefreshTabAction->setVisible( mWorkSpace->currentWorkSheet()->updateInterval() == 0 ); } void TopLevel::currentTabChanged(int index) { QWidget *wdg = mWorkSpace->widget(index); WorkSheet *sheet = (WorkSheet *)(wdg); Q_ASSERT(sheet); bool locked = !sheet || sheet->isLocked(); mTabRemoveAction->setVisible(!locked); mTabExportAction->setVisible(!locked); mHotNewWorksheetUploadAction->setVisible(!locked); mMonitorRemoteAction->setVisible(!locked); //only show refresh option is update interval is 0 (manual) mRefreshTabAction->setVisible( sheet->updateInterval() == 0 ); if(!locked && !mSensorBrowser) { startSensorBrowserWidget(); } if(mSensorBrowser) { if(mSensorBrowser->isVisible() && locked) //going from visible to not visible to save the state mSplitterSize = mSplitter->sizes(); mSensorBrowser->setVisible(!locked); } } void TopLevel::startSensorBrowserWidget() { if(mSensorBrowser) return; mSensorBrowser = new SensorBrowserWidget( 0, KSGRD::SensorMgr ); mSplitter->insertWidget(2,mSensorBrowser); mSplitter->setSizes( mSplitterSize ); } /* * DBUS Interface functions */ void TopLevel::showOnCurrentDesktop() { KWindowSystem::setOnDesktop( winId(), KWindowSystem::currentDesktop() ); KUserTimestamp::updateUserTimestamp(); KWindowSystem::forceActiveWindow( winId() ); } void TopLevel::importWorkSheet( const QString &fileName ) { mWorkSpace->importWorkSheet(QUrl::fromLocalFile(fileName)); } void TopLevel::removeWorkSheet( const QString &fileName ) { mWorkSpace->removeWorkSheet( fileName ); } void TopLevel::getHotNewWorksheet() { mWorkSpace->getHotNewWorksheet( ); } QStringList TopLevel::listSensors( const QString &hostName ) { if(!mSensorBrowser) { setUpdatesEnabled(false); startSensorBrowserWidget(); mSensorBrowser->setVisible(false); setUpdatesEnabled(true); } return mSensorBrowser->listSensors( hostName ); } QStringList TopLevel::listHosts() { if(!mSensorBrowser) { setUpdatesEnabled(false); startSensorBrowserWidget(); mSensorBrowser->setVisible(false); setUpdatesEnabled(true); } return mSensorBrowser->listHosts(); } void TopLevel::initStatusBar() { KSGRD::SensorMgr->engage( QStringLiteral("localhost"), QLatin1String(""), QStringLiteral("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( QStringLiteral("localhost"), QStringLiteral("mem/swap/used?"), (KSGRD::SensorClient*)this, 7 ); KToggleAction *sb = dynamic_cast(action("options_show_statusbar")); if (sb) connect(sb, &QAction::toggled, this, &TopLevel::updateStatusBar); setupGUI(QSize(800,600), ToolBar | Keys | StatusBar | Save | Create); 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() { HostConnector hostConnector( this ); // hostConnector.setHostNames( mHostList ); // hostConnector.setCommands( mCommandList ); // hostConnector.setCurrentHostName( "" ); if ( !hostConnector.exec() ) return; // mHostList = hostConnector.hostNames(); // mCommandList = hostConnector.commands(); QString shell = QLatin1String(""); QString command = QLatin1String(""); int port = -1; /* Check which radio button is selected and set parameters * appropriately. */ if ( hostConnector.useSsh() ) shell = QStringLiteral("ssh"); else if ( hostConnector.useRsh() ) shell = QStringLiteral("rsh"); else if ( hostConnector.useDaemon() ) port = hostConnector.port(); else command = hostConnector.currentCommand(); KSGRD::SensorMgr->engage( hostConnector.currentHostName(), shell, command, port ); } void TopLevel::disconnectHost() { if(mSensorBrowser) mSensorBrowser->disconnect(); } bool TopLevel::event( QEvent *e ) { if ( e->type() == QEvent::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, static_cast(e)->message() ); return true; } return KXmlGuiWindow::event( e ); } void TopLevel::timerEvent( QTimerEvent* ) { if ( statusBar()->isVisibleTo( this ) ) { /* Request some info about the memory status. The requested * information will be received by answerReceived(). */ KSGRD::SensorMgr->sendRequest( QStringLiteral("localhost"), QStringLiteral("cpu/idle"), (KSGRD::SensorClient*)this, 1 ); KSGRD::SensorMgr->sendRequest( QStringLiteral("localhost"), QStringLiteral("mem/physical/free"), (KSGRD::SensorClient*)this, 2 ); KSGRD::SensorMgr->sendRequest( QStringLiteral("localhost"), QStringLiteral("mem/physical/used"), (KSGRD::SensorClient*)this, 3 ); KSGRD::SensorMgr->sendRequest( QStringLiteral("localhost"), QStringLiteral("mem/physical/application"), (KSGRD::SensorClient*)this, 4 ); KSGRD::SensorMgr->sendRequest( QStringLiteral("localhost"), QStringLiteral("mem/swap/free"), (KSGRD::SensorClient*)this, 5 ); KSGRD::SensorMgr->sendRequest( QStringLiteral("localhost"), QStringLiteral("mem/swap/used"), (KSGRD::SensorClient*)this, 6 ); } } void TopLevel::updateProcessCount() { const QString s = i18np( "1 process" "\u009C" "1", "%1 processes" "\u009C" "%1", mLocalProcessController->processList()->visibleProcessesCount() ); sbProcessCount->setText( s ); } void TopLevel::changeEvent( QEvent * event ) { if (event->type() == QEvent::LanguageChange) { KSGRD::SensorMgr->retranslate(); setUpdatesEnabled(false); setupGUI(ToolBar | Keys | StatusBar | Create); retranslateUi(); setUpdatesEnabled(true); } KXmlGuiWindow::changeEvent(event); } bool TopLevel::queryClose() { if ( !mWorkSpace->saveOnQuit() ) return false; KConfigGroup cg( KSharedConfig::openConfig(), "MainWindow" ); saveProperties( cg ); KSharedConfig::openConfig()->sync(); return true; } void TopLevel::readProperties( const KConfigGroup& cfg ) { /* we can ignore 'isMaximized' because we can't set the window maximized, so we save the coordinates instead */ // if ( cfg.readEntry( "isMinimized" , false) == true ) // showMinimized(); mSplitterSize = cfg.readEntry( "SplitterSizeList",QList() ); if ( mSplitterSize.isEmpty() ) { // start with a 30/70 ratio mSplitterSize.append( 10 ); mSplitterSize.append( 90 ); } KSGRD::SensorMgr->readProperties( cfg ); KSGRD::Style->readProperties( cfg ); mWorkSpace->readProperties( cfg ); } void TopLevel::saveProperties( KConfigGroup& cfg ) { cfg.writeEntry( "isMinimized", isMinimized() ); if(mSensorBrowser && mSensorBrowser->isVisible()) cfg.writeEntry( "SplitterSizeList", mSplitter->sizes()); else if(mSplitterSize.size() == 2 && mSplitterSize.value(0) != 0 && mSplitterSize.value(1) != 0) cfg.writeEntry( "SplitterSizeList", mSplitterSize ); KSGRD::Style->saveProperties( cfg ); KSGRD::SensorMgr->saveProperties( cfg ); saveMainWindowSettings( cfg ); mWorkSpace->saveProperties( cfg ); } void TopLevel::answerReceived( int id, const QList &answerList ) { // we have received an answer from the daemon. QByteArray answer; if(!answerList.isEmpty()) answer = answerList[0]; QString s; static QString unit; static qlonglong mFree = 0; static qlonglong mUsedApplication = 0; static qlonglong mUsedTotal = 0; static qlonglong sUsed = 0; static qlonglong sFree = 0; switch ( id ) { case 1: s = i18n( "CPU: %1%\xc2\x9c%1%", (int) (100 - answer.toFloat()) ); sbCpuStat->setText( s ); break; case 2: mFree = answer.toLongLong(); break; case 3: mUsedTotal = answer.toLongLong(); break; case 4: mUsedApplication = answer.toLongLong(); //Use a multi-length string s = i18nc( "Arguments are formatted byte sizes (used/total)", "Memory: %1 / %2" "\xc2\x9c" "Mem: %1 / %2" "\xc2\x9c" "Mem: %1" "\xc2\x9c" "%1", KFormat().formatByteSize( mUsedApplication*1024), KFormat().formatByteSize( (mFree+mUsedTotal)*1024 ) ); sbMemTotal->setText( s ); break; case 5: sFree = answer.toLongLong(); break; case 6: sUsed = answer.toLongLong(); setSwapInfo( sUsed, sFree, unit ); break; case 7: { KSGRD::SensorIntegerInfo info( answer ); unit = KSGRD::SensorMgr->translateUnit( info.unit() ); break; } } } void TopLevel::setSwapInfo( qlonglong used, qlonglong free, const QString & ) { QString msg; if ( used == 0 && free == 0 ) // no swap available msg = i18n( " No swap space available " ); else { msg = i18nc( "Arguments are formatted byte sizes (used/total)", "Swap: %1 / %2" "\xc2\x9c" "Swap: %1" "\xc2\x9c" "%1" , KFormat().formatByteSize( used*1024 ), KFormat().formatByteSize( (free+used)*1024) ); } sbSwapTotal->setText( msg ); } /* * Once upon a time... */ extern "C" Q_DECL_EXPORT int kdemain( int argc, char** argv ) { // initpipe is used to keep the parent process around till the child // has registered with dbus #ifdef FORK_KSYSGUARD int initpipe[ 2 ]; pipe( initpipe ); /* This forking will put ksysguard in it's own session not having a * controlling terminal attached to it. This prevents ssh from * using this terminal for password requests. Thus, you * need a ssh with ssh-askpass support to popup an X dialog to * enter the password. */ 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(); #endif QApplication app(argc, argv); KLocalizedString::setApplicationDomain("ksysguard"); KAboutData aboutData( QStringLiteral("ksysguard"), i18n( "System Monitor" ), PROJECT_VERSION, i18n(Description), KAboutLicense::GPL, i18n( "(c) 1996-2016 The KDE System Monitor Developers" ) ); aboutData.setOrganizationDomain(QByteArray("kde.org")); aboutData.addAuthor( i18n("John Tapsell"), i18n("Current Maintainer"), QStringLiteral("john.tapsell@kde.org") ); aboutData.addAuthor( i18n("Chris Schlaeger"), i18n("Previous Maintainer"), QStringLiteral("cs@kde.org") ); aboutData.addAuthor( i18n("Greg Martyn"), QString(), QStringLiteral("greg.martyn@gmail.com") ); aboutData.addAuthor( i18n("Tobias Koenig"), QString(), QStringLiteral("tokoe@kde.org") ); aboutData.addAuthor( i18n("Nicolas Leclercq"), QString(), QStringLiteral("nicknet@planete.net") ); aboutData.addAuthor( i18n("Alex Sanda"), QString(), QStringLiteral("alex@darkstart.ping.at") ); aboutData.addAuthor( i18n("Bernd Johannes Wuebben"), QString(), QStringLiteral("wuebben@math.cornell.edu") ); aboutData.addAuthor( i18n("Ralf Mueller"), QString(), QStringLiteral("rlaf@bj-ig.de") ); aboutData.addAuthor( i18n("Hamish Rodda"), QString(), QStringLiteral("rodda@kde.org") ); aboutData.addAuthor( i18n("Torsten Kasch"), i18n( "Solaris Support\n" "Parts derived (by permission) from the sunos5\n" "module of William LeFebvre's \"top\" utility." ), QStringLiteral("tk@Genetik.Uni-Bielefeld.DE") ); KAboutData::setApplicationData(aboutData); app.setWindowIcon(QIcon::fromTheme(QStringLiteral("utilities-system-monitor"))); QCommandLineParser parser; aboutData.setupCommandLine(&parser); parser.addPositionalArgument(QStringLiteral("[worksheet]"), i18n( "Optional worksheet files to load" )); parser.process(app); aboutData.processCommandLine(&parser); KSGRD::SensorMgr = new KSGRD::SensorManager(); KSGRD::Style = new KSGRD::StyleEngine(); #ifdef FORK_KSYSGUARD char c = 0; write( initpipe[ 1 ], &c, 1 ); close( initpipe[ 1 ] ); #endif Toplevel = new TopLevel(); // create top-level widget Toplevel->readProperties( KConfigGroup( KSharedConfig::openConfig(), "MainWindow" ) ); // setup the statusbar, toolbar etc. // Note that this comes after creating the top-level widgets whcih also // sets up the various QActions that the user may have added to the toolbar Toplevel->initStatusBar(); //There seems to be some serious bugs with the session restore code. Disabling // if ( app->isSessionRestored() ) // Toplevel->restore( 1 ); Toplevel->show(); KSGRD::SensorMgr->setBroadcaster( Toplevel ); // SensorMgr uses a QPointer for toplevel, so it is okay if Toplevel is deleted first // register to DBus const KDBusService dbusService(KDBusService::Multiple); // run the application int result = app.exec(); delete KSGRD::SensorMgr; delete KSGRD::Style; return result; }