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