44c30d1416b80caf4fe45e2fcac3a69e36bffe4b
[platform/upstream/libzypp.git] / zypp / ui / SelectableImpl.h
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/ui/SelectableImpl.h
10  *
11 */
12 #ifndef ZYPP_UI_SELECTABLEIMPL_H
13 #define ZYPP_UI_SELECTABLEIMPL_H
14
15 #include <iostream>
16 #include "zypp/base/LogTools.h"
17
18 #include "zypp/base/PtrTypes.h"
19
20 #include "zypp/ResPool.h"
21 #include "zypp/Resolver.h"
22 #include "zypp/ui/Selectable.h"
23 #include "zypp/ui/SelectableTraits.h"
24
25 using std::endl;
26
27 ///////////////////////////////////////////////////////////////////
28 namespace zypp
29 { /////////////////////////////////////////////////////////////////
30   ///////////////////////////////////////////////////////////////////
31   namespace ui
32   { /////////////////////////////////////////////////////////////////
33
34     ///////////////////////////////////////////////////////////////////
35     //
36     //  CLASS NAME : Selectable::Impl
37     //
38     /** Selectable implementation.
39      * \note Implementation is based in PoolItem, just the Selectable
40      * inteface restricts them to ResObject::constPtr.
41     */
42     struct Selectable::Impl
43     {
44     public:
45
46       typedef SelectableTraits::AvailableItemSet         AvailableItemSet;
47       typedef SelectableTraits::available_iterator       available_iterator;
48       typedef SelectableTraits::available_const_iterator available_const_iterator;
49       typedef SelectableTraits::available_size_type      available_size_type;
50
51       typedef SelectableTraits::InstalledItemSet         InstalledItemSet;
52       typedef SelectableTraits::installed_iterator       installed_iterator;
53       typedef SelectableTraits::installed_const_iterator installed_const_iterator;
54       typedef SelectableTraits::installed_size_type      installed_size_type;
55
56       typedef SelectableTraits::PickList                PickList;
57
58     public:
59       template <class _Iterator>
60       Impl( const ResObject::Kind & kind_r,
61             const std::string & name_r,
62             _Iterator begin_r,
63             _Iterator end_r )
64       : _ident( sat::Solvable::SplitIdent( kind_r, name_r ).ident() )
65       , _kind( kind_r )
66       , _name( name_r )
67       {
68         for_( it, begin_r, end_r )
69         {
70           if ( it->status().isInstalled() )
71             _installedItems.insert( *it );
72           else
73             _availableItems.insert( *it );
74         }
75       }
76
77     public:
78       /**  */
79       IdString ident() const
80       { return _ident; }
81
82       /**  */
83       ResObject::Kind kind() const
84       { return _kind; }
85
86       /**  */
87       const std::string & name() const
88       { return _name; }
89
90       /**  */
91       Status status() const;
92
93       /**  */
94       bool setStatus( Status state_r, ResStatus::TransactByValue causer_r );
95
96       /** Installed object (transacting ot highest version). */
97       PoolItem installedObj() const
98       {
99         if ( installedEmpty() )
100           return PoolItem();
101         PoolItem ret( transactingInstalled() );
102         return ret ? ret : *_installedItems.begin();
103       }
104
105       /** Best among available objects.
106        * The transacting candidate or the one scheduled to receive
107        * the transact bit.
108       */
109       PoolItem candidateObj() const
110       {
111         PoolItem ret( transactingCandidate() );
112         if ( ret )
113           return ret;
114         return _candidate ? _candidate : defaultCandidate();
115       }
116
117       /** Set a userCandidate (out of available objects).
118        * \return The new userCandidate or NULL if choice was invalid
119        * (not among availableObjs).
120       */
121       PoolItem setCandidate( const PoolItem & newCandidate_r, ResStatus::TransactByValue causer_r );
122
123       /** The best candidate provided by a specific \ref Repository, if there is one.
124        * In contrary to \ref candidateObj, this may return no item even if
125        * there are available objects. This simply means the \ref Repository
126        * does not provide this object.
127        */
128       PoolItem candidateObjFrom( Repository repo_r ) const
129       {
130         for_( it, availableBegin(), availableEnd() )
131         {
132           if ( (*it)->repository() == repo_r )
133             return *it;
134         }
135         return PoolItem();
136       }
137
138       /** The best candidate for update, if there is one.
139        * In contrary to \ref candidateObj, this may return no item even if
140        * there are available objects. This simply means the best object is
141        * already installed, and all available objects violate at least one
142        * update policy.
143        */
144       PoolItem updateCandidateObj() const
145       {
146         PoolItem defaultCand( defaultCandidate() );
147
148         // multiversionInstall: This returns the candidate for the last
149         // instance installed. Actually we'd need a list here.
150
151         if ( installedEmpty() || ! defaultCand )
152           return defaultCand;
153         // Here: installed and defaultCand are non NULL and it's not a
154         //       multiversion install.
155
156         PoolItem installed( installedObj() );
157         // check vendor change
158         if ( ! ( ResPool::instance().resolver().allowVendorChange()
159                  || VendorAttr::instance().equivalent( defaultCand->vendor(), installed->vendor() ) ) )
160           return PoolItem();
161
162         // check arch change (arch noarch changes are allowed)
163         if ( defaultCand->arch() != installed->arch()
164            && ! ( defaultCand->arch() == Arch_noarch || installed->arch() == Arch_noarch ) )
165           return PoolItem();
166
167         // check greater edition
168         if ( defaultCand->edition() <= installed->edition() )
169           return PoolItem();
170
171         return defaultCand;
172       }
173
174       /** \copydoc Selectable::highestAvailableVersionObj()const */
175       PoolItem highestAvailableVersionObj() const
176       {
177         PoolItem ret;
178         for_( it, availableBegin(), availableEnd() )
179         {
180           if ( !ret || (*it).satSolvable().edition() > ret.satSolvable().edition() )
181             ret = *it;
182         }
183         return ret;
184       }
185
186       /** \copydoc Selectable::identicalAvailable( const PoolItem & )const */
187       bool identicalAvailable( const PoolItem & rhs ) const
188       { return bool(identicalAvailableObj( rhs )); }
189
190       /** \copydoc Selectable::identicalInstalled( const PoolItem & )const */
191       bool identicalInstalled( const PoolItem & rhs ) const
192       { return bool(identicalInstalledObj( rhs )); }
193
194       /** \copydoc Selectable::identicalAvailableObj( const PoolItem & rhs ) const */
195       PoolItem identicalAvailableObj( const PoolItem & rhs ) const
196       {
197         if ( !availableEmpty() && rhs )
198         {
199           for_( it, _availableItems.begin(), _availableItems.end() )
200           {
201             if ( identical( *it, rhs ) )
202               return *it;
203           }
204         }
205         return PoolItem();
206       }
207
208       /** \copydoc Selectable::identicalInstalledObj( const PoolItem & rhs ) const */
209       PoolItem identicalInstalledObj( const PoolItem & rhs ) const
210       {
211         if ( !installedEmpty() && rhs )
212         {
213           for_( it, _installedItems.begin(), _installedItems.end() )
214           {
215             if ( identical( *it, rhs ) )
216               return *it;
217           }
218         }
219         return PoolItem();
220       }
221
222       /** Best among all objects. */
223       PoolItem theObj() const
224       {
225         PoolItem ret( candidateObj() );
226         if ( ret )
227           return ret;
228         return installedObj();
229       }
230
231       ////////////////////////////////////////////////////////////////////////
232
233       bool availableEmpty() const
234       { return _availableItems.empty(); }
235
236       available_size_type availableSize() const
237       { return _availableItems.size(); }
238
239       available_const_iterator availableBegin() const
240       { return _availableItems.begin(); }
241
242       available_const_iterator availableEnd() const
243       { return _availableItems.end(); }
244
245       ////////////////////////////////////////////////////////////////////////
246
247       bool installedEmpty() const
248       { return _installedItems.empty(); }
249
250       installed_size_type installedSize() const
251       { return _installedItems.size(); }
252
253       installed_iterator installedBegin() const
254       { return _installedItems.begin(); }
255
256       installed_iterator installedEnd() const
257       { return _installedItems.end(); }
258
259       ////////////////////////////////////////////////////////////////////////
260
261       const PickList & picklist() const
262       {
263         if ( ! _picklistPtr )
264         {
265           _picklistPtr.reset( new PickList );
266           // installed without identical avaialble first:
267           for_( it, _installedItems.begin(), _installedItems.end() )
268           {
269             if ( ! identicalAvailable( *it ) )
270               _picklistPtr->push_back( *it );
271           }
272           _picklistPtr->insert( _picklistPtr->end(), availableBegin(), availableEnd() );
273         }
274         return *_picklistPtr;
275       }
276
277       bool picklistEmpty() const
278       { return picklist().empty(); }
279
280       picklist_size_type picklistSize() const
281       { return picklist().size(); }
282
283       picklist_iterator picklistBegin() const
284       { return picklist().begin(); }
285
286       picklist_iterator picklistEnd() const
287       { return picklist().end(); }
288
289       ////////////////////////////////////////////////////////////////////////
290
291       bool isUnmaintained() const
292       { return availableEmpty(); }
293
294       bool multiversionInstall() const
295       { return sat::Pool::instance().isMultiversion( ident() ); }
296
297       bool pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r );
298
299       bool pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r );
300
301       Status pickStatus( const PoolItem & pi_r ) const;
302
303       bool setPickStatus( const PoolItem & pi_r, Status state_r, ResStatus::TransactByValue causer_r );
304
305       ////////////////////////////////////////////////////////////////////////
306
307       bool isUndetermined() const
308       {
309         PoolItem cand( candidateObj() );
310         return ! cand || cand.isUndetermined();
311       }
312       bool isRelevant() const
313       {
314         PoolItem cand( candidateObj() );
315         return cand && cand.isRelevant();
316       }
317       bool isSatisfied() const
318        {
319         PoolItem cand( candidateObj() );
320         return cand && cand.isSatisfied();
321       }
322       bool isBroken() const
323       {
324         PoolItem cand( candidateObj() );
325         return cand && cand.isBroken();
326       }
327
328       /** Return who caused the modification. */
329       ResStatus::TransactByValue modifiedBy() const;
330
331       /** Return value of LicenceConfirmed bit. */
332       bool hasLicenceConfirmed() const
333       { return candidateObj() && candidateObj().status().isLicenceConfirmed(); }
334
335       /** Set LicenceConfirmed bit. */
336       void setLicenceConfirmed( bool val_r )
337       { if ( candidateObj() ) candidateObj().status().setLicenceConfirmed( val_r ); }
338
339       /** \copydoc Selectable::hasLocks()const */
340       bool hasLocks() const
341       {
342         for_( it, availableBegin(), availableEnd() )
343         {
344           const PoolItem & pi( *it );
345           if ( pi.status().isLocked() )
346             return true;
347         }
348         for_( it, installedBegin(), installedEnd() )
349         {
350           const PoolItem & pi( *it );
351           if ( pi.status().isLocked() )
352             return true;
353         }
354         return false;
355       }
356
357     private:
358       PoolItem transactingInstalled() const
359       {
360         for_( it, installedBegin(), installedEnd() )
361           {
362             if ( (*it).status().transacts() )
363               return (*it);
364           }
365         return PoolItem();
366       }
367
368       PoolItem transactingCandidate() const
369       {
370         for_( it, availableBegin(), availableEnd() )
371           {
372             if ( (*it).status().transacts() )
373               return (*it);
374           }
375         return PoolItem();
376       }
377
378       PoolItem defaultCandidate() const
379       {
380         if ( ! installedEmpty() )
381         {
382           // prefer the installed objects arch and vendor
383           bool solver_allowVendorChange( ResPool::instance().resolver().allowVendorChange() );
384           for ( installed_const_iterator iit = installedBegin();
385                 iit != installedEnd(); ++iit )
386           {
387             PoolItem sameArch; // in case there's no same vendor at least stay with same arch.
388             for ( available_const_iterator it = availableBegin();
389                   it != availableEnd(); ++it )
390             {
391               // 'same arch' includes allowed changes to/from noarch.
392               if ( (*iit)->arch() == (*it)->arch() || (*iit)->arch() == Arch_noarch || (*it)->arch() == Arch_noarch )
393               {
394                 if ( ! solver_allowVendorChange )
395                 {
396                   if ( VendorAttr::instance().equivalent( (*iit), (*it) ) )
397                     return *it;
398                   else if ( ! sameArch ) // remember best same arch in case no same vendor found
399                      sameArch = *it;
400                 }
401                 else // same arch is sufficient
402                   return *it;
403               }
404             }
405             if ( sameArch )
406               return sameArch;
407           }
408         }
409         if ( _availableItems.empty() )
410           return PoolItem();
411
412         return *_availableItems.begin();
413       }
414
415       bool allCandidatesLocked() const
416       {
417         for ( available_const_iterator it = availableBegin();
418               it != availableEnd(); ++it )
419           {
420             if ( ! (*it).status().isLocked() )
421               return false;
422           }
423         return( ! _availableItems.empty() );
424       }
425
426       bool allInstalledLocked() const
427       {
428         for ( installed_const_iterator it = installedBegin();
429               it != installedEnd(); ++it )
430           {
431             if ( ! (*it).status().isLocked() )
432               return false;
433           }
434         return( ! _installedItems.empty() );
435       }
436
437
438     private:
439       const IdString         _ident;
440       const ResObject::Kind  _kind;
441       const std::string      _name;
442       InstalledItemSet       _installedItems;
443       AvailableItemSet       _availableItems;
444       //! The object selected by setCandidateObj() method.
445       PoolItem               _candidate;
446       //! lazy initialized picklist
447       mutable scoped_ptr<PickList> _picklistPtr;
448     };
449     ///////////////////////////////////////////////////////////////////
450
451     /** \relates Selectable::Impl Stream output */
452     inline std::ostream & operator<<( std::ostream & str, const Selectable::Impl & obj )
453     {
454       return str << '[' << obj.kind() << ']' << obj.name() << ": " << obj.status()
455                  << " (I " << obj.installedSize() << ")"
456                  << " (A " << obj.availableSize() << ")"
457                  << obj.candidateObj();
458     }
459
460     /** \relates Selectable::Impl Stream output */
461     inline std::ostream & dumpOn( std::ostream & str, const Selectable::Impl & obj )
462     {
463       str << '[' << obj.kind() << ']' << obj.name() << ": " << obj.status()
464           << ( obj.multiversionInstall() ? " (multiversion)" : "") << endl;
465
466       if ( obj.installedEmpty() )
467         str << "   (I 0) {}" << endl << "   ";
468       else
469       {
470         PoolItem icand( obj.installedObj() );
471         str << "   (I " << obj.installedSize() << ") {" << endl;
472         for_( it, obj.installedBegin(), obj.installedEnd() )
473         {
474           char t = ' ';
475           if ( *it == icand )
476           {
477             t = 'i';
478           }
479           str << " " << t << " " << *it << endl;
480         }
481         str << "}  ";
482       }
483
484       if ( obj.availableEmpty() )
485       {
486         str << "(A 0) {}" << endl << "   ";
487       }
488       else
489       {
490         PoolItem cand( obj.candidateObj() );
491         PoolItem up( obj.updateCandidateObj() );
492         str << "(A " << obj.availableSize() << ") {" << endl;
493         for_( it, obj.availableBegin(), obj.availableEnd() )
494         {
495           char t = ' ';
496           if ( *it == cand )
497           {
498             t = *it == up ? 'C' : 'c';
499           }
500           else if ( *it == up )
501           {
502             t = 'u';
503           }
504           str << " " << t << " " << *it << endl;
505         }
506         str << "}  ";
507       }
508
509       if ( obj.picklistEmpty() )
510       {
511         str << "(P 0) {}";
512       }
513       else
514       {
515         PoolItem cand( obj.candidateObj() );
516         PoolItem up( obj.updateCandidateObj() );
517         str << "(P " << obj.picklistSize() << ") {" << endl;
518         for_( it, obj.picklistBegin(), obj.picklistEnd() )
519         {
520           char t = ' ';
521           if ( *it == cand )
522           {
523             t = *it == up ? 'C' : 'c';
524           }
525           else if ( *it == up )
526           {
527             t = 'u';
528           }
529           str << " " << t << " " << *it << "\t" << obj.pickStatus( *it ) << endl;
530         }
531         str << "}  ";
532       }
533
534       return str;
535     }
536     /////////////////////////////////////////////////////////////////
537   } // namespace ui
538   ///////////////////////////////////////////////////////////////////
539   /////////////////////////////////////////////////////////////////
540 } // namespace zypp
541 ///////////////////////////////////////////////////////////////////
542 #endif // ZYPP_UI_SELECTABLEIMPL_H