1 /*---------------------------------------------------------------------\
3 | __ __ ____ _____ ____ |
4 | \ \ / /_ _/ ___|_ _|___ \ |
5 | \ V / _` \___ \ | | __) | |
6 | | | (_| |___) || | / __/ |
7 | |_|\__,_|____/ |_| |_____| |
11 \----------------------------------------------------------------------/
13 File: YQPkgPatchList.cc
15 Author: Stefan Hundhammer <sh@suse.de>
17 Textdomain "packages-qt"
21 #define y2log_component "qt-pkg"
22 #include <ycp/y2log.h>
27 #include <zypp/ui/PatchContents.h>
33 #include "YQPkgPatchList.h"
34 #include "YQPkgTextDialog.h"
37 #define VERBOSE_PATCH_LIST 1
40 typedef zypp::ui::PatchContents ZyppPatchContents;
41 typedef zypp::ui::PatchContents::const_iterator ZyppPatchContentsIterator;
47 YQPkgPatchList::YQPkgPatchList( QWidget * parent )
48 : YQPkgObjList( parent )
50 y2debug( "Creating patch list" );
52 _filterCriteria = RelevantPatches;
58 headers << ""; _statusCol = numCol++;
59 headers << _( "Patch" ); _nameCol = numCol++;
60 headers << _( "Summary" ); _summaryCol = numCol++;
61 headers << _( "Category" ); _categoryCol = numCol++;
62 headers << _( "Size" ); _sizeCol = numCol++;
63 headers << _( "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 setHeaderLabels(headers);
73 setAllColumnsShowFocus( true );
74 //FIXME setColumnAlignment( sizeCol(), Qt::AlignRight );
76 connect( this, SIGNAL( currentItemChanged ( QTreeWidgetItem * ) ),
77 this, SLOT ( filter() ) );
79 sortItems( categoryCol(), Qt::AscendingOrder );
82 y2debug( "Creating patch list done" );
86 YQPkgPatchList::~YQPkgPatchList()
93 YQPkgPatchList::polish()
95 // Delayed initialization after widget is fully created etc.
97 // Only now send currentItemChanged() signal so attached details views also
98 // display something if their showDetailsIfVisible() slot is connected to
99 // currentItemChanged() signals.
105 YQPkgPatchList::setFilterCriteria( FilterCriteria filterCriteria )
107 _filterCriteria = filterCriteria;
112 YQPkgPatchList::fillList()
115 y2debug( "Filling patch list" );
117 for ( ZyppPoolIterator it = zyppPatchesBegin();
118 it != zyppPatchesEnd();
121 ZyppSel selectable = *it;
122 ZyppPatch zyppPatch = tryCastToZyppPatch( selectable->theObj() );
126 bool displayPatch = false;
128 switch ( _filterCriteria )
130 case RelevantPatches: // needed + broken + satisfied (but not installed)
132 if ( selectable->hasInstalledObj() ) // installed?
134 if ( selectable->installedPoolItem().status().isIncomplete() ) // patch broken?
136 // The patch is broken: It had been installed, but the user somehow
137 // downgraded individual packages belonging to the patch to older versions.
141 y2warning( "Installed patch is broken: %s - %s",
142 zyppPatch->name().c_str(),
143 zyppPatch->summary().c_str() );
146 else // not installed
148 if ( selectable->hasCandidateObj() &&
149 selectable->candidatePoolItem().status().isSatisfied() )
151 // This is a pretty exotic case, but still it might happen:
153 // The patch itelf is not installed, but it is satisfied because the
154 // user updated all the packages belonging to the patch to the versions
155 // the patch requires. All that is missing now is to get the patch meta
156 // data onto the system. So let's display the patch to give the user
157 // a chance to install it (if he so chooses).
161 y2milestone( "Patch satisfied, but not installed yet: %s - %s",
162 zyppPatch->name().c_str(),
163 zyppPatch->summary().c_str() );
167 if ( selectable->hasCandidateObj() ) // candidate available?
169 // The most common case: There is a candidate patch, i.e. one that could be
170 // installed, but either no version of that patch is installed or there is a
171 // newer one to which the patch could be updated.
173 if ( selectable->candidatePoolItem().status().isNeeded() ) // patch really needed?
175 // Patches are needed if any of the packages that belong to the patch
176 // are installed on the system.
182 // None of the packages that belong to the patch is installed on the system.
184 y2debug( "Patch not needed: %s - %s",
185 zyppPatch->name().c_str(),
186 zyppPatch->summary().c_str() );
192 case RelevantAndInstalledPatches: // needed + broken + installed
194 if ( selectable->hasInstalledObj() ) // installed?
198 else // not installed - display only if needed
200 zypp::ResStatus candidateStatus = selectable->candidatePoolItem().status();
202 if ( candidateStatus.isNeeded() ||
203 candidateStatus.isSatisfied() )
209 y2milestone( "Patch not needed: %s - %s",
210 zyppPatch->name().c_str(),
211 zyppPatch->summary().c_str() );
221 // Intentionally omitting "default" so the compiler
222 // can catch unhandled enum values
227 #if VERBOSE_PATCH_LIST
228 y2debug( "Displaying patch %s - %s", zyppPatch->name().c_str(), zyppPatch->summary().c_str() );
230 addPatchItem( *it, zyppPatch);
235 y2error( "Found non-patch selectable" );
240 if ( ! firstChild() )
241 message( _( "No patches available." ) );
244 y2debug( "patch list filled" );
250 YQPkgPatchList::message( const QString & text )
252 QY2ListViewItem * item = new QY2ListViewItem( this );
255 item->setText( 1, text );
256 item->setBackgroundColor( QColor( 0xE0, 0xE0, 0xF8 ) );
262 YQPkgPatchList::filterIfVisible()
270 YQPkgPatchList::filter()
273 std::set<ZyppSel> patchSelectables;
277 ZyppPatch patch = selection()->zyppPatch();
281 ZyppPatchContents patchContents( patch );
283 for ( ZyppPatchContentsIterator it = patchContents.begin();
284 it != patchContents.end();
287 ZyppPkg pkg = tryCastToZyppPkg( *it );
291 y2debug( "Found patch pkg: %s arch: %s", (*it)->name().c_str(), (*it)->arch().asString().c_str() );
293 ZyppSel sel = _selMapper.findZyppSel( pkg );
297 if ( contains( patchSelectables, sel ) )
299 y2milestone( "Suppressing duplicate selectable %s-%s arch: %s",
300 (*it)->name().c_str(),
301 (*it)->edition().asString().c_str(),
302 (*it)->arch().asString().c_str() );
306 patchSelectables.insert( sel );
307 emit filterMatch( sel, pkg );
311 y2error( "No selectable for pkg %s", (*it)->name().c_str() );
313 else // No ZyppPkg - some other kind of object (script, message)
315 if ( zypp::isKind<zypp::Script> ( *it ) )
317 y2debug( "Found patch script %s", (*it)->name().c_str() );
318 emit filterMatch( _( "Script" ), fromUTF8( (*it)->name() ), -1 );
320 else if ( zypp::isKind<zypp::Message> ( *it ) )
322 y2debug( "Found patch message %s (ignoring)", (*it)->name().c_str() );
326 y2error( "Found unknown object of kind %s in patch: %s-%s arch: %s",
327 (*it)->kind().asString().c_str(),
328 (*it)->name().c_str(),
329 (*it)->edition().asString().c_str(),
330 (*it)->arch().asString().c_str() );
337 emit filterFinished();
342 YQPkgPatchList::addPatchItem( ZyppSel selectable,
343 ZyppPatch zyppPatch )
347 y2error( "NULL ZyppSel!" );
351 YQPkgPatchListItem * item = new YQPkgPatchListItem( this, selectable, zyppPatch );
352 applyExcludeRules( item );
357 YQPkgPatchList::selection() const
360 QTreeWidgetItem * item = selectedItem();
365 return dynamic_cast<YQPkgPatchListItem *> (item);
373 YQPkgPatchList::createNotInstalledContextMenu()
375 _notInstalledContextMenu = new QMenu( this );
376 Q_CHECK_PTR( _notInstalledContextMenu );
378 _notInstalledContextMenu->addAction(actionSetCurrentInstall);
379 _notInstalledContextMenu->addAction(actionSetCurrentDontInstall);
380 _notInstalledContextMenu->addAction(actionSetCurrentTaboo);
382 addAllInListSubMenu( _notInstalledContextMenu );
387 YQPkgPatchList::createInstalledContextMenu()
389 _installedContextMenu = new QMenu( this );
390 Q_CHECK_PTR( _installedContextMenu );
392 _installedContextMenu->addAction(actionSetCurrentKeepInstalled);
394 #if ENABLE_DELETING_PATCHES
395 _installedContextMenu->addAction(actionSetCurrentDelete);
398 _installedContextMenu->addAction(actionSetCurrentUpdate);
399 _installedContextMenu->addAction(actionSetCurrentProtected);
401 addAllInListSubMenu( _installedContextMenu );
406 YQPkgPatchList::addAllInListSubMenu( QMenu * menu )
408 QMenu * submenu = new QMenu( menu );
409 Q_CHECK_PTR( submenu );
411 submenu->addAction(actionSetListInstall);
412 submenu->addAction(actionSetListDontInstall);
413 submenu->addAction(actionSetListKeepInstalled);
415 #if ENABLE_DELETING_PATCHES
416 submenu->addAction(actionSetListDelete);
419 submenu->addAction(actionSetListUpdate);
420 submenu->addAction(actionSetListUpdateForce);
421 submenu->addAction(actionSetListTaboo);
422 submenu->addAction(actionSetListProtected);
424 QAction *action = menu->addMenu(submenu);
425 action->setText(_( "&All in This List" ));
432 YQPkgPatchList::keyPressEvent( QKeyEvent * event )
436 #if ! ENABLE_DELETING_PATCHES
437 if ( event->ascii() == '-' )
439 QTreeWidgetItem * selectedListViewItem = currentItem();
441 if ( selectedListViewItem )
443 YQPkgPatchListItem * item = dynamic_cast<YQPkgPatchListItem *> (selectedListViewItem);
445 if ( item && item->selectable()->hasInstalledObj() )
447 y2warning( "Deleting patches is not supported" );
455 YQPkgObjList::keyPressEvent( event );
461 YQPkgPatchListItem::YQPkgPatchListItem( YQPkgPatchList * patchList,
463 ZyppPatch zyppPatch )
464 : YQPkgObjListItem( patchList, selectable, zyppPatch )
465 , _patchList( patchList )
466 , _zyppPatch( zyppPatch )
469 _zyppPatch = tryCastToZyppPatch( selectable->theObj() );
475 _patchCategory = patchCategory( _zyppPatch->category() );
477 if ( categoryCol() > -1 )
478 setText( categoryCol(), asString( _patchCategory ) );
480 if ( summaryCol() > -1 && _zyppPatch->summary().empty() )
481 setText( summaryCol(), _zyppPatch->name() ); // use name as fallback
483 switch ( _patchCategory )
485 case YQPkgYaSTPatch: setTextColor( QColor( 0, 0, 0xC0 ) ); break; // medium blue
486 case YQPkgSecurityPatch: setTextColor( Qt::red ); break;
487 case YQPkgRecommendedPatch: setTextColor( QColor( 0, 0, 0xC0 ) ); break; // medium blue
488 case YQPkgOptionalPatch: break;
489 case YQPkgDocumentPatch: break;
490 case YQPkgUnknownPatchCategory: break;
495 YQPkgPatchListItem::~YQPkgPatchListItem()
502 YQPkgPatchListItem::patchCategory( const string & category )
504 return patchCategory( fromUTF8( category ) );
509 YQPkgPatchListItem::patchCategory( QString category )
511 category = category.toLower();
513 if ( category == "yast" ) return YQPkgYaSTPatch;
514 if ( category == "security" ) return YQPkgSecurityPatch;
515 if ( category == "recommended" ) return YQPkgRecommendedPatch;
516 if ( category == "optional" ) return YQPkgOptionalPatch;
517 if ( category == "document" ) return YQPkgDocumentPatch;
519 y2warning( "Unknown patch category \"%s\"", qPrintable(category) );
520 return YQPkgUnknownPatchCategory;
525 YQPkgPatchListItem::asString( YQPkgPatchCategory category )
529 // Translators: These are patch categories
530 case YQPkgYaSTPatch: return _( "YaST" );
531 case YQPkgSecurityPatch: return _( "security" );
532 case YQPkgRecommendedPatch: return _( "recommended" );
533 case YQPkgOptionalPatch: return _( "optional" );
534 case YQPkgDocumentPatch: return _( "document" );
535 case YQPkgUnknownPatchCategory: return "";
543 YQPkgPatchListItem::cycleStatus()
545 YQPkgObjListItem::cycleStatus();
547 #if ! ENABLE_DELETING_PATCHES
548 if ( status() == S_Del ) // Can't delete patches
549 setStatus( S_KeepInstalled );
555 YQPkgPatchListItem::toolTip( int col )
559 if ( col == statusCol() )
561 text = YQPkgObjListItem::toolTip( col );
565 if ( ( col == brokenIconCol() && isBroken() ) ||
566 ( col == satisfiedIconCol() && isSatisfied() ) )
568 text = YQPkgObjListItem::toolTip( col );
572 text = fromUTF8( zyppPatch()->category() );
574 if ( ! text.isEmpty() )
577 text += fromUTF8( zyppPatch()->size().asString().c_str() );
586 YQPkgPatchListItem::applyChanges()
588 solveResolvableCollections();
592 bool YQPkgPatchListItem::operator< ( const QTreeWidgetItem & otherListViewItem ) const
594 const YQPkgPatchListItem * other = dynamic_cast<const YQPkgPatchListItem *> (&otherListViewItem);
595 int col = treeWidget()->sortColumn();
598 if ( col == categoryCol() )
600 return ( this->patchCategory() < other->patchCategory() );
603 return YQPkgObjListItem::operator<( otherListViewItem );
608 #include "YQPkgPatchList.moc"