]> icculus.org git repositories - duncan/yast2-qt4.git/blob - src/pkg/YQPkgPatchList.cc
#ifdefed out everything not compiling so it can be ported
[duncan/yast2-qt4.git] / src / pkg / YQPkgPatchList.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                        (C) SuSE GmbH |
11 \----------------------------------------------------------------------/
12
13   File:       YQPkgPatchList.cc
14
15   Author:     Stefan Hundhammer <sh@suse.de>
16
17   Textdomain "packages-qt"
18
19 /-*/
20
21
22 #define y2log_component "qt-pkg"
23 #include <ycp/y2log.h>
24
25 #include <q3popupmenu.h>
26 #include <q3action.h>
27 //Added by qt3to4:
28 #include <qevent.h>
29 #include <zypp/ui/PatchContents.h>
30 #include <set>
31
32 #include "YQi18n.h"
33 #include "utf8.h"
34
35 #include "YQPkgPatchList.h"
36 #include "YQPkgTextDialog.h"
37
38
39 #define VERBOSE_PATCH_LIST      1
40
41
42 typedef zypp::ui::PatchContents                 ZyppPatchContents;
43 typedef zypp::ui::PatchContents::const_iterator ZyppPatchContentsIterator;
44
45 using std::list;
46 using std::set;
47
48
49 YQPkgPatchList::YQPkgPatchList( QWidget * parent )
50     : YQPkgObjList( parent )
51 {
52     y2debug( "Creating patch list" );
53
54     _filterCriteria = RelevantPatches;
55
56     int numCol = 0;
57 #if FIXME
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++;
64
65     // Can use the same colum for "broken" and "satisfied":
66     // Both states are mutually exclusive
67
68     _satisfiedIconCol   = _summaryCol;
69     _brokenIconCol      = _summaryCol;
70
71     setAllColumnsShowFocus( true );
72     setColumnAlignment( sizeCol(), Qt::AlignRight );
73
74     connect( this,      SIGNAL( selectionChanged        ( Q3ListViewItem * ) ),
75              this,      SLOT  ( filter()                                    ) );
76
77     setSorting( categoryCol() );
78     fillList();
79 #endif
80
81     y2debug( "Creating patch list done" );
82 }
83
84
85 YQPkgPatchList::~YQPkgPatchList()
86 {
87     // NOP
88 }
89
90
91 void
92 YQPkgPatchList::polish()
93 {
94     // Delayed initialization after widget is fully created etc.
95
96     // Only now send selectionChanged() signal so attached details views also
97     // display something if their showDetailsIfVisible() slot is connected to
98     // selectionChanged() signals.
99     selectSomething();
100 }
101
102
103 void
104 YQPkgPatchList::setFilterCriteria( FilterCriteria filterCriteria )
105 {
106     _filterCriteria = filterCriteria;
107 }
108
109
110 void
111 YQPkgPatchList::fillList()
112 {
113     clear();
114     y2debug( "Filling patch list" );
115
116     for ( ZyppPoolIterator it = zyppPatchesBegin();
117           it != zyppPatchesEnd();
118           ++it )
119     {
120         ZyppSel   selectable = *it;
121         ZyppPatch zyppPatch = tryCastToZyppPatch( selectable->theObj() );
122
123         if ( zyppPatch )
124         {
125             bool displayPatch = false;
126
127             switch ( _filterCriteria )
128             {
129                 case RelevantPatches:   // needed + broken + satisfied (but not installed)
130
131                     if ( selectable->hasInstalledObj() ) // installed?
132                     {
133                         if ( selectable->installedPoolItem().status().isIncomplete() ) // patch broken?
134                         {
135                             // The patch is broken: It had been installed, but the user somehow
136                             // downgraded individual packages belonging to the patch to older versions.
137
138                             displayPatch = true;
139
140                             y2warning( "Installed patch is broken: %s - %s",
141                                        zyppPatch->name().c_str(),
142                                        zyppPatch->summary().c_str() );
143                         }
144                     }
145                     else // not installed
146                     {
147                         if ( selectable->hasCandidateObj() &&
148                              selectable->candidatePoolItem().status().isSatisfied() )
149                         {
150                             // This is a pretty exotic case, but still it might happen:
151                             //
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).
157
158                             displayPatch = true;
159
160                             y2milestone( "Patch satisfied, but not installed yet: %s - %s",
161                                          zyppPatch->name().c_str(),
162                                          zyppPatch->summary().c_str() );
163                         }
164                     }
165
166                     if ( selectable->hasCandidateObj() )        // candidate available?
167                     {
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.
171
172                         if ( selectable->candidatePoolItem().status().isNeeded() ) // patch really needed?
173                         {
174                             // Patches are needed if any of the packages that belong to the patch
175                             // are installed on the system.
176
177                             displayPatch = true;
178                         }
179                         else
180                         {
181                             // None of the packages that belong to the patch is installed on the system.
182
183                             y2debug( "Patch not needed: %s - %s",
184                                      zyppPatch->name().c_str(),
185                                      zyppPatch->summary().c_str() );
186                         }
187                     }
188                     break;
189
190
191                 case RelevantAndInstalledPatches:       // needed + broken + installed
192
193                     if ( selectable->hasInstalledObj() ) // installed?
194                     {
195                         displayPatch = true;
196                     }
197                     else // not installed - display only if needed
198                     {
199                         zypp::ResStatus candidateStatus = selectable->candidatePoolItem().status();
200
201                         if ( candidateStatus.isNeeded() ||
202                              candidateStatus.isSatisfied() )
203                         {
204                             displayPatch = true;
205                         }
206                         else
207                         {
208                             y2milestone( "Patch not needed: %s - %s",
209                                          zyppPatch->name().c_str(),
210                                          zyppPatch->summary().c_str() );
211                         }
212                     }
213                     break;
214
215
216                 case AllPatches:
217                     displayPatch = true;
218                     break;
219
220                 // Intentionally omitting "default" so the compiler
221                 // can catch unhandled enum values
222             }
223
224             if ( displayPatch )
225             {
226 #if VERBOSE_PATCH_LIST
227                 y2debug( "Displaying patch %s - %s", zyppPatch->name().c_str(), zyppPatch->summary().c_str() );
228 #endif
229                 addPatchItem( *it, zyppPatch);
230             }
231         }
232         else
233         {
234             y2error( "Found non-patch selectable" );
235         }
236     }
237
238 #if FIXME
239     if ( ! firstChild() )
240         message( _( "No patches available." ) );
241 #endif
242
243     y2debug( "patch list filled" );
244 }
245
246
247
248 void
249 YQPkgPatchList::message( const QString & text )
250 {
251     QY2ListViewItem * item = new QY2ListViewItem( this );
252     Q_CHECK_PTR( item );
253
254     item->setText( 1, text );
255     item->setBackgroundColor( QColor( 0xE0, 0xE0, 0xF8 ) );
256 }
257
258
259
260 void
261 YQPkgPatchList::filterIfVisible()
262 {
263     if ( isVisible() )
264         filter();
265 }
266
267
268 void
269 YQPkgPatchList::filter()
270 {
271     emit filterStart();
272     std::set<ZyppSel> patchSelectables;
273
274     if ( selection() )
275     {
276         ZyppPatch patch = selection()->zyppPatch();
277
278         if ( patch )
279         {
280             ZyppPatchContents patchContents( patch );
281
282             for ( ZyppPatchContentsIterator it = patchContents.begin();
283                   it != patchContents.end();
284                   ++it )
285             {
286                 ZyppPkg pkg = tryCastToZyppPkg( *it );
287
288                 if ( pkg )
289                 {
290                     y2debug( "Found patch pkg: %s arch: %s", (*it)->name().c_str(), (*it)->arch().asString().c_str() );
291
292                     ZyppSel sel = _selMapper.findZyppSel( pkg );
293
294                     if ( sel )
295                     {
296                         if ( contains( patchSelectables, sel ) )
297                         {
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() );
302                         }
303                         else
304                         {
305                             patchSelectables.insert( sel );
306                             emit filterMatch( sel, pkg );
307                         }
308                     }
309                     else
310                         y2error( "No selectable for pkg %s",  (*it)->name().c_str() );
311                 }
312                 else // No ZyppPkg - some other kind of object (script, message)
313                 {
314                     if ( zypp::isKind<zypp::Script> ( *it ) )
315                     {
316                         y2debug( "Found patch script %s", (*it)->name().c_str() );
317                         emit filterMatch( _( "Script" ),  fromUTF8( (*it)->name() ), -1 );
318                     }
319                     else if ( zypp::isKind<zypp::Message> ( *it ) )
320                     {
321                         y2debug( "Found patch message %s (ignoring)", (*it)->name().c_str() );
322                     }
323                     else
324                     {
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() );
330                     }
331                 }
332             }
333         }
334     }
335
336     emit filterFinished();
337 }
338
339
340 void
341 YQPkgPatchList::addPatchItem( ZyppSel   selectable,
342                               ZyppPatch zyppPatch )
343 {
344     if ( ! selectable )
345     {
346         y2error( "NULL ZyppSel!" );
347         return;
348     }
349
350     YQPkgPatchListItem * item = new YQPkgPatchListItem( this, selectable, zyppPatch );
351     applyExcludeRules( item );
352 }
353
354
355 YQPkgPatchListItem *
356 YQPkgPatchList::selection() const
357 {
358 #if FIXME
359     Q3ListViewItem * item = selectedItem();
360
361     if ( ! item )
362         return 0;
363
364     return dynamic_cast<YQPkgPatchListItem *> (item);
365 #else
366     return 0;
367 #endif
368 }
369
370
371 void
372 YQPkgPatchList::createNotInstalledContextMenu()
373 {
374     _notInstalledContextMenu = new Q3PopupMenu( this );
375     Q_CHECK_PTR( _notInstalledContextMenu );
376
377     actionSetCurrentInstall->addTo( _notInstalledContextMenu );
378     actionSetCurrentDontInstall->addTo( _notInstalledContextMenu );
379     actionSetCurrentTaboo->addTo( _notInstalledContextMenu );
380
381     addAllInListSubMenu( _notInstalledContextMenu );
382 }
383
384
385 void
386 YQPkgPatchList::createInstalledContextMenu()
387 {
388     _installedContextMenu = new Q3PopupMenu( this );
389     Q_CHECK_PTR( _installedContextMenu );
390
391     actionSetCurrentKeepInstalled->addTo( _installedContextMenu );
392
393 #if ENABLE_DELETING_PATCHES
394     actionSetCurrentDelete->addTo( _installedContextMenu );
395 #endif
396
397     actionSetCurrentUpdate->addTo( _installedContextMenu );
398     actionSetCurrentProtected->addTo( _installedContextMenu );
399
400     addAllInListSubMenu( _installedContextMenu );
401 }
402
403
404 Q3PopupMenu *
405 YQPkgPatchList::addAllInListSubMenu( Q3PopupMenu * menu )
406 {
407     Q3PopupMenu * submenu = new Q3PopupMenu( menu );
408     Q_CHECK_PTR( submenu );
409
410     actionSetListInstall->addTo( submenu );
411     actionSetListDontInstall->addTo( submenu );
412     actionSetListKeepInstalled->addTo( submenu );
413
414 #if ENABLE_DELETING_PATCHES
415     actionSetListDelete->addTo( submenu );
416 #endif
417
418     actionSetListUpdate->addTo( submenu );
419     actionSetListUpdateForce->addTo( submenu );
420     actionSetListTaboo->addTo( submenu );
421     actionSetListProtected->addTo( submenu );
422
423     menu->insertItem( _( "&All in This List" ), submenu );
424
425     return submenu;
426 }
427
428
429 void
430 YQPkgPatchList::keyPressEvent( QKeyEvent * event )
431 {
432     if ( event )
433     {
434 #if ! ENABLE_DELETING_PATCHES
435         if ( event->ascii() == '-' )
436         {
437             Q3ListViewItem * selectedListViewItem = selectedItem();
438
439             if ( selectedListViewItem )
440             {
441                 YQPkgPatchListItem * item = dynamic_cast<YQPkgPatchListItem *> (selectedListViewItem);
442
443                 if ( item && item->selectable()->hasInstalledObj() )
444                 {
445                     y2warning( "Deleting patches is not supported" );
446                     return;
447                 }
448             }
449         }
450 #endif
451     }
452
453     YQPkgObjList::keyPressEvent( event );
454 }
455
456
457
458
459 YQPkgPatchListItem::YQPkgPatchListItem( YQPkgPatchList *        patchList,
460                                         ZyppSel                 selectable,
461                                         ZyppPatch               zyppPatch )
462     : YQPkgObjListItem( patchList, selectable, zyppPatch )
463     , _patchList( patchList )
464     , _zyppPatch( zyppPatch )
465 {
466     if ( ! _zyppPatch )
467         _zyppPatch = tryCastToZyppPatch( selectable->theObj() );
468
469     if ( ! _zyppPatch )
470         return;
471
472     setStatusIcon();
473     _patchCategory = patchCategory( _zyppPatch->category() );
474
475     if ( categoryCol() > -1 )
476         setText( categoryCol(), asString( _patchCategory ) );
477
478     if ( summaryCol() > -1 && _zyppPatch->summary().empty() )
479         setText( summaryCol(), _zyppPatch->name() );            // use name as fallback
480
481     switch ( _patchCategory )
482     {
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;
489     }
490 }
491
492
493 YQPkgPatchListItem::~YQPkgPatchListItem()
494 {
495     // NOP
496 }
497
498
499 YQPkgPatchCategory
500 YQPkgPatchListItem::patchCategory( const string & category )
501 {
502     return patchCategory( fromUTF8( category ) );
503 }
504
505
506 YQPkgPatchCategory
507 YQPkgPatchListItem::patchCategory( QString category )
508 {
509     category = category.lower();
510
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;
516
517     y2warning( "Unknown patch category \"%s\"", (const char *) category );
518     return YQPkgUnknownPatchCategory;
519 }
520
521
522 QString
523 YQPkgPatchListItem::asString( YQPkgPatchCategory category )
524 {
525     switch ( category )
526     {
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 "";
534     }
535
536     return "";
537 }
538
539
540 void
541 YQPkgPatchListItem::cycleStatus()
542 {
543     YQPkgObjListItem::cycleStatus();
544
545 #if ! ENABLE_DELETING_PATCHES
546     if ( status() == S_Del )    // Can't delete patches
547         setStatus( S_KeepInstalled );
548 #endif
549 }
550
551
552 QString
553 YQPkgPatchListItem::toolTip( int col )
554 {
555     QString text;
556
557     if ( col == statusCol() )
558     {
559         text = YQPkgObjListItem::toolTip( col );
560     }
561     else
562     {
563         if (  ( col == brokenIconCol()    && isBroken()    ) ||
564               ( col == satisfiedIconCol() && isSatisfied() )   )
565         {
566             text = YQPkgObjListItem::toolTip( col );
567         }
568         else
569         {
570             text = fromUTF8( zyppPatch()->category() );
571
572             if ( ! text.isEmpty() )
573                 text += "\n";
574
575             text += fromUTF8( zyppPatch()->size().asString().c_str() );
576         }
577     }
578
579     return text;
580 }
581
582
583 void
584 YQPkgPatchListItem::applyChanges()
585 {
586     solveResolvableCollections();
587 }
588
589
590 /**
591  * Comparison function used for sorting the list.
592  * Returns:
593  * -1 if this <  other
594  *  0 if this == other
595  * +1 if this >  other
596  **/
597 int
598 YQPkgPatchListItem::compare( QTreeWidgetItem *  otherListViewItem,
599                              int                col,
600                              bool               ascending ) const
601 {
602     YQPkgPatchListItem * other = dynamic_cast<YQPkgPatchListItem *> (otherListViewItem);
603
604     if ( other )
605     {
606         if ( col == categoryCol() )
607         {
608             if ( this->patchCategory() < other->patchCategory() ) return -1;
609             if ( this->patchCategory() > other->patchCategory() ) return  1;
610             return 0;
611         }
612     }
613     return YQPkgObjListItem::compare( otherListViewItem, col, ascending );
614 }
615
616
617
618 #include "YQPkgPatchList.moc"