source: branches/stable/CORE/arb_progress.h

Last change on this file was 12267, checked in by westram, 5 years ago
File size: 8.7 KB
Line 
1// ================================================================ //
2//                                                                  //
3//   File      : arb_progress.h                                     //
4//   Purpose   :                                                    //
5//                                                                  //
6//   Coded by Ralf Westram (coder@reallysoft.de) in November 2010   //
7//   Institute of Microbiology (Technical University Munich)        //
8//   http://www.arb-home.de/                                        //
9//                                                                  //
10// ================================================================ //
11
12#ifndef ARB_PROGRESS_H
13#define ARB_PROGRESS_H
14
15#ifndef ARB_ASSERT_H
16#include <arb_assert.h>
17#endif
18#ifndef ARB_ERROR_H
19#include <arb_error.h>
20#endif
21#ifndef ARBTOOLS_H
22#include <arbtools.h>
23#endif
24
25#if defined(DEBUG)
26#if defined(DEVEL_RALF)
27#define DUMP_PROGRESS
28#define TEST_COUNTERS
29#endif
30#endif
31
32
33class  arb_parent_progress;
34struct arb_status_implementation;
35
36class arb_progress_counter : virtual Noncopyable {
37protected:
38    arb_parent_progress *progress;
39public:
40    arb_progress_counter(arb_parent_progress *progress_)
41        : progress(progress_)
42    {}
43    virtual ~arb_progress_counter() {}
44
45    virtual void inc()                              = 0;
46    virtual void implicit_inc()                     = 0;
47    virtual void child_updates_gauge(double gauge)  = 0;
48    virtual void done()                             = 0;
49    virtual void force_update()                     = 0;
50    virtual void restart(int overall_count)         = 0;
51    virtual void auto_subtitles(const char *prefix) = 0;
52    virtual bool has_auto_subtitles()               = 0;
53
54#if defined(DUMP_PROGRESS)
55    virtual void dump() = 0;
56#endif
57
58    virtual arb_progress_counter *clone(arb_parent_progress *parent, int overall_count) const = 0;
59};
60
61const int LEVEL_TITLE    = 0;
62const int LEVEL_SUBTITLE = 1;
63
64class arb_parent_progress : virtual Noncopyable {
65    arb_parent_progress *prev_recent;
66    bool                 reuse_allowed; // display may be reused by childs
67
68protected:
69#if defined(DUMP_PROGRESS)
70    char *name;
71#endif
72   
73    bool                  has_title;
74    arb_progress_counter *counter;
75
76    static arb_parent_progress       *recent;
77    static arb_status_implementation *impl; // defines implementation to display status
78
79    virtual SmartPtr<arb_parent_progress> create_child_progress(const char *title, int overall_count) = 0;
80
81    arb_parent_progress(arb_progress_counter *counter_, bool has_title_) 
82        : reuse_allowed(false),
83          has_title(has_title_),
84          counter(counter_)
85    {
86        prev_recent = recent;
87        recent      = this;
88       
89#if defined(DUMP_PROGRESS)
90        name = NULL;
91#endif
92
93#if defined(TEST_COUNTERS)
94        accept_invalid_counters = false;
95#endif
96    }
97public:
98#if defined(TEST_COUNTERS)
99    bool accept_invalid_counters; // if true, do not complain about unfinished counters
100#endif
101
102    virtual ~arb_parent_progress() {
103        delete counter;
104        recent = prev_recent;
105#if defined(DUMP_PROGRESS)
106        free(name);
107#endif
108    }
109
110    static SmartPtr<arb_parent_progress> create(const char *title, int overall_count);
111    static SmartPtr<arb_parent_progress> create_suppressor();
112
113    virtual bool aborted() const                       = 0;
114    virtual void set_text(int level, const char *text) = 0;
115    virtual void update_gauge(double gauge)            = 0;
116
117#if defined(DUMP_PROGRESS)
118    virtual void dump();
119#endif
120
121    void child_sets_text(int level, const char *text) {
122        set_text(level+1-reuse_allowed+counter->has_auto_subtitles(), text);
123    }
124    void allow_title_reuse() { reuse_allowed = true; }
125
126    void child_updates_gauge(double gauge) { counter->child_updates_gauge(gauge); }
127    void child_terminated() { counter->implicit_inc(); }
128
129    arb_progress_counter *clone_counter(int overall_count) { return counter->clone(this, overall_count); }
130    void initial_update() { counter->force_update(); }
131    void force_update() { counter->force_update(); }
132
133    void inc() { counter->inc(); }
134    void done() { counter->done(); }
135    void auto_subtitles(const char *prefix) { counter->auto_subtitles(prefix); }
136
137    static void show_comment(const char *comment) {
138        if (recent) recent->set_text(LEVEL_SUBTITLE, comment);
139    }
140};
141
142class arb_progress {
143    SmartPtr<arb_parent_progress> used;
144
145    void setup(const char *title, int overall_count) {
146        used = arb_parent_progress::create(title, overall_count);
147        used->initial_update();
148    }
149    // cppcheck-suppress functionConst
150    void accept_invalid_counters() {
151#if defined(TEST_COUNTERS)
152        used->accept_invalid_counters = true;
153#endif
154    }
155
156public:
157    // ------------------------------
158    // recommended interface:
159
160    arb_progress(const char *title, int overall_count) {
161        // open a progress indicator
162        //
163        // expects to be incremented 'overall_count' times
164        //      incrementation is done either
165        //      - explicitely by calling one of the inc...()-functions below or
166        //      - implicitely by creating another arb_progress while this one remains
167        //
168        // if you can't ahead-determine the exact number of incrementations,
169        // specify an upper-limit and call .done() before dtor.
170
171        arb_assert(overall_count >= 0);
172        setup(title, overall_count);
173    }
174    explicit arb_progress(const char *title) {
175        // open a wrapping progress indicator
176        //
177        // expects NOT to be incremented explicitely!
178        //      if arb_progresses are created while this exists, they reuse the progress window.
179        //      Useful to avoid spamming the user with numerous popping-up progress windows.
180        setup(title, 0);
181    }
182    explicit arb_progress(int overall_count) {
183        // open counting progress (reuses text of parent progress).
184        //
185        // Useful to separate text- from gauge-display or
186        // to summarize several consecutive child-progresses into one.
187        setup(NULL, overall_count);
188    }
189    arb_progress() {
190        // plain wrapper (avoids multiple implicit increments of its parent).
191        //
192        // usage-conditions:
193        // * caller increments progress in a loop and
194        // * loop calls one or more callees and callees open multiple progress bars.
195        //
196        // in this case the parent progress would be implicitely incremented several times
197        // per loop, resulting in wrong gauge.
198        //
199        // if you know the number of opened progresses, use arb_progress(int),
200        // otherwise add one wrapper-progress into the loop.
201        setup(NULL, 0);
202    }
203
204    void allow_title_reuse() { used->allow_title_reuse(); }
205
206    void subtitle(const char *stitle) { used->set_text(LEVEL_SUBTITLE, stitle); }
207
208    GB_ERROR error_if_aborted() {
209        return aborted() ? "Operation aborted on user request" : NULL;
210    }
211
212    GB_ERROR inc_and_error_if_aborted() {
213        inc();
214        return error_if_aborted();
215    }
216
217    void inc_and_check_user_abort(GB_ERROR& error)  { if (!error) error = inc_and_error_if_aborted(); else accept_invalid_counters(); }
218    void inc_and_check_user_abort(ARB_ERROR& error) { if (!error) error = inc_and_error_if_aborted(); else accept_invalid_counters(); }
219
220    bool aborted() {
221        // true if user pressed "Abort"
222        bool aborted_ = used->aborted();
223#if defined(TEST_COUNTERS)
224        if (aborted_) accept_invalid_counters();
225#endif
226        return aborted_;
227    }
228
229    void auto_subtitles(const char *prefix) {
230        // automatically update subtitles ("prefix #/#")
231        // prefix = NULL -> switch off
232        used->auto_subtitles(prefix);
233    }
234    static void show_comment(const char *comment) {
235        // Like subtitle(), but w/o needing to know anything about a eventually open progress
236        // e.g. used to show ARB is connecting to ptserver
237        arb_parent_progress::show_comment(comment);
238    }
239   
240    // ------------------------------
241    // less recommended interface:
242
243    void inc() { used->inc(); } // increment progress
244    const arb_progress& operator++() { inc(); return *this; } // ++progress
245
246    void inc_by(int count) { arb_assert(count>0); while (count--) inc(); }
247
248    void sub_progress_skipped() { used->child_terminated(); }
249
250    void done() { used->done(); } // set "done" (aka 100%). Useful when exiting some loop early
251#if defined(DUMP_PROGRESS)
252    void dump();
253#endif
254    void force_update() { used->force_update(); }
255};
256
257class arb_suppress_progress {
258    SmartPtr<arb_parent_progress> suppressor;
259public:
260    arb_suppress_progress()
261        : suppressor(arb_parent_progress::create_suppressor())
262    {}
263};
264
265#else
266#error arb_progress.h included twice
267#endif // ARB_PROGRESS_H
Note: See TracBrowser for help on using the repository browser.