1 /*---------------------------------------------------------------------\
3 | __ __ ____ _____ ____ |
4 | \ \ / /_ _/ ___|_ _|___ \ |
5 | \ V / _` \___ \ | | __) | |
6 | | | (_| |___) || | / __/ |
7 | |_|\__,_|____/ |_| |_____| |
11 \----------------------------------------------------------------------/
13 File: YQPkgPatchList.cc
15 Author: Stefan Hundhammer <sh@suse.de>
17 Textdomain "packages-qt"
23 #define y2log_component "qt-pkg"
24 #include <ycp/y2log.h>
29 #include <zypp/ui/PatchContents.h>
35 #include "YQPkgPatchList.h"
36 #include "YQPkgTextDialog.h"
39 #define VERBOSE_PATCH_LIST 1
42 typedef zypp::ui::PatchContents ZyppPatchContents;
43 typedef zypp::ui::PatchContents::const_iterator ZyppPatchContentsIterator;
49 YQPkgPatchList::YQPkgPatchList( QWidget * parent )
50 : YQPkgObjList( parent )
52 y2debug( "Creating patch list" );
54 _filterCriteria = RelevantPatches;
58 addColumn( "" ); _statusCol = numCol++;
59 addColumn( _( "Patch" ) ); _nameCol = numCol++;
60 addColumn( _( "Summary" ) ); _summaryCol = numCol++;
61 addColumn( _( "Category" ) ); _categoryCol = numCol++;
62 addColumn( _( "Size" ) ); _sizeCol = numCol++;
63 addColumn( _( "Version" ) ); _versionCol = numCol++;
65 // Can use the same colum for "broken" and "satisfied":
66 // Both states are mutually exclusive
68 _satisfiedIconCol = _summaryCol;
69 _brokenIconCol = _summaryCol;
71 setAllColumnsShowFocus( true );
72 setColumnAlignment( sizeCol(), Qt::AlignRight );
74 connect( this, SIGNAL( currentItemChanged ( QTreeWidgetItem * ) ),
75 this, SLOT ( filter() ) );
77 setSorting( categoryCol() );
81 y2debug( "Creating patch list done" );
85 YQPkgPatchList::~YQPkgPatchList()
92 YQPkgPatchList::polish()
94 // Delayed initialization after widget is fully created etc.
96 // Only now send currentItemChanged() signal so attached details views also
97 // display something if their showDetailsIfVisible() slot is connected to
98 // currentItemChanged() signals.
104 YQPkgPatchList::setFilterCriteria( FilterCriteria filterCriteria )
106 _filterCriteria = filterCriteria;
111 YQPkgPatchList::fillList()
114 y2debug( "Filling patch list" );
116 for ( ZyppPoolIterator it = zyppPatchesBegin();
117 it != zyppPatchesEnd();
120 ZyppSel selectable = *it;
121 ZyppPatch zyppPatch = tryCastToZyppPatch( selectable->theObj() );
125 bool displayPatch = false;
127 switch ( _filterCriteria )
129 case RelevantPatches: // needed + broken + satisfied (but not installed)
131 if ( selectable->hasInstalledObj() ) // installed?
133 if ( selectable->installedPoolItem().status().isIncomplete() ) // patch broken?
135 // The patch is broken: It had been installed, but the user somehow
136 // downgraded individual packages belonging to the patch to older versions.
140 y2warning( "Installed patch is broken: %s - %s",
141 zyppPatch->name().c_str(),
142 zyppPatch->summary().c_str() );
145 else // not installed
147 if ( selectable->hasCandidateObj() &&
148 selectable->candidatePoolItem().status().isSatisfied() )
150 // This is a pretty exotic case, but still it might happen:
152 // The patch itelf is not installed, but it is satisfied because the
153 // user updated all the packages belonging to the patch to the versions
154 // the patch requires. All that is missing now is to get the patch meta
155 // data onto the system. So let's display the patch to give the user
156 // a chance to install it (if he so chooses).
160 y2milestone( "Patch satisfied, but not installed yet: %s - %s",
161 zyppPatch->name().c_str(),
162 zyppPatch->summary().c_str() );
166 if ( selectable->hasCandidateObj() ) // candidate available?
168 // The most common case: There is a candidate patch, i.e. one that could be
169 // installed, but either no version of that patch is installed or there is a
170 // newer one to which the patch could be updated.
172 if ( selectable->candidatePoolItem().status().isNeeded() ) // patch really needed?
174 // Patches are needed if any of the packages that belong to the patch
175 // are installed on the system.
181 // None of the packages that belong to the patch is installed on the system.
183 y2debug( "Patch not needed: %s - %s",
184 zyppPatch->name().c_str(),
185 zyppPatch->summary().c_str() );
191 case RelevantAndInstalledPatches: // needed + broken + installed
193 if ( selectable->hasInstalledObj() ) // installed?
197 else // not installed - display only if needed
199 zypp::ResStatus candidateStatus = selectable->candidatePoolItem().status();
201 if ( candidateStatus.isNeeded() ||
202 candidateStatus.isSatisfied() )
208 y2milestone( "Patch not needed: %s - %s",
209 zyppPatch->name().c_str(),
210 zyppPatch->summary().c_str() );
220 // Intentionally omitting "default" so the compiler
221 // can catch unhandled enum values
226 #if VERBOSE_PATCH_LIST
227 y2debug( "Displaying patch %s - %s", zyppPatch->name().c_str(), zyppPatch->summary().c_str() );
229 addPatchItem( *it, zyppPatch);
234 y2error( "Found non-patch selectable" );
239 if ( ! firstChild() )
240 message( _( "No patches available." ) );
243 y2debug( "patch list filled" );
249 YQPkgPatchList::message( const QString & text )
251 QY2ListViewItem * item = new QY2ListViewItem( this );
254 item->setText( 1, text );
255 item->setBackgroundColor( QColor( 0xE0, 0xE0, 0xF8 ) );
261 YQPkgPatchList::filterIfVisible()
269 YQPkgPatchList::filter()
272 std::set<ZyppSel> patchSelectables;
276 ZyppPatch patch = selection()->zyppPatch();
280 ZyppPatchContents patchContents( patch );
282 for ( ZyppPatchContentsIterator it = patchContents.begin();
283 it != patchContents.end();
286 ZyppPkg pkg = tryCastToZyppPkg( *it );
290 y2debug( "Found patch pkg: %s arch: %s", (*it)->name().c_str(), (*it)->arch().asString().c_str() );
292 ZyppSel sel = _selMapper.findZyppSel( pkg );
296 if ( contains( patchSelectables, sel ) )
298 y2milestone( "Suppressing duplicate selectable %s-%s arch: %s",
299 (*it)->name().c_str(),
300 (*it)->edition().asString().c_str(),
301 (*it)->arch().asString().c_str() );
305 patchSelectables.insert( sel );
306 emit filterMatch( sel, pkg );
310 y2error( "No selectable for pkg %s", (*it)->name().c_str() );
312 else // No ZyppPkg - some other kind of object (script, message)
314 if ( zypp::isKind<zypp::Script> ( *it ) )
316 y2debug( "Found patch script %s", (*it)->name().c_str() );
317 emit filterMatch( _( "Script" ), fromUTF8( (*it)->name() ), -1 );
319 else if ( zypp::isKind<zypp::Message> ( *it ) )
321 y2debug( "Found patch message %s (ignoring)", (*it)->name().c_str() );
325 y2error( "Found unknown object of kind %s in patch: %s-%s arch: %s",
326 (*it)->kind().asString().c_str(),
327 (*it)->name().c_str(),
328 (*it)->edition().asString().c_str(),
329 (*it)->arch().asString().c_str() );
336 emit filterFinished();
341 YQPkgPatchList::addPatchItem( ZyppSel selectable,
342 ZyppPatch zyppPatch )
346 y2error( "NULL ZyppSel!" );
350 YQPkgPatchListItem * item = new YQPkgPatchListItem( this, selectable, zyppPatch );
351 applyExcludeRules( item );
356 YQPkgPatchList::selection() const
359 QTreeWidgetItem * item = selectedItem();
364 return dynamic_cast<YQPkgPatchListItem *> (item);
372 YQPkgPatchList::createNotInstalledContextMenu()
374 _notInstalledContextMenu = new QMenu( this );
375 Q_CHECK_PTR( _notInstalledContextMenu );
377 actionSetCurrentInstall->addTo( _notInstalledContextMenu );
378 actionSetCurrentDontInstall->addTo( _notInstalledContextMenu );
379 actionSetCurrentTaboo->addTo( _notInstalledContextMenu );
381 addAllInListSubMenu( _notInstalledContextMenu );
386 YQPkgPatchList::createInstalledContextMenu()
388 _installedContextMenu = new QMenu( this );
389 Q_CHECK_PTR( _installedContextMenu );
391 actionSetCurrentKeepInstalled->addTo( _installedContextMenu );
393 #if ENABLE_DELETING_PATCHES
394 actionSetCurrentDelete->addTo( _installedContextMenu );
397 actionSetCurrentUpdate->addTo( _installedContextMenu );
398 actionSetCurrentProtected->addTo( _installedContextMenu );
400 addAllInListSubMenu( _installedContextMenu );
405 YQPkgPatchList::addAllInListSubMenu( QMenu * menu )
407 QMenu * submenu = new QMenu( menu );
408 Q_CHECK_PTR( submenu );
410 actionSetListInstall->addTo( submenu );
411 actionSetListDontInstall->addTo( submenu );
412 actionSetListKeepInstalled->addTo( submenu );
414 #if ENABLE_DELETING_PATCHES
415 actionSetListDelete->addTo( submenu );
418 actionSetListUpdate->addTo( submenu );
419 actionSetListUpdateForce->addTo( submenu );
420 actionSetListTaboo->addTo( submenu );
421 actionSetListProtected->addTo( submenu );
423 menu->insertItem( _( "&All in This List" ), submenu );
430 YQPkgPatchList::keyPressEvent( QKeyEvent * event )
434 #if ! ENABLE_DELETING_PATCHES
435 if ( event->ascii() == '-' )
437 QTreeWidgetItem * selectedListViewItem = currentItem();
439 if ( selectedListViewItem )
441 YQPkgPatchListItem * item = dynamic_cast<YQPkgPatchListItem *> (selectedListViewItem);
443 if ( item && item->selectable()->hasInstalledObj() )
445 y2warning( "Deleting patches is not supported" );
453 YQPkgObjList::keyPressEvent( event );
459 YQPkgPatchListItem::YQPkgPatchListItem( YQPkgPatchList * patchList,
461 ZyppPatch zyppPatch )
462 : YQPkgObjListItem( patchList, selectable, zyppPatch )
463 , _patchList( patchList )
464 , _zyppPatch( zyppPatch )
467 _zyppPatch = tryCastToZyppPatch( selectable->theObj() );
473 _patchCategory = patchCategory( _zyppPatch->category() );
475 if ( categoryCol() > -1 )
476 setText( categoryCol(), asString( _patchCategory ) );
478 if ( summaryCol() > -1 && _zyppPatch->summary().empty() )
479 setText( summaryCol(), _zyppPatch->name() ); // use name as fallback
481 switch ( _patchCategory )
483 case YQPkgYaSTPatch: setTextColor( QColor( 0, 0, 0xC0 ) ); break; // medium blue
484 case YQPkgSecurityPatch: setTextColor( Qt::red ); break;
485 case YQPkgRecommendedPatch: setTextColor( QColor( 0, 0, 0xC0 ) ); break; // medium blue
486 case YQPkgOptionalPatch: break;
487 case YQPkgDocumentPatch: break;
488 case YQPkgUnknownPatchCategory: break;
493 YQPkgPatchListItem::~YQPkgPatchListItem()
500 YQPkgPatchListItem::patchCategory( const string & category )
502 return patchCategory( fromUTF8( category ) );
507 YQPkgPatchListItem::patchCategory( QString category )
509 category = category.lower();
511 if ( category == "yast" ) return YQPkgYaSTPatch;
512 if ( category == "security" ) return YQPkgSecurityPatch;
513 if ( category == "recommended" ) return YQPkgRecommendedPatch;
514 if ( category == "optional" ) return YQPkgOptionalPatch;
515 if ( category == "document" ) return YQPkgDocumentPatch;
517 y2warning( "Unknown patch category \"%s\"", (const char *) category );
518 return YQPkgUnknownPatchCategory;
523 YQPkgPatchListItem::asString( YQPkgPatchCategory category )
527 // Translators: These are patch categories
528 case YQPkgYaSTPatch: return _( "YaST" );
529 case YQPkgSecurityPatch: return _( "security" );
530 case YQPkgRecommendedPatch: return _( "recommended" );
531 case YQPkgOptionalPatch: return _( "optional" );
532 case YQPkgDocumentPatch: return _( "document" );
533 case YQPkgUnknownPatchCategory: return "";
541 YQPkgPatchListItem::cycleStatus()
543 YQPkgObjListItem::cycleStatus();
545 #if ! ENABLE_DELETING_PATCHES
546 if ( status() == S_Del ) // Can't delete patches
547 setStatus( S_KeepInstalled );
553 YQPkgPatchListItem::toolTip( int col )
557 if ( col == statusCol() )
559 text = YQPkgObjListItem::toolTip( col );
563 if ( ( col == brokenIconCol() && isBroken() ) ||
564 ( col == satisfiedIconCol() && isSatisfied() ) )
566 text = YQPkgObjListItem::toolTip( col );
570 text = fromUTF8( zyppPatch()->category() );
572 if ( ! text.isEmpty() )
575 text += fromUTF8( zyppPatch()->size().asString().c_str() );
584 YQPkgPatchListItem::applyChanges()
586 solveResolvableCollections();
591 * Comparison function used for sorting the list.
598 YQPkgPatchListItem::compare( QTreeWidgetItem * otherListViewItem,
600 bool ascending ) const
602 YQPkgPatchListItem * other = dynamic_cast<YQPkgPatchListItem *> (otherListViewItem);
606 if ( col == categoryCol() )
608 if ( this->patchCategory() < other->patchCategory() ) return -1;
609 if ( this->patchCategory() > other->patchCategory() ) return 1;
613 return YQPkgObjListItem::compare( otherListViewItem, col, ascending );
618 #include "YQPkgPatchList.moc"