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>
25 #include <q3popupmenu.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;
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 ( Q3ListViewItem * ) ),
74 this, SLOT ( filter() ) );
76 setSorting( categoryCol() );
79 y2debug( "Creating patch list done" );
83 YQPkgPatchList::~YQPkgPatchList()
90 YQPkgPatchList::polish()
92 // Delayed initialization after widget is fully created etc.
94 // Only now send selectionChanged() signal so attached details views also
95 // display something if their showDetailsIfVisible() slot is connected to
96 // selectionChanged() signals.
102 YQPkgPatchList::setFilterCriteria( FilterCriteria filterCriteria )
104 _filterCriteria = filterCriteria;
109 YQPkgPatchList::fillList()
112 y2debug( "Filling patch list" );
114 for ( ZyppPoolIterator it = zyppPatchesBegin();
115 it != zyppPatchesEnd();
118 ZyppSel selectable = *it;
119 ZyppPatch zyppPatch = tryCastToZyppPatch( selectable->theObj() );
123 bool displayPatch = false;
125 switch ( _filterCriteria )
127 case RelevantPatches: // needed + broken + satisfied (but not installed)
129 if ( selectable->hasInstalledObj() ) // installed?
131 if ( selectable->installedPoolItem().status().isIncomplete() ) // patch broken?
133 // The patch is broken: It had been installed, but the user somehow
134 // downgraded individual packages belonging to the patch to older versions.
138 y2warning( "Installed patch is broken: %s - %s",
139 zyppPatch->name().c_str(),
140 zyppPatch->summary().c_str() );
143 else // not installed
145 if ( selectable->hasCandidateObj() &&
146 selectable->candidatePoolItem().status().isSatisfied() )
148 // This is a pretty exotic case, but still it might happen:
150 // The patch itelf is not installed, but it is satisfied because the
151 // user updated all the packages belonging to the patch to the versions
152 // the patch requires. All that is missing now is to get the patch meta
153 // data onto the system. So let's display the patch to give the user
154 // a chance to install it (if he so chooses).
158 y2milestone( "Patch satisfied, but not installed yet: %s - %s",
159 zyppPatch->name().c_str(),
160 zyppPatch->summary().c_str() );
164 if ( selectable->hasCandidateObj() ) // candidate available?
166 // The most common case: There is a candidate patch, i.e. one that could be
167 // installed, but either no version of that patch is installed or there is a
168 // newer one to which the patch could be updated.
170 if ( selectable->candidatePoolItem().status().isNeeded() ) // patch really needed?
172 // Patches are needed if any of the packages that belong to the patch
173 // are installed on the system.
179 // None of the packages that belong to the patch is installed on the system.
181 y2debug( "Patch not needed: %s - %s",
182 zyppPatch->name().c_str(),
183 zyppPatch->summary().c_str() );
189 case RelevantAndInstalledPatches: // needed + broken + installed
191 if ( selectable->hasInstalledObj() ) // installed?
195 else // not installed - display only if needed
197 zypp::ResStatus candidateStatus = selectable->candidatePoolItem().status();
199 if ( candidateStatus.isNeeded() ||
200 candidateStatus.isSatisfied() )
206 y2milestone( "Patch not needed: %s - %s",
207 zyppPatch->name().c_str(),
208 zyppPatch->summary().c_str() );
218 // Intentionally omitting "default" so the compiler
219 // can catch unhandled enum values
224 #if VERBOSE_PATCH_LIST
225 y2debug( "Displaying patch %s - %s", zyppPatch->name().c_str(), zyppPatch->summary().c_str() );
227 addPatchItem( *it, zyppPatch);
232 y2error( "Found non-patch selectable" );
237 if ( ! firstChild() )
238 message( _( "No patches available." ) );
240 y2debug( "patch list filled" );
246 YQPkgPatchList::message( const QString & text )
248 QY2ListViewItem * item = new QY2ListViewItem( this );
251 item->setText( 1, text );
252 item->setBackgroundColor( QColor( 0xE0, 0xE0, 0xF8 ) );
258 YQPkgPatchList::filterIfVisible()
266 YQPkgPatchList::filter()
269 std::set<ZyppSel> patchSelectables;
273 ZyppPatch patch = selection()->zyppPatch();
277 ZyppPatchContents patchContents( patch );
279 for ( ZyppPatchContentsIterator it = patchContents.begin();
280 it != patchContents.end();
283 ZyppPkg pkg = tryCastToZyppPkg( *it );
287 y2debug( "Found patch pkg: %s arch: %s", (*it)->name().c_str(), (*it)->arch().asString().c_str() );
289 ZyppSel sel = _selMapper.findZyppSel( pkg );
293 if ( contains( patchSelectables, sel ) )
295 y2milestone( "Suppressing duplicate selectable %s-%s arch: %s",
296 (*it)->name().c_str(),
297 (*it)->edition().asString().c_str(),
298 (*it)->arch().asString().c_str() );
302 patchSelectables.insert( sel );
303 emit filterMatch( sel, pkg );
307 y2error( "No selectable for pkg %s", (*it)->name().c_str() );
309 else // No ZyppPkg - some other kind of object (script, message)
311 if ( zypp::isKind<zypp::Script> ( *it ) )
313 y2debug( "Found patch script %s", (*it)->name().c_str() );
314 emit filterMatch( _( "Script" ), fromUTF8( (*it)->name() ), -1 );
316 else if ( zypp::isKind<zypp::Message> ( *it ) )
318 y2debug( "Found patch message %s (ignoring)", (*it)->name().c_str() );
322 y2error( "Found unknown object of kind %s in patch: %s-%s arch: %s",
323 (*it)->kind().asString().c_str(),
324 (*it)->name().c_str(),
325 (*it)->edition().asString().c_str(),
326 (*it)->arch().asString().c_str() );
333 emit filterFinished();
338 YQPkgPatchList::addPatchItem( ZyppSel selectable,
339 ZyppPatch zyppPatch )
343 y2error( "NULL ZyppSel!" );
347 YQPkgPatchListItem * item = new YQPkgPatchListItem( this, selectable, zyppPatch );
348 applyExcludeRules( item );
353 YQPkgPatchList::selection() const
355 Q3ListViewItem * item = selectedItem();
360 return dynamic_cast<YQPkgPatchListItem *> (item);
365 YQPkgPatchList::createNotInstalledContextMenu()
367 _notInstalledContextMenu = new Q3PopupMenu( this );
368 Q_CHECK_PTR( _notInstalledContextMenu );
370 actionSetCurrentInstall->addTo( _notInstalledContextMenu );
371 actionSetCurrentDontInstall->addTo( _notInstalledContextMenu );
372 actionSetCurrentTaboo->addTo( _notInstalledContextMenu );
374 addAllInListSubMenu( _notInstalledContextMenu );
379 YQPkgPatchList::createInstalledContextMenu()
381 _installedContextMenu = new Q3PopupMenu( this );
382 Q_CHECK_PTR( _installedContextMenu );
384 actionSetCurrentKeepInstalled->addTo( _installedContextMenu );
386 #if ENABLE_DELETING_PATCHES
387 actionSetCurrentDelete->addTo( _installedContextMenu );
390 actionSetCurrentUpdate->addTo( _installedContextMenu );
391 actionSetCurrentProtected->addTo( _installedContextMenu );
393 addAllInListSubMenu( _installedContextMenu );
398 YQPkgPatchList::addAllInListSubMenu( Q3PopupMenu * menu )
400 Q3PopupMenu * submenu = new Q3PopupMenu( menu );
401 Q_CHECK_PTR( submenu );
403 actionSetListInstall->addTo( submenu );
404 actionSetListDontInstall->addTo( submenu );
405 actionSetListKeepInstalled->addTo( submenu );
407 #if ENABLE_DELETING_PATCHES
408 actionSetListDelete->addTo( submenu );
411 actionSetListUpdate->addTo( submenu );
412 actionSetListUpdateForce->addTo( submenu );
413 actionSetListTaboo->addTo( submenu );
414 actionSetListProtected->addTo( submenu );
416 menu->insertItem( _( "&All in This List" ), submenu );
423 YQPkgPatchList::keyPressEvent( QKeyEvent * event )
427 #if ! ENABLE_DELETING_PATCHES
428 if ( event->ascii() == '-' )
430 Q3ListViewItem * selectedListViewItem = selectedItem();
432 if ( selectedListViewItem )
434 YQPkgPatchListItem * item = dynamic_cast<YQPkgPatchListItem *> (selectedListViewItem);
436 if ( item && item->selectable()->hasInstalledObj() )
438 y2warning( "Deleting patches is not supported" );
446 YQPkgObjList::keyPressEvent( event );
452 YQPkgPatchListItem::YQPkgPatchListItem( YQPkgPatchList * patchList,
454 ZyppPatch zyppPatch )
455 : YQPkgObjListItem( patchList, selectable, zyppPatch )
456 , _patchList( patchList )
457 , _zyppPatch( zyppPatch )
460 _zyppPatch = tryCastToZyppPatch( selectable->theObj() );
466 _patchCategory = patchCategory( _zyppPatch->category() );
468 if ( categoryCol() > -1 )
469 setText( categoryCol(), asString( _patchCategory ) );
471 if ( summaryCol() > -1 && _zyppPatch->summary().empty() )
472 setText( summaryCol(), _zyppPatch->name() ); // use name as fallback
474 switch ( _patchCategory )
476 case YQPkgYaSTPatch: setTextColor( QColor( 0, 0, 0xC0 ) ); break; // medium blue
477 case YQPkgSecurityPatch: setTextColor( Qt::red ); break;
478 case YQPkgRecommendedPatch: setTextColor( QColor( 0, 0, 0xC0 ) ); break; // medium blue
479 case YQPkgOptionalPatch: break;
480 case YQPkgDocumentPatch: break;
481 case YQPkgUnknownPatchCategory: break;
486 YQPkgPatchListItem::~YQPkgPatchListItem()
493 YQPkgPatchListItem::patchCategory( const string & category )
495 return patchCategory( fromUTF8( category ) );
500 YQPkgPatchListItem::patchCategory( QString category )
502 category = category.lower();
504 if ( category == "yast" ) return YQPkgYaSTPatch;
505 if ( category == "security" ) return YQPkgSecurityPatch;
506 if ( category == "recommended" ) return YQPkgRecommendedPatch;
507 if ( category == "optional" ) return YQPkgOptionalPatch;
508 if ( category == "document" ) return YQPkgDocumentPatch;
510 y2warning( "Unknown patch category \"%s\"", (const char *) category );
511 return YQPkgUnknownPatchCategory;
516 YQPkgPatchListItem::asString( YQPkgPatchCategory category )
520 // Translators: These are patch categories
521 case YQPkgYaSTPatch: return _( "YaST" );
522 case YQPkgSecurityPatch: return _( "security" );
523 case YQPkgRecommendedPatch: return _( "recommended" );
524 case YQPkgOptionalPatch: return _( "optional" );
525 case YQPkgDocumentPatch: return _( "document" );
526 case YQPkgUnknownPatchCategory: return "";
534 YQPkgPatchListItem::cycleStatus()
536 YQPkgObjListItem::cycleStatus();
538 #if ! ENABLE_DELETING_PATCHES
539 if ( status() == S_Del ) // Can't delete patches
540 setStatus( S_KeepInstalled );
546 YQPkgPatchListItem::toolTip( int col )
550 if ( col == statusCol() )
552 text = YQPkgObjListItem::toolTip( col );
556 if ( ( col == brokenIconCol() && isBroken() ) ||
557 ( col == satisfiedIconCol() && isSatisfied() ) )
559 text = YQPkgObjListItem::toolTip( col );
563 text = fromUTF8( zyppPatch()->category() );
565 if ( ! text.isEmpty() )
568 text += fromUTF8( zyppPatch()->size().asString().c_str() );
577 YQPkgPatchListItem::applyChanges()
579 solveResolvableCollections();
584 * Comparison function used for sorting the list.
591 YQPkgPatchListItem::compare( Q3ListViewItem * otherListViewItem,
593 bool ascending ) const
595 YQPkgPatchListItem * other = dynamic_cast<YQPkgPatchListItem *> (otherListViewItem);
599 if ( col == categoryCol() )
601 if ( this->patchCategory() < other->patchCategory() ) return -1;
602 if ( this->patchCategory() > other->patchCategory() ) return 1;
606 return YQPkgObjListItem::compare( otherListViewItem, col, ascending );
611 #include "YQPkgPatchList.moc"