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