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 306 Lines • ▼ Show 20 Line(s) | 348 | case ProcessModel::BytesRate: | |||
345 | return processLeft->ioCharactersWrittenRate() > processRight->ioCharactersWrittenRate(); | 349 | return processLeft->ioCharactersWrittenRate() > processRight->ioCharactersWrittenRate(); | ||
346 | case ProcessModel::SyscallsRate: | 350 | case ProcessModel::SyscallsRate: | ||
347 | return processLeft->ioWriteSyscallsRate() > processRight->ioWriteSyscallsRate(); | 351 | return processLeft->ioWriteSyscallsRate() > processRight->ioWriteSyscallsRate(); | ||
348 | case ProcessModel::ActualBytesRate: | 352 | case ProcessModel::ActualBytesRate: | ||
349 | return processLeft->ioCharactersActuallyWrittenRate() > processRight->ioCharactersActuallyWrittenRate(); | 353 | return processLeft->ioCharactersActuallyWrittenRate() > processRight->ioCharactersActuallyWrittenRate(); | ||
350 | } | 354 | } | ||
351 | } | 355 | } | ||
352 | //Sort by the display string if we do not have an explicit sorting here | 356 | //Sort by the display string if we do not have an explicit sorting here | ||
357 | | ||||
358 | if (data(left, ProcessModel::PlainValueRole).toInt() == data(right, ProcessModel::PlainValueRole).toInt()) { | ||||
353 | return data(left, Qt::DisplayRole).toString() < data(right, Qt::DisplayRole).toString(); | 359 | return data(left, Qt::DisplayRole).toString() < data(right, Qt::DisplayRole).toString(); | ||
354 | } | 360 | } | ||
361 | return data(left, ProcessModel::PlainValueRole).toInt() < data(right, ProcessModel::PlainValueRole).toInt(); | ||||
362 | } | ||||
355 | 363 | | |||
356 | ProcessModel::~ProcessModel() | 364 | ProcessModel::~ProcessModel() | ||
357 | { | 365 | { | ||
358 | delete d; | 366 | delete d; | ||
359 | } | 367 | } | ||
360 | 368 | | |||
361 | KSysGuard::Processes *ProcessModel::processController() const | 369 | KSysGuard::Processes *ProcessModel::processController() const | ||
362 | { | 370 | { | ||
▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Line(s) | 494 | #ifdef Q_WS_X11_DISABLE | |||
488 | mPidToWindowInfo.clear(); | 496 | mPidToWindowInfo.clear(); | ||
489 | #endif | 497 | #endif | ||
490 | delete mProcesses; | 498 | delete mProcesses; | ||
491 | mProcesses = nullptr; | 499 | mProcesses = nullptr; | ||
492 | q->beginResetModel(); | 500 | q->beginResetModel(); | ||
493 | q->endResetModel(); | 501 | q->endResetModel(); | ||
494 | } | 502 | } | ||
495 | 503 | | |||
496 | mProcesses = new KSysGuard::Processes(mHostName); | 504 | mProcesses = new KSysGuard::ExtendedProcesses(); | ||
497 | 505 | | |||
498 | connect( mProcesses, &KSysGuard::Processes::processChanged, this, &ProcessModelPrivate::processChanged); | 506 | connect( mProcesses, &KSysGuard::Processes::processChanged, this, &ProcessModelPrivate::processChanged); | ||
499 | connect( mProcesses, &KSysGuard::Processes::beginAddProcess, this, &ProcessModelPrivate::beginInsertRow); | 507 | connect( mProcesses, &KSysGuard::Processes::beginAddProcess, this, &ProcessModelPrivate::beginInsertRow); | ||
500 | connect( mProcesses, &KSysGuard::Processes::endAddProcess, this, &ProcessModelPrivate::endInsertRow); | 508 | connect( mProcesses, &KSysGuard::Processes::endAddProcess, this, &ProcessModelPrivate::endInsertRow); | ||
501 | connect( mProcesses, &KSysGuard::Processes::beginRemoveProcess, this, &ProcessModelPrivate::beginRemoveRow); | 509 | connect( mProcesses, &KSysGuard::Processes::beginRemoveProcess, this, &ProcessModelPrivate::beginRemoveRow); | ||
502 | connect( mProcesses, &KSysGuard::Processes::endRemoveProcess, this, &ProcessModelPrivate::endRemoveRow); | 510 | connect( mProcesses, &KSysGuard::Processes::endRemoveProcess, this, &ProcessModelPrivate::endRemoveRow); | ||
503 | connect( mProcesses, &KSysGuard::Processes::beginMoveProcess, this, | 511 | connect( mProcesses, &KSysGuard::Processes::beginMoveProcess, this, | ||
504 | &ProcessModelPrivate::beginMoveProcess); | 512 | &ProcessModelPrivate::beginMoveProcess); | ||
505 | connect( mProcesses, &KSysGuard::Processes::endMoveProcess, this, &ProcessModelPrivate::endMoveRow); | 513 | connect( mProcesses, &KSysGuard::Processes::endMoveProcess, this, &ProcessModelPrivate::endMoveRow); | ||
506 | mNumProcessorCores = mProcesses->numberProcessorCores(); | 514 | mNumProcessorCores = mProcesses->numberProcessorCores(); | ||
507 | if(mNumProcessorCores < 1) mNumProcessorCores=1; //Default to 1 if there was an error getting the number | 515 | if(mNumProcessorCores < 1) mNumProcessorCores=1; //Default to 1 if there was an error getting the number | ||
516 | | ||||
517 | mExtraAttributes = mProcesses->attributes(); | ||||
518 | for (int i = 0 ; i < mExtraAttributes.count(); i ++) { | ||||
519 | mExtraAttributes[i]->setEnabled(true); // In future we will toggle this based on column visibility | ||||
broulik: Store `mExtraAttributes` in a variable | |||||
520 | | ||||
521 | connect(mExtraAttributes[i], &KSysGuard::ProcessAttribute::dataChanged, this, [this, i](KSysGuard::Process *process) { | ||||
522 | 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. | |||||
523 | emit q->dataChanged(index, index); | ||||
524 | }); | ||||
525 | } | ||||
508 | } | 526 | } | ||
509 | 527 | | |||
510 | #if HAVE_X11 | 528 | #if HAVE_X11 | ||
511 | void ProcessModelPrivate::windowChanged(WId wid, unsigned int properties) | 529 | void ProcessModelPrivate::windowChanged(WId wid, unsigned int properties) | ||
512 | { | 530 | { | ||
513 | updateWindowInfo(wid, properties, false); | 531 | updateWindowInfo(wid, properties, false); | ||
514 | } | 532 | } | ||
515 | 533 | | |||
▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Line(s) | 647 | { | |||
642 | } | 660 | } | ||
643 | Q_ASSERT(process); | 661 | Q_ASSERT(process); | ||
644 | int num_rows = process->children().count(); | 662 | int num_rows = process->children().count(); | ||
645 | return num_rows; | 663 | return num_rows; | ||
646 | } | 664 | } | ||
647 | 665 | | |||
648 | int ProcessModel::columnCount ( const QModelIndex & ) const | 666 | int ProcessModel::columnCount ( const QModelIndex & ) const | ||
649 | { | 667 | { | ||
650 | return d->mHeadings.count(); | 668 | return d->mHeadings.count() + d->mExtraAttributes.count(); | ||
651 | } | 669 | } | ||
652 | 670 | | |||
653 | bool ProcessModel::hasChildren ( const QModelIndex & parent = QModelIndex() ) const | 671 | bool ProcessModel::hasChildren ( const QModelIndex & parent = QModelIndex() ) const | ||
654 | { | 672 | { | ||
655 | 673 | | |||
656 | if(d->mSimple) { | 674 | if(d->mSimple) { | ||
657 | if(parent.isValid()) return 0; //In flat mode, none of the processes have children | 675 | if(parent.isValid()) return 0; //In flat mode, none of the processes have children | ||
658 | return !d->mProcesses->getAllProcesses().isEmpty(); | 676 | return !d->mProcesses->getAllProcesses().isEmpty(); | ||
Show All 12 Lines | |||||
671 | 689 | | |||
672 | Q_ASSERT((rowCount(parent) > 0) == has_children); | 690 | Q_ASSERT((rowCount(parent) > 0) == has_children); | ||
673 | return has_children; | 691 | return has_children; | ||
674 | } | 692 | } | ||
675 | 693 | | |||
676 | QModelIndex ProcessModel::index ( int row, int column, const QModelIndex & parent ) const | 694 | QModelIndex ProcessModel::index ( int row, int column, const QModelIndex & parent ) const | ||
677 | { | 695 | { | ||
678 | if(row<0) return QModelIndex(); | 696 | if(row<0) return QModelIndex(); | ||
679 | if(column<0 || column >= d->mHeadings.count() ) return QModelIndex(); | 697 | if(column<0 || column >= columnCount() ) return QModelIndex(); | ||
680 | 698 | | |||
681 | if(d->mSimple) { | 699 | if(d->mSimple) { | ||
682 | if( parent.isValid()) return QModelIndex(); | 700 | if( parent.isValid()) return QModelIndex(); | ||
683 | if( d->mProcesses->processCount() <= row) return QModelIndex(); | 701 | if( d->mProcesses->processCount() <= row) return QModelIndex(); | ||
684 | return createIndex( row, column, d->mProcesses->getAllProcesses().at(row)); | 702 | return createIndex( row, column, d->mProcesses->getAllProcesses().at(row)); | ||
685 | } | 703 | } | ||
686 | 704 | | |||
687 | //Deal with the case that we are showing it as a tree | 705 | //Deal with the case that we are showing it as a tree | ||
▲ Show 20 Lines • Show All 275 Lines • ▼ Show 20 Line(s) | 980 | else | |||
963 | return getQModelIndex(process->parent(), 0); | 981 | return getQModelIndex(process->parent(), 0); | ||
964 | } | 982 | } | ||
965 | 983 | | |||
966 | QVariant ProcessModel::headerData(int section, Qt::Orientation orientation, | 984 | QVariant ProcessModel::headerData(int section, Qt::Orientation orientation, | ||
967 | int role) const | 985 | int role) const | ||
968 | { | 986 | { | ||
969 | if(orientation != Qt::Horizontal) | 987 | if(orientation != Qt::Horizontal) | ||
970 | return QVariant(); | 988 | return QVariant(); | ||
971 | if(section < 0 || section >= d->mHeadings.count()) | 989 | if(section < 0) | ||
972 | return QVariant(); //is this needed? | 990 | return QVariant(); //is this needed? | ||
991 | | ||||
992 | 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… | |||||
993 | int attr = section - d->mHeadings.count(); | ||||
994 | switch (role) { | ||||
995 | case Qt::DisplayRole: | ||||
996 | return d->mExtraAttributes[attr]->shortName(); | ||||
997 | } | ||||
998 | return QVariant(); | ||||
999 | } | ||||
1000 | | ||||
973 | switch( role ) { | 1001 | switch( role ) { | ||
974 | case Qt::TextAlignmentRole: | 1002 | case Qt::TextAlignmentRole: | ||
975 | { | 1003 | { | ||
976 | switch(section) { | 1004 | switch(section) { | ||
977 | case HeadingPid: | 1005 | case HeadingPid: | ||
978 | case HeadingTty: | 1006 | case HeadingTty: | ||
979 | case HeadingMemory: | 1007 | case HeadingMemory: | ||
980 | case HeadingXMemory: | 1008 | case HeadingXMemory: | ||
▲ Show 20 Lines • Show All 277 Lines • ▼ Show 20 Line(s) | 1271 | QString ProcessModelPrivate::getUsernameForUser(long uid, bool withuid) const { | |||
1258 | if(withuid) | 1286 | if(withuid) | ||
1259 | return i18nc("User name and user id", "%1 (uid: %2)", username, (long int)uid); | 1287 | return i18nc("User name and user id", "%1 (uid: %2)", username, (long int)uid); | ||
1260 | return username; | 1288 | return username; | ||
1261 | } | 1289 | } | ||
1262 | 1290 | | |||
1263 | QVariant ProcessModel::data(const QModelIndex &index, int role) const | 1291 | QVariant ProcessModel::data(const QModelIndex &index, int role) const | ||
1264 | { | 1292 | { | ||
1265 | //This function must be super duper ultra fast because it's called thousands of times every few second :( | 1293 | //This function must be super duper ultra fast because it's called thousands of times every few second :( | ||
1266 | //I think it should be optomised for role first, hence the switch statement (fastest possible case) | 1294 | //I think it should be optimised for role first, hence the switch statement (fastest possible case) | ||
1267 | 1295 | | |||
1268 | if (!index.isValid()) { | 1296 | if (!index.isValid()) { | ||
1269 | return QVariant(); | 1297 | return QVariant(); | ||
1270 | } | 1298 | } | ||
1299 | | ||||
1300 | if (index.column() > columnCount()) { | ||||
1301 | return QVariant(); | ||||
1302 | } | ||||
1303 | //plugin stuff first | ||||
1271 | if (index.column() >= d->mHeadings.count()) { | 1304 | if (index.column() >= d->mHeadings.count()) { | ||
1305 | int attr = index.column() - d->mHeadings.count(); | ||||
1306 | switch (role) { | ||||
1307 | case ProcessModel::PlainValueRole: { | ||||
1308 | KSysGuard::Process *process = reinterpret_cast< KSysGuard::Process * > (index.internalPointer()); | ||||
1309 | const QVariant value = d->mExtraAttributes[attr]->data(process); | ||||
1310 | return value; | ||||
1311 | } | ||||
1312 | case Qt::DisplayRole: { | ||||
1313 | KSysGuard::Process *process = reinterpret_cast< KSysGuard::Process * > (index.internalPointer()); | ||||
1314 | const QVariant value = d->mExtraAttributes[attr]->data(process); | ||||
1315 | return KSysGuard::Formatter::formatValue(value, d->mExtraAttributes[attr]->unit()); | ||||
1316 | } | ||||
1317 | case Qt::TextAlignmentRole: { | ||||
1318 | KSysGuard::Process *process = reinterpret_cast< KSysGuard::Process * > (index.internalPointer()); | ||||
1319 | const QVariant value = d->mExtraAttributes[attr]->data(process); | ||||
1320 | if (value.canConvert(QMetaType::LongLong) | ||||
1321 | && static_cast<QMetaType::Type>(value.type()) != QMetaType::QString) { | ||||
1322 | return Qt::AlignRight + Qt::AlignVCenter; | ||||
1323 | } | ||||
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… | |||||
1324 | 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. | |||||
1325 | } | ||||
1326 | } | ||||
1272 | return QVariant(); | 1327 | return QVariant(); | ||
1273 | } | 1328 | } | ||
1274 | 1329 | | |||
1275 | KFormat format; | 1330 | KFormat format; | ||
1276 | switch (role){ | 1331 | switch (role){ | ||
1277 | case Qt::DisplayRole: { | 1332 | case Qt::DisplayRole: { | ||
1278 | KSysGuard::Process *process = reinterpret_cast< KSysGuard::Process * > (index.internalPointer()); | 1333 | KSysGuard::Process *process = reinterpret_cast< KSysGuard::Process * > (index.internalPointer()); | ||
1279 | switch(index.column()) { | 1334 | switch(index.column()) { | ||
▲ Show 20 Lines • Show All 748 Lines • ▼ Show 20 Line(s) | 2081 | if (d->mIsX11) { | |||
2028 | headings << i18nc("process heading", "Window Title"); | 2083 | headings << i18nc("process heading", "Window Title"); | ||
2029 | } | 2084 | } | ||
2030 | #endif | 2085 | #endif | ||
2031 | headings << i18nc("process heading", "CGroup"); | 2086 | headings << i18nc("process heading", "CGroup"); | ||
2032 | headings << i18nc("process heading", "MAC Context"); | 2087 | headings << i18nc("process heading", "MAC Context"); | ||
2033 | headings << i18nc("process heading", "Total Memory"); | 2088 | headings << i18nc("process heading", "Total Memory"); | ||
2034 | 2089 | | |||
2035 | if(d->mHeadings.isEmpty()) { // If it's empty, this is the first time this has been called, so insert the headings | 2090 | if(d->mHeadings.isEmpty()) { // If it's empty, this is the first time this has been called, so insert the headings | ||
2036 | beginInsertColumns(QModelIndex(), 0, headings.count()-1); | | |||
2037 | { | | |||
2038 | d->mHeadings = headings; | 2091 | d->mHeadings = headings; | ||
2039 | } | | |||
2040 | endInsertColumns(); | | |||
2041 | } else { | 2092 | } else { | ||
2042 | // This was called to retranslate the headings. Just use the new translations and call headerDataChanged | 2093 | // This was called to retranslate the headings. Just use the new translations and call headerDataChanged | ||
2043 | Q_ASSERT(d->mHeadings.count() == headings.count()); | 2094 | Q_ASSERT(d->mHeadings.count() == headings.count()); | ||
2044 | d->mHeadings = headings; | 2095 | d->mHeadings = headings; | ||
2045 | headerDataChanged(Qt::Horizontal, 0 , headings.count()-1); | 2096 | headerDataChanged(Qt::Horizontal, 0 , headings.count()-1); | ||
2046 | 2097 | | |||
2047 | } | 2098 | } | ||
2048 | } | 2099 | } | ||
▲ Show 20 Lines • Show All 261 Lines • Show Last 20 Lines |
Store mExtraAttributes in a variable