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 wheter
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 * \todo Complete the progess sending.
131 * \todo Tell recipient whether percentage or keepalive is sent,
132 * the id and name might be helpfull, and maybe tell whether task
133 * is abortable or not; i.e extend the ReceiverFnc signature.
135 class ProgressData : public base::ProvideNumericId<ProgressData,unsigned>
138 typedef long long value_type;
139 /** Most simple version of progress reporting
140 * The percentage in most cases. Sometimes just keepalive.
141 * \p sender ProgressData object who sends the progress info
144 typedef function<bool( const ProgressData & )> ReceiverFnc;
147 enum State { INIT, RUN, END };
152 Data( value_type min_r, value_type max_r, value_type val_r )
153 : _state( INIT ), _min( min_r ), _max( max_r ), _val( val_r )
154 , _last_val( 0 ), _last_send( 0 )
164 ReceiverFnc _receiver;
165 value_type _last_val;
169 /** clone for RWCOW_pointer */
170 friend Data * rwcowClone<Data>( const Data * rhs );
171 Data * clone() const { return new Data( *this ); }
175 /** Ctor no range <tt>[0,0](0)</tt>. */
177 : _d( new Data( 0, 0, 0 ) )
180 /** Ctor <tt>[0,max](0)</tt>. */
181 ProgressData( value_type max_r )
182 : _d( new Data( 0, max_r, 0 ) )
185 /** Ctor <tt>[min,max](min)</tt>. */
186 ProgressData( value_type min_r, value_type max_r )
187 : _d( new Data( min_r, max_r, min_r ) )
190 /** Ctor <tt>[min,max](val)</tt>. */
191 ProgressData( value_type min_r, value_type max_r, value_type val_r )
192 : _d( new Data( min_r, max_r, val_r ) )
197 if ( _d->_state == RUN )
205 /** Set new \c min value. */
206 void min( value_type min_r )
207 { _d->_min = min_r; }
209 /** Set new \c max value. */
210 void max( value_type max_r )
211 { _d->_max = max_r; }
213 /** Set no range <tt>[0,0]</tt>. */
217 /** Set new <tt>[0,max]</tt>. */
218 void range( value_type max_r )
219 { range( 0, max_r ); }
221 /** Set new <tt>[min,max]</tt>. */
222 void range( value_type min_r, value_type max_r )
223 { min( min_r ); max( max_r ); }
226 /** Set counter name. */
227 void name( const std::string & name_r )
228 { _d->_name = name_r; }
230 /** Set ReceiverFnc. */
231 void sendTo( const ReceiverFnc & fnc_r )
232 { _d->_receiver = fnc_r; }
234 /** Set no ReceiverFnc. */
236 { _d->_receiver = ReceiverFnc(); }
239 /** \name Progress reporting.
241 * These methods may actually cause a progress report to be sent.
243 * All methods return \c bool, because a progress receiver may
244 * return \c false to indicate the desire to abort the pending
245 * action. The incident is logged, but it's finaly up to the caller
250 /** Set new counter \c value. */
251 bool set( value_type val_r )
257 /** Increment counter \c value (default by 1). */
258 bool incr( value_type val_r = 1 )
259 { return set( val() + val_r ); }
261 /** Decrement counter \c value (default by 1). */
262 bool decr( value_type val_r = 1 )
263 { return set( val() - val_r ); }
265 /** Set counter value to current \c min value. */
267 { return set( min() ); }
269 /** Set counter value to current \c max value (unless no range). */
271 { return set( hasRange() ? max() : val() ); }
273 /** Leave counter value unchanged (still alive). */
275 { return set( val() ); }
280 /** \name Progress receiving.
283 /** @return Current \c min value. */
284 value_type min() const
287 /** @return Current \c max value. */
288 value_type max() const
291 /** @return Current counter \c value. */
292 value_type val() const
295 /** @return Wheter <tt>[min,max]</tt> defines a nonempty range. */
296 bool hasRange() const
297 { return min() != max(); }
299 /** @return Wheter \ref reportValue will return a percent value.
300 * Same as \ref hasRange.
301 * \see \ref reportAlive
303 bool reportPercent() const
304 { return hasRange(); }
306 /** @return Wheter \ref reportValue always returns -1, because we
307 * trigger 'still alive' messages. I.e. \ref hasrange is \c false.
308 * \see \ref reportPercent
310 bool reportAlive() const
311 { return ! hasRange(); }
313 /** @return Either a a percent value or -1.
314 * \see \ref reportPercent and \ref reportAlive.
316 value_type reportValue() const
317 { return hasRange() ? val() * 100 / ( max() - min() ) : -1; }
319 /** @return The counters name. */
320 const std::string & name() const
321 { return _d->_name; }
323 /** @return The ReceiverFnc. */
324 const ReceiverFnc & receiver() const
325 { return _d->_receiver; }
327 /** @return Retrun \c true if this the final report sent by the
330 bool finalReport() const
331 { return( _d->_state == END ); }
336 /** Send report if necessary. */
339 /** Pointer to data. */
340 RWCOW_pointer<Data> _d;
342 ///////////////////////////////////////////////////////////////////
344 /** \relates ProgressData Stream output */
345 std::ostream & operator<<( std::ostream & str, const ProgressData & obj );
347 ///////////////////////////////////////////////////////////////////
350 /** \relates ProgressData Setup from \ref InputStream. */
351 ProgressData makeProgressData( const InputStream & input_r );
353 ///////////////////////////////////////////////////////////////////
356 * \short Progress callback from another progress
358 * This class allows you to pass a progress callback to a
359 * subtask based on a current progress data, plus a weight
360 * value. Every progress reported by the subtask via
361 * this callback will be forwarded to the main progress
362 * data, with the corresponding weight.
368 * // receiver for main task
369 * void task_receiver( ProgressData &progress );
371 * // subtask prototypes
372 * void do_subtask_one( ProgressData::ReceiverFnc &fnc );
373 * void do_subtask_two( ProgressData::ReceiverFnc &fnc );
376 * ProgressData progress;
377 * //progress for subtask 1
379 * CombinedProgressData sub1(pd, 80);
380 * // the second is only 20%
381 * CombinedProgressData sub2(pd, 20);
382 * do_subtask_one( sub1 );
383 * do_subtask_two( sub2 );
387 class CombinedProgressData
393 * Creates a \ref ProgressData::ReceiverFnc
394 * from a \ref ProgressData object
396 * \param pd \ref ProgressData object
397 * \param weight Weight of the subtask
398 * relative to the main task range.
400 * If weight is 0, or \param pd only reports
401 * keepalives. then only ticks are sent.
404 CombinedProgressData( ProgressData &pd,
405 ProgressData::value_type weight = 0 );
408 * Implements the \ref ProgressData::ReceiverFnc
411 bool operator()( const ProgressData &progress );
414 ProgressData::value_type _weight;
415 ProgressData::value_type _last_value;
419 /////////////////////////////////////////////////////////////////
421 ///////////////////////////////////////////////////////////////////
422 #endif // ZYPP_PROGRESSDATA_H