Update the process model instead of resetting it

master
Jos van den Oever 2017-08-24 20:14:53 +02:00
parent b8170dbe7e
commit d78e6d1192
10 changed files with 137 additions and 38 deletions

View File

@ -79,7 +79,7 @@ if (Qt5Charts_FOUND)
endif()
set(Demo_SRCS src/main.cpp src/Fibonacci.cpp src/Tree.cpp src/TimeSeries.cpp
src/Processes.cpp resource_file.qrc)
src/modeltest.cpp src/Processes.cpp resource_file.qrc)
add_executable(Demo ${Demo_SRCS})
add_dependencies(Demo rust_target)

View File

@ -26,26 +26,20 @@ pub struct Processes {
incoming: Arc<Mutex<Option<ProcessTree>>>
}
fn check() {
fn check_process_hierarchy(parent: Option<pid_t>, processes: &HashMap<pid_t,Process>) {
for (pid, process) in processes {
assert_eq!(process.pid, *pid);
if !parent.is_none() {
assert_eq!(process.parent, parent);
}
check_process_hierarchy(Some(*pid), &process.tasks);
fn check_process_hierarchy(parent: Option<pid_t>, processes: &HashMap<pid_t,Process>) {
for (pid, process) in processes {
assert_eq!(process.pid, *pid);
if !parent.is_none() {
assert_eq!(process.parent, parent);
}
check_process_hierarchy(Some(*pid), &process.tasks);
}
let mut sysinfo = System::new();
sysinfo.refresh_processes();
check_process_hierarchy(None, sysinfo.get_process_list());
}
fn collect_processes(tasks: &HashMap<pid_t,Process>,
mut processes: &mut HashMap<pid_t, ProcessItem>) -> f32 {
let mut cpusum = 0.0;
for (pid, process) in tasks {
for process in tasks.values() {
processes.insert(process.pid, ProcessItem {
row: 0,
tasks: Vec::new(),
@ -63,42 +57,49 @@ fn handle_tasks(mut processes: &mut HashMap<pid_t, ProcessItem>) -> Vec<pid_t> {
let pids: Vec<pid_t> = processes.keys().map(|p| *p).collect();
for pid in pids {
if let Some(parent) = processes[&pid].process.parent {
let row = {
let p = processes.get_mut(&parent).unwrap();
let row = p.tasks.len();
p.tasks.push(pid);
row
};
processes.get_mut(&pid).unwrap().row = row;
let p = processes.get_mut(&parent).unwrap();
p.tasks.push(pid);
} else {
top.push(pid);
}
}
top.sort();
top
}
fn sort_tasks(mut processes: &mut HashMap<pid_t, ProcessItem>) {
for process in processes.values_mut() {
process.tasks.sort();
fn update_rows(list: Vec<pid_t>, mut processes: &mut HashMap<pid_t, ProcessItem>) {
let mut row = 0;
for pid in list {
processes.get_mut(&pid).unwrap().row = row;
let l = processes[&pid].tasks.clone();
update_rows(l, processes);
row += 1;
}
}
fn sort_tasks(p: &mut ProcessTree) {
for process in p.processes.values_mut() {
process.tasks.sort();
}
p.top.sort();
update_rows(p.top.clone(), &mut p.processes);
}
fn update() -> ProcessTree {
check();
let mut p = ProcessTree::default();
let mut sysinfo = System::new();
sysinfo.refresh_processes();
p.cpusum = collect_processes(sysinfo.get_process_list(), &mut p.processes);
let list = sysinfo.get_process_list();
check_process_hierarchy(None, list);
p.cpusum = collect_processes(list, &mut p.processes);
p.top = handle_tasks(&mut p.processes);
sort_tasks(&mut p.processes);
sort_tasks(&mut p);
p
}
fn update_thread(emit: ProcessesEmitter, incoming: Arc<Mutex<Option<ProcessTree>>>) {
thread::spawn(move || {
let second = time::Duration::new(1, 0);
while true {
loop {
*incoming.lock().unwrap() = Some(update());
emit.new_data_ready(None);
thread::sleep(second);
@ -113,9 +114,84 @@ impl Processes {
}
}
fn move_process(pid: pid_t, amap: &mut HashMap<pid_t, ProcessItem>,
bmap: &mut HashMap<pid_t, ProcessItem>) {
if let Some(e) = bmap.remove(&pid) {
amap.insert(pid, e);
let ts = amap[&pid].tasks.clone();
for t in ts {
move_process(t, amap, bmap);
}
}
}
fn sync_tree(model: &ProcessesUniformTree, parent: Option<usize>,
avec: &mut Vec<pid_t>,
amap: &mut HashMap<pid_t, ProcessItem>,
bvec: &Vec<pid_t>,
bmap: &mut HashMap<pid_t, ProcessItem>) {
let mut a = 0;
let mut b = 0;
while a < avec.len() && b < bvec.len() {
if avec[a] < bvec[a] { // a process has disappeared
let pid = avec[a];
println!("removing {} '{}' {}", pid, amap[&pid].process.exe,
amap[&pid].process.cmd.join(" "));
model.begin_remove_rows(parent, a, a);
amap.remove(&pid);
avec.remove(a);
model.end_remove_rows();
} else if avec[a] > bvec[b] { // a process has appeared
let pid = bvec[b];
println!("adding {} '{}' {}", pid, bmap[&pid].process.exe,
bmap[&pid].process.cmd.join(" "));
model.begin_insert_rows(parent, a, a);
move_process(pid, amap, bmap);
avec.insert(a, pid);
let e = amap.get_mut(&pid).unwrap();
assert_eq!(e.row, a);
assert_eq!(e.process.parent.map(|p| p as usize), parent);
model.end_insert_rows();
a += 1;
b += 1;
} else {
let pid = bvec[b];
let mut av = amap[&pid].tasks.clone();
let bv = bmap[&pid].tasks.clone();
sync_tree(model, Some(pid as usize), &mut av, amap, &bv, bmap);
let e = amap.get_mut(&pid).unwrap();
e.tasks = av;
e.row = a;
assert_eq!(e.process.parent.map(|p| p as usize), parent);
a += 1;
b += 1;
}
}
while a < bvec.len() {
let pid = bvec[b];
model.begin_insert_rows(parent, a, a);
move_process(pid, amap, bmap);
avec.push(pid);
assert_eq!(amap.get_mut(&pid).unwrap().row, a);
model.end_insert_rows();
a += 1;
b += 1;
}
while b < avec.len() {
model.begin_remove_rows(parent, a, a);
amap.remove(&avec[a]);
avec.remove(a);
model.end_remove_rows();
}
assert_eq!(a, b);
assert_eq!(a, avec.len());
assert_eq!(avec.len(), bvec.len());
}
impl ProcessesTrait for Processes {
fn create(emit: ProcessesEmitter, model: ProcessesUniformTree) -> Processes {
let mut p = Processes {
let p = Processes {
emit: emit.clone(),
model: model,
p: ProcessTree::default(),
@ -145,6 +221,9 @@ impl ProcessesTrait for Processes {
self.get(item).process.parent.map(|pid| pid as usize)
}
fn can_fetch_more(&self, item: Option<usize>) -> bool {
if item.is_some() {
return false;
}
if let Ok(ref incoming) = self.incoming.try_lock() {
incoming.is_some()
} else {
@ -152,12 +231,17 @@ impl ProcessesTrait for Processes {
}
}
fn fetch_more(&mut self, item: Option<usize>) {
if let Ok(ref mut incoming) = self.incoming.try_lock() {
if let Some(more) = incoming.take() {
self.model.begin_reset_model();
self.p = more;
self.model.end_reset_model();
}
if item.is_some() {
return;
}
let new = if let Ok(ref mut incoming) = self.incoming.try_lock() {
incoming.take()
} else {
None
};
if let Some(mut new) = new {
sync_tree(&self.model, None, &mut self.p.top, &mut self.p.processes,
&new.top, &mut new.processes);
}
}
fn row(&self, item: usize) -> usize {

View File

@ -121,6 +121,7 @@ Qt::ItemFlags FibonacciList::flags(const QModelIndex &i) const
QVariant FibonacciList::data(const QModelIndex &index, int role) const
{
QVariant v;
Q_ASSERT(rowCount(index.parent()) > index.row());
QString s;
QByteArray b;
switch (index.column()) {

View File

@ -138,6 +138,7 @@ Qt::ItemFlags Processes::flags(const QModelIndex &i) const
QVariant Processes::data(const QModelIndex &index, int role) const
{
QVariant v;
Q_ASSERT(rowCount(index.parent()) > index.row());
QString s;
QByteArray b;
switch (index.column()) {

View File

@ -123,6 +123,7 @@ Qt::ItemFlags TimeSeries::flags(const QModelIndex &i) const
QVariant TimeSeries::data(const QModelIndex &index, int role) const
{
QVariant v;
Q_ASSERT(rowCount(index.parent()) > index.row());
QString s;
QByteArray b;
switch (index.column()) {

View File

@ -137,6 +137,7 @@ Qt::ItemFlags Tree::flags(const QModelIndex &i) const
QVariant Tree::data(const QModelIndex &index, int role) const
{
QVariant v;
Q_ASSERT(rowCount(index.parent()) > index.row());
QString s;
QByteArray b;
switch (index.column()) {

View File

@ -2,6 +2,7 @@
#include "Fibonacci.h"
#include "TimeSeries.h"
#include "Processes.h"
#include "modeltest.h"
#ifdef QT_CHARTS_LIB
#include <QtCharts>
@ -211,8 +212,14 @@ QWidget* createProcessesTab(Models* models) {
view->setUniformRowHeights(true);
view->setSortingEnabled(true);
view->setModel(&models->sortedProcesses);
auto root = models->sortedFileSystem.index(0, 0);
view->expand(root);
// expand when the model is populated
view->connect(&models->sortedProcesses, &QAbstractItemModel::rowsInserted,
view, [view](const QModelIndex& index) {
if (!index.isValid()) {
view->expandAll();
}
});
view->expandAll();
view->sortByColumn(0, Qt::AscendingOrder);
return view;
}
@ -310,6 +317,7 @@ int main (int argc, char *argv[])
parser.process(app);
Models models;
//new ModelTest(&models.processes);
models.fileSystem.setPath("/");
models.sortedFileSystem.setSourceModel(&models.fileSystem);
models.sortedFileSystem.setDynamicSortFilter(true);

View File

@ -220,6 +220,7 @@ Qt::ItemFlags %1::flags(const QModelIndex &i) const
QVariant %1::data(const QModelIndex &index, int role) const
{
QVariant v;
Q_ASSERT(rowCount(index.parent()) > index.row());
QString s;
QByteArray b;
switch (index.column()) {

View File

@ -118,6 +118,7 @@ Qt::ItemFlags Persons::flags(const QModelIndex &i) const
QVariant Persons::data(const QModelIndex &index, int role) const
{
QVariant v;
Q_ASSERT(rowCount(index.parent()) > index.row());
QString s;
QByteArray b;
switch (index.column()) {

View File

@ -136,6 +136,7 @@ Qt::ItemFlags Persons::flags(const QModelIndex &i) const
QVariant Persons::data(const QModelIndex &index, int role) const
{
QVariant v;
Q_ASSERT(rowCount(index.parent()) > index.row());
QString s;
QByteArray b;
switch (index.column()) {