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