~ubuntu-branches/ubuntu/maverick/freecad/maverick

« back to all changes in this revision

Viewing changes to src/Base/Sequencer.h

  • Committer: Bazaar Package Importer
  • Author(s): Teemu Ikonen
  • Date: 2009-07-16 18:37:41 UTC
  • Revision ID: james.westby@ubuntu.com-20090716183741-oww9kcxqrk991i1n
Tags: upstream-0.8.2237
Import upstream version 0.8.2237

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (c) 2004 Werner Mayer <werner.wm.mayer@gmx.de>              *
 
3
 *                                                                         *
 
4
 *   This file is part of the FreeCAD CAx development system.              *
 
5
 *                                                                         *
 
6
 *   This library is free software; you can redistribute it and/or         *
 
7
 *   modify it under the terms of the GNU Library General Public           *
 
8
 *   License as published by the Free Software Foundation; either          *
 
9
 *   version 2 of the License, or (at your option) any later version.      *
 
10
 *                                                                         *
 
11
 *   This library  is distributed in the hope that it will be useful,      *
 
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
14
 *   GNU Library General Public License for more details.                  *
 
15
 *                                                                         *
 
16
 *   You should have received a copy of the GNU Library General Public     *
 
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
 
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 
20
 *                                                                         *
 
21
 ***************************************************************************/
 
22
 
 
23
 
 
24
#ifndef BASE_SEQUENCER_H
 
25
#define BASE_SEQUENCER_H
 
26
 
 
27
#include <vector>
 
28
 
 
29
#include "Exception.h"
 
30
 
 
31
namespace Base
 
