1 /*---------------------------------------------------------------------\
3 | __ __ ____ _____ ____ |
4 | \ \ / /_ _/ ___|_ _|___ \ |
5 | \ V / _` \___ \ | | __) | |
6 | | | (_| |___) || | / __/ |
7 | |_|\__,_|____/ |_| |_____| |
11 \----------------------------------------------------------------------/
13 File: YQPkgPatchList.cc
15 Author: Stefan Hundhammer <sh@suse.de>
17 Textdomain "packages-qt"
22 #define y2log_component "qt-pkg"
23 #include <ycp/y2log.h>
28 #include <zypp/ui/PatchContents.h>
34 #include "YQPkgPatchList.h"
35 #include "YQPkgTextDialog.h"
38 #define VERBOSE_PATCH_LIST 1
41 typedef zypp::ui::PatchContents ZyppPatchContents;
42 typedef zypp::ui::PatchContents::const_iterator ZyppPatchContentsIterator;
48 YQPkgPatchList::YQPkgPatchList( QWidget * parent )
49 : YQPkgObjList( parent )
51 y2debug( "Creating patch list" );
53 _filterCriteria = RelevantPatches;
57 addColumn( "" ); _statusCol = numCol++;
58 addColumn( _( "Patch" ) ); _nameCol = numCol++;
59 addColumn( _( "Summary" ) ); _summaryCol = numCol++;
60 addColumn( _( "Category" ) ); _categoryCol = numCol++;
61 addColumn( _( "Size" ) ); _sizeCol = numCol++;
62 addColumn( _( "Version" ) ); _versionCol = numCol++;
64 // Can use the same colum for "broken" and "satisfied":
65 // Both states are mutually exclusive
67 _satisfiedIconCol = _summaryCol;
68 _brokenIconCol = _summaryCol;
70 setAllColumnsShowFocus( true );
71 setColumnAlignment( sizeCol(), Qt::AlignRight );
73 connect( this, SIGNAL( selectionChanged ( QTreeWidgetItem * ) ),
74 this, SLOT ( filter() ) );
76 setSorting( categoryCol() );
80 y2debug( "Creating patch list done" );
84 YQPkgPatchList::~YQPkgPatchList()
91 YQPkgPatchList::polish()
93 // Delayed initialization after widget is fully created etc.
95 // Only now send selectionChanged() signal so attached details views also
96 // display something if their showDetailsIfVisible() slot is connected to
97 // selectionChanged() signals.
103 YQPkgPatchList::setFilterCriteria( FilterCriteria filterCriteria )
105 _filterCriteria = filterCriteria;
110 YQPkgPatchList::fillList()
113 y2debug( "Filling patch list" );
115 for ( ZyppPoolIterator it = zyppPatchesBegin();
116 it != zyppPatchesEnd();
119 ZyppSel selectable = *it;
120 ZyppPatch zyppPatch = tryCastToZyppPatch( selectable->theObj() );
124 bool displayPatch = false;
126 switch ( _filterCriteria )
128 case RelevantPatches: // needed + broken + satisfied (but not installed)
130 if ( selectable->hasInstalledObj() ) // installed?
132 if ( selectable->installedPoolItem().status().isIncomplete() ) // patch broken?
134 // The patch is broken: It had been installed, but the user somehow
135 // downgraded individual packages belonging to the patch to older versions.
139 y2warning( "Installed patch is broken: %s - %s",
140 zyppPatch->name().c_str(),
141 zyppPatch->summary().c_str() );
144 else // not installed
146 if ( selectable->hasCandidateObj() &&
147 selectable->candidatePoolItem().status().isSatisfied() )
149 // This is a pretty exotic case, but still it might happen:
151 // The patch itelf is not installed, but it is satisfied because the
152 // user updated all the packages belonging to the patch to the versions
153 // the patch requires. All that is missing now is to get the patch meta
154 // data onto the system. So let's display the patch to give the user
155 // a chance to install it (if he so chooses).
159 y2milestone( "Patch satisfied, but not installed yet: %s - %s",
160 zyppPatch->name().c_str(),
161 zyppPatch->summary().c_str() );
165 if ( selectable->hasCandidateObj() ) // candidate available?
167 // The most common case: There is a candidate patch, i.e. one that could be
168 // installed, but either no version of that patch is installed or there is a
169 // newer one to which the patch could be updated.
171 if ( selectable->candidatePoolItem().status().isNeeded() ) // patch really needed?
173 // Patches are needed if any of the packages that belong to the patch
174 // are installed on the system.
180 // None of the packages that belong to the patch is installed on the system.
182 y2debug( "Patch not needed: %s - %s",
183 zyppPatch->name().c_str(),
184 zyppPatch->summary().c_str() );
190 case RelevantAndInstalledPatches: // needed + broken + installed
192 if ( selectable->hasInstalledObj() ) // installed?
196 else // not installed - display only if needed
198 zypp::ResStatus candidateStatus = selectable->candidatePoolItem().status();
200 if ( candidateStatus.isNeeded() ||
201 candidateStatus.isSatisfied() )
207 y2milestone( "Patch not needed: %s - %s",
208 zyppPatch->name().c_str(),
209 zyppPatch->summary().c_str() );
219 // Intentionally omitting "default" so the compiler
220 // can catch unhandled enum values
225 #if VERBOSE_PATCH_LIST
226 y2debug( "Displaying patch %s - %s", zyppPatch->name().c_str(), zyppPatch->summary().c_str() );
228 addPatchItem( *it, zyppPatch);
233 y2error( "Found non-patch selectable" );
238 if ( ! firstChild() )
239 message( _( "No patches available." ) );
242 y2debug( "patch list filled" );
248 YQPkgPatchList::message( const QString & text )
250 QY2ListViewItem * item = new QY2ListViewItem( this );
253 item->setText( 1, text );
254 item->setBackgroundColor( QColor( 0xE0, 0xE0, 0xF8 ) );
260 YQPkgPatchList::filterIfVisible()
268 YQPkgPatchList::filter()
271 std::set<ZyppSel> patchSelectables;
275 ZyppPatch patch = selection()->zyppPatch();
279 ZyppPatchContents patchContents( patch );
281 for ( ZyppPatchContentsIterator it = patchContents.begin();
282 it != patchContents.end();
285 ZyppPkg pkg = tryCastToZyppPkg( *it );
289 y2debug( "Found patch pkg: %s arch: %s", (*it)->name().c_str(), (*it)->arch().asString().c_str() );
291 ZyppSel sel = _selMapper.findZyppSel( pkg );
295 if ( contains( patchSelectables, sel ) )
297 y2milestone( "Suppressing duplicate selectable %s-%s arch: %s",
298 (*it)->name().c_str(),
299 (*it)->edition().asString().c_str(),
300 (*it)->arch().asString().c_str() );
304 patchSelectables.insert( sel );
305 emit filterMatch( sel, pkg );
309 y2error( "No selectable for pkg %s", (*it)->name().c_str() );
311 else // No ZyppPkg - some other kind of object (script, message)
313 if ( zypp::isKind<zypp::Script> ( *it ) )
315 y2debug( "Found patch script %s", (*it)->name().c_str() );
316 emit filterMatch( _( "Script" ), fromUTF8( (*it)->name() ), -1 );
318 else if ( zypp::isKind<zypp::Message> ( *it ) )
320 y2debug( "Found patch message %s (ignoring)", (*it)->name().c_str() );
324 y2error( "Found unknown object of kind %s in patch: %s-%s arch: %s",
325 (*it)->kind().asString().c_str(),
326 (*it)->name().c_str(),
327 (*it)->edition().asString().c_str(),
328 (*it)->arch().asString().c_str() );
335 emit filterFinished();
340 YQPkgPatchList::addPatchItem( ZyppSel selectable,
341 ZyppPatch zyppPatch )
345 y2error( "NULL ZyppSel!" );
349 YQPkgPatchListItem * item = new YQPkgPatchListItem( this, selectable, zyppPatch );
350 applyExcludeRules( item );
355 YQPkgPatchList::selection() const
358 QTreeWidgetItem * item = selectedItem();
363 return dynamic_cast<YQPkgPatchListItem *> (item);
371 YQPkgPatchList::createNotInstalledContextMenu()
373 _notInstalledContextMenu = new QMenu( this );
374 Q_CHECK_PTR( _notInstalledContextMenu );
376 actionSetCurrentInstall->addTo( _notInstalledContextMenu );
377 actionSetCurrentDontInstall->addTo( _notInstalledContextMenu );
378 actionSetCurrentTaboo->addTo( _notInstalledContextMenu );
380 addAllInListSubMenu( _notInstalledContextMenu );
385 YQPkgPatchList::createInstalledContextMenu()
387 _installedContextMenu = new QMenu( this );
388 Q_CHECK_PTR( _installedContextMenu );
390 actionSetCurrentKeepInstalled->addTo( _installedContextMenu );
392 #if ENABLE_DELETING_PATCHES
393 actionSetCurrentDelete->addTo( _installedContextMenu );
396 actionSetCurrentUpdate->addTo( _installedContextMenu );
397 actionSetCurrentProtected->addTo( _installedContextMenu );
399 addAllInListSubMenu( _installedContextMenu );
404 YQPkgPatchList::addAllInListSubMenu( QMenu * menu )
406 QMenu * submenu = new QMenu( menu );
407 Q_CHECK_PTR( submenu );
409 actionSetListInstall->addTo( submenu );
410 actionSetListDontInstall->addTo( submenu );
411 actionSetListKeepInstalled->addTo( submenu );
413 #if ENABLE_DELETING_PATCHES
414 actionSetListDelete->addTo( submenu );
417 actionSetListUpdate->addTo( submenu );
418 actionSetListUpdateForce->addTo( submenu );
419 actionSetListTaboo->addTo( submenu );
420 actionSetListProtected->addTo( submenu );
422 menu->insertItem( _( "&All in This List" ), submenu );
429 YQPkgPatchList::keyPressEvent( QKeyEvent * event )
433 #if ! ENABLE_DELETING_PATCHES
434 if ( event->ascii() == '-' )
436 QTreeWidgetItem * selectedListViewItem = currentItem();
438 if ( selectedListViewItem )
440 YQPkgPatchListItem * item = dynamic_cast<YQPkgPatchListItem *> (selectedListViewItem);
442 if ( item && item->selectable()->hasInstalledObj() )
444 y2warning( "Deleting patches is not supported" );
452 YQPkgObjList::keyPressEvent( event );
458 YQPkgPatchListItem::YQPkgPatchListItem( YQPkgPatchList * patchList,
460 ZyppPatch zyppPatch )
461 : YQPkgObjListItem( patchList, selectable, zyppPatch )
462 , _patchList( patchList )
463 , _zyppPatch( zyppPatch )
466 _zyppPatch = tryCastToZyppPatch( selectable->theObj() );
472 _patchCategory = patchCategory( _zyppPatch->category() );
474 if ( categoryCol() > -1 )
475 setText( categoryCol(), asString( _patchCategory ) );
477 if ( summaryCol() > -1 && _zyppPatch->summary().empty() )
478 setText( summaryCol(), _zyppPatch->name() ); // use name as fallback
480 switch ( _patchCategory )
482 case YQPkgYaSTPatch: setTextColor( QColor( 0, 0, 0xC0 ) ); break; // medium blue
483 case YQPkgSecurityPatch: setTextColor( Qt::red ); break;
484 case YQPkgRecommendedPatch: setTextColor( QColor( 0, 0, 0xC0 ) ); break; // medium blue
485 case YQPkgOptionalPatch: break;
486 case YQPkgDocumentPatch: break;
487 case YQPkgUnknownPatchCategory: break;
492 YQPkgPatchListItem::~YQPkgPatchListItem()
499 YQPkgPatchListItem::patchCategory( const string & category )
501 return patchCategory( fromUTF8( category ) );
506 YQPkgPatchListItem::patchCategory( QString category )
508 category = category.lower();
510 if ( category == "yast" ) return YQPkgYaSTPatch;
511 if ( category == "security" ) return YQPkgSecurityPatch;
512 if ( category == "recommended" ) return YQPkgRecommendedPatch;
513 if ( category == "optional" ) return YQPkgOptionalPatch;
514 if ( category == "document" ) return YQPkgDocumentPatch;
516 y2warning( "Unknown patch category \"%s\"", (const char *) category );
517 return YQPkgUnknownPatchCategory;
522 YQPkgPatchListItem::asString( YQPkgPatchCategory category )
526 // Translators: These are patch categories
527 case YQPkgYaSTPatch: return _( "YaST" );
528 case YQPkgSecurityPatch: return _( "security" );
529 case YQPkgRecommendedPatch: return _( "recommended" );
530 case YQPkgOptionalPatch: return _( "optional" );
531 case YQPkgDocumentPatch: return _( "document" );
532 case YQPkgUnknownPatchCategory: return "";
540 YQPkgPatchListItem::cycleStatus()
542 YQPkgObjListItem::cycleStatus();
544 #if ! ENABLE_DELETING_PATCHES
545 if ( status() == S_Del ) // Can't delete patches
546 setStatus( S_KeepInstalled );
552 YQPkgPatchListItem::toolTip( int col )
556 if ( col == statusCol() )
558 text = YQPkgObjListItem::toolTip( col );
562 if ( ( col == brokenIconCol() && isBroken() ) ||
563 ( col == satisfiedIconCol() && isSatisfied() ) )
565 text = YQPkgObjListItem::toolTip( col );
569 text = fromUTF8( zyppPatch()->category() );
571 if ( ! text.isEmpty() )
574 text += fromUTF8( zyppPatch()->size().asString().c_str() );
583 YQPkgPatchListItem::applyChanges()
585 solveResolvableCollections();
590 * Comparison function used for sorting the list.
597 YQPkgPatchListItem::compare( QTreeWidgetItem * otherListViewItem,
599 bool ascending ) const
601 YQPkgPatchListItem * other = dynamic_cast<YQPkgPatchListItem *> (otherListViewItem);
605 if ( col == categoryCol() )
607 if ( this->patchCategory() < other->patchCategory() ) return -1;
608 if ( this->patchCategory() > other->patchCategory() ) return 1;
612 return YQPkgObjListItem::compare( otherListViewItem, col, ascending );
617 #include "YQPkgPatchList.moc"