File: run_with_qprogressdialog.h

package info (click to toggle)
cgal 6.1.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 144,952 kB
  • sloc: cpp: 811,597; ansic: 208,576; sh: 493; python: 411; makefile: 286; javascript: 174
file content (140 lines) | stat: -rw-r--r-- 3,281 bytes parent folder | download | duplicates (2)
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