1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
#ifndef RUN_WITH_QPROGRESSDIALOG_H
#define RUN_WITH_QPROGRESSDIALOG_H
#include <QProgressDialog>
#include <CGAL/Real_timer.h>
#include "Callback_signaler.h"
#include <atomic>
typedef CGAL::Parallel_if_available_tag Concurrency_tag;
class Signal_callback
{
private:
CGAL::Real_timer timer;
double t_start;
mutable double t_latest;
mutable std::size_t nb;
public:
std::shared_ptr<double> latest_adv;
std::shared_ptr<bool> state;
std::shared_ptr<Callback_signaler> signaler;
Signal_callback(bool)
: latest_adv (new double(0))
, state (new bool(true))
, signaler (new Callback_signaler())
{
timer.start();
t_start = timer.time();
t_latest = t_start;
}
~Signal_callback()
{
}
bool operator() (double advancement) const
{
if (!state)
return false;
*latest_adv = advancement;
// Avoid calling time() at every single iteration, which could
// impact performances very badly
++ nb;
if (advancement != 1 && nb % 1000 != 0)
return *state;
// If the limit is reach, interrupt the algorithm
double t = timer.time();
if (advancement == 1 || (t - t_latest) > 0.25)
{
signaler->emit_signal (int (100. * advancement));
t_latest = t;
if (signaler->is_canceled)
*state = false;
}
return *state;
}
};
class Functor_with_signal_callback
{
protected:
std::shared_ptr<Signal_callback> m_callback;
public:
Signal_callback* callback() { return m_callback.get(); }
Functor_with_signal_callback()
: m_callback (new Signal_callback(true)) { }
virtual void operator()() = 0;
};
template <typename Functor>
void run_with_qprogressdialog (Functor& functor,
const char* title,
QWidget* mainWindow)
{
return run_with_qprogressdialog<Concurrency_tag> (functor, title, mainWindow);
}
template <typename ConcurrencyTag, typename Functor>
void run_with_qprogressdialog (Functor& functor,
const char* title,
QWidget* mainWindow)
{
mainWindow->setEnabled(false);
QProgressDialog progress (QString(title),
QString("Cancel"),
0, 100,
mainWindow);
progress.setMinimumDuration(0);
Signal_callback* signal_callback = functor.callback();
QEventLoop::connect (signal_callback->signaler.get(), SIGNAL(progressChanged(int)),
&progress, SLOT(setValue(int)));
QEventLoop::connect (&progress, SIGNAL(canceled()),
signal_callback->signaler.get(), SLOT(cancel()));
#ifdef CGAL_HAS_STD_THREADS
if (std::is_convertible<ConcurrencyTag, CGAL::Parallel_tag>::value)
{
std::thread thread (functor);
while (*signal_callback->latest_adv != 1. &&
*signal_callback->state)
{
typedef std::chrono::nanoseconds nanoseconds;
nanoseconds ns (nanoseconds::rep (1000000000.0 * 0.1));
std::this_thread::sleep_for(ns);
QApplication::processEvents ();
}
thread.join();
}
else
#endif // Sequential version
{
progress.setWindowModality(Qt::WindowModal);
functor();
}
mainWindow->setEnabled(true);
}
#endif // RUN_WITH_QPROGRESSDIALOG_H
|