Changeset View
Standalone View
processui/ProcessModel.cpp
Show All 20 Lines | |||||
21 | 21 | | |||
22 | */ | 22 | */ | ||
23 | 23 | | |||
24 | 24 | | |||
25 | #include "ProcessModel.h" | 25 | #include "ProcessModel.h" | ||
26 | #include "ProcessModel_p.h" | 26 | #include "ProcessModel_p.h" | ||
27 | #include "timeutil.h" | 27 | #include "timeutil.h" | ||
28 | 28 | | |||
29 | #include "processcore/processes.h" | 29 | #include "processcore/extended_process_list.h" | ||
30 | #include "processcore/process_data_provider.h" | ||||
30 | #include "processcore/process.h" | 31 | #include "processcore/process.h" | ||
32 | #include "processcore/formatter.h" | ||||
33 | | ||||
31 | #include "processui_debug.h" | 34 | #include "processui_debug.h" | ||
32 | 35 | | |||
33 | #include <kcolorscheme.h> | 36 | #include <kcolorscheme.h> | ||
34 | #include <kiconloader.h> | 37 | #include <kiconloader.h> | ||
35 | #include <KLocalizedString> | 38 | #include <KLocalizedString> | ||
36 | #include <KFormat> | 39 | #include <KFormat> | ||
37 | #include <QApplication> | 40 | #include <QApplication> | ||
38 | #include <QBitmap> | 41 | #include <QBitmap> | ||
▲ Show 20 Lines • Show All 303 Lines • ▼ Show 20 Line(s) | 344 | case ProcessModel::BytesRate: | |||
342 | return processLeft->ioCharactersWrittenRate() > processRight->ioCharactersWrittenRate(); | 345 | return processLeft->ioCharactersWrittenRate() > processRight->ioCharactersWrittenRate(); | ||
343 | case ProcessModel::SyscallsRate: | 346 | case ProcessModel::SyscallsRate: | ||
344 | return processLeft->ioWriteSyscallsRate() > processRight->ioWriteSyscallsRate(); | 347 | return processLeft->ioWriteSyscallsRate() > processRight->ioWriteSyscallsRate(); | ||
345 | case ProcessModel::ActualBytesRate: | 348 | case ProcessModel::ActualBytesRate: | ||
346 | return processLeft->ioCharactersActuallyWrittenRate() > processRight->ioCharactersActuallyWrittenRate(); | 349 | return processLeft->ioCharactersActuallyWrittenRate() > processRight->ioCharactersActuallyWrittenRate(); | ||
347 | } | 350 | } | ||
348 | } | 351 | } | ||
349 | //Sort by the display string if we do not have an explicit sorting here | 352 | //Sort by the display string if we do not have an explicit sorting here | ||
353 | | ||||
354 | if (data(left, ProcessModel::PlainValueRole).toInt() == data(right, ProcessModel::PlainValueRole).toInt()) { | ||||
350 | return data(left, Qt::DisplayRole).toString() < data(right, Qt::DisplayRole).toString(); | 355 | return data(left, Qt::DisplayRole).toString() < data(right, Qt::DisplayRole).toString(); | ||
351 | } | 356 | } | ||
357 | return data(left, ProcessModel::PlainValueRole).toInt() < data(right, ProcessModel::PlainValueRole).toInt(); | ||||
358 | } | ||||
352 | 359 | | |||
353 | ProcessModel::~ProcessModel() | 360 | ProcessModel::~ProcessModel() | ||
354 | { | 361 | { | ||
355 | delete d; | 362 | delete d; | ||
356 | } | 363 | } | ||
357 | 364 | | |||
358 | KSysGuard::Processes *ProcessModel::processController() const | 365 | KSysGuard::Processes *ProcessModel::processController() const | ||
359 | { | 366 | { | ||
▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Line(s) | 490 | #ifdef Q_WS_X11_DISABLE | |||
485 | mPidToWindowInfo.clear(); | 492 | mPidToWindowInfo.clear(); | ||
486 | #endif | 493 | #endif | ||
487 | delete mProcesses; | 494 | delete mProcesses; | ||
488 | mProcesses = nullptr; | 495 | mProcesses = nullptr; | ||
489 | q->beginResetModel(); | 496 | q->beginResetModel(); | ||
490 | q->endResetModel(); | 497 | q->endResetModel(); | ||
491 | } | 498 | } | ||
492 | 499 | | |||
493 | mProcesses = new KSysGuard::Processes(mHostName); | 500 | mProcesses = new KSysGuard::ExtendedProcesses(); | ||
494 | 501 | | |||
495 | connect( mProcesses, &KSysGuard::Processes::processChanged, this, &ProcessModelPrivate::processChanged); | 502 | connect( mProcesses, &KSysGuard::Processes::processChanged, this, &ProcessModelPrivate::processChanged); | ||
496 | connect( mProcesses, &KSysGuard::Processes::beginAddProcess, this, &ProcessModelPrivate::beginInsertRow); | 503 | connect( mProcesses, &KSysGuard::Processes::beginAddProcess, this, &ProcessModelPrivate::beginInsertRow); | ||
497 | connect( mProcesses, &KSysGuard::Processes::endAddProcess, this, &ProcessModelPrivate::endInsertRow); | 504 | connect( mProcesses, &KSysGuard::Processes::endAddProcess, this, &ProcessModelPrivate::endInsertRow); | ||
498 | connect( mProcesses, &KSysGuard::Processes::beginRemoveProcess, this, &ProcessModelPrivate::beginRemoveRow); | 505 | connect( mProcesses, &KSysGuard::Processes::beginRemoveProcess, this, &ProcessModelPrivate::beginRemoveRow); | ||
499 | connect( mProcesses, &KSysGuard::Processes::endRemoveProcess, this, &ProcessModelPrivate::endRemoveRow); | 506 | connect( mProcesses, &KSysGuard::Processes::endRemoveProcess, this, &ProcessModelPrivate::endRemoveRow); | ||
500 | connect( mProcesses, &KSysGuard::Processes::beginMoveProcess, this, | 507 | connect( mProcesses, &KSysGuard::Processes::beginMoveProcess, this, | ||
501 | &ProcessModelPrivate::beginMoveProcess); | 508 | &ProcessModelPrivate::beginMoveProcess); | ||
502 | connect( mProcesses, &KSysGuard::Processes::endMoveProcess, this, &ProcessModelPrivate::endMoveRow); | 509 | connect( mProcesses, &KSysGuard::Processes::endMoveProcess, this, &ProcessModelPrivate::endMoveRow); | ||
503 | mNumProcessorCores = mProcesses->numberProcessorCores(); | 510 | mNumProcessorCores = mProcesses->numberProcessorCores(); | ||
504 | if(mNumProcessorCores < 1) mNumProcessorCores=1; //Default to 1 if there was an error getting the number | 511 | if(mNumProcessorCores < 1) mNumProcessorCores=1; //Default to 1 if there was an error getting the number | ||
512 | | ||||
513 | mExtraAttributes = mProcesses->attributes(); | ||||
514 | for (int i = 0 ; i < mExtraAttributes.count(); i ++) { | ||||
515 | mExtraAttributes[i]->setEnabled(true); // In future we will toggle this based on column visibility | ||||
broulik: Store `mExtraAttributes` in a variable | |||||
516 | | ||||
517 | connect(mExtraAttributes[i], &KSysGuard::ProcessAttribute::dataChanged, this, [this, i](KSysGuard::Process *process) { | ||||
518 | const QModelIndex index = q->getQModelIndex(process, mHeadings.count() + i); | ||||
Can this become out of sync, given you capture i as a copy into the lambda? broulik: Can this become out of sync, given you capture `i` as a copy into the lambda? | |||||
If mExtraAttributes changed during the lifespan, it would, but that currently doesn't happen. We show all columns and then enable or disable them to populate updates. davidedmundson: If mExtraAttributes changed during the lifespan, it would, but that currently doesn't happen. | |||||
519 | emit q->dataChanged(index, index); | ||||
520 | }); | ||||
521 | } | ||||
505 | } | 522 | } | ||
506 | 523 | | |||
507 | #if HAVE_X11 | 524 | #if HAVE_X11 | ||
508 | void ProcessModelPrivate::windowChanged(WId wid, unsigned int properties) | 525 | void ProcessModelPrivate::windowChanged(WId wid, unsigned int properties) | ||
509 | { | 526 | { | ||
510 | updateWindowInfo(wid, properties, false); | 527 | updateWindowInfo(wid, properties, false); | ||
511 | } | 528 | } | ||
512 | 529 | | |||
▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Line(s) | 643 | { | |||
639 | } | 656 | } | ||
640 | Q_ASSERT(process); | 657 | Q_ASSERT(process); | ||
641 | int num_rows = process->children().count(); | 658 | int num_rows = process->children().count(); | ||
642 | return num_rows; | 659 | return num_rows; | ||
643 | } | 660 | } | ||
644 | 661 | | |||
645 | int ProcessModel::columnCount ( const QModelIndex & ) const | 662 | int ProcessModel::columnCount ( const QModelIndex & ) const | ||
646 | { | 663 | { | ||
647 | return d->mHeadings.count(); | 664 | return d->mHeadings.count() + d->mExtraAttributes.count(); | ||
648 | } | 665 | } | ||
649 | 666 | | |||
650 | bool ProcessModel::hasChildren ( const QModelIndex & parent = QModelIndex() ) const | 667 | bool ProcessModel::hasChildren ( const QModelIndex & parent = QModelIndex() ) const | ||
651 | { | 668 | { | ||
652 | 669 | | |||
653 | if(d->mSimple) { | 670 | if(d->mSimple) { | ||
654 | if(parent.isValid()) return 0; //In flat mode, none of the processes have children | 671 | if(parent.isValid()) return 0; //In flat mode, none of the processes have children | ||
655 | return !d->mProcesses->getAllProcesses().isEmpty(); | 672 | return !d->mProcesses->getAllProcesses().isEmpty(); | ||
Show All 12 Lines | |||||
668 | 685 | | |||
669 | Q_ASSERT((rowCount(parent) > 0) == has_children); | 686 | Q_ASSERT((rowCount(parent) > 0) == has_children); | ||
670 | return has_children; | 687 | return has_children; | ||
671 | } | 688 | } | ||
672 | 689 | | |||
673 | QModelIndex ProcessModel::index ( int row, int column, const QModelIndex & parent ) const | 690 | QModelIndex ProcessModel::index ( int row, int column, const QModelIndex & parent ) const | ||
674 | { | 691 | { | ||
675 | if(row<0) return QModelIndex(); | 692 | if(row<0) return QModelIndex(); | ||
676 | if(column<0 || column >= d->mHeadings.count() ) return QModelIndex(); | 693 | if(column<0 || column >= columnCount() ) return QModelIndex(); | ||
677 | 694 | | |||
678 | if(d->mSimple) { | 695 | if(d->mSimple) { | ||
679 | if( parent.isValid()) return QModelIndex(); | 696 | if( parent.isValid()) return QModelIndex(); | ||
680 | if( d->mProcesses->processCount() <= row) return QModelIndex(); | 697 | if( d->mProcesses->processCount() <= row) return QModelIndex(); | ||
681 | return createIndex( row, column, d->mProcesses->getAllProcesses().at(row)); | 698 | return createIndex( row, column, d->mProcesses->getAllProcesses().at(row)); | ||
682 | } | 699 | } | ||
683 | 700 | | |||
684 | //Deal with the case that we are showing it as a tree | 701 | //Deal with the case that we are showing it as a tree | ||
▲ Show 20 Lines • Show All 270 Lines • ▼ Show 20 Line(s) | 971 | else | |||
955 | return getQModelIndex(process->parent(), 0); | 972 | return getQModelIndex(process->parent(), 0); | ||
956 | } | 973 | } | ||
957 | 974 | | |||
958 | QVariant ProcessModel::headerData(int section, Qt::Orientation orientation, | 975 | QVariant ProcessModel::headerData(int section, Qt::Orientation orientation, | ||
959 | int role) const | 976 | int role) const | ||
960 | { | 977 | { | ||
961 | if(orientation != Qt::Horizontal) | 978 | if(orientation != Qt::Horizontal) | ||
962 | return QVariant(); | 979 | return QVariant(); | ||
963 | if(section < 0 || section >= d->mHeadings.count()) | 980 | if(section < 0) | ||
964 | return QVariant(); //is this needed? | 981 | return QVariant(); //is this needed? | ||
982 | | ||||
983 | if (section >= d->mHeadings.count() && section < columnCount()) { | ||||
So when you now request a column >= columnCount() this cndition won't be met and you potentially access out of bounds below somewhere broulik: So when you now request a column >= `columnCount()` this cndition won't be met and you… | |||||
984 | int attr = section - d->mHeadings.count(); | ||||
985 | switch (role) { | ||||
986 | case Qt::DisplayRole: | ||||
987 | return d->mExtraAttributes[attr]->shortName(); | ||||
988 | } | ||||
989 | return QVariant(); | ||||
990 | } | ||||
991 | | ||||
965 | switch( role ) { | 992 | switch( role ) { | ||
966 | case Qt::TextAlignmentRole: | 993 | case Qt::TextAlignmentRole: | ||
967 | { | 994 | { | ||
968 | switch(section) { | 995 | switch(section) { | ||
969 | case HeadingPid: | 996 | case HeadingPid: | ||
970 | case HeadingTty: | 997 | case HeadingTty: | ||
971 | case HeadingMemory: | 998 | case HeadingMemory: | ||
972 | case HeadingXMemory: | 999 | case HeadingXMemory: | ||
▲ Show 20 Lines • Show All 272 Lines • ▼ Show 20 Line(s) | 1257 | QString ProcessModelPrivate::getUsernameForUser(long uid, bool withuid) const { | |||
1245 | if(withuid) | 1272 | if(withuid) | ||
1246 | return i18nc("User name and user id", "%1 (uid: %2)", username, (long int)uid); | 1273 | return i18nc("User name and user id", "%1 (uid: %2)", username, (long int)uid); | ||
1247 | return username; | 1274 | return username; | ||
1248 | } | 1275 | } | ||
1249 | 1276 | | |||
1250 | QVariant ProcessModel::data(const QModelIndex &index, int role) const | 1277 | QVariant ProcessModel::data(const QModelIndex &index, int role) const | ||
1251 | { | 1278 | { | ||
1252 | //This function must be super duper ultra fast because it's called thousands of times every few second :( | 1279 | //This function must be super duper ultra fast because it's called thousands of times every few second :( | ||
1253 | //I think it should be optomised for role first, hence the switch statement (fastest possible case) | 1280 | //I think it should be optimised for role first, hence the switch statement (fastest possible case) | ||
1254 | 1281 | | |||
1255 | if (!index.isValid()) { | 1282 | if (!index.isValid()) { | ||
1256 | return QVariant(); | 1283 | return QVariant(); | ||
1257 | } | 1284 | } | ||
1285 | | ||||
1286 | if (index.column() > columnCount()) { | ||||
1287 | return QVariant(); | ||||
1288 | } | ||||
1289 | //plugin stuff first | ||||
1258 | if (index.column() >= d->mHeadings.count()) { | 1290 | if (index.column() >= d->mHeadings.count()) { | ||
1291 | int attr = index.column() - d->mHeadings.count(); | ||||
1292 | switch (role) { | ||||
1293 | case ProcessModel::PlainValueRole: { | ||||
1294 | KSysGuard::Process *process = reinterpret_cast< KSysGuard::Process * > (index.internalPointer()); | ||||
1295 | const QVariant value = d->mExtraAttributes[attr]->data(process); | ||||
1296 | return value; | ||||
1297 | } | ||||
1298 | case Qt::DisplayRole: { | ||||
1299 | KSysGuard::Process *process = reinterpret_cast< KSysGuard::Process * > (index.internalPointer()); | ||||
1300 | const QVariant value = d->mExtraAttributes[attr]->data(process); | ||||
1301 | return KSysGuard::Formatter::formatValue(value, d->mExtraAttributes[attr]->unit()); | ||||
1302 | } | ||||
1303 | case Qt::TextAlignmentRole: { | ||||
1304 | KSysGuard::Process *process = reinterpret_cast< KSysGuard::Process * > (index.internalPointer()); | ||||
1305 | const QVariant value = d->mExtraAttributes[attr]->data(process); | ||||
1306 | if (value.canConvert(QMetaType::LongLong) | ||||
1307 | && static_cast<QMetaType::Type>(value.type()) != QMetaType::QString) { | ||||
1308 | return Qt::AlignRight + Qt::AlignVCenter; | ||||
1309 | } | ||||
broulik: `value.type() == QVariant::String`? | |||||
from qt docs: Returns the storage type of the value stored in the variant. Although this function is declared as returning QVariant::Type, the return value should be interpreted as QMetaType::Type. In particular, QVariant::UserType is returned here only if the value is equal or greater than QMetaType::User. davidedmundson: from qt docs:
Returns the storage type of the value stored in the variant. Although this… | |||||
1310 | return Qt::AlignLeft + Qt::AlignVCenter; | ||||
Shouldn't those be or'd together? Interestingly, Qt documentation also uses addition. broulik: Shouldn't those be or'd together? Interestingly, Qt documentation also uses addition. | |||||
For independent flags it's the same thing. Can change if you like, but it matches the docs. davidedmundson: For independent flags it's the same thing.
Can change if you like, but it matches the docs. | |||||
1311 | } | ||||
1312 | } | ||||
1259 | return QVariant(); | 1313 | return QVariant(); | ||
1260 | } | 1314 | } | ||
1261 | 1315 | | |||
1262 | KFormat format; | 1316 | KFormat format; | ||
1263 | switch (role){ | 1317 | switch (role){ | ||
1264 | case Qt::DisplayRole: { | 1318 | case Qt::DisplayRole: { | ||
1265 | KSysGuard::Process *process = reinterpret_cast< KSysGuard::Process * > (index.internalPointer()); | 1319 | KSysGuard::Process *process = reinterpret_cast< KSysGuard::Process * > (index.internalPointer()); | ||
1266 | switch(index.column()) { | 1320 | switch(index.column()) { | ||
▲ Show 20 Lines • Show All 719 Lines • ▼ Show 20 Line(s) | 2039 | if (d->mIsX11) { | |||
1986 | headings << i18nc("process heading", "X11 Memory"); | 2040 | headings << i18nc("process heading", "X11 Memory"); | ||
1987 | headings << i18nc("process heading", "Window Title"); | 2041 | headings << i18nc("process heading", "Window Title"); | ||
1988 | } | 2042 | } | ||
1989 | #endif | 2043 | #endif | ||
1990 | headings << i18nc("process heading", "CGroup"); | 2044 | headings << i18nc("process heading", "CGroup"); | ||
1991 | headings << i18nc("process heading", "MAC Context"); | 2045 | headings << i18nc("process heading", "MAC Context"); | ||
1992 | 2046 | | |||
1993 | if(d->mHeadings.isEmpty()) { // If it's empty, this is the first time this has been called, so insert the headings | 2047 | if(d->mHeadings.isEmpty()) { // If it's empty, this is the first time this has been called, so insert the headings | ||
1994 | beginInsertColumns(QModelIndex(), 0, headings.count()-1); | | |||
1995 | { | | |||
1996 | d->mHeadings = headings; | 2048 | d->mHeadings = headings; | ||
1997 | } | | |||
1998 | endInsertColumns(); | | |||
1999 | } else { | 2049 | } else { | ||
2000 | // This was called to retranslate the headings. Just use the new translations and call headerDataChanged | 2050 | // This was called to retranslate the headings. Just use the new translations and call headerDataChanged | ||
2001 | Q_ASSERT(d->mHeadings.count() == headings.count()); | 2051 | Q_ASSERT(d->mHeadings.count() == headings.count()); | ||
2002 | d->mHeadings = headings; | 2052 | d->mHeadings = headings; | ||
2003 | headerDataChanged(Qt::Horizontal, 0 , headings.count()-1); | 2053 | headerDataChanged(Qt::Horizontal, 0 , headings.count()-1); | ||
2004 | 2054 | | |||
2005 | } | 2055 | } | ||
2006 | } | 2056 | } | ||
▲ Show 20 Lines • Show All 261 Lines • Show Last 20 Lines |
Store mExtraAttributes in a variable