]> icculus.org git repositories - duncan/yast2-qt4.git/blob - src/pkg/YQPackageSelector.cc
restart qt4 porting
[duncan/yast2-qt4.git] / src / pkg / YQPackageSelector.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                        (C) SuSE GmbH |
11 \----------------------------------------------------------------------/
12
13   File:       YQPackageSelector.cc
14   See also:   YQPackageSelectorHelp.cc
15
16   Author:     Stefan Hundhammer <sh@suse.de>
17
18   Textdomain "packages-qt"
19
20 /-*/
21
22 #define CHECK_DEPENDENCIES_ON_STARTUP                   1
23 #define DEPENDENCY_FEEDBACK_IF_OK                       1
24 #define AUTO_CHECK_DEPENDENCIES_DEFAULT                 true
25 #define ALWAYS_SHOW_PATCHES_VIEW_IF_PATCHES_AVAILABLE   0
26 #define GLOBAL_UPDATE_CONFIRMATION_THRESHOLD            20
27
28 #include <fstream>
29 #include <boost/bind.hpp>
30
31 #include <qaction.h>
32 #include <qapplication.h>
33 #include <qaccel.h>
34 #include <qcheckbox.h>
35 #include <qdialog.h>
36 #include <qfiledialog.h>
37 #include <qhbox.h>
38 #include <qlabel.h>
39 #include <qmap.h>
40 #include <qmenubar.h>
41 #include <qmessagebox.h>
42 #include <qpushbutton.h>
43 #include <qsplitter.h>
44 #include <qtabwidget.h>
45 #include <qtimer.h>
46
47 #define y2log_component "qt-pkg"
48 #include <ycp/y2log.h>
49
50 #include "QY2LayoutUtils.h"
51
52 #include "YQPackageSelector.h"
53 #include "YQPkgChangeLogView.h"
54 #include "YQPkgChangesDialog.h"
55 #include "YQPkgConflictDialog.h"
56 #include "YQPkgConflictList.h"
57 #include "YQPkgDependenciesView.h"
58 #include "YQPkgDescriptionView.h"
59 #include "YQPkgDiskUsageList.h"
60 #include "YQPkgDiskUsageWarningDialog.h"
61 #include "YQPkgFileListView.h"
62 #include "YQPkgRepoFilterView.h"
63 #include "YQPkgRepoList.h"
64 #include "YQPkgLangList.h"
65 #include "YQPkgList.h"
66 #include "YQPkgPatchFilterView.h"
67 #include "YQPkgPatchList.h"
68 #include "YQPkgPatternList.h"
69 #include "YQPkgProductDialog.h"
70 #include "YQPkgRpmGroupTagsFilterView.h"
71 #include "YQPkgSearchFilterView.h"
72 #include "YQPkgSelList.h"
73 #include "YQPkgStatusFilterView.h"
74 #include "YQPkgTechnicalDetailsView.h"
75 #include "YQPkgTextDialog.h"
76 #include "YQPkgUpdateProblemFilterView.h"
77 #include "YQPkgVersionsView.h"
78 #include "zypp/SysContent.h"
79
80 #include "QY2ComboTabWidget.h"
81 #include "YQDialog.h"
82 #include "utf8.h"
83 #include "YQUI.h"
84 #include "YEvent.h"
85 #include "YQi18n.h"
86
87
88 using std::max;
89 using std::string;
90 using std::map;
91 using std::pair;
92
93 #define SPACING                         6
94 #define MARGIN                          4
95 #define DEFAULT_EXPORT_FILE_NAME        "user-packages.xml"
96 #define FAST_SOLVER                     1
97
98
99
100 YQPackageSelector::YQPackageSelector( YWidget *         parent,
101                                       long              modeFlags )
102     : YQPackageSelectorBase( parent, modeFlags )
103 {
104     _showChangesDialog          = true;
105     _autoDependenciesCheckBox   = 0;
106     _detailsViews               = 0;
107     _diskUsageList              = 0;
108     _filters                    = 0;
109     _repoFilterView             = 0;
110     _langList                   = 0;
111     _patternList                = 0;
112     _pkgChangeLogView           = 0;
113     _pkgDependenciesView        = 0;
114     _pkgDescriptionView         = 0;
115     _pkgFileListView            = 0;
116     _pkgList                    = 0;
117     _pkgTechnicalDetailsView    = 0;
118     _pkgVersionsView            = 0;
119     _rpmGroupTagsFilterView     = 0;
120     _searchFilterView           = 0;
121     _selList                    = 0;
122     _statusFilterView           = 0;
123     _updateProblemFilterView    = 0;
124     _patchFilterView            = 0;
125     _patchList                  = 0;
126     _excludeDevelPkgs           = 0;
127     _excludeDebugInfoPkgs       = 0;
128
129
130     if ( onlineUpdateMode() )   y2milestone( "Online update mode" );
131     if ( updateMode() )         y2milestone( "Update mode" );
132
133
134     basicLayout();
135     addMenus();         // Only after all widgets are created!
136     makeConnections();
137     emit loadData();
138
139     if ( _pkgList )
140         _pkgList->clear();
141
142     if ( _patchFilterView && onlineUpdateMode() )
143     {
144         if ( _filters && _patchFilterView && _patchList )
145         {
146             _filters->showPage( _patchFilterView );
147             _patchList->filter();
148         }
149     }
150     else if ( _repoFilterView && repoMode() )
151     {
152         if ( YQPkgRepoList::countEnabledRepositories() > 1 )
153         {
154             _filters->showPage( _repoFilterView );
155             _repoFilterView->filter();
156         }
157         else if ( _searchFilterView )
158         {
159             y2milestone( "No multiple repositories - falling back to search mode" );
160             _filters->showPage( _searchFilterView );
161             _searchFilterView->filter();
162             QTimer::singleShot( 0, _searchFilterView, SLOT( setFocus() ) );
163         }
164     }
165     else if ( _updateProblemFilterView )
166     {
167         _filters->showPage( _updateProblemFilterView );
168         _updateProblemFilterView->filter();
169
170     }
171     else if ( searchMode() && _searchFilterView )
172     {
173         _filters->showPage( _searchFilterView );
174         _searchFilterView->filter();
175         QTimer::singleShot( 0, _searchFilterView, SLOT( setFocus() ) );
176     }
177     else if ( summaryMode() && _statusFilterView )
178     {
179         _filters->showPage( _statusFilterView );
180         _statusFilterView->filter();
181     }
182     else if ( _patternList )
183     {
184         _filters->showPage( _patternList );
185         _patternList->filter();
186     }
187     else if ( _selList )
188     {
189         _filters->showPage( _selList );
190         _selList->filter();
191     }
192
193
194     if ( _diskUsageList )
195         _diskUsageList->updateDiskUsage();
196
197     y2milestone( "PackageSelector init done" );
198
199
200 #if CHECK_DEPENDENCIES_ON_STARTUP
201
202     if ( ! testMode() && ! onlineUpdateMode() )
203     {
204         // Fire up the first dependency check in the main loop.
205         // Don't do this right away - wait until all initializations are finished.
206         QTimer::singleShot( 0, this, SLOT( resolveDependencies() ) );
207     }
208 #endif
209 }
210
211
212 void
213 YQPackageSelector::basicLayout()
214 {
215     layoutMenuBar( this );
216
217     QSplitter * outer_splitter = new QSplitter( QSplitter::Horizontal, this );
218     CHECK_PTR( outer_splitter );
219
220     QWidget * left_pane  = layoutLeftPane ( outer_splitter );
221     QWidget * right_pane = layoutRightPane( outer_splitter );
222
223     outer_splitter->setResizeMode( left_pane,  QSplitter::KeepSize );
224     outer_splitter->setResizeMode( right_pane, QSplitter::Stretch );
225 }
226
227
228 QWidget *
229 YQPackageSelector::layoutLeftPane( QWidget * parent )
230 {
231     QSplitter * splitter = new QSplitter( QSplitter::Vertical, parent );
232     CHECK_PTR( splitter );
233     splitter->setMargin( MARGIN );
234
235     QVBox * upper_vbox = new QVBox( splitter );
236     CHECK_PTR( upper_vbox );
237     layoutFilters( upper_vbox );
238     addVSpacing( upper_vbox, MARGIN );
239
240     QVBox * lower_vbox = new QVBox( splitter );
241     addVSpacing( lower_vbox, MARGIN );
242     _diskUsageList = new YQPkgDiskUsageList( lower_vbox );
243     CHECK_PTR( _diskUsageList );
244
245     splitter->setResizeMode( upper_vbox, QSplitter::Stretch );
246     splitter->setResizeMode( lower_vbox, QSplitter::FollowSizeHint );
247
248     return splitter;
249 }
250
251
252 void
253 YQPackageSelector::layoutFilters( QWidget * parent )
254 {
255     _filters = new QY2ComboTabWidget( _( "Fi&lter:" ), parent );
256     CHECK_PTR( _filters );
257
258
259     //
260     // Update problem view
261     //
262
263     if ( updateMode() )
264     {
265         if ( YQPkgUpdateProblemFilterView::haveProblematicPackages()
266              || testMode() )
267         {
268             _updateProblemFilterView = new YQPkgUpdateProblemFilterView( parent );
269             CHECK_PTR( _updateProblemFilterView );
270             _filters->addPage( _( "Update Problems" ), _updateProblemFilterView );
271         }
272     }
273
274
275     //
276     // Patches view
277     //
278
279     if ( onlineUpdateMode()
280 #if ALWAYS_SHOW_PATCHES_VIEW_IF_PATCHES_AVAILABLE
281          || ! zyppPool().empty<zypp::Patch>()
282 #endif
283          )
284         addPatchFilterView();
285
286
287     //
288     // Patterns view
289     //
290
291     if ( ! zyppPool().empty<zypp::Pattern>() || testMode() )
292     {
293         _patternList = new YQPkgPatternList( parent, true );
294         CHECK_PTR( _patternList );
295         _filters->addPage( _( "Patterns" ), _patternList );
296
297         connect( _patternList,          SIGNAL( statusChanged()                 ),
298                  this,                  SLOT  ( autoResolveDependencies()       ) );
299
300         connect( this,                  SIGNAL( refresh()                       ),
301                  _patternList,          SLOT  ( updateItemStates()              ) );
302
303         if ( _pkgConflictDialog )
304         {
305             connect( _pkgConflictDialog, SIGNAL( updatePackages()               ),
306                      _patternList,       SLOT  ( updateItemStates()             ) );
307         }
308     }
309
310
311     //
312     // Selections view
313     //
314
315     if ( ! zyppPool().empty<zypp::Selection>() || testMode() )
316     {
317
318         _selList = new YQPkgSelList( parent, true );
319         CHECK_PTR( _selList );
320         _filters->addPage( _( "Selections" ), _selList );
321
322         connect( _selList,              SIGNAL( statusChanged()                 ),
323                  this,                  SLOT  ( autoResolveDependencies()       ) );
324
325         connect( this,                  SIGNAL( refresh()                       ),
326                  _selList,               SLOT  ( updateItemStates()             ) );
327
328         if ( _pkgConflictDialog )
329         {
330             connect( _pkgConflictDialog, SIGNAL( updatePackages()               ),
331                      _selList,           SLOT  ( updateItemStates()             ) );
332         }
333     }
334
335
336     //
337     // RPM group tags view
338     //
339
340     _rpmGroupTagsFilterView = new YQPkgRpmGroupTagsFilterView( parent );
341     CHECK_PTR( _rpmGroupTagsFilterView );
342     _filters->addPage( _( "Package Groups" ), _rpmGroupTagsFilterView );
343
344     connect( this,                      SIGNAL( loadData() ),
345              _rpmGroupTagsFilterView,   SLOT  ( filter()   ) );
346
347
348     //
349     // Languages view
350     //
351
352     _langList = new YQPkgLangList( parent );
353     CHECK_PTR( _langList );
354
355     _filters->addPage( _( "Languages" ), _langList );
356     _langList->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ) ); // hor/vert
357
358     connect( _langList,         SIGNAL( statusChanged()                 ),
359              this,              SLOT  ( autoResolveDependencies()       ) );
360
361     connect( this,              SIGNAL( refresh()                       ),
362              _langList,         SLOT  ( updateItemStates()              ) );
363
364
365     //
366     // Repository view
367     //
368
369     _repoFilterView = new YQPkgRepoFilterView( parent );
370     CHECK_PTR( _repoFilterView );
371     _filters->addPage( _( "Repositories" ), _repoFilterView );
372
373
374     //
375     // Package search view
376     //
377
378     _searchFilterView = new YQPkgSearchFilterView( parent );
379     CHECK_PTR( _searchFilterView );
380     _filters->addPage( _( "Search" ), _searchFilterView );
381
382
383     //
384     // Status change view
385     //
386
387     _statusFilterView = new YQPkgStatusFilterView( parent );
388     CHECK_PTR( _statusFilterView );
389     _filters->addPage( _( "Installation Summary" ), _statusFilterView );
390
391
392 #if 0
393     // DEBUG
394
395     _filters->addPage( _( "Keywords"   ), new QLabel( "Keywords\nfilter\n\nfor future use", 0 ) );
396     _filters->addPage( _( "MIME Types" ), new QLabel( "MIME Types\nfilter\n\nfor future use" , 0 ) );
397 #endif
398
399 }
400
401
402 QWidget *
403 YQPackageSelector::layoutRightPane( QWidget * parent )
404 {
405     QVBox * right_pane_vbox = new QVBox( parent );
406     CHECK_PTR( right_pane_vbox );
407     right_pane_vbox->setMargin( MARGIN );
408
409     QSplitter * splitter = new QSplitter( QSplitter::Vertical, right_pane_vbox );
410     CHECK_PTR( splitter );
411
412     QVBox * splitter_vbox = new QVBox( splitter );
413     CHECK_PTR( splitter_vbox );
414     layoutPkgList( splitter_vbox );
415     addVSpacing( splitter_vbox, MARGIN );
416
417     layoutDetailsViews( splitter );
418
419     layoutButtons( right_pane_vbox );
420
421     return right_pane_vbox;
422 }
423
424
425 void
426 YQPackageSelector::layoutPkgList( QWidget * parent )
427 {
428     _pkgList= new YQPkgList( parent );
429     CHECK_PTR( _pkgList );
430
431     connect( _pkgList,  SIGNAL( statusChanged()           ),
432              this,      SLOT  ( autoResolveDependencies() ) );
433 }
434
435
436 void
437 YQPackageSelector::layoutDetailsViews( QWidget * parent )
438 {
439     bool haveInstalledPkgs = YQPkgList::haveInstalledPkgs();
440
441     QVBox * details_vbox = new QVBox( parent );
442     CHECK_PTR( details_vbox );
443     details_vbox->setMinimumSize( 0, 0 );
444
445     addVSpacing( details_vbox, 8 );
446
447     _detailsViews = new QTabWidget( details_vbox );
448     CHECK_PTR( _detailsViews );
449     _detailsViews->setMargin( MARGIN );
450
451     // _detailsViews->setTabPosition( QTabWidget::Bottom );
452
453
454     //
455     // Description
456     //
457
458     _pkgDescriptionView = new YQPkgDescriptionView( _detailsViews );
459     CHECK_PTR( _pkgDescriptionView );
460
461     _detailsViews->addTab( _pkgDescriptionView, _( "D&escription" ) );
462     _detailsViews->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
463
464     connect( _pkgList,                  SIGNAL( selectionChanged    ( ZyppSel ) ),
465              _pkgDescriptionView,       SLOT  ( showDetailsIfVisible( ZyppSel ) ) );
466
467     //
468     // Technical details
469     //
470
471     _pkgTechnicalDetailsView = new YQPkgTechnicalDetailsView( _detailsViews );
472     CHECK_PTR( _pkgTechnicalDetailsView );
473
474     _detailsViews->addTab( _pkgTechnicalDetailsView, _( "&Technical Data" ) );
475
476     connect( _pkgList,                  SIGNAL( selectionChanged    ( ZyppSel ) ),
477              _pkgTechnicalDetailsView,  SLOT  ( showDetailsIfVisible( ZyppSel ) ) );
478
479
480     //
481     // Dependencies
482     //
483
484     _pkgDependenciesView = new YQPkgDependenciesView( _detailsViews );
485     CHECK_PTR( _pkgDependenciesView );
486
487     _detailsViews->addTab( _pkgDependenciesView, _( "Dependencies" ) );
488     _detailsViews->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
489
490     connect( _pkgList,                  SIGNAL( selectionChanged    ( ZyppSel ) ),
491              _pkgDependenciesView,      SLOT  ( showDetailsIfVisible( ZyppSel ) ) );
492
493
494
495     //
496     // Versions
497     //
498
499     _pkgVersionsView = new YQPkgVersionsView( _detailsViews,
500                                               true );   // userCanSwitchVersions
501     CHECK_PTR( _pkgVersionsView );
502
503     _detailsViews->addTab( _pkgVersionsView, _( "&Versions" ) );
504
505     connect( _pkgList,          SIGNAL( selectionChanged    ( ZyppSel ) ),
506              _pkgVersionsView,  SLOT  ( showDetailsIfVisible( ZyppSel ) ) );
507
508
509     //
510     // File List
511     //
512
513     if ( haveInstalledPkgs )    // file list information is only available for installed pkgs
514     {
515         _pkgFileListView = new YQPkgFileListView( _detailsViews );
516         CHECK_PTR( _pkgFileListView );
517
518         _detailsViews->addTab( _pkgFileListView, _( "File List" ) );
519         _detailsViews->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
520
521         connect( _pkgList,              SIGNAL( selectionChanged    ( ZyppSel ) ),
522                  _pkgFileListView,      SLOT  ( showDetailsIfVisible( ZyppSel ) ) );
523     }
524
525
526     //
527     // Change Log
528     //
529
530     if ( haveInstalledPkgs )    // change log information is only available for installed pkgs
531     {
532         _pkgChangeLogView = new YQPkgChangeLogView( _detailsViews );
533         CHECK_PTR( _pkgChangeLogView );
534
535         _detailsViews->addTab( _pkgChangeLogView, _( "Change Log" ) );
536         _detailsViews->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
537
538         connect( _pkgList,              SIGNAL( selectionChanged    ( ZyppSel ) ),
539                  _pkgChangeLogView,     SLOT  ( showDetailsIfVisible( ZyppSel ) ) );
540     }
541 }
542
543
544 void
545 YQPackageSelector::layoutButtons( QWidget * parent )
546 {
547     QHBox * button_box = new QHBox( parent );
548     CHECK_PTR( button_box );
549     button_box->setSpacing( SPACING );
550
551     // Button: Dependency check
552     // Translators: Please keep this short!
553     _checkDependenciesButton = new QPushButton( _( "Chec&k" ), button_box );
554     CHECK_PTR( _checkDependenciesButton );
555     _checkDependenciesButton->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); // hor/vert
556     _normalButtonBackground = _checkDependenciesButton->paletteBackgroundColor();
557
558     connect( _checkDependenciesButton,  SIGNAL( clicked() ),
559              this,                      SLOT  ( manualResolvePackageDependencies() ) );
560
561
562     // Checkbox: Automatically check dependencies for every package status change?
563     // Translators: Please keep this short!
564     _autoDependenciesCheckBox = new QCheckBox( _( "A&utocheck" ), button_box );
565     CHECK_PTR( _autoDependenciesCheckBox );
566     _autoDependenciesCheckBox->setChecked( AUTO_CHECK_DEPENDENCIES_DEFAULT );
567
568     addHStretch( button_box );
569
570     QPushButton * cancel_button = new QPushButton( _( "&Cancel" ), button_box );
571     CHECK_PTR( cancel_button );
572     cancel_button->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); // hor/vert
573
574     connect( cancel_button, SIGNAL( clicked() ),
575              this,          SLOT  ( reject()   ) );
576
577
578     QPushButton * accept_button = new QPushButton( _( "&Accept" ), button_box );
579     CHECK_PTR( accept_button );
580     accept_button->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); // hor/vert
581
582     connect( accept_button, SIGNAL( clicked() ),
583              this,          SLOT  ( accept()   ) );
584
585     button_box->setFixedHeight( button_box->sizeHint().height() );
586 }
587
588
589 void
590 YQPackageSelector::layoutMenuBar( QWidget * parent )
591 {
592     _menuBar = new QMenuBar( parent );
593     CHECK_PTR( _menuBar );
594
595     _fileMenu           = 0;
596     _viewMenu           = 0;
597     _pkgMenu            = 0;
598     _patchMenu          = 0;
599     _extrasMenu         = 0;
600     _helpMenu           = 0;
601
602 }
603
604
605 void
606 YQPackageSelector::addMenus()
607 {
608     //
609     // File menu
610     //
611
612     _fileMenu = new QPopupMenu( _menuBar );
613     CHECK_PTR( _fileMenu );
614     _menuBar->insertItem( _( "&File" ), _fileMenu );
615
616     _fileMenu->insertItem( _( "&Import..." ),   this, SLOT( pkgImport() ) );
617     _fileMenu->insertItem( _( "&Export..." ),   this, SLOT( pkgExport() ) );
618
619     _fileMenu->insertSeparator();
620
621     _fileMenu->insertItem( _( "E&xit -- Discard Changes" ), this, SLOT( reject() ) );
622     _fileMenu->insertItem( _( "&Quit -- Save Changes"    ), this, SLOT( accept() ) );
623
624
625     if ( _pkgList )
626     {
627         //
628         // View menu
629         //
630
631         _viewMenu = new QPopupMenu( _menuBar );
632         CHECK_PTR( _viewMenu );
633         _menuBar->insertItem( _( "&View" ), _viewMenu );
634
635         // Translators: This is about packages ending in "-devel", so don't translate that "-devel"!
636         _viewShowDevelID = _viewMenu->insertItem( _( "Show -de&vel Packages" ),
637                                                        this, SLOT( pkgExcludeRulesChanged( int ) ), Key_F7 );
638         _viewMenu->setItemChecked( _viewShowDevelID, true );
639         _excludeDevelPkgs = new YQPkgObjList::ExcludeRule( _pkgList, QRegExp( ".*-devel(-\\d+bit)?$" ), _pkgList->nameCol() );
640         CHECK_PTR( _excludeDevelPkgs );
641         _excludeDevelPkgs->enable( false );
642
643         // Translators: This is about packages ending in "-debuginfo", so don't translate that "-debuginfo"!
644         _viewShowDebugInfoID = _viewMenu->insertItem( _( "Show -&debuginfo Packages" ),
645                                                        this, SLOT( pkgExcludeRulesChanged( int ) ), Key_F8 );
646         _viewMenu->setItemChecked( _viewShowDebugInfoID, true );
647         _excludeDebugInfoPkgs = new YQPkgObjList::ExcludeRule( _pkgList, QRegExp( ".*-debuginfo$" ), _pkgList->nameCol() );
648         CHECK_PTR( _excludeDebugInfoPkgs );
649         _excludeDebugInfoPkgs->enable( false );
650
651
652         //
653         // Package menu
654         //
655
656         _pkgMenu = new QPopupMenu( _menuBar );
657         CHECK_PTR( _pkgMenu );
658         _menuBar->insertItem( _( "&Package" ), _pkgMenu );
659
660         _pkgList->actionSetCurrentInstall->addTo( _pkgMenu );
661         _pkgList->actionSetCurrentDontInstall->addTo( _pkgMenu );
662         _pkgList->actionSetCurrentKeepInstalled->addTo( _pkgMenu );
663         _pkgList->actionSetCurrentDelete->addTo( _pkgMenu );
664         _pkgList->actionSetCurrentUpdate->addTo( _pkgMenu );
665         _pkgList->actionSetCurrentTaboo->addTo( _pkgMenu );
666         _pkgList->actionSetCurrentProtected->addTo( _pkgMenu );
667
668         _pkgMenu->insertSeparator();
669
670         _pkgList->actionInstallSourceRpm->addTo( _pkgMenu );
671         _pkgList->actionDontInstallSourceRpm->addTo( _pkgMenu );
672
673         _pkgMenu->insertSeparator();
674         QPopupMenu * submenu = _pkgList->addAllInListSubMenu( _pkgMenu );
675         CHECK_PTR( submenu );
676
677         submenu->insertSeparator();
678         _pkgList->actionInstallListSourceRpms->addTo( submenu );
679         _pkgList->actionDontInstallListSourceRpms->addTo( submenu );
680
681
682         //
683         // Submenu for all packages
684         //
685
686         submenu = new QPopupMenu( _pkgMenu );
687         CHECK_PTR( submenu );
688
689         // Translators: Unlike the "all in this list" submenu, this submenu
690         // refers to all packages globally, not only to those that are
691         // currently visible in the packages list.
692         _pkgMenu->insertItem( _( "All Packages" ), submenu );
693
694         submenu->insertItem( _( "Update if newer version available" ),
695                              this, SLOT( globalUpdatePkg() ) );
696
697         submenu->insertItem( _( "Update unconditionally" ),
698                              this, SLOT( globalUpdatePkgForce() ) );
699     }
700
701
702     if ( _patchList )
703     {
704         //
705         // Patch menu
706         //
707
708         _patchMenu = new QPopupMenu( _menuBar );
709         CHECK_PTR( _patchMenu );
710         _menuBar->insertItem( _( "&Patch" ), _patchMenu );
711
712         _patchList->actionSetCurrentInstall->addTo( _patchMenu );
713         _patchList->actionSetCurrentDontInstall->addTo( _patchMenu );
714         _patchList->actionSetCurrentKeepInstalled->addTo( _patchMenu );
715 #if ENABLE_DELETING_PATCHES
716         _patchList->actionSetCurrentDelete->addTo( _patchMenu );
717 #endif
718         _patchList->actionSetCurrentUpdate->addTo( _patchMenu );
719         _patchList->actionSetCurrentTaboo->addTo( _patchMenu );
720
721         _patchMenu->insertSeparator();
722         _patchList->addAllInListSubMenu( _patchMenu );
723     }
724
725
726     //
727     // Extras menu
728     //
729
730     _extrasMenu = new QPopupMenu( _menuBar );
731     CHECK_PTR( _extrasMenu );
732     _menuBar->insertItem( _( "&Extras" ), _extrasMenu );
733
734     _extrasMenu->insertItem( _( "Show &Products"                  ), this, SLOT( showProducts()    ) );
735     _extrasMenu->insertItem( _( "Show &Automatic Package Changes" ), this, SLOT( showAutoPkgList() ), CTRL + Key_A );
736     _extrasMenu->insertItem( _( "&Verify System"                  ), this, SLOT( verifySystem()    ) );
737
738     _extrasMenu->insertSeparator();
739
740     // Translators: This is about packages ending in "-devel", so don't translate that "-devel"!
741     _extrasMenu->insertItem( _( "Install All Matching -&devel Packages" ), this, SLOT( installDevelPkgs() ) );
742
743     // Translators: This is about packages ending in "-debuginfo", so don't translate that "-debuginfo"!
744     _extrasMenu->insertItem( _( "Install All Matching -de&buginfo Packages" ), this, SLOT( installDebugInfoPkgs() ) );
745
746     _extrasMenu->insertSeparator();
747
748     if ( _pkgConflictDialog )
749         _extrasMenu->insertItem( _( "Generate Dependency Resolver &Test Case" ),
750                                     _pkgConflictDialog, SLOT( askCreateSolverTestCase() ) );
751
752     if ( _actionResetIgnoredDependencyProblems )
753         _actionResetIgnoredDependencyProblems->addTo( _extrasMenu );
754
755
756 #ifdef FIXME
757     if ( _patchList )
758         _patchList->actionShowRawPatchInfo->addTo( _extrasMenu );
759 #endif
760
761
762     //
763     // Help menu
764     //
765
766     _helpMenu = new QPopupMenu( _menuBar );
767     CHECK_PTR( _helpMenu );
768     _menuBar->insertSeparator();
769     _menuBar->insertItem( _( "&Help" ), _helpMenu );
770
771     // Note: The help functions and their texts are moved out
772     // to a separate source file YQPackageSelectorHelp.cc
773
774     // Menu entry for help overview
775     _helpMenu->insertItem( _( "&Overview" ), this, SLOT( help()         ), Key_F1         );
776
777     // Menu entry for help about used symbols ( icons )
778     _helpMenu->insertItem( _( "&Symbols" ), this, SLOT( symbolHelp()    ), SHIFT + Key_F1 );
779
780     // Menu entry for keyboard help
781     _helpMenu->insertItem( _( "&Keys" ), this, SLOT( keyboardHelp() )                 );
782 }
783
784
785 void
786 YQPackageSelector::connectFilter( QWidget * filter,
787                                   QWidget * pkgList,
788                                   bool hasUpdateSignal )
789 {
790     if ( ! filter  )    return;
791     if ( ! pkgList )    return;
792
793     if ( _filters )
794     {
795         connect( _filters,      SIGNAL( currentChanged(QWidget *) ),
796                  filter,        SLOT  ( filterIfVisible()            ) );
797     }
798
799     connect( this,      SIGNAL( refresh()         ),
800              filter,    SLOT  ( filterIfVisible() ) );
801
802     connect( filter,    SIGNAL( filterStart()   ),
803              pkgList,   SLOT  ( clear()         ) );
804
805     connect( filter,    SIGNAL( filterMatch( ZyppSel, ZyppPkg ) ),
806              pkgList,   SLOT  ( addPkgItem ( ZyppSel, ZyppPkg ) ) );
807
808     connect( filter,    SIGNAL( filterFinished()  ),
809              pkgList,   SLOT  ( selectSomething() ) );
810
811     connect( filter,    SIGNAL( filterFinished()       ),
812              pkgList,   SLOT  ( logExcludeStatistics() ) );
813
814
815     if ( hasUpdateSignal )
816     {
817         connect( filter,                SIGNAL( updatePackages()   ),
818                  pkgList,               SLOT  ( updateItemStates() ) );
819
820         if ( _diskUsageList )
821         {
822             connect( filter,            SIGNAL( updatePackages()  ),
823                      _diskUsageList,    SLOT  ( updateDiskUsage() ) );
824         }
825     }
826 }
827
828
829 void
830 YQPackageSelector::makeConnections()
831 {
832     connect( this, SIGNAL( resolvingStarted()   ),
833              this, SLOT  ( animateCheckButton() ) );
834
835     connect( this, SIGNAL( resolvingFinished()  ),
836              this, SLOT  ( restoreCheckButton() ) );
837
838     connectFilter( _updateProblemFilterView,    _pkgList, false );
839     connectFilter( _patternList,                _pkgList );
840     connectFilter( _selList,                    _pkgList );
841     connectFilter( _repoFilterView,             _pkgList, false );
842     connectFilter( _rpmGroupTagsFilterView,     _pkgList, false );
843     connectFilter( _langList,                   _pkgList );
844     connectFilter( _statusFilterView,           _pkgList, false );
845     connectFilter( _searchFilterView,           _pkgList, false );
846
847     if ( _searchFilterView && _pkgList )
848     {
849         connect( _searchFilterView,     SIGNAL( message( const QString & ) ),
850                  _pkgList,              SLOT  ( message( const QString & ) ) );
851     }
852
853     if ( _repoFilterView && _pkgList )
854     {
855         connect( _repoFilterView,       SIGNAL( filterNearMatch  ( ZyppSel, ZyppPkg ) ),
856                  _pkgList,              SLOT  ( addPkgItemDimmed ( ZyppSel, ZyppPkg ) ) );
857     }
858
859     if ( _pkgList && _diskUsageList )
860     {
861
862         connect( _pkgList,              SIGNAL( statusChanged()   ),
863                  _diskUsageList,        SLOT  ( updateDiskUsage() ) );
864     }
865
866     connectPatchList();
867
868
869
870     //
871     // Connect package conflict dialog
872     //
873
874     if ( _pkgConflictDialog )
875     {
876         if (_pkgList )
877         {
878             connect( _pkgConflictDialog,        SIGNAL( updatePackages()   ),
879                      _pkgList,                  SLOT  ( updateItemStates() ) );
880         }
881
882         if ( _patternList )
883         {
884             connect( _pkgConflictDialog,        SIGNAL( updatePackages()   ),
885                      _patternList,              SLOT  ( updateItemStates() ) );
886         }
887
888         if ( _selList )
889         {
890             connect( _pkgConflictDialog,        SIGNAL( updatePackages()   ),
891                      _selList,                  SLOT  ( updateItemStates() ) );
892         }
893
894         if ( _diskUsageList )
895         {
896             connect( _pkgConflictDialog,        SIGNAL( updatePackages()   ),
897                      _diskUsageList,            SLOT  ( updateDiskUsage()  ) );
898         }
899     }
900
901
902     //
903     // Connect package versions view
904     //
905
906     if ( _pkgVersionsView && _pkgList )
907     {
908         connect( _pkgVersionsView,      SIGNAL( candidateChanged( ZyppObj ) ),
909                  _pkgList,              SLOT  ( updateItemData()    ) );
910     }
911
912
913     //
914     // Hotkey to enable "patches" filter view on the fly
915     //
916
917     QAccel * accel = new QAccel( this );
918     CHECK_PTR( accel );
919     accel->connectItem( accel->insertItem( Key_F2 ),
920                         this, SLOT( hotkeyInsertPatchFilterView() ) );
921
922
923     //
924     // Update actions just before opening menus
925     //
926
927     if ( _pkgMenu && _pkgList )
928     {
929         connect( _pkgMenu,      SIGNAL( aboutToShow()   ),
930                  _pkgList,      SLOT  ( updateActions() ) );
931     }
932
933     if ( _patchMenu && _patchList )
934     {
935         connect( _patchMenu,    SIGNAL( aboutToShow()   ),
936                  _patchList,    SLOT  ( updateActions() ) );
937     }
938 }
939
940
941 void
942 YQPackageSelector::animateCheckButton()
943 {
944     if ( _checkDependenciesButton )
945     {
946         _checkDependenciesButton->setPaletteBackgroundColor( QColor( 0xE0, 0xE0, 0xF8 ) );
947         _checkDependenciesButton->repaint();
948     }
949 }
950
951
952 void
953 YQPackageSelector::restoreCheckButton()
954 {
955     if ( _checkDependenciesButton )
956         _checkDependenciesButton->setPaletteBackgroundColor( _normalButtonBackground );
957 }
958
959
960 void
961 YQPackageSelector::autoResolveDependencies()
962 {
963     if ( _autoDependenciesCheckBox && ! _autoDependenciesCheckBox->isChecked() )
964         return;
965
966     resolveDependencies();
967 }
968
969
970 int
971 YQPackageSelector::manualResolvePackageDependencies()
972 {
973     if ( ! _pkgConflictDialog )
974     {
975         y2error( "No package conflict dialog existing" );
976         return QDialog::Accepted;
977     }
978
979     YQUI::ui()->busyCursor();
980     int result = _pkgConflictDialog->solveAndShowConflicts();
981     YQUI::ui()->normalCursor();
982
983 #if DEPENDENCY_FEEDBACK_IF_OK
984
985     if ( result == QDialog::Accepted )
986     {
987         QMessageBox::information( this, "",
988                                   _( "All package dependencies are OK." ),
989                                   QMessageBox::Ok );
990     }
991 #endif
992
993     return result;
994 }
995
996
997 void
998 YQPackageSelector::addPatchFilterView()
999 {
1000     if ( ! _patchFilterView )
1001     {
1002         _patchFilterView = new YQPkgPatchFilterView( this );
1003         CHECK_PTR( _patchFilterView );
1004         _filters->addPage( _( "Patches" ), _patchFilterView );
1005
1006         _patchList = _patchFilterView->patchList();
1007         CHECK_PTR( _patchList );
1008
1009         connectPatchList();
1010     }
1011 }
1012
1013
1014 void
1015 YQPackageSelector::hotkeyInsertPatchFilterView()
1016 {
1017     if ( ! _patchFilterView )
1018     {
1019         y2milestone( "Activating patches filter view" );
1020
1021         addPatchFilterView();
1022         connectPatchList();
1023
1024         _filters->showPage( _patchFilterView );
1025         _pkgList->clear();
1026         _patchList->filter();
1027     }
1028 }
1029
1030
1031 void
1032 YQPackageSelector::connectPatchList()
1033 {
1034     if ( _pkgList && _patchList )
1035     {
1036         connectFilter( _patchList, _pkgList );
1037
1038         connect( _patchList, SIGNAL( filterMatch   ( const QString &, const QString &, FSize ) ),
1039                  _pkgList,   SLOT  ( addPassiveItem( const QString &, const QString &, FSize ) ) );
1040
1041         connect( _patchList,            SIGNAL( statusChanged()                 ),
1042                  this,                  SLOT  ( autoResolveDependencies()       ) );
1043
1044         if ( _pkgConflictDialog )
1045         {
1046             connect( _pkgConflictDialog,SIGNAL( updatePackages()                ),
1047                      _patchList,        SLOT  ( updateItemStates()              ) );
1048         }
1049
1050         connect( this,                  SIGNAL( refresh()                       ),
1051                  _patchList,            SLOT  ( updateItemStates()              ) );
1052
1053     }
1054 }
1055
1056
1057 void
1058 YQPackageSelector::pkgExport()
1059 {
1060     QString filename = YQUI::ui()->askForSaveFileName( QString( DEFAULT_EXPORT_FILE_NAME ),     // startsWith
1061                                                        QString( "*.xml;;*" ),                   // filter
1062                                                        _( "Save Package List" ) );
1063
1064     if ( ! filename.isEmpty() )
1065     {
1066         zypp::syscontent::Writer writer;
1067         const zypp::ResPool & pool = zypp::getZYpp()->pool();
1068
1069         // The ZYPP obfuscated C++ contest proudly presents:
1070
1071         for_each( pool.begin(), pool.end(),
1072                   boost::bind( &zypp::syscontent::Writer::addIf,
1073                                boost::ref( writer ),
1074                                _1 ) );
1075         // Yuck. What a mess.
1076         //
1077         // Does anybody seriously believe this kind of thing is easier to read,
1078         // let alone use? Get real. This is an argument in favour of all C++
1079         // haters. And it's one that is really hard to counter.
1080         //
1081         // -sh 2006-12-13
1082
1083         try
1084         {
1085             std::ofstream exportFile( toUTF8( filename ).c_str() );
1086             exportFile.exceptions( std::ios_base::badbit | std::ios_base::failbit );
1087             exportFile << writer;
1088
1089             y2milestone( "Package list exported to %s", (const char *) filename );
1090         }
1091         catch ( std::exception & exception )
1092         {
1093             y2warning( "Error exporting package list to %s", (const char *) filename );
1094
1095             // The export might have left over a partially written file.
1096             // Try to delete it. Don't care if it doesn't exist and unlink() fails.
1097             (void) unlink( (const char *) filename );
1098
1099             // Post error popup
1100             QMessageBox::warning( this,                                         // parent
1101                                   _( "Error" ),                                 // caption
1102                                   _( "Error exporting package list to %1" ).arg( filename ),
1103                                   QMessageBox::Ok | QMessageBox::Default,       // button0
1104                                   QMessageBox::NoButton,                        // button1
1105                                   QMessageBox::NoButton );                      // button2
1106         }
1107     }
1108 }
1109
1110
1111 void
1112 YQPackageSelector::pkgImport()
1113 {
1114     QString filename =  QFileDialog::getOpenFileName( DEFAULT_EXPORT_FILE_NAME,         // startsWith
1115                                                       "*.xml+;;*",                      // filter
1116                                                       this,                             // parent
1117                                                       0,                                // name
1118                                                       _( "Load Package List" ) );       // caption
1119
1120     if ( ! filename.isEmpty() )
1121     {
1122         y2milestone( "Importing package list from %s", (const char *) filename );
1123
1124         try
1125         {
1126             std::ifstream importFile( toUTF8( filename ).c_str() );
1127             zypp::syscontent::Reader reader( importFile );
1128
1129             //
1130             // Put reader contents into maps
1131             //
1132
1133             typedef zypp::syscontent::Reader::Entry     ZyppReaderEntry;
1134             typedef std::pair<string, ZyppReaderEntry>  ImportMapPair;
1135
1136             map<string, ZyppReaderEntry> importPkg;
1137             map<string, ZyppReaderEntry> importPatterns;
1138
1139             for ( zypp::syscontent::Reader::const_iterator it = reader.begin();
1140                   it != reader.end();
1141                   ++ it )
1142             {
1143                 string kind = it->kind();
1144
1145                 if      ( kind == "package" )   importPkg.insert     ( ImportMapPair( it->name(), *it ) );
1146                 else if ( kind == "pattern" )   importPatterns.insert( ImportMapPair( it->name(), *it ) );
1147             }
1148
1149             y2debug( "Found %zu packages and %zu patterns in %s",
1150                      importPkg.size(),
1151                      importPatterns.size(),
1152                      (const char *) filename );
1153
1154
1155             //
1156             // Set status of all patterns and packages according to import map
1157             //
1158
1159             for ( ZyppPoolIterator it = zyppPatternsBegin();
1160                   it != zyppPatternsEnd();
1161                   ++it )
1162             {
1163                 ZyppSel selectable = *it;
1164                 importSelectable( *it, importPatterns.find( selectable->name() ) != importPatterns.end(), "pattern" );
1165             }
1166
1167             for ( ZyppPoolIterator it = zyppPkgBegin();
1168                   it != zyppPkgEnd();
1169                   ++it )
1170             {
1171                 ZyppSel selectable = *it;
1172                 importSelectable( *it, importPkg.find( selectable->name() ) != importPkg.end(), "package" );
1173             }
1174
1175
1176             //
1177             // Display result
1178             //
1179
1180             emit refresh();
1181
1182             if ( _statusFilterView )
1183             {
1184                 // Switch to "Installation Summary" filter view
1185
1186                 _filters->showPage( _statusFilterView );
1187                 _statusFilterView->filter();
1188             }
1189
1190         }
1191         catch ( const zypp::Exception & exception )
1192         {
1193             y2warning( "Error reading package list from %s", (const char *) filename );
1194
1195             // Post error popup
1196             QMessageBox::warning( this,                                         // parent
1197                                   _( "Error" ),                                 // caption
1198                                   _( "Error loading package list from %1" ).arg( filename ),
1199                                   QMessageBox::Ok | QMessageBox::Default,       // button0
1200                                   QMessageBox::NoButton,                        // button1
1201                                   QMessageBox::NoButton );                      // button2
1202         }
1203     }
1204 }
1205
1206
1207 void
1208 YQPackageSelector::importSelectable( ZyppSel            selectable,
1209                                      bool               isWanted,
1210                                      const char *       kind )
1211 {
1212     ZyppStatus oldStatus = selectable->status();
1213     ZyppStatus newStatus = oldStatus;
1214
1215     if ( isWanted )
1216     {
1217         //
1218         // Make sure this selectable does not get installed
1219         //
1220
1221         switch ( oldStatus )
1222         {
1223             case S_Install:
1224             case S_AutoInstall:
1225             case S_KeepInstalled:
1226             case S_Protected:
1227             case S_Update:
1228             case S_AutoUpdate:
1229                 newStatus = oldStatus;
1230                 break;
1231
1232             case S_Del:
1233             case S_AutoDel:
1234                 newStatus = S_KeepInstalled;
1235                 y2debug( "Keeping %s %s", kind, selectable->name().c_str() );
1236                 break;
1237
1238             case S_NoInst:
1239             case S_Taboo:
1240
1241                 if ( selectable->hasCandidateObj() )
1242                 {
1243                     newStatus = S_Install;
1244                     y2debug( "Adding %s %s", kind, selectable->name().c_str() );
1245                 }
1246                 else
1247                 {
1248                     y2debug( "Can't add %s %s: No candidate",
1249                              kind, selectable->name().c_str() );
1250                 }
1251                 break;
1252         }
1253     }
1254     else // ! isWanted
1255     {
1256         //
1257         // Make sure this selectable does not get installed
1258         //
1259
1260         switch ( oldStatus )
1261         {
1262             case S_Install:
1263             case S_AutoInstall:
1264             case S_KeepInstalled:
1265             case S_Protected:
1266             case S_Update:
1267             case S_AutoUpdate:
1268                 newStatus = S_Del;
1269                 y2debug( "Deleting %s %s", kind, selectable->name().c_str() );
1270                 break;
1271
1272             case S_Del:
1273             case S_AutoDel:
1274             case S_NoInst:
1275             case S_Taboo:
1276                 newStatus = oldStatus;
1277                 break;
1278         }
1279     }
1280
1281     if ( oldStatus != newStatus )
1282         selectable->set_status( newStatus );
1283 }
1284
1285
1286 void
1287 YQPackageSelector::globalUpdatePkg( bool force )
1288 {
1289     if ( ! _pkgList )
1290         return;
1291
1292     int count = _pkgList->globalSetPkgStatus( S_Update, force,
1293                                               true ); // countOnly
1294     y2milestone( "%d pkgs found for update", count );
1295
1296     if ( count >= GLOBAL_UPDATE_CONFIRMATION_THRESHOLD )
1297     {
1298         if ( QMessageBox::question( this, "",   // caption
1299                                     // Translators: %1 is the number of affected packages
1300                                     _( "%1 packages will be updated" ).arg( count ),
1301                                     _( "&Continue" ), _( "C&ancel" ),
1302                                     0,          // defaultButtonNumber (from 0)
1303                                     1 )         // escapeButtonNumber
1304              == 1 )     // "Cancel"?
1305         {
1306             return;
1307         }
1308     }
1309
1310     (void) _pkgList->globalSetPkgStatus( S_Update, force,
1311                                          false ); // countOnly
1312
1313     if ( _statusFilterView )
1314     {
1315         _filters->showPage( _statusFilterView );
1316         _statusFilterView->clear();
1317         _statusFilterView->showTransactions();
1318         _statusFilterView->filter();
1319     }
1320 }
1321
1322
1323 void
1324 YQPackageSelector::showProducts()
1325 {
1326     YQPkgProductDialog::showProductDialog();
1327 }
1328
1329 void
1330 YQPackageSelector::installDevelPkgs()
1331 {
1332     installSubPkgs( "-devel" );
1333 }
1334
1335
1336 void
1337 YQPackageSelector::installDebugInfoPkgs()
1338 {
1339     installSubPkgs( "-debuginfo" );
1340 }
1341
1342
1343 void
1344 YQPackageSelector::pkgExcludeRulesChanged( int menuItemID )
1345 {
1346     if ( _viewMenu && _pkgList )
1347     {
1348         _viewMenu->setItemChecked( menuItemID, ! _viewMenu->isItemChecked( menuItemID ) );
1349
1350         if ( _excludeDevelPkgs )
1351             _excludeDevelPkgs->enable( ! _viewMenu->isItemChecked( _viewShowDevelID ) );
1352
1353         if ( _excludeDebugInfoPkgs )
1354             _excludeDebugInfoPkgs->enable( ! _viewMenu->isItemChecked( _viewShowDebugInfoID ) );
1355
1356         _pkgList->applyExcludeRules();
1357     }
1358 }
1359
1360
1361 void
1362 YQPackageSelector::installSubPkgs( const QString suffix )
1363 {
1364     // Find all matching packages and put them into a QMap
1365
1366     QMap<QString, ZyppSel> subPkgs;
1367
1368     for ( ZyppPoolIterator it = zyppPkgBegin();
1369           it != zyppPkgEnd();
1370           ++it )
1371     {
1372         QString name = (*it)->name().c_str();
1373
1374         if ( name.endsWith( suffix ) )
1375         {
1376             subPkgs[ name ] = *it;
1377
1378             y2debug( "Found subpackage: %s", (const char *) name );
1379         }
1380     }
1381
1382
1383     // Now go through all packages and look if there is a corresponding subpackage in the QMap
1384
1385     for ( ZyppPoolIterator it = zyppPkgBegin();
1386           it != zyppPkgEnd();
1387           ++it )
1388     {
1389         QString name = (*it)->name().c_str();
1390
1391         if ( subPkgs.contains( name + suffix ) )
1392         {
1393             QString subPkgName( name + suffix );
1394             ZyppSel subPkg = subPkgs[ subPkgName ];
1395
1396             switch ( (*it)->status() )
1397             {
1398                 case S_AutoDel:
1399                 case S_NoInst:
1400                 case S_Protected:
1401                 case S_Taboo:
1402                 case S_Del:
1403                     // Don't install the subpackage
1404                     y2milestone( "Ignoring unwanted subpackage %s", (const char *) subPkgName );
1405                     break;
1406
1407                 case S_AutoInstall:
1408                 case S_Install:
1409                 case S_KeepInstalled:
1410
1411                     // Install the subpackage, but don't try to update it
1412
1413                     if ( ! subPkg->installedObj() )
1414                     {
1415                         subPkg->set_status( S_Install );
1416                         y2milestone( "Installing subpackage %s", (const char *) subPkgName );
1417                     }
1418                     break;
1419
1420
1421                 case S_Update:
1422                 case S_AutoUpdate:
1423
1424                     // Install or update the subpackage
1425
1426                     if ( ! subPkg->installedObj() )
1427                     {
1428                         subPkg->set_status( S_Install );
1429                         y2milestone( "Installing subpackage %s", (const char *) subPkgName );
1430                     }
1431                     else
1432                     {
1433                         subPkg->set_status( S_Update );
1434                         y2milestone( "Updating subpackage %s", (const char *) subPkgName );
1435                     }
1436                     break;
1437
1438                     // Intentionally omitting 'default' branch so the compiler can
1439                     // catch unhandled enum states
1440             }
1441         }
1442     }
1443
1444
1445     if ( _filters && _statusFilterView )
1446     {
1447         _filters->showPage( _statusFilterView );
1448         _statusFilterView->filter();
1449     }
1450
1451     YQPkgChangesDialog::showChangesDialog( _( "Added Subpackages:" ),
1452                                            QRegExp( ".*" + suffix + "$" ),
1453                                            _( "&OK" ),
1454                                            QString::null,       // rejectButtonLabel
1455                                            true );              // showIfEmpty
1456 }
1457
1458
1459 #include "YQPackageSelector.moc"