1 /*---------------------------------------------------------------------\
3 | __ __ ____ _____ ____ |
4 | \ \ / /_ _/ ___|_ _|___ \ |
5 | \ V / _` \___ \ | | __) | |
6 | | | (_| |___) || | / __/ |
7 | |_|\__,_|____/ |_| |_____| |
11 \----------------------------------------------------------------------/
13 File: YQPackageSelector.cc
14 See also: YQPackageSelectorHelp.cc
16 Author: Stefan Hundhammer <sh@suse.de>
18 Textdomain "packages-qt"
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
29 #include <boost/bind.hpp>
31 #include <QHBoxLayout>
32 #include <QVBoxLayout>
35 #include <QApplication>
38 #include <QFileDialog>
42 #include <QMessageBox>
43 #include <QPushButton>
49 #define y2log_component "qt-pkg"
50 #include <ycp/y2log.h>
52 #include "QY2LayoutUtils.h"
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"
82 #include "QY2ComboTabWidget.h"
97 #define DEFAULT_EXPORT_FILE_NAME "user-packages.xml"
102 YQPackageSelector::YQPackageSelector( YWidget * parent,
104 : YQPackageSelectorBase( parent, modeFlags )
106 _showChangesDialog = true;
107 _autoDependenciesCheckBox = 0;
114 _pkgChangeLogView = 0;
115 _pkgDependenciesView = 0;
116 _pkgDescriptionView = 0;
117 _pkgFileListView = 0;
119 _pkgTechnicalDetailsView = 0;
120 _pkgVersionsView = 0;
121 _rpmGroupTagsFilterView = 0;
122 _searchFilterView = 0;
124 _statusFilterView = 0;
125 _updateProblemFilterView = 0;
126 _patchFilterView = 0;
128 _excludeDevelPkgs = 0;
129 _excludeDebugInfoPkgs = 0;
132 if ( onlineUpdateMode() ) y2milestone( "Online update mode" );
133 if ( updateMode() ) y2milestone( "Update mode" );
137 addMenus(); // Only after all widgets are created!
144 if ( _patchFilterView && onlineUpdateMode() )
146 if ( _filters && _patchFilterView && _patchList )
148 _filters->showPage( _patchFilterView );
149 _patchList->filter();
152 else if ( _repoFilterView && repoMode() )
154 if ( YQPkgRepoList::countEnabledRepositories() > 1 )
156 _filters->showPage( _repoFilterView );
157 _repoFilterView->filter();
159 else if ( _searchFilterView )
161 y2milestone( "No multiple repositories - falling back to search mode" );
162 _filters->showPage( _searchFilterView );
163 _searchFilterView->filter();
164 QTimer::singleShot( 0, _searchFilterView, SLOT( setFocus() ) );
167 else if ( _updateProblemFilterView )
169 _filters->showPage( _updateProblemFilterView );
170 _updateProblemFilterView->filter();
173 else if ( searchMode() && _searchFilterView )
175 _filters->showPage( _searchFilterView );
176 _searchFilterView->filter();
177 QTimer::singleShot( 0, _searchFilterView, SLOT( setFocus() ) );
179 else if ( summaryMode() && _statusFilterView )
181 _filters->showPage( _statusFilterView );
182 _statusFilterView->filter();
184 else if ( _patternList )
186 _filters->showPage( _patternList );
187 _patternList->filter();
191 _filters->showPage( _selList );
196 if ( _diskUsageList )
197 _diskUsageList->updateDiskUsage();
199 y2milestone( "PackageSelector init done" );
202 #if CHECK_DEPENDENCIES_ON_STARTUP
204 if ( ! testMode() && ! onlineUpdateMode() )
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() ) );
216 YQPackageSelector::basicLayout()
219 layoutMenuBar(layout());
221 QSplitter * outer_splitter = new QSplitter( Qt::Horizontal, this );
222 QVBoxLayout *layout = new QVBoxLayout(outer_splitter);
223 outer_splitter->setLayout(layout);
225 Q_CHECK_PTR( outer_splitter );
227 QWidget * left_pane = layoutLeftPane ( outer_splitter->layout() );
228 this->layout()->addWidget(left_pane);
230 QWidget * right_pane = layoutRightPane( outer_splitter->layout() );
231 this->layout()->addWidget(right_pane);
233 outer_splitter->setResizeMode( left_pane, QSplitter::KeepSize );
234 outer_splitter->setResizeMode( right_pane, QSplitter::Stretch );
239 YQPackageSelector::layoutLeftPane( QLayout *parent_layout )
241 QSplitter * splitter = new QSplitter( Qt::Vertical, this );
242 Q_CHECK_PTR( splitter );
243 splitter->setMargin( MARGIN );
244 parent_layout->addWidget(splitter);
246 QWidget * upper_vbox = new QWidget( splitter );
247 QVBoxLayout *layout = new QVBoxLayout(upper_vbox);
248 upper_vbox->setLayout(layout);
250 Q_CHECK_PTR( upper_vbox );
251 layoutFilters( upper_vbox->layout() );
252 addVSpacing( upper_vbox, MARGIN );
254 QWidget * lower_vbox = new QWidget( splitter );
255 layout = new QVBoxLayout(lower_vbox);
256 lower_vbox->setLayout(layout);
258 addVSpacing( lower_vbox, MARGIN );
259 _diskUsageList = new YQPkgDiskUsageList( lower_vbox );
260 Q_CHECK_PTR( _diskUsageList );
261 layout->addWidget(_diskUsageList);
263 splitter->setResizeMode( upper_vbox, QSplitter::Stretch );
264 splitter->setResizeMode( lower_vbox, QSplitter::KeepSize );
271 YQPackageSelector::layoutFilters( QLayout *parent_layout )
273 _filters = new QY2ComboTabWidget( _( "Fi<er:" ), this );
274 Q_CHECK_PTR( _filters );
275 parent_layout->addWidget(_filters);
278 // Update problem view
283 if ( YQPkgUpdateProblemFilterView::haveProblematicPackages()
286 _updateProblemFilterView = new YQPkgUpdateProblemFilterView( this );
287 Q_CHECK_PTR( _updateProblemFilterView );
288 _filters->addPage( _( "Update Problems" ), _updateProblemFilterView );
297 if ( onlineUpdateMode()
298 #if ALWAYS_SHOW_PATCHES_VIEW_IF_PATCHES_AVAILABLE
299 || ! zyppPool().empty<zypp::Patch>()
302 addPatchFilterView();
309 if ( ! zyppPool().empty<zypp::Pattern>() || testMode() )
311 _patternList = new YQPkgPatternList( this, true );
312 Q_CHECK_PTR( _patternList );
313 _filters->addPage( _( "Patterns" ), _patternList );
315 connect( _patternList, SIGNAL( statusChanged() ),
316 this, SLOT ( autoResolveDependencies() ) );
318 connect( this, SIGNAL( refresh() ),
319 _patternList, SLOT ( updateItemStates() ) );
321 if ( _pkgConflictDialog )
323 connect( _pkgConflictDialog, SIGNAL( updatePackages() ),
324 _patternList, SLOT ( updateItemStates() ) );
333 if ( ! zyppPool().empty<zypp::Selection>() || testMode() )
336 _selList = new YQPkgSelList( this, true );
337 Q_CHECK_PTR( _selList );
338 _filters->addPage( _( "Selections" ), _selList );
340 connect( _selList, SIGNAL( statusChanged() ),
341 this, SLOT ( autoResolveDependencies() ) );
343 connect( this, SIGNAL( refresh() ),
344 _selList, SLOT ( updateItemStates() ) );
346 if ( _pkgConflictDialog )
348 connect( _pkgConflictDialog, SIGNAL( updatePackages() ),
349 _selList, SLOT ( updateItemStates() ) );
355 // RPM group tags view
358 _rpmGroupTagsFilterView = new YQPkgRpmGroupTagsFilterView( this );
359 Q_CHECK_PTR( _rpmGroupTagsFilterView );
360 _filters->addPage( _( "Package Groups" ), _rpmGroupTagsFilterView );
362 connect( this, SIGNAL( loadData() ),
363 _rpmGroupTagsFilterView, SLOT ( filter() ) );
370 _langList = new YQPkgLangList( this );
371 Q_CHECK_PTR( _langList );
373 _filters->addPage( _( "Languages" ), _langList );
374 _langList->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ) ); // hor/vert
376 connect( _langList, SIGNAL( statusChanged() ),
377 this, SLOT ( autoResolveDependencies() ) );
379 connect( this, SIGNAL( refresh() ),
380 _langList, SLOT ( updateItemStates() ) );
387 _repoFilterView = new YQPkgRepoFilterView( this );
388 Q_CHECK_PTR( _repoFilterView );
389 _filters->addPage( _( "Repositories" ), _repoFilterView );
393 // Package search view
396 _searchFilterView = new YQPkgSearchFilterView( this );
397 Q_CHECK_PTR( _searchFilterView );
398 _filters->addPage( _( "Search" ), _searchFilterView );
402 // Status change view
405 _statusFilterView = new YQPkgStatusFilterView( this );
406 Q_CHECK_PTR( _statusFilterView );
407 _filters->addPage( _( "Installation Summary" ), _statusFilterView );
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 ) );
421 YQPackageSelector::layoutRightPane( QLayout *parent_layout )
423 QWidget * right_pane_vbox = new QWidget( this );
425 QVBoxLayout *layout = new QVBoxLayout(right_pane_vbox);
426 right_pane_vbox->setLayout(layout);
428 Q_CHECK_PTR( right_pane_vbox );
429 parent_layout->addWidget(right_pane_vbox);
431 layout->setMargin( MARGIN );
434 QSplitter * splitter = new QSplitter( Qt::Vertical, right_pane_vbox );
435 Q_CHECK_PTR( splitter );
436 layout->addWidget(splitter);
438 QWidget * splitter_vbox = new QWidget( splitter );
439 layout = new QVBoxLayout(splitter_vbox);
440 splitter_vbox->setLayout(layout);
442 Q_CHECK_PTR( splitter_vbox );
443 layoutPkgList( right_pane_vbox->layout() );
444 addVSpacing( splitter_vbox, MARGIN );
446 layoutDetailsViews( right_pane_vbox->layout() );
448 layoutButtons( right_pane_vbox->layout() );
450 return right_pane_vbox;
455 YQPackageSelector::layoutPkgList( QLayout *parent_layout )
457 _pkgList= new YQPkgList( this );
458 parent_layout->addWidget(_pkgList);
459 Q_CHECK_PTR( _pkgList );
461 connect( _pkgList, SIGNAL( statusChanged() ),
462 this, SLOT ( autoResolveDependencies() ) );
467 YQPackageSelector::layoutDetailsViews( QLayout *parent_layout )
469 bool haveInstalledPkgs = YQPkgList::haveInstalledPkgs();
471 QWidget * details_vbox = new QWidget( this );
472 Q_CHECK_PTR( details_vbox );
473 parent_layout->addWidget(details_vbox);
475 QVBoxLayout *layout = new QVBoxLayout(details_vbox);
476 details_vbox->setLayout(layout);
477 //details_vbox->setMinimumSize( 0, 0 );
479 addVSpacing( details_vbox, 8 );
481 _detailsViews = new QTabWidget( details_vbox );
482 layout->addWidget(_detailsViews);
484 Q_CHECK_PTR( _detailsViews );
485 _detailsViews->setMargin( MARGIN );
487 // _detailsViews->setTabPosition( QTabWidget::Bottom );
494 _pkgDescriptionView = new YQPkgDescriptionView( _detailsViews );
495 Q_CHECK_PTR( _pkgDescriptionView );
497 _detailsViews->addTab( _pkgDescriptionView, _( "D&escription" ) );
498 _detailsViews->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
500 connect( _pkgList, SIGNAL( selectionChanged ( ZyppSel ) ),
501 _pkgDescriptionView, SLOT ( showDetailsIfVisible( ZyppSel ) ) );
507 _pkgTechnicalDetailsView = new YQPkgTechnicalDetailsView( _detailsViews );
508 Q_CHECK_PTR( _pkgTechnicalDetailsView );
510 _detailsViews->addTab( _pkgTechnicalDetailsView, _( "&Technical Data" ) );
512 connect( _pkgList, SIGNAL( selectionChanged ( ZyppSel ) ),
513 _pkgTechnicalDetailsView, SLOT ( showDetailsIfVisible( ZyppSel ) ) );
520 _pkgDependenciesView = new YQPkgDependenciesView( _detailsViews );
521 Q_CHECK_PTR( _pkgDependenciesView );
523 _detailsViews->addTab( _pkgDependenciesView, _( "Dependencies" ) );
524 _detailsViews->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
526 connect( _pkgList, SIGNAL( selectionChanged ( ZyppSel ) ),
527 _pkgDependenciesView, SLOT ( showDetailsIfVisible( ZyppSel ) ) );
535 _pkgVersionsView = new YQPkgVersionsView( _detailsViews,
536 true ); // userCanSwitchVersions
537 Q_CHECK_PTR( _pkgVersionsView );
539 _detailsViews->addTab( _pkgVersionsView, _( "&Versions" ) );
541 connect( _pkgList, SIGNAL( selectionChanged ( ZyppSel ) ),
542 _pkgVersionsView, SLOT ( showDetailsIfVisible( ZyppSel ) ) );
549 if ( haveInstalledPkgs ) // file list information is only available for installed pkgs
551 _pkgFileListView = new YQPkgFileListView( _detailsViews );
552 Q_CHECK_PTR( _pkgFileListView );
554 _detailsViews->addTab( _pkgFileListView, _( "File List" ) );
555 _detailsViews->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
557 connect( _pkgList, SIGNAL( selectionChanged ( ZyppSel ) ),
558 _pkgFileListView, SLOT ( showDetailsIfVisible( ZyppSel ) ) );
566 if ( haveInstalledPkgs ) // change log information is only available for installed pkgs
568 _pkgChangeLogView = new YQPkgChangeLogView( _detailsViews );
569 Q_CHECK_PTR( _pkgChangeLogView );
571 _detailsViews->addTab( _pkgChangeLogView, _( "Change Log" ) );
572 _detailsViews->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
574 connect( _pkgList, SIGNAL( selectionChanged ( ZyppSel ) ),
575 _pkgChangeLogView, SLOT ( showDetailsIfVisible( ZyppSel ) ) );
581 YQPackageSelector::layoutButtons( QLayout *parent_layout )
583 QWidget * button_box = new QWidget( this );
584 Q_CHECK_PTR( button_box );
585 parent_layout->addWidget(button_box);
587 QHBoxLayout *layout = new QHBoxLayout(button_box);
588 button_box->setLayout(layout);
590 layout->setSpacing( SPACING );
592 // Button: Dependency check
593 // Translators: Please keep this short!
594 _checkDependenciesButton = new QPushButton( _( "Chec&k" ), button_box );
595 layout->addWidget(_checkDependenciesButton);
597 Q_CHECK_PTR( _checkDependenciesButton );
598 _checkDependenciesButton->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); // hor/vert
599 _normalButtonBackground = _checkDependenciesButton->paletteBackgroundColor();
601 connect( _checkDependenciesButton, SIGNAL( clicked() ),
602 this, SLOT ( manualResolvePackageDependencies() ) );
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);
611 _autoDependenciesCheckBox->setChecked( AUTO_CHECK_DEPENDENCIES_DEFAULT );
613 addHStretch( button_box );
615 QPushButton * cancel_button = new QPushButton( _( "&Cancel" ), button_box );
616 Q_CHECK_PTR( cancel_button );
617 layout->addWidget(cancel_button);
619 cancel_button->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); // hor/vert
621 connect( cancel_button, SIGNAL( clicked() ),
622 this, SLOT ( reject() ) );
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
630 connect( accept_button, SIGNAL( clicked() ),
631 this, SLOT ( accept() ) );
633 button_box->setFixedHeight( button_box->sizeHint().height() );
638 YQPackageSelector::layoutMenuBar( QLayout *parent_layout )
640 _menuBar = new QMenuBar( this );
641 parent_layout->addWidget(_menuBar);
642 Q_CHECK_PTR( _menuBar );
655 YQPackageSelector::addMenus()
661 _fileMenu = new QMenu( _menuBar );
662 Q_CHECK_PTR( _fileMenu );
663 _menuBar->insertItem( _( "&File" ), _fileMenu );
665 _fileMenu->insertItem( _( "&Import..." ), this, SLOT( pkgImport() ) );
666 _fileMenu->insertItem( _( "&Export..." ), this, SLOT( pkgExport() ) );
668 _fileMenu->insertSeparator();
670 _fileMenu->insertItem( _( "E&xit -- Discard Changes" ), this, SLOT( reject() ) );
671 _fileMenu->insertItem( _( "&Quit -- Save Changes" ), this, SLOT( accept() ) );
680 _viewMenu = new QMenu( _menuBar );
681 Q_CHECK_PTR( _viewMenu );
682 _menuBar->insertItem( _( "&View" ), _viewMenu );
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 );
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 );
705 _pkgMenu = new QMenu( _menuBar );
706 Q_CHECK_PTR( _pkgMenu );
707 _menuBar->insertItem( _( "&Package" ), _pkgMenu );
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 );
717 _pkgMenu->insertSeparator();
719 _pkgList->actionInstallSourceRpm->addTo( _pkgMenu );
720 _pkgList->actionDontInstallSourceRpm->addTo( _pkgMenu );
722 _pkgMenu->insertSeparator();
723 QMenu * submenu = _pkgList->addAllInListSubMenu( _pkgMenu );
724 Q_CHECK_PTR( submenu );
726 submenu->insertSeparator();
727 _pkgList->actionInstallListSourceRpms->addTo( submenu );
728 _pkgList->actionDontInstallListSourceRpms->addTo( submenu );
732 // Submenu for all packages
735 submenu = new QMenu( _pkgMenu );
736 Q_CHECK_PTR( submenu );
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 );
743 submenu->insertItem( _( "Update if newer version available" ),
744 this, SLOT( globalUpdatePkg() ) );
746 submenu->insertItem( _( "Update unconditionally" ),
747 this, SLOT( globalUpdatePkgForce() ) );
757 _patchMenu = new QMenu( _menuBar );
758 Q_CHECK_PTR( _patchMenu );
759 _menuBar->insertItem( _( "&Patch" ), _patchMenu );
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 );
767 _patchList->actionSetCurrentUpdate->addTo( _patchMenu );
768 _patchList->actionSetCurrentTaboo->addTo( _patchMenu );
770 _patchMenu->insertSeparator();
771 _patchList->addAllInListSubMenu( _patchMenu );
779 _extrasMenu = new QMenu( _menuBar );
780 Q_CHECK_PTR( _extrasMenu );
781 _menuBar->insertItem( _( "&Extras" ), _extrasMenu );
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() ) );
787 _extrasMenu->insertSeparator();
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() ) );
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() ) );
795 _extrasMenu->insertSeparator();
797 if ( _pkgConflictDialog )
798 _extrasMenu->insertItem( _( "Generate Dependency Resolver &Test Case" ),
799 _pkgConflictDialog, SLOT( askCreateSolverTestCase() ) );
801 if ( _actionResetIgnoredDependencyProblems )
802 _actionResetIgnoredDependencyProblems->addTo( _extrasMenu );
807 _patchList->actionShowRawPatchInfo->addTo( _extrasMenu );
815 _helpMenu = new QMenu( _menuBar );
816 Q_CHECK_PTR( _helpMenu );
817 _menuBar->insertSeparator();
818 _menuBar->insertItem( _( "&Help" ), _helpMenu );
820 // Note: The help functions and their texts are moved out
821 // to a separate source file YQPackageSelectorHelp.cc
823 // Menu entry for help overview
824 _helpMenu->insertItem( _( "&Overview" ), this, SLOT( help() ), Qt::Key_F1 );
826 // Menu entry for help about used symbols ( icons )
827 _helpMenu->insertItem( _( "&Symbols" ), this, SLOT( symbolHelp() ), Qt::SHIFT + Qt::Key_F1 );
829 // Menu entry for keyboard help
830 _helpMenu->insertItem( _( "&Keys" ), this, SLOT( keyboardHelp() ) );
835 YQPackageSelector::connectFilter( QWidget * filter,
837 bool hasUpdateSignal )
839 if ( ! filter ) return;
840 if ( ! pkgList ) return;
844 connect( _filters, SIGNAL( currentChanged(QWidget *) ),
845 filter, SLOT ( filterIfVisible() ) );
848 connect( this, SIGNAL( refresh() ),
849 filter, SLOT ( filterIfVisible() ) );
851 connect( filter, SIGNAL( filterStart() ),
852 pkgList, SLOT ( clear() ) );
854 connect( filter, SIGNAL( filterMatch( ZyppSel, ZyppPkg ) ),
855 pkgList, SLOT ( addPkgItem ( ZyppSel, ZyppPkg ) ) );
857 connect( filter, SIGNAL( filterFinished() ),
858 pkgList, SLOT ( selectSomething() ) );
860 connect( filter, SIGNAL( filterFinished() ),
861 pkgList, SLOT ( logExcludeStatistics() ) );
864 if ( hasUpdateSignal )
866 connect( filter, SIGNAL( updatePackages() ),
867 pkgList, SLOT ( updateItemStates() ) );
869 if ( _diskUsageList )
871 connect( filter, SIGNAL( updatePackages() ),
872 _diskUsageList, SLOT ( updateDiskUsage() ) );
879 YQPackageSelector::makeConnections()
881 connect( this, SIGNAL( resolvingStarted() ),
882 this, SLOT ( animateCheckButton() ) );
884 connect( this, SIGNAL( resolvingFinished() ),
885 this, SLOT ( restoreCheckButton() ) );
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 );
896 if ( _searchFilterView && _pkgList )
898 connect( _searchFilterView, SIGNAL( message( const QString & ) ),
899 _pkgList, SLOT ( message( const QString & ) ) );
902 if ( _repoFilterView && _pkgList )
904 connect( _repoFilterView, SIGNAL( filterNearMatch ( ZyppSel, ZyppPkg ) ),
905 _pkgList, SLOT ( addPkgItemDimmed ( ZyppSel, ZyppPkg ) ) );
908 if ( _pkgList && _diskUsageList )
911 connect( _pkgList, SIGNAL( statusChanged() ),
912 _diskUsageList, SLOT ( updateDiskUsage() ) );
920 // Connect package conflict dialog
923 if ( _pkgConflictDialog )
927 connect( _pkgConflictDialog, SIGNAL( updatePackages() ),
928 _pkgList, SLOT ( updateItemStates() ) );
933 connect( _pkgConflictDialog, SIGNAL( updatePackages() ),
934 _patternList, SLOT ( updateItemStates() ) );
939 connect( _pkgConflictDialog, SIGNAL( updatePackages() ),
940 _selList, SLOT ( updateItemStates() ) );
943 if ( _diskUsageList )
945 connect( _pkgConflictDialog, SIGNAL( updatePackages() ),
946 _diskUsageList, SLOT ( updateDiskUsage() ) );
952 // Connect package versions view
955 if ( _pkgVersionsView && _pkgList )
957 connect( _pkgVersionsView, SIGNAL( candidateChanged( ZyppObj ) ),
958 _pkgList, SLOT ( updateItemData() ) );
963 // Hotkey to enable "patches" filter view on the fly
966 QShortcut * accel = new QShortcut( Qt::Key_F2, this, SLOT( hotkeyInsertPatchFilterView() ) );
967 Q_CHECK_PTR( accel );
970 // Update actions just before opening menus
973 if ( _pkgMenu && _pkgList )
975 connect( _pkgMenu, SIGNAL( aboutToShow() ),
976 _pkgList, SLOT ( updateActions() ) );
979 if ( _patchMenu && _patchList )
981 connect( _patchMenu, SIGNAL( aboutToShow() ),
982 _patchList, SLOT ( updateActions() ) );
988 YQPackageSelector::animateCheckButton()
990 if ( _checkDependenciesButton )
992 _checkDependenciesButton->setPaletteBackgroundColor( QColor( 0xE0, 0xE0, 0xF8 ) );
993 _checkDependenciesButton->repaint();
999 YQPackageSelector::restoreCheckButton()
1001 if ( _checkDependenciesButton )
1002 _checkDependenciesButton->setPaletteBackgroundColor( _normalButtonBackground );
1007 YQPackageSelector::autoResolveDependencies()
1009 if ( _autoDependenciesCheckBox && ! _autoDependenciesCheckBox->isChecked() )
1012 resolveDependencies();
1017 YQPackageSelector::manualResolvePackageDependencies()
1019 if ( ! _pkgConflictDialog )
1021 y2error( "No package conflict dialog existing" );
1022 return QDialog::Accepted;
1025 YQUI::ui()->busyCursor();
1026 int result = _pkgConflictDialog->solveAndShowConflicts();
1027 YQUI::ui()->normalCursor();
1029 #if DEPENDENCY_FEEDBACK_IF_OK
1031 if ( result == QDialog::Accepted )
1033 QMessageBox::information( this, "",
1034 _( "All package dependencies are OK." ),
1044 YQPackageSelector::addPatchFilterView()
1046 if ( ! _patchFilterView )
1048 _patchFilterView = new YQPkgPatchFilterView( this );
1049 Q_CHECK_PTR( _patchFilterView );
1050 _filters->addPage( _( "Patches" ), _patchFilterView );
1052 _patchList = _patchFilterView->patchList();
1053 Q_CHECK_PTR( _patchList );
1061 YQPackageSelector::hotkeyInsertPatchFilterView()
1063 if ( ! _patchFilterView )
1065 y2milestone( "Activating patches filter view" );
1067 addPatchFilterView();
1070 _filters->showPage( _patchFilterView );
1072 _patchList->filter();
1078 YQPackageSelector::connectPatchList()
1080 if ( _pkgList && _patchList )
1082 connectFilter( _patchList, _pkgList );
1084 connect( _patchList, SIGNAL( filterMatch ( const QString &, const QString &, FSize ) ),
1085 _pkgList, SLOT ( addPassiveItem( const QString &, const QString &, FSize ) ) );
1087 connect( _patchList, SIGNAL( statusChanged() ),
1088 this, SLOT ( autoResolveDependencies() ) );
1090 if ( _pkgConflictDialog )
1092 connect( _pkgConflictDialog,SIGNAL( updatePackages() ),
1093 _patchList, SLOT ( updateItemStates() ) );
1096 connect( this, SIGNAL( refresh() ),
1097 _patchList, SLOT ( updateItemStates() ) );
1104 YQPackageSelector::pkgExport()
1106 QString filename = YQUI::ui()->askForSaveFileName( QString( DEFAULT_EXPORT_FILE_NAME ), // startsWith
1107 QString( "*.xml;;*" ), // filter
1108 _( "Save Package List" ) );
1110 if ( ! filename.isEmpty() )
1112 zypp::syscontent::Writer writer;
1113 const zypp::ResPool & pool = zypp::getZYpp()->pool();
1115 // The ZYPP obfuscated C++ contest proudly presents:
1117 for_each( pool.begin(), pool.end(),
1118 boost::bind( &zypp::syscontent::Writer::addIf,
1119 boost::ref( writer ),
1121 // Yuck. What a mess.
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.
1131 std::ofstream exportFile( toUTF8( filename ).c_str() );
1132 exportFile.exceptions( std::ios_base::badbit | std::ios_base::failbit );
1133 exportFile << writer;
1135 y2milestone( "Package list exported to %s", (const char *) filename );
1137 catch ( std::exception & exception )
1139 y2warning( "Error exporting package list to %s", (const char *) filename );
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 );
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
1158 YQPackageSelector::pkgImport()
1160 QString filename = QFileDialog::getOpenFileName( this, _( "Load Package List" ), DEFAULT_EXPORT_FILE_NAME, // startsWi
1161 "*.xml+;;*"// filter
1164 if ( ! filename.isEmpty() )
1166 y2milestone( "Importing package list from %s", (const char *) filename );
1170 std::ifstream importFile( toUTF8( filename ).c_str() );
1171 zypp::syscontent::Reader reader( importFile );
1174 // Put reader contents into maps
1177 typedef zypp::syscontent::Reader::Entry ZyppReaderEntry;
1178 typedef std::pair<string, ZyppReaderEntry> ImportMapPair;
1180 map<string, ZyppReaderEntry> importPkg;
1181 map<string, ZyppReaderEntry> importPatterns;
1183 for ( zypp::syscontent::Reader::const_iterator it = reader.begin();
1187 string kind = it->kind();
1189 if ( kind == "package" ) importPkg.insert ( ImportMapPair( it->name(), *it ) );
1190 else if ( kind == "pattern" ) importPatterns.insert( ImportMapPair( it->name(), *it ) );
1193 y2debug( "Found %zu packages and %zu patterns in %s",
1195 importPatterns.size(),
1196 (const char *) filename );
1200 // Set status of all patterns and packages according to import map
1203 for ( ZyppPoolIterator it = zyppPatternsBegin();
1204 it != zyppPatternsEnd();
1207 ZyppSel selectable = *it;
1208 importSelectable( *it, importPatterns.find( selectable->name() ) != importPatterns.end(), "pattern" );
1211 for ( ZyppPoolIterator it = zyppPkgBegin();
1215 ZyppSel selectable = *it;
1216 importSelectable( *it, importPkg.find( selectable->name() ) != importPkg.end(), "package" );
1226 if ( _statusFilterView )
1228 // Switch to "Installation Summary" filter view
1230 _filters->showPage( _statusFilterView );
1231 _statusFilterView->filter();
1235 catch ( const zypp::Exception & exception )
1237 y2warning( "Error reading package list from %s", (const char *) filename );
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
1252 YQPackageSelector::importSelectable( ZyppSel selectable,
1256 ZyppStatus oldStatus = selectable->status();
1257 ZyppStatus newStatus = oldStatus;
1262 // Make sure this selectable does not get installed
1265 switch ( oldStatus )
1269 case S_KeepInstalled:
1273 newStatus = oldStatus;
1278 newStatus = S_KeepInstalled;
1279 y2debug( "Keeping %s %s", kind, selectable->name().c_str() );
1285 if ( selectable->hasCandidateObj() )
1287 newStatus = S_Install;
1288 y2debug( "Adding %s %s", kind, selectable->name().c_str() );
1292 y2debug( "Can't add %s %s: No candidate",
1293 kind, selectable->name().c_str() );
1301 // Make sure this selectable does not get installed
1304 switch ( oldStatus )
1308 case S_KeepInstalled:
1313 y2debug( "Deleting %s %s", kind, selectable->name().c_str() );
1320 newStatus = oldStatus;
1325 if ( oldStatus != newStatus )
1326 selectable->set_status( newStatus );
1331 YQPackageSelector::globalUpdatePkg( bool force )
1336 int count = _pkgList->globalSetPkgStatus( S_Update, force,
1337 true ); // countOnly
1338 y2milestone( "%d pkgs found for update", count );
1340 if ( count >= GLOBAL_UPDATE_CONFIRMATION_THRESHOLD )
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
1354 (void) _pkgList->globalSetPkgStatus( S_Update, force,
1355 false ); // countOnly
1357 if ( _statusFilterView )
1359 _filters->showPage( _statusFilterView );
1360 _statusFilterView->clear();
1361 _statusFilterView->showTransactions();
1362 _statusFilterView->filter();
1368 YQPackageSelector::showProducts()
1370 YQPkgProductDialog::showProductDialog();
1374 YQPackageSelector::installDevelPkgs()
1376 installSubPkgs( "-devel" );
1381 YQPackageSelector::installDebugInfoPkgs()
1383 installSubPkgs( "-debuginfo" );
1388 YQPackageSelector::pkgExcludeRulesChanged( int menuItemID )
1390 if ( _viewMenu && _pkgList )
1392 _viewMenu->setItemChecked( menuItemID, ! _viewMenu->isItemChecked( menuItemID ) );
1394 if ( _excludeDevelPkgs )
1395 _excludeDevelPkgs->enable( ! _viewMenu->isItemChecked( _viewShowDevelID ) );
1397 if ( _excludeDebugInfoPkgs )
1398 _excludeDebugInfoPkgs->enable( ! _viewMenu->isItemChecked( _viewShowDebugInfoID ) );
1400 _pkgList->applyExcludeRules();
1406 YQPackageSelector::installSubPkgs( const QString suffix )
1408 // Find all matching packages and put them into a QMap
1410 QMap<QString, ZyppSel> subPkgs;
1412 for ( ZyppPoolIterator it = zyppPkgBegin();
1416 QString name = (*it)->name().c_str();
1418 if ( name.endsWith( suffix ) )
1420 subPkgs[ name ] = *it;
1422 y2debug( "Found subpackage: %s", (const char *) name );
1427 // Now go through all packages and look if there is a corresponding subpackage in the QMap
1429 for ( ZyppPoolIterator it = zyppPkgBegin();
1433 QString name = (*it)->name().c_str();
1435 if ( subPkgs.contains( name + suffix ) )
1437 QString subPkgName( name + suffix );
1438 ZyppSel subPkg = subPkgs[ subPkgName ];
1440 switch ( (*it)->status() )
1447 // Don't install the subpackage
1448 y2milestone( "Ignoring unwanted subpackage %s", (const char *) subPkgName );
1453 case S_KeepInstalled:
1455 // Install the subpackage, but don't try to update it
1457 if ( ! subPkg->installedObj() )
1459 subPkg->set_status( S_Install );
1460 y2milestone( "Installing subpackage %s", (const char *) subPkgName );
1468 // Install or update the subpackage
1470 if ( ! subPkg->installedObj() )
1472 subPkg->set_status( S_Install );
1473 y2milestone( "Installing subpackage %s", (const char *) subPkgName );
1477 subPkg->set_status( S_Update );
1478 y2milestone( "Updating subpackage %s", (const char *) subPkgName );
1482 // Intentionally omitting 'default' branch so the compiler can
1483 // catch unhandled enum states
1489 if ( _filters && _statusFilterView )
1491 _filters->showPage( _statusFilterView );
1492 _statusFilterView->filter();
1495 YQPkgChangesDialog::showChangesDialog( _( "Added Subpackages:" ),
1496 QRegExp( ".*" + suffix + "$" ),
1498 QString::null, // rejectButtonLabel
1499 true ); // showIfEmpty
1503 #include "YQPackageSelector.moc"