namespace ui
{ /////////////////////////////////////////////////////////////////
+ /** Simple ResStatus backup stack.
+ * \ref restore simply rewinds all remembered status.
+ */
+ class StatusBackup
+ {
+ public:
+ typedef ResStatus::TransactByValue Causer;
+
+ public:
+ /** Backup status. */
+ ResStatus & backup( ResStatus & status_r )
+ {
+ _backup.push_back( status_r );
+ return status_r;
+ }
+ /** \overload */
+ ResStatus & backup( const PoolItem & pi_r )
+ { return backup( pi_r.status() ); }
+
+ /** Backup status. */
+ ResStatus & operator()( ResStatus & status_r )
+ { return backup( status_r ); }
+ /** \overload */
+ ResStatus & operator()( const PoolItem & pi_r )
+ { return backup( pi_r.status() ); }
+
+ /** Restore all status. */
+ bool restore()
+ {
+ for_( rit, _backup.rbegin(), _backup.rend() )
+ rit->replay();
+ return false; // restore is done on error - return restore();
+ }
+
+ public:
+ /** lowlevel \c ResStatus::setTransact */
+ bool setTransact( const PoolItem & pi_r, bool yesno_r, Causer causer_r )
+ { return backup( pi_r ).setTransact( yesno_r, causer_r ); }
+
+ /** lowlevel \c ResStatus::setLock */
+ bool setLock( const PoolItem & pi_r, bool yesno_r, Causer causer_r )
+ { return backup( pi_r ).setLock( yesno_r, causer_r ); }
+
+ /** lowlevel \c ResStatus::setTransact(true). */
+ bool setTransactTrue( const PoolItem & pi_r, Causer causer_r )
+ { return setTransact( pi_r, true, causer_r ); }
+
+ /** lowlevel \c ResStatus::setTransact(false). */
+ bool setTransactFalse( const PoolItem & pi_r, Causer causer_r )
+ { return setTransact( pi_r, false, causer_r ); }
+
+ public:
+ /** highevel set transact (force unlock). */
+ bool transact( const PoolItem & pi_r, Causer causer_r )
+ {
+ ResStatus & status( backup( pi_r ) );
+ if ( ! status.setLock( false, causer_r ) ) return false;
+ if ( ! status.setTransact( true, causer_r ) ) return false;
+ return true;
+ }
+
+ /** highlevel set locked. */
+ bool lock( const PoolItem & pi_r, Causer causer_r )
+ {
+ ResStatus & status( backup( pi_r ) );
+ if ( ! status.setTransact( false, causer_r ) ) return false;
+ if ( ! status.setLock( true, causer_r ) ) return false;
+ return true;
+ }
+
+ /** highlevel unlock (also unsets transact). */
+ bool unlock( const PoolItem & pi_r, Causer causer_r )
+ {
+ ResStatus & status( backup( pi_r ) );
+ if ( ! status.setTransact( false, causer_r ) ) return false;
+ if ( ! status.setLock( false, causer_r ) ) return false;
+ return true;
+ }
+
+ /** Highlevel action. */
+ typedef bool (StatusBackup::*Action)( const PoolItem &, Causer );
+
+ /** Highlevel action on range of items. */
+ template <class _Iter>
+ bool forEach( _Iter begin_r, _Iter end_r, Action action_r, Causer causer_r )
+ {
+ for_( it, begin_r, end_r )
+ if ( ! (this->*action_r)( *it, causer_r ) )
+ return false;
+ return true;
+ }
+
+ private:
+ std::vector<resstatus::StatusBackup> _backup;
+ };
+
///////////////////////////////////////////////////////////////////
//
// CLASS NAME : StatusHelper
ResStatus & inststatus( backup( inst.status() ) );
if ( ! inststatus.setTransact( false, causer ) ) return restore();
if ( ! inststatus.setLock ( false, causer ) ) return restore();
- if ( ! cand->installOnly() )
+ if ( ! cand->multiversionInstall() )
{
// This is what the solver most probabely will do.
// If we are wrong the solver will correct it. But
ResStatus::TransactByValue causer;
private:
- // No backup replay needed if causer is user,
- // because actions should always succeed.
-
- ResStatus & backup( ResStatus & status_r )
- {
- if ( causer != ResStatus::USER )
- _backup.push_back( status_r );
- return status_r;
- }
-
- bool restore()
- {
- if ( causer != ResStatus::USER )
- {
- for_( rit, _backup.rbegin(), _backup.rend() )
- {
- rit->replay();
- }
- }
- return false; // restore is done on error - return restore();
- }
-
- std::vector<resstatus::StatusBackup> _backup;
+ bool restore() { return backup.restore(); }
+ StatusBackup backup;
};
///////////////////////////////////////////////////////////////////
return S_NoInst;
}
- bool Selectable::Impl::setStatus( const Status state_r, ResStatus::TransactByValue causer_r )
+ bool Selectable::Impl::setStatus( Status state_r, ResStatus::TransactByValue causer_r )
{
StatusHelper self( *this, causer_r );
}
///////////////////////////////////////////////////////////////////
-
- bool Selectable::Impl::setPickStatus( const PoolItem & pi_r, const Status state_r, ResStatus::TransactByValue causer_r )
+ bool Selectable::Impl::setPickStatus( const PoolItem & pi_r, Status state_r, ResStatus::TransactByValue causer_r )
{
+ if ( pi_r.satSolvable().ident() == ident() )
+ return false; // not my PoolItem
+
+ if ( ! multiversionInstall() )
+ return false; // We're not yet ready for this.
+ // TODO: Without multiversionInstall take care at most ONE available is set
+ // to install. Upon install ALL installed get deleted. Only upon deletetion
+ // one might pick individual versions (but more than one would be an error here).
+
+ StatusBackup backup;
+ std::vector<PoolItem> i;
+ std::vector<PoolItem> a;
+
+ for_( it, installedBegin(), installedEnd() )
+ if ( identical( *it, pi_r ) )
+ i.push_back( *it );
+ for_( it, availableBegin(), availableEnd() )
+ if ( identical( *it, pi_r ) )
+ i.push_back( *it );
+
+ switch ( state_r )
+ {
+ case S_Protected:
+ if ( causer_r == ResStatus::USER && ! i.empty() )
+ {
+ if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
+ if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
+ return true;
+ }
+ break;
+
+ case S_Taboo:
+ if ( causer_r == ResStatus::USER && ! a.empty() )
+ {
+ if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
+ return true;
+ }
+ break;
+
+ case S_AutoDel:
+ case S_AutoInstall:
+ case S_AutoUpdate:
+ // Auto level is SOLVER level. UI may query, but not
+ // set at this level.
+ break;
+
+ case S_Del:
+ if ( ! i.empty() )
+ {
+ if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::transact, causer_r ) ) return backup.restore();
+ if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
+ return true;
+ }
+ break;
+
+ case S_Install:
+ if ( i.empty() && ! a.empty() )
+ {
+ // maybe unlock candidate only?
+ if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+ const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r ); // status already backed up above
+ if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
+ return true;
+ }
+ break;
+
+ case S_Update:
+ if ( ! i.empty() && ! a.empty() )
+ {
+ if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+ if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::setTransactTrue, ResStatus::SOLVER ) ) return backup.restore();
+
+ return true;
+ }
+ break;
+
+ case S_KeepInstalled:
+ if ( ! i.empty() )
+ {
+ if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+ if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+ return true;
+ }
+ break;
+
+ case S_NoInst:
+ if ( i.empty() )
+ {
+ if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+ return true;
+ }
+ break;
+ }
return false;
}