32
{
 
33
 
 
34
class AbortException;
 
35
class SequencerLauncher;
 
36
 
 
37
/**
 
38
 * \brief This class gives the user an indication of the progress of an operation and
 
39
 * it is used to reassure him that the application is still running.
 
40
 *
 
41
 * Here are some code snippets of how to use the sequencer:
 
42
 *  \code
 
43
 *
 
44
 *  #include <Base/Sequencer.h>
 
45
 *
 
46
 *  //first example
 
47
 *  Base::SequencerLauncher seq("my text", 10))
 
48
 *  for (int i=0; i<10; i++)
 
49
 *  {
 
50
 *    // do something
 
51
 *    seq.next ();
 
52
 *  }
 
53
 *
 
54
 *  //second example
 
55
 *  Base::SequencerLauncher seq("my text", 10))
 
56
 *  do
 
57
 *  {
 
58
 *    // do something
 
59
 *  }
 
60
 *  while (seq.next());
 
61
 *
 
62
 *  \endcode
 
63
 *
 
64
 * The implementation of this class also supports several nested instances
 
65
 * at a time. But note, that only the first instance has an effect. Any further
 
66
 * sequencer instance doesn't influence the total numer of iteration steps. This
 
67
 * is simply because it's impossible to get the exact number of iteration steps
 
68
 * for nested instances and thus we have either too few steps estimated then the 
 
69
 * sequencer may indicate 100% but the algorithm still running or we have too many
 
70
 * steps estimated so that the an algorithm may stop long before the sequencer
 
71
 * reaches 100%. 
 
72
 *
 
73
 *  \code
 
74
 *  try {
 
75
 *    //start the first operation
 
76
 *    Base::SequencerLauncher seq1("my text", 10)
 
77
 *    for (int i=0; i<10, i++)
 
78
 *    {
 
79
 *      // do something
 
80
 *
 
81
 *      // start the second operation while the first one is still running
 
82
 *      Base::SequencerLauncher seq2("another text", 10);
 
83
 *      for (int j=0; j<10; j++)
 
84
 *      {
 
85
 *        // do something different
 
86
 *        seq2.next ();
 
87
 *      }
 
88
 *
 
89
 *      seq1.next ( true ); // allow to cancel
 
90
 *    }
 
91
 *  }
 
92
 *  catch(const Base::AbortException&){
 
93
 *    // cleanup your data if needed
 
94
 *  }
 
95
 *
 
96
 *  \endcode
 
97
 *
 
98
 * \note If using the sequencer with SequencerLauncher.next(\a true) then you must
 
99
 * take into account that the exception \a AbortException could be thrown, e.g. in
 
100
 * case the ESC button was pressed. So in this case it's always a good idea to use
 
101
 * the sequencer within a try-catch block.
 
102
 *
 
103
 * \note Instances of SequencerLauncher should always be created on the stack.
 
104
 * This is because if an exception somewhere is thrown the destructor is auto-
 
105
 * matically called to clean-up internal data.
 
106
 *
 
107
 * \author Werner Mayer
 
108
 */
 
109
class BaseExport SequencerBase
 
110
{
 
111
    friend class SequencerLauncher;
 
112
 
 
113
protected:
 
114
    /**
 
115
     * Starts a new operation, returns false if there is already a pending operation,
 
116
     * otherwise it returns true.
 
117
     * In this method startStep() gets invoked that can be reimplemented in sub-classes.
 
118
     */
 
119
    bool start(const char* pszStr, size_t steps);
 
120
    /**
 
121
     * Performs the next step and returns true if the operation is not yet finished.
 
122
     * But note, when 0 was passed to start() as the number of total steps this method
 
123
     * always returns false.
 
124
     *
 
125
     * In this method nextStep() gets invoked that can be reimplemented in sub-classes.
 
126
     * If \a canAbort is true then the operations can be aborted, otherwise (the default)
 
127
     * the operation cannot be aborted. In case it gets aborted an exception AbortException
 
128
     * is thrown.
 
129
     */
 
130
    bool next(bool canAbort = false);
 
131
    /**
 
132
     * Stops the sequencer if all operations are finished. It returns false if
 
133
     * there are still pending operations, otherwise it returns true.
 
134
     */
 
135
    bool stop();
 
136
 
 
137
public:
 
138
    /**
 
139
     * Returns the last created sequencer instance.
 
140
     * If you create an instance of a class inheriting SequencerBase
 
141
     * this object is retrieved instead.
 
142
     *
 
143
     * This mechanism is very useful to have an own sequencer for each layer of FreeCAD.
 
144
     * For example, if FreeCAD is running in server mode you have/need no GUI layer
 
145
     * and therewith no (graphical) progress bar; in this case ConsoleSequencer is taken.
 
146
     * But in cases FreeCAD is running with GUI the @ref Gui::ProgressBar is taken instead.
 
147
     * @see Sequencer
 
148
     */
 
149
    static SequencerBase& Instance();
 
150
    /**
 
151
     * Breaks the sequencer if needed. The default implementation does nothing.
 
152
     * Every pause() must eventually be followed by a corresponding @ref resume().
 
153
     * @see Gui::ProgressBar.
 
154
     */
 
155
    virtual void pause();
 
156
    /**
 
157
     * Continues with progress. The default implementation does nothing.
 
158
     * @see pause(), @see Gui::ProgressBar.
 
159
     */
 
160
    virtual void resume();
 
161
    /**
 
162
     * Returns true if the running sequencer is blocking any user input.
 
163
     * This might be only of interest of the GUI where the progress bar or dialog
 
164
     * is used from a thread. If started from a thread this method should return
 
165
     * false, otherwise true. The default implementation always returns true.
 
166
     */
 
167
    virtual bool isBlocking() const;
 
168
    /** If \a bLock is true then the sequencer gets locked. startStep() and nextStep()
 
169
     * don't get invoked any more until the sequencer gets unlocked again.
 
170
     * This method returns the previous lock state.
 
171
     */
 
172
    bool setLocked(bool bLock);
 
173
    /** Returns true if the sequencer was locked, false otherwise. */
 
174
    bool isLocked() const;
 
175
    /** Returns true if the sequencer is running, otherwise returns false. */
 
176
    bool isRunning() const;
 
177
    /**
 
178
     * Returns true if the pending operation was canceled.
 
179
     */
 
180
    bool wasCanceled() const;
 
181
    /**
 
182
     * Try to cancel the pending operation(s).
 
183
     * E.g. @ref Gui::ProgressBar calls this method after the ESC button was pressed.
 
184
     */
 
185
    void tryToCancel();
 
186
    /**
 
187
     * If you tried to cancel but then decided to continue the operation.
 
188
     * E.g. in @ref Gui::ProgressBar a dialog appears asking if you really want to
 
189
     * cancel. If you decide to continue this method must be called.
 
190
     */
 
191
    void rejectCancel();
 
192
    /** Returns the current state of progress in percent. */
 
193
    int progressInPercent() const;
 
194
 
 
195
protected:
 
196
    /** construction */
 
197
    SequencerBase();
 
198
    /** Destruction */
 
199
    virtual ~SequencerBase();
 
200
    /**
 
201
     * Sets a text what the pending operation is doing. The default implementation
 
202
     * does nothing.
 
203
     */
 
204
    virtual void setText (const char* pszTxt);
 
205
    /**
 
206
     * This method can be reimplemented in sub-classes to give the user a feedback
 
207
     * when a new sequence starts. The default implementation does nothing.
 
208
     */
 
209
    virtual void startStep();
 
210
    /**
 
211
     * This method can be reimplemented in sub-classes to give the user a feedback
 
212
     * when the next is performed. The default implementation does nothing. If \a canAbort
 
213
     * is true then the pending operation can aborted, otherwise not. Depending on the
 
214
     * re-implementation this method can throw an AbortException if canAbort is true.
 
215
     */
 
216
    virtual void nextStep(bool canAbort);
 
217
    /**
 
218
     * Resets internal data.
 
219
     * If you want to reimplement this method, it is very important to call it �n
 
220
     * the re-implemented method.
 
221
     */
 
222
    virtual void resetData();
 
223
 
 
224
protected:
 
225
    size_t nProgress; /**< Stores the current amount of progress.*/
 
226
    size_t nTotalSteps; /**< Stores the total number of steps */
 
227
 
 
228
private:
 
229
    /** Sets a global sequencer object.
 
230
     * Access to the last registered object is performed by @see Sequencer().
 
231
     */
 
232
    void _setGlobalInstance ();
 
233
 
 
234
    bool _bLocked; /**< Lock/unlock sequencer. */
 
235
    bool _bCanceled; /**< Is set to true if the last pending operation was canceled */
 
236
    int _nLastPercentage; /**< Progress in percent. */
 
237
    static std::vector<SequencerBase*> _aclInstances; /**< A vector of all created instances */
 
238
    static SequencerLauncher* _topLauncher; /**< The outermost launcher */
 
239
};
 
240
 
 
241
/** This special sequencer might be useful if you want to suppress any indication
 
242
 * of the progress to the user.
 
243
 */
 
244
class BaseExport EmptySequencer : public Base::SequencerBase
 
245
{
 
246
public:
 
247
    /** construction */
 
248
    EmptySequencer();
 
249
    /** Destruction */
 
250
    ~EmptySequencer();
 
251
};
 
252
 
 
253
/**
 
254
 * \brief This class writes the progress to the console window.
 
255
 */
 
256
class BaseExport ConsoleSequencer : public SequencerBase
 
257
{
 
258
public:
 
259
    /** construction */
 
260
    ConsoleSequencer ();
 
261
    /** Destruction */
 
262
    ~ConsoleSequencer ();
 
263
 
 
264
protected:
 
265
    /** Starts the sequencer */
 
266
    void startStep();
 
267
    /** Writes the current progress to the console window. */
 
268
    void nextStep(bool canAbort);
 
269
 
 
270
private:
 
271
    /** Puts text to the console window */
 
272
    void setText (const char* pszTxt);
 
273
    /** Resets the sequencer */
 
274
    void resetData();
 
275
};
 
276
 
 
277
/** The SequencerLauncher class is provided for convenience. It allows you to run an instance of the
 
278
 * sequencer by instanciating an object of this class -- most suitable on the stack. So this mechanism
 
279
 * can be used for try-catch-blocks to destroy the object automatically if the C++ exception mechanism
 
280
 * cleans up the stack.
 
281
 *
 
282
 * This class has been introduced to simplify the use with the sequencer. In the FreeCAD Gui layer there
 
283
 * is a subclass of SequencerBase called ProgressBar that grabs the keyboard and filters most of the incoming
 
284
 * events. If the programmer uses the API of SequencerBase directly to start an instance without due diligence
 
285
 * with exceptions then a not handled exception could block the whole application -- the user has to kill the
 
286
 * application then.
 
287
 *
 
288
 * Below is an example of a not correctly used sequencer.
 
289
 *
 
290
 * \code
 
291
 *
 
292
 *  #include <Base/Sequencer.h>
 
293
 *
 
294
 *  void runOperation();
 
295
 *
 
296
 *  void myTest()
 
297
 *  {
 
298
 *    try{
 
299
 *       runOperation();
 
300
 *    } catch(...) {
 
301
 *       // the programmer forgot to stop the sequencer here
 
302
 *       // Under circumstances the sequencer never gets stopped so the keyboard never gets ungrabbed and
 
303
 *       // all Gui events still gets filtered.
 
304
 *    }
 
305
 *  }
 
306
 *
 
307
 *  void runOperation()
 
308
 *  {
 
309
 *    Base::Sequencer().start ("my text", 10);
 
310
 *
 
311
 *    for (int i=0; i<10; i++)
 
312
 *    {
 
313
 *      // do something where an exception be thrown
 
314
 *      ...
 
315
 *      Base::Sequencer().next ();
 
316
 *    }
 
317
 *
 
318
 *    Base::Sequencer().stop ();
 
319
 *  }
 
320
 *
 
321
 * \endcode
 
322
 *
 
323
 * To avoid such problems the SequencerLauncher class can be used as follows:
 
324
 *
 
325
 * \code
 
326
 *
 
327
 *  #include <Base/Sequencer.h>
 
328
 *
 
329
 *  void runOperation();
 
330
 *
 
331
 *  void myTest()
 
332
 *  {
 
333
 *    try{
 
334
 *       runOperation();
 
335
 *    } catch(...) {
 
336
 *       // the programmer forgot to halt the sequencer here
 
337
 *       // If SequencerLauncher leaves its scope the object gets destructed automatically and
 
338
 *       // stops the running sequencer.
 
339
 *    }
 
340
 *  }
 
341
 *
 
342
 *  void runOperation()
 
343
 *  {
 
344
 *    // create an instance on the stack (not on any terms on the heap)
 
345
 *    SequencerLauncher seq("my text", 10);
 
346
 *
 
347
 *    for (int i=0; i<10; i++)
 
348
 *    {
 
349
 *      // do something (e.g. here can be thrown an exception)
 
350
 *      ...
 
351
 *      seq.next ();
 
352
 *    }
 
353
 *  }
 
354
 *
 
355
 * \endcode
 
356
 *
 
357
 * @author Werner Mayer
 
358
 */
 
359
class BaseExport SequencerLauncher
 
360
{
 
361
public:
 
362
    SequencerLauncher(const char* pszStr, size_t steps);
 
363
    ~SequencerLauncher();
 
364
    void setText (const char* pszTxt);
 
365
    bool next(bool canAbort = false);
 
366
};
 
367
 
 
368
/** Access to the only SequencerBase instance */
 
369
inline SequencerBase& Sequencer ()
 
370
{
 
371
    return SequencerBase::Instance();
 
372
}
 
373
 
 
374
} // namespace Base
 
375
 
 
376
#endif // BASE_SEQUENCER_H