[prev in list] [next in list] [prev in thread] [next in thread]
List: koffice-devel
Subject: design discussion: progress classes in KOffice
From: Jos van den Oever <jos.van.den.oever () kogmbh ! com>
Date: 2010-08-10 7:22:49
Message-ID: 201008101240.50113.jos.van.den.oever () kogmbh ! com
[Download RAW message or body]
Hi all,
I've been using the progress classes quite a bit the last week and come to the
conclusion that I do not like them. Mainly I think the api of the classes
KoUpdater, KoUpdaterPrivate, KoProgressUpdater is confusing and overly heavy.
So I've come up with a new design in the form of a header file and I would like
people to have a look at it and see if they like it.
Progress reporting should be able to deal with
- named tasks
- splitting tasks up in subtasks
- weighted tasks, the weight is an estimate of how much time a task takes
relative to other tasks on the same level
- tasks running in threads; for each task progress reporting is allowed to be
done in one arbitrary thread
- support having a main progress bar and progress bar for subtasks
- support logging of progress with timestamps by simply implementing another
proxy
Advantages over current approach
- less public classes, less functions, less confusion
- more robust API due to automatic unwinding of the stack
- only one range: 0-100
- no mixing in of unassociated function (interrupt, abort)
- no use of QObject for more lightweight reporting
- more foolproof
This design is simply a suggestion which could be implemented if people like
it better than the current API.
Cheers,
Jos
--
Jos van den Oever, software architect
+49 391 25 19 15 53
http://kogmbh.com/legal/
["p.cpp" (text/x-c++src)]
#include "p.h"
/** very incomplete implementation, not relevant for interface discussion **/
class ProgressTaskStackPrivate {
public:
ProgressTask createSubTask(int, const QString &) {
return ProgressTask(this);
}
};
class ProgressTaskPrivate {
public:
ProgressTaskStackPrivate * const stack;
ProgressTaskPrivate(ProgressTaskStackPrivate *stack_)
:stack(stack_) {}
};
ProgressProxy::~ProgressProxy() {
}
ProgressTaskStack::ProgressTaskStack()
:d(new ProgressTaskStackPrivate()) {
}
ProgressTaskStack::~ProgressTaskStack() {
// check that all tasks have been deleted already
delete d;
}
ProgressTask
ProgressTaskStack::createSubTask(int weight, const QString &name) {
return d->createSubTask(weight, name);
}
ProgressTask::ProgressTask(const ProgressTask& p)
:d(p.d) {
}
ProgressTask::ProgressTask(ProgressTaskStackPrivate *stack)
:d(new ProgressTaskPrivate(stack)) {
}
ProgressTask::~ProgressTask() {
delete d;
}
ProgressTask
ProgressTask::createSubTask(int, const QString &) {
return ProgressTask(d->stack);
}
void
ProgressTask::start() {
}
void
ProgressTask::setProgress(int) {
}
["p.h" (text/x-chdr)]
#ifndef P_H
#define P_H
#include <QtCore/QString>
class ProgressTask;
class ProgressTaskPrivate;
class ProgressTaskStackPrivate;
/**
* ProgressProxy is a simple interface for receiving progress events.
* Implementations of this interface can report to e.g. a progress bar
* or a profiler.
**/
class ProgressProxy {
public:
/**
* Destructor
**/
virtual ~ProgressProxy();
/**
* Handle a progress report message for the task to associated task.
* This function should be implemented in derived classes.
* The implementation of this function should be thread-safe
* if tasks that are being reported on will be run from multiple threads.
* @param value Current progress value, must be in the range from 0 to 100.
* @param task The task of which the progress is reported
**/
virtual void setProgress(int value, const ProgressTask& task) = 0;
};
/**
* ProgressTaskStack is a class that keeps track of ProgressTask objects.
* It holds the stack of progress tasks and allows to put new subtasks on the
* stack by creating them. When the task goes out of scope, it is removed
* from the stack.
**/
class ProgressTaskStack {
public:
/**
* Constructor
**/
ProgressTaskStack();
/**
* Destructor
* All tasks created from this stack should have gone out of scope
* or have otherwise been deleted before ProgressTaskStack is destructed.
**/
~ProgressTaskStack();
/**
* Create a subtask from the current task.
* The current task is the task that has last been started in this thread.
*
**/
ProgressTask createSubTask(int weight, const QString &name);
private:
// do not allow copying
explicit ProgressTaskStack(const ProgressTaskStack &);
void operator=(const ProgressTaskStack &);
ProgressTaskStackPrivate * const d;
};
class ProgressTask {
friend class ProgressTaskStackPrivate;
public:
/**
* Create a shallow copy of this task.
**/
ProgressTask(const ProgressTask &);
/**
* Destructor
**/
~ProgressTask();
/**
* Return the name of the task.
**/
QString getName() const;
/**
* Set a proxy to report on the progress status of this task.
**/
void addProgressProxy(ProgressProxy *proxy);
/**
* Remove a proxy to report on the progress status of this task.
**/
void removeProgressProxy(ProgressProxy *proxy);
/**
* Create a subtask.
**/
ProgressTask createSubTask(int weight, const QString &name);
/**
* Start this task.
* This call also makes this task the current task for the thread,
* which means the ProgressTaskStack uses this task for creating
* subtasks of in this thread.
**/
void start();
/**
* Set the progress of this task.
* Once you call this, you cannot call createSubTask.
* A task has either direct progress reporting or subtasks.
* @param progress Progress of the task in the inclusive range 0-100
**/
void setProgress(int progress);
/**
* Get the parent task
* This function is useful for logging purposes where one would like
* to write out the parents of a particular task.
* @return parent task or 0 if this is the top tasks
**/
const ProgressTask *parent() const;
private:
// do not allow copying or implicit creation
ProgressTask();
void operator=(const ProgressTask &);
ProgressTask(ProgressTaskStackPrivate * stack);
ProgressTaskPrivate * const d;
};
#endif
["main.cpp" (text/x-c++src)]
#include "p.h"
/** use cases **/
/** dummy proxy class for discussion purposes **/
class MyProgressProxy : public ProgressProxy {
public:
virtual void setProgress(int value, const ProgressTask& currentTask);
};
void
MyProgressProxy::setProgress(int /*value*/, const ProgressTask& /*currentTask*/) {
}
class Document {
private:
ProgressTaskStack m_progressstack;
public:
ProgressTaskStack* progressStack() {
return &m_progressstack;
}
};
void
function1(Document* doc) {
// initialize all subtasks
ProgressTask progress = doc->progressStack()->createSubTask(1, "myfunction1");
progress.start();
sleep(1);
progress.setProgress(50);
sleep(1);
progress.setProgress(100);
// destructors clean up and unwind the stack
}
void
function2(Document* doc) {
// initialize all subtasks
ProgressTask progress = doc->progressStack()->createSubTask(1, "myfunction2");
ProgressTask task1 = progress.createSubTask(1, "task1");
ProgressTask task2 = progress.createSubTask(5, "task2");
// start work and reporting progress
task1.start();
sleep(1);
task1.setProgress(50);
sleep(1);
task1.setProgress(100);
task2.start();
sleep(5);
task2.setProgress(50);
sleep(5);
task2.setProgress(100);
// destructors clean up and unwind the stack
}
/** dummy threading class for discussion purposes **/
class Runner {
private:
Document *doc;
ProgressTask task;
public:
Runner(Document* d, const ProgressTask &task);
void start() {}
void run();
void wait() {}
};
void
parallelfunction(Document *doc) {
ProgressTask progress = doc->progressStack()->createSubTask(1, "myfunction");
ProgressTask task1 = progress.createSubTask(1, "task1");
ProgressTask task2 = progress.createSubTask(5, "task2");
Runner* runner1 = new Runner(doc, task1);
Runner* runner2 = new Runner(doc, task2);
runner1->start();
runner2->start();
runner1->wait();
runner2->wait();
}
Runner::Runner(Document* d, const ProgressTask &t)
:doc(d), task(t) {
}
void
Runner::run() {
task.start();
sleep(1);
task.setProgress(50);
sleep(1);
task.setProgress(100);
}
int
main() {
Document d;
MyProgressProxy progressproxy;
ProgressTaskStack stack;
function1(&d);
function2(&d);
parallelfunction(&d);
return 0;
}
_______________________________________________
koffice-devel mailing list
koffice-devel@kde.org
https://mail.kde.org/mailman/listinfo/koffice-devel
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic