kde-workspace/plasma/applets/system-monitor/hdd_activity.cpp
Ivailo Monev efbde9e504 plasma: organize sub-directories
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2015-12-24 22:48:47 +02:00

291 lines
9 KiB
C++

/*
* Copyright (C) 2011, 2012 Shaun Reich <shaun.reich@kdemail.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library 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 "hdd_activity.h"
#include "monitoricon.h"
#include "plotter.h"
#include <KDebug>
#include <KConfigDialog>
#include <KColorUtils>
#include <QFileInfo>
#include <QGraphicsLinearLayout>
#include <Plasma/Meter>
#include <Plasma/Containment>
#include <Plasma/Theme>
#include <Plasma/ToolTipManager>
/**
* Examples of what the regexp has to handle...
*
* Note actually it's now set to an inclusive-only mode, far cleaner.
*
* Included items only:
*
*
* RAID blocks (there *could* be more if not using mdadm, I think):
*
* disk/md<something>/Rate/rio
* disk/md<something>/Rate/wio
*
* SATA disks:
*
* disk/sd<something>/Rate/rio
* disk/sd<something>/Rate/wio
*
* IDE/PATA disks:
*
* disk/hd<something>/Rate/rio
* disk/hd<something>/Rate/wio
*
* Does NOT include partitions, since I don't think many people will use that.
*
* RAID regexp handling needs further testing, I have a feeling it works just for me.
*
*/
Hdd_Activity::Hdd_Activity(QObject *parent, const QVariantList &args)
: SM::Applet(parent, args),
m_regexp("disk/(?:md|sd|hd)[a-z|0-9]_.*/Rate/(?:rblk|wblk)")
{
setHasConfigurationInterface(true);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}
Hdd_Activity::~Hdd_Activity()
{
}
void Hdd_Activity::init()
{
KGlobal::locale()->insertCatalog("plasma_applet_system-monitor");
setEngine(dataEngine("systemmonitor"));
setTitle(i18n("Disk Activity"));
/* At the time this method is running, not all sources may be connected. */
connect(engine(), SIGNAL(sourceAdded(QString)), this, SLOT(sourceChanged(QString)));
connect(engine(), SIGNAL(sourceRemoved(QString)), this, SLOT(sourceChanged(QString)));
foreach (const QString& source, engine()->sources()) {
sourceChanged(source);
}
configChanged();
}
void Hdd_Activity::sourceChanged(const QString& name)
{
//kDebug() << "######## sourceChanged name: " << name;
//kDebug() << "###### regexp captures: " << m_regexp.capturedTexts();
if (m_regexp.indexIn(name) != -1) {
m_possibleHdds.append(name);
}
}
void Hdd_Activity::sourcesChanged()
{
configChanged();
}
void Hdd_Activity::dataUpdated(const QString& source, const Plasma::DataEngine::Data &data)
{
const double value = data["value"].toDouble();
QVector<double>& valueVector = m_data[source];
if (valueVector.size() < 2) {
valueVector.resize(2);
}
QString sneakySource = source;
// we're interested in all source for a device which are
// rblk and wblk. however, only 1 vis per that. so it wouldn't be unique and we'd only
// get the values for rblk.
// so add data to the hash, since we obtain the pair
// on separate dataUpdated calls, so we'll need to map them
if (sneakySource.endsWith("rblk")) {
valueVector[0] = value;
} else if (sneakySource.endsWith("wblk")) {
valueVector[1] = value;
//make the source *appear* to be a rblk.
sneakySource.remove("wblk");
sneakySource.append("rblk");
}
// we look up the visualization that is /...disk/rblk only. there is
// not a rblk vis, so one just holds all data.
SM::Plotter *plotter = qobject_cast<SM::Plotter*>(visualization(sneakySource));
// plotter is invalid if we're e.g. switching monitored stuff
if (!plotter) {
return;
}
//only graph it if it's got both rblk and wblk
if (valueVector.count() == 2) {
QString read = KGlobal::locale()->formatNumber(valueVector.at(0), 1);
QString write = KGlobal::locale()->formatNumber(valueVector.at(1), 1);
//FIXME: allow plotter->addSample overload for QVector.
plotter->addSample(valueVector.toList());
if (mode() == SM::Applet::Panel) {
const QString tooltip = QString("<tr><td>%1&nbsp;</td><td>rio: %2%</td><td>wio: %3</td></tr>")
.arg(plotter->title()).arg(read).arg(write);
setToolTip(source, tooltip);
}
}
}
void Hdd_Activity::createConfigurationInterface(KConfigDialog *parent)
{
QWidget *widget = new QWidget();
ui.setupUi(widget);
m_hddModel.clear();
m_hddModel.setHorizontalHeaderLabels(QStringList() << i18n("Name"));
QStandardItem *parentItem = m_hddModel.invisibleRootItem();
foreach (const QString& hdd, m_possibleHdds) {
if (m_regexp.indexIn(hdd) != -1) {
if (hdd.endsWith("rblk")) {
// so the user only sees 1 device (which includes both rblk/wblk
QString trimmedHdd = hdd;
trimmedHdd.remove("rblk");
QStandardItem *item1 = new QStandardItem(trimmedHdd);
item1->setEditable(false);
item1->setCheckable(true);
// store the pair of real sources (rblk, wblk) into data
QStringList realSources;
realSources.append(trimmedHdd + "rblk");
realSources.append(trimmedHdd + "wblk");
item1->setData(realSources);
// but the behind the scenes still uses the source separation,
// so be sure to use that.
if (sources().contains(hdd)) {
item1->setCheckState(Qt::Checked);
}
parentItem->appendRow(QList<QStandardItem *>() << item1);
}
}
}
ui.treeView->setModel(&m_hddModel);
ui.treeView->resizeColumnToContents(0);
ui.intervalSpinBox->setValue(interval() / 1000.0);
ui.intervalSpinBox->setSuffix(i18nc("second", " s"));
parent->addPage(widget, i18n("Hard Disks"), "drive-harddisk");
connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
connect(ui.treeView, SIGNAL(clicked(QModelIndex)), parent, SLOT(settingsModified()));
connect(ui.intervalSpinBox, SIGNAL(valueChanged(QString)), parent, SLOT(settingsModified()));
}
void Hdd_Activity::configChanged()
{
//kDebug() << "#### configChanged m_hdds:" << m_hdds;
KConfigGroup cg = config();
QStringList default_hdds = m_possibleHdds;
// default to 2 seconds (2000 ms interval
setInterval(cg.readEntry("interval", 2.0) * 1000.0);
setSources(cg.readEntry("hdds", default_hdds));
connectToEngine();
}
void Hdd_Activity::configAccepted()
{
KConfigGroup cg = config();
QStandardItem *parentItem = m_hddModel.invisibleRootItem();
clear();
for (int i = 0; i < parentItem->rowCount(); ++i) {
QStandardItem *item = parentItem->child(i, 0);
if (item) {
if (item->checkState() == Qt::Checked) {
QStringList actualSources = item->data().toStringList();
const QString& rblk = actualSources.at(0);
const QString& wblk = actualSources.at(1);
appendSource(rblk);
appendSource(wblk);
}
}
}
cg.writeEntry("hdds", sources());
uint interval = ui.intervalSpinBox->value();
cg.writeEntry("interval", interval);
emit configNeedsSaving();
}
bool Hdd_Activity::addVisualization(const QString& source)
{
QStringList splits = source.split('/');
// 0 == "disk" 1 == "sde_(8:64)" 2 == "Rate" 3 == "rblk"
Q_ASSERT(splits.count() == 4);
// only monitor rblk for each device. we watch all sources/connect to them
// but only need 1 vis per actual device (otherwise there'd be 1 for rblk, 1
// for wblk, which isn't what I have in mind -sreich
if (splits.at(3) == "rblk") {
QString hdd = source;
hdd = hdd.remove("rblk");
//kDebug() << "#### ADD VIS hdd: " << hdd;
SM::Plotter *plotter = new SM::Plotter(this);
plotter->setTitle(hdd);
// FIXME: localize properly..including units.
// ksysguard just gives us 1024 KiB for sources, we need to convert for anything else.
plotter->setUnit("KiB/s");
// should be read, write, respectively
plotter->setCustomPlots(QList<QColor>() << QColor("#0057AE") << QColor("#E20800"));
appendVisualization(source, plotter);
setPreferredItemHeight(80);
}
// if we return false here, it thinks we don't want
// source updates for this source
// which makes sense (since there's no vis). but not in
// this case.
return true;
}
#include "moc_hdd_activity.cpp"