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