1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/ProgressData.h
12 #ifndef ZYPP_PROGRESSDATA_H
13 #define ZYPP_PROGRESSDATA_H
18 #include "zypp/base/PtrTypes.h"
19 #include "zypp/base/Function.h"
20 #include "zypp/base/ProvideNumericId.h"
22 #include "zypp/Date.h"
24 ///////////////////////////////////////////////////////////////////
26 { /////////////////////////////////////////////////////////////////
28 ///////////////////////////////////////////////////////////////////
30 // CLASS NAME : ProgressData
32 /** Maintain <tt>[min,max]</tt> and counter <tt>(value)</tt> for progress counting.
34 * This class should provide everything the producer of progress data
35 * needs. As a convention, a zero sizes range indicates that you are just
36 * able to send <em>'still alive'</em> triggers.
38 * The counter should be updated in reasonable intervals. Don't mind whether
39 * the counter value actually increased or not. ProgressData will recognize
40 * your triggers and knows when to actually send notification to a consumer.
42 * Each ProgressData object provides a unique numeric id and you may assign
46 * bool exampleReceiver( ProgressData::value_type v )
48 * DBG << "got ->" << v << endl;
49 * return( v <= 100 ); // Abort if ( v > 100 )
56 * Example( const ProgressData::ReceiverFnc & fnc_r = ProgressData::ReceiverFnc() )
60 * void SendTo( const ProgressData::ReceiverFnc & fnc_r )
67 * ProgressData tics( 10 ); // Expect range 0 -> 10
68 * tics.name( "test ticks" ); // Some arbitrary name
69 * tics.sendTo( _fnc ); // Send reports to _fnc
70 * tics.toMin(); // start sending min (0)
72 * for ( int i = 0; i < 10; ++i )
74 * if ( ! tics.set( i ) )
75 * return; // user requested abort
78 * tics.toMax(); // take care 100% are reported on success
83 * ProgressData tics; // Just send 'still alive' messages
84 * tics.name( "test ticks" ); // Some arbitrary name
85 * tics.sendTo( _fnc ); // Send reports to _fnc
86 * tics.toMin(); // start sending min (0)
88 * for ( int i = 0; i < 10; ++i )
90 * if ( ! tics.set( i ) )
91 * return; // user requested abort
98 * ProgressData::ReceiverFnc _fnc;
102 * Example t( exampleReceiver );
103 * DBG << "Reporting %:" << endl;
105 * DBG << "Reporting 'still alive':" << endl;
122 * Reporting 'still alive':
127 * The different ammount of triggers is due to different rules for sending
128 * percent or 'still alive' messages.
130 class ProgressData : public base::ProvideNumericId<ProgressData,unsigned>
133 typedef long long value_type;
134 /** Most simple version of progress reporting
135 * The percentage in most cases. Sometimes just keepalive.
136 * \p sender ProgressData object who sends the progress info
139 typedef function<bool( const ProgressData & )> ReceiverFnc;
142 enum State { INIT, RUN, END };
147 Data( value_type min_r, value_type max_r, value_type val_r )
148 : _state( INIT ), _min( min_r ), _max( max_r ), _val( val_r )
149 , _last_val( 0 ), _last_send( 0 )
159 ReceiverFnc _receiver;
160 value_type _last_val;
164 /** clone for RWCOW_pointer */
165 friend Data * rwcowClone<Data>( const Data * rhs );
166 Data * clone() const { return new Data( *this ); }
170 /** Ctor no range <tt>[0,0](0)</tt>. */
172 : _d( new Data( 0, 0, 0 ) )
175 /** Ctor <tt>[0,max](0)</tt>. */
176 ProgressData( value_type max_r )
177 : _d( new Data( 0, max_r, 0 ) )
180 /** Ctor <tt>[min,max](min)</tt>. */
181 ProgressData( value_type min_r, value_type max_r )
182 : _d( new Data( min_r, max_r, min_r ) )
185 /** Ctor <tt>[min,max](val)</tt>. */
186 ProgressData( value_type min_r, value_type max_r, value_type val_r )
187 : _d( new Data( min_r, max_r, val_r ) )
192 if ( _d->_state == RUN )
200 /** Set new \c min value. */
201 void min( value_type min_r )
202 { _d->_min = min_r; }
204 /** Set new \c max value. */
205 void max( value_type max_r )
206 { _d->_max = max_r; }
208 /** Set no range <tt>[0,0]</tt>. */
212 /** Set new <tt>[0,max]</tt>. */
213 void range( value_type max_r )
214 { range( 0, max_r ); }
216 /** Set new <tt>[min,max]</tt>. */
217 void range( value_type min_r, value_type max_r )
218 { min( min_r ); max( max_r ); }
221 /** Set counter name. */
222 void name( const std::string & name_r )
223 { _d->_name = name_r; }
225 /** Set ReceiverFnc. */
226 void sendTo( const ReceiverFnc & fnc_r )
227 { _d->_receiver = fnc_r; }
229 /** Set no ReceiverFnc. */
231 { _d->_receiver = ReceiverFnc(); }
234 /** \name Progress reporting.
236 * These methods may actually cause a progress report to be sent.
238 * All methods return \c bool, because a progress receiver may
239 * return \c false to indicate the desire to abort the pending
240 * action. The incident is logged, but it's finaly up to the caller
245 /** Set new counter \c value. */
246 bool set( value_type val_r )
252 /** Set range and counter from an other \ref ProgressData. */
253 bool set( const ProgressData & rhs )
257 return set( rhs.val() );
260 /** Increment counter \c value (default by 1). */
261 bool incr( value_type val_r = 1 )
262 { return set( val() + val_r ); }
264 /** Decrement counter \c value (default by 1). */
265 bool decr( value_type val_r = 1 )
266 { return set( val() - val_r ); }
268 /** Set counter value to current \c min value. */
270 { return set( min() ); }
272 /** Set counter value to current \c max value (unless no range). */
274 { return hasRange() ? set( max() ) : tick(); }
276 /** Leave counter value unchanged (still alive). */
283 /** \name Progress receiving.
286 /** @return Current \c min value. */
287 value_type min() const
290 /** @return Current \c max value. */
291 value_type max() const
294 /** @return Current counter \c value. */
295 value_type val() const
298 /** @return Whether <tt>[min,max]</tt> defines a nonempty range. */
299 bool hasRange() const
300 { return min() != max(); }
302 /** @return Whether \ref reportValue will return a percent value.
303 * Same as \ref hasRange.
304 * \see \ref reportAlive
306 bool reportPercent() const
307 { return hasRange(); }
309 /** @return Whether \ref reportValue always returns -1, because we
310 * trigger 'still alive' messages. I.e. \ref hasrange is \c false.
311 * \see \ref reportPercent
313 bool reportAlive() const
314 { return ! hasRange(); }
316 /** @return Either a a percent value or -1.
317 * \see \ref reportPercent and \ref reportAlive.
319 value_type reportValue() const
320 { return hasRange() ? val() * 100 / ( max() - min() ) : -1; }
322 /** @return The counters name. */
323 const std::string & name() const
324 { return _d->_name; }
326 /** @return The ReceiverFnc. */
327 const ReceiverFnc & receiver() const
328 { return _d->_receiver; }
330 /** @return Return \c true if this is the final report sent by the
333 bool finalReport() const
334 { return( _d->_state == END ); }
339 /** Send report if necessary. */
342 /** Pointer to data. */
343 RWCOW_pointer<Data> _d;
345 ///////////////////////////////////////////////////////////////////
347 /** \relates ProgressData Stream output */
348 std::ostream & operator<<( std::ostream & str, const ProgressData & obj );
350 ///////////////////////////////////////////////////////////////////
353 /** \relates ProgressData Setup from \ref InputStream. */
354 ProgressData makeProgressData( const InputStream & input_r );
356 ///////////////////////////////////////////////////////////////////
359 * \short Progress callback from another progress
361 * This class allows you to pass a progress callback to a
362 * subtask based on a current progress data, plus a weight
363 * value. Every progress reported by the subtask via
364 * this callback will be forwarded to the main progress
365 * data, with the corresponding weight.
371 * // receiver for main task
372 * void task_receiver( ProgressData &progress );
374 * // subtask prototypes
375 * void do_subtask_one( ProgressData::ReceiverFnc &fnc );
376 * void do_subtask_two( ProgressData::ReceiverFnc &fnc );
379 * ProgressData progress;
380 * //progress for subtask 1
382 * CombinedProgressData sub1(pd, 80);
383 * // the second is only 20%
384 * CombinedProgressData sub2(pd, 20);
385 * do_subtask_one( sub1 );
386 * do_subtask_two( sub2 );
390 class CombinedProgressData
396 * Creates a \ref ProgressData::ReceiverFnc
397 * from a \ref ProgressData object
399 * \param pd \ref ProgressData object
400 * \param weight Weight of the subtask
401 * relative to the main task range.
403 * If weight is 0, or \param pd only reports
404 * keepalives. then only ticks are sent.
407 CombinedProgressData( ProgressData &pd,
408 ProgressData::value_type weight = 0 );
411 * Implements the \ref ProgressData::ReceiverFnc
414 bool operator()( const ProgressData &progress );
417 ProgressData::value_type _weight;
418 ProgressData::value_type _last_value;
422 /////////////////////////////////////////////////////////////////
424 ///////////////////////////////////////////////////////////////////
425 #endif // ZYPP_PROGRESSDATA_H