My two cents (with top quote apology :) I really like it when classes get added to Qt that can be used out of the box without sub-classing. That's been a guideline in the past, functionality that the end users of Qt can use right away. I really really like that philosophy (and the change to make QThread's run method non-virtual is an example of that).
I also think that it is even better when functionality gets added to Qt that is used within, by other classes in the same module or by other modules (at least for classes that are lower down in the dependency chain). Alternatively it is great if API is in place that makes combining it with a specific other class particularly easy. With that in mind, I think that the job class represents an example that is perhaps more interesting for a framework developer on top of Qt, not an application developer. Consequently I suggest to let it have the term "Abstract" in its name. I also wonder if it makes sense to perhaps provide convenience API to connect this with the state machine framework? Lastly IMHO this should be accompanied with a documented example that shows how to build a job based framework. Simon Fra: David Faure Sendt: 19:47 fredag 6. september 2013 Til: development@qt-project.org Emne: [Development] A QtCore class for event-driven jobs I would like to propose the inclusion of a QJob class in QtCore, based on years of experience with KIO::Job and KJob. The idea is to encapsulate an event driven asynchronous operation into a job class. Example use cases: - a network download with QNetworkAccessManager. - operations (command+reply) over a QLocalSocket or QTcpSocket (like akonadi). - long async dbus calls (special case of the previous line) - long tasks executed by external processes (e.g. "make" from an IDE, "unrar" from an archive program) ... At the core, QJob is really just a class with start() and kill(), calling pure virtual methods doStart() and doKill(), and signals, most importantly the result(QJob *) signal. The expected use case is: void SomeClass::methodWithAsynchronousJobCall() { QJob* job = someoperation(some parameters); connect(job, SIGNAL(result(QJob*)), this, SLOT(handleResult(QJob*))); job->start(); // or it could just autostart, which I actually prefer... } (other connects, specific to the job) And handleResult is usually at least: void SomeClass::handleResult( QJob *job ) { if (job->error()) { // handle error } else { // handle succesful job completion, if needed } } But it can and should also have the following features: * error code, error text * suspend/resume with doSuspend/doResume virtual methods * capabilities Killable and Suspendable, to avoid trying these on jobs that don't support them * kill(Quietly) vs kill(EmitResult), for the app's convenience * a finished signal that is emitted with both types of killing, for things like progress dialogs * auto-deletion (on by default, can be turned off) * synchronous exec() using a QEventLoop, with a big fat huge warning about not using that in GUI apps (ideally only to be used in unittests or separate threads). * more standard signals for progress info, messages, warnings.. The whole point of standardizing such signals is that it allows generic GUIs to be built on top, so that your app or your desktop can show the progress of multiple concurrent jobs, of different types (file download, CD burning, mail checking, etc. etc.) Finally, for the benefit of job implementors, QJob would support sub-jobs. The job implementation would choose when to create these subjobs (all at once initially, to have them run in parallel, or one after the other, for sequence of operations). KDE currently does that in a subclass (KCompositeJob) but Thiago and I (and kio, and akonadi) agree that it's better to have it all in one class instead. We also have a standard interface for error handling so that all jobs from a given framework can have their error handled the same way, but thinking about it, that part could stay separate, at least for now. Well, that's it. So why this email? Because Thiago asked me to, and to gather some support. I plan to make a merge request for Qt 5.2. Thiago asked more specifically: * API-wise, can't this be merged with QFuture? -> no, because QFuture encapsulates a value, with blocking methods for getting the value, even available as casting-to-the-value. If we imagine a QFuture that wraps a QJob, and the blocking method calling exec(), we'd have a lot more nested event loops than is good for the health of our programs. On the other hand, QJob would not be related to any value. It's really a QObject that informs of progress via signals. * relation to QRunnable? A runnable is also some sort of "job", but the implementation is completely different: a runnable is one sync method, while a qjob is all signals/slots based, with start() returning immediately. So one can't be used like the other, a given task implementation is either a blocking task for a thread with no event loop (QRunnable) or an async task that can actually be used in any thread with an event loop. * relation to QNetworkReply? If that one didn't exist yet, we'd definitely write it as a QJob subclass. So instead, I propose to wrap QNetworkReply into a QNetworkJob or something, in order to offer the QJob interface for QNAM requests. On one hand this doesn't have to go in at the same time as QJob itself, but OTOH it could be a real- world testcase for it, proving its usefulness and correctness... Any other questions? -- David Faure | david.fa...@kdab.com | Managing Director KDAB France KDAB (France) S.A.S., a KDAB Group company Tel. France +33 (0)4 90 84 08 53, Sweden (HQ) +46-563-540090 KDAB - Qt Experts - Platform-independent software solutions _______________________________________________ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
_______________________________________________ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development