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