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