Commit 28b8ed6e authored by Thomas Zander's avatar Thomas Zander

Moved progress updater class to koguiutils lib.

svn path=/trunk/koffice/; revision=689690
parent ea40faaa
......@@ -81,8 +81,6 @@ set(kritaimage_LIB_SRCS
kis_perspective_math.cpp
kis_mask.cc
kis_effect_mask.cc
kis_progress_updater.cpp
kis_progress_updater_p.cpp
kis_image_view_converter.cpp
kis_image_commands.cc
kis_layer_commands.cc
......
/*
* Copyright (c) 2006 Thomas Zander <zander@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_progress_updater.h"
#include "kis_progress_updater_p.h"
#include <threadAction/KoAction.h>
#include <threadAction/KoExecutePolicy.h>
#include <threadweaver/ThreadWeaver.h>
#include <QProgressBar>
#include <QString>
KisProgressUpdater::KisProgressUpdater(QProgressBar *progressBar)
: m_progressBar(progressBar),
m_totalWeight(0),
m_currentProgress(0)
{
Q_ASSERT(m_progressBar);
m_action = new KoAction(this);
m_action->setExecutePolicy(KoExecutePolicy::onlyLastPolicy);
connect(m_action, SIGNAL(triggered(const QVariant &)), SLOT(update()));
connect(m_action, SIGNAL(updateUi(const QVariant &)), SLOT(updateUi()));
}
KisProgressUpdater::~KisProgressUpdater() {
qDeleteAll(m_subtasks);
m_subtasks.clear();
}
void KisProgressUpdater::start(int range, const QString &text) {
m_lock.lock();
qDeleteAll(m_subtasks);
m_subtasks.clear();
m_progressBar->setRange(0, range-1);
m_progressBar->setValue(0);
if(! text.isEmpty())
m_progressBar->setFormat(text);
m_totalWeight = 0;
m_lock.unlock();
}
KisUpdater KisProgressUpdater::startSubtask(int weight) {
m_lock.lock();
KisUpdaterPrivate *p = new KisUpdaterPrivate(this, weight);
m_totalWeight += weight;
m_subtasks.append(p);
m_lock.unlock();
return KisUpdater(p);
}
void KisProgressUpdater::scheduleUpdate() {
m_action->execute();
}
void KisProgressUpdater::update() {
// this method is called by the action. The action will ensure it is called
// serially from one thread only. With an updateUi followed directly after
// this one (forced to the Gui Thread).
m_lock.lock();
int totalProgress =0;
foreach(KisUpdaterPrivate *Kisupdater, m_subtasks) {
if(Kisupdater->interrupted()) {
m_currentProgress = -1;
break;
}
int progress = Kisupdater->progress();
if(progress > 100 || progress < 0)
progress = Kisupdater->progress(); // see comment in KisUpdaterPrivate cpp file
totalProgress += progress * Kisupdater->weight();
}
m_currentProgress = totalProgress / m_totalWeight;
m_lock.unlock();
}
void KisProgressUpdater::updateUi() {
if(m_currentProgress == -1) {
m_progressBar->setValue(m_progressBar->maximum());
// should we hide the progressbar after a little while?
return;
}
m_progressBar->setValue(m_currentProgress);
}
void KisProgressUpdater::cancel() {
m_lock.lock();
foreach(KisUpdaterPrivate *Kisupdater, m_subtasks) {
Kisupdater->setProgress(100);
Kisupdater->interrupt();
}
m_lock.unlock();
scheduleUpdate();
}
// -------- KisUpdater ----------
KisUpdater::KisUpdater(const KisUpdater &other) {
d = other.d;
}
KisUpdater::KisUpdater(KisUpdaterPrivate *p)
{
d = p;
Q_ASSERT(p);
Q_ASSERT(!d.isNull());
}
void KisUpdater::cancel() {
if(!d.isNull())
d->cancel();
}
void KisUpdater::setProgress(int percent) {
if(!d.isNull())
d->setProgress(percent);
}
int KisUpdater::progress() const {
if(d.isNull())
return 100;
return d->progress();
}
bool KisUpdater::interrupted() const {
if(d.isNull())
return true;
return d->interrupted();
}
#include "kis_progress_updater.moc"
/*
* Copyright (c) 2006 Thomas Zander <zander@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PROGRESSUPDATER_H
#define PROGRESSUPDATER_H
#include <QList>
#include <QString>
#include <QMutex>
#include <QPointer>
class QProgressBar;
class KisUpdater;
class KisUpdaterPrivate;
class KoAction;
/**
* Allow multiple subtasks to safely update and report progress.
* This class is able to update a progress bar with the total progress
* of a project that may be separated into different subtasks.
* Each subtask will use one KisUpdater which that subtask can then report
* progress to. Each KisUpdater.setProgress() call will automatically calculate
* the total progress over the whole tasks made and update the progress bar
* with the total progress so far.
*
* This class is created specifically with threading in mind so that subtasks
* can report their progress from their personal subthread and the progress bar
* will be updated correctly and not more often then repaints can return.
*
* Typical usage can be:
* @code
KisProgressUpdater *pu = new KisProgressUpdater(myProgressBar);
pu->start(100);
// create the subtasks
KisUpdater smooth = pu->startSubtask(5);
KisUpdater scale = pu->startSubtask(5);
KisUpdater cleanup = pu->startSubtask(1);
@endcode
* Doing an smooth.setProgress(50) will move the progress bar to 50% of the share
* of task 'smooth' which is 5 / 11 of the total and thus to 22.
*/
class KisProgressUpdater : public QObject {
Q_OBJECT
public:
/**
* Constructor.
* @param progressBar the progress bar to update.
*/
KisProgressUpdater(QProgressBar *progressBar);
/// destructor
virtual ~KisProgressUpdater();
/**
* Start a new task.
* This will invalidate any previously created subtasks and set the range of
* the progressBar as well as the text in the progressbar.
* @param range the total range of progress bar makes.
* @param text The text to show in the progressBar.
* @see QProgressBar::setRange()
* @see QProgressBar::setFormat()
*/
void start(int range = 100, const QString &text = "%p%");
/**
* After calling start() you can create any number of Updaters, one for each subtask.
* @param weight use a weight to specify the weight this subtask has compared
* to the rest of the subtasks.
*/
KisUpdater startSubtask(int weight=1);
/**
* Cancelling the action will make each subtask be marked as 'interrupted' and
* set the total progress to 100%.
*/
void cancel();
protected:
//friend class KisUpdater;
friend class KisUpdaterPrivate;
void scheduleUpdate();
private slots:
/// called by the action based on a scheduleUpdate
void update();
/// called by the action based on a scheduleUpdate
void updateUi();
private:
QProgressBar *m_progressBar;
QList<KisUpdaterPrivate*> m_subtasks;
int m_totalWeight;
int m_currentProgress; // used for the update and updateUi methods. Don't use elsewhere
QMutex m_lock; // protects access to m_subtasks
KoAction *m_action;
};
/**
* An Kisupdater is a helper for keeping the progress of each subtask up to speed.
* This class is not thread safe, and it should only be used from one thread.
* The thread it is used in can be different from any other subtask or the
* KisProgressUpdater, though.
* @see KisProgressUpdater::startSubtask()
*/
class KisUpdater {
public:
/// copy constructor.
KisUpdater(const KisUpdater &other);
/**
* Call this when this subtask wants to abort all the actions.
*/
void cancel();
/**
* Update your progress. Progress is always from 0 to 100.
* The global progress shown to the user is determined by the total
* amount of subtasks there are. This means that each subtasks can just
* report its own private progress in the range from 0 to 100.
*/
void setProgress(int percent);
/**
* return true when this task should stop processing immediately.
* When the task has been cancelled all the subtasks will get interrupted
* and should stop working. It is therefor important to have repeated calls to
* this method at regular (time) intervals and as soon as the method returns true
* cancel the subtask.
* @return true when this task should stop processing immediately.
*/
bool interrupted() const;
/**
* return the progress this subtask has made.
*/
int progress() const;
protected:
friend class KisProgressUpdater;
KisUpdater(KisUpdaterPrivate *p);
private:
QPointer<KisUpdaterPrivate> d;
};
#endif
/*
* Copyright (c) 2006 Thomas Zander <zander@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <kis_progress_updater.h>
#include <kis_progress_updater_p.h>
// technically speaking the access to the progress integer should be guarded
// by a mutex, even if we assume that it will only ever be set from one thread.
// The reason is that while the KoAction is reading it its possible to alter the
// int and as an effect get an unpredictable value in the slider on screen.
KisUpdaterPrivate::KisUpdaterPrivate(KisProgressUpdater *parent, int weight)
: m_progress(0),
m_weight(weight),
m_interrupted(false),
m_parent(parent)
{
}
void KisUpdaterPrivate::setProgress(int progress) {
if(m_progress >= progress)
return;
m_progress = progress;
m_parent->scheduleUpdate();
}
void KisUpdaterPrivate::cancel() {
m_parent->cancel();
}
#include <kis_progress_updater_p.moc>
/*
* Copyright (c) 2006 Thomas Zander <zander@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PROGRESSUPDATER_P_H
#define PROGRESSUPDATER_P_H
#include <QObject>
class KisProgressUpdater;
/// @internal
/// the private member for the KisUpdater
class KisUpdaterPrivate : public QObject {
Q_OBJECT
public:
KisUpdaterPrivate(KisProgressUpdater *parent, int weight);
inline bool interrupted() const { return m_interrupted; }
inline int progress() const { return m_progress; }
inline int weight() const { return m_weight; }
void cancel();
inline void interrupt() { m_interrupted = true; }
void setProgress(int percent);
private:
int m_progress; // always in percent
int m_weight;
bool m_interrupted;
KisProgressUpdater *m_parent;
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment