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