libyui-qt-pkg  2.47.5
YQPackageSelector.cc
1 /**************************************************************************
2 Copyright (C) 2000 - 2010 Novell, Inc.
3 All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 
19 **************************************************************************/
20 
21 
22 /*---------------------------------------------------------------------\
23 | |
24 | __ __ ____ _____ ____ |
25 | \ \ / /_ _/ ___|_ _|___ \ |
26 | \ V / _` \___ \ | | __) | |
27 | | | (_| |___) || | / __/ |
28 | |_|\__,_|____/ |_| |_____| |
29 | |
30 | core system |
31 | (C) SuSE GmbH |
32 \----------------------------------------------------------------------/
33 
34  File: YQPackageSelector.cc
35  See also: YQPackageSelectorHelp.cc
36 
37  Author: Stefan Hundhammer <sh@suse.de>
38 
39  Textdomain "qt-pkg"
40 
41  /-*/
42 
43 #define CHECK_DEPENDENCIES_ON_STARTUP 1
44 #define DEPENDENCY_FEEDBACK_IF_OK 1
45 #define AUTO_CHECK_DEPENDENCIES_DEFAULT true
46 #define ALWAYS_SHOW_PATCHES_VIEW_IF_PATCHES_AVAILABLE 0
47 #define GLOBAL_UPDATE_CONFIRMATION_THRESHOLD 20
48 #define ENABLE_SOURCE_RPMS 0
49 #define BRAINDEAD_LIB_NAMING_SCHEME 1
50 #define MARGIN 6 // around the widget
51 #define SPACING_BELOW_MENU_BAR 4
52 #define SPLITTER_HALF_SPACING 4
53 
54 
55 #include <fstream>
56 #include <algorithm>
57 #include <boost/bind.hpp>
58 
59 #include <QHBoxLayout>
60 #include <QVBoxLayout>
61 #include <QAction>
62 #include <QShortcut>
63 #include <QApplication>
64 #include <QCheckBox>
65 #include <QDialog>
66 #include <QFileDialog>
67 #include <QLabel>
68 #include <QMap>
69 #include <QMenuBar>
70 #include <QMessageBox>
71 #include <QPushButton>
72 #include <QSplitter>
73 #include <QTabWidget>
74 #include <QTimer>
75 #include <QMenu>
76 #include <QSettings>
77 
78 #define YUILogComponent "qt-pkg"
79 #include "YUILog.h"
80 
81 #include "QY2LayoutUtils.h"
82 
83 #include "YQZypp.h"
84 #include "YQPackageSelector.h"
85 #include "YQPkgChangeLogView.h"
86 #include "YQPkgChangesDialog.h"
87 #include "YQPkgConflictDialog.h"
88 #include "YQPkgConflictList.h"
89 #include "YQPkgDependenciesView.h"
90 #include "YQPkgDescriptionView.h"
91 #include "YQPkgDiskUsageList.h"
92 #include "YQPkgDiskUsageWarningDialog.h"
93 #include "YQPkgFileListView.h"
94 #include "YQPkgFilterTab.h"
95 #include "YQPkgHistoryDialog.h"
96 #include "YQPkgLangList.h"
97 #include "YQPkgList.h"
98 #include "YQPkgClassFilterView.h"
99 #include "YQPkgPatchFilterView.h"
100 #include "YQPkgPatchList.h"
101 #include "YQPkgPatternList.h"
102 #include "YQPkgProductDialog.h"
103 #include "YQPkgRepoFilterView.h"
104 #include "YQPkgRepoList.h"
105 #include "YQPkgSearchFilterView.h"
106 #include "YQPkgServiceFilterView.h"
107 #include "YQPkgStatusFilterView.h"
108 #include "YQPkgTechnicalDetailsView.h"
109 #include "YQPkgTextDialog.h"
110 #include "YQPkgUpdateProblemFilterView.h"
111 #include "YQPkgVersionsView.h"
112 
113 #include "zypp/SysContent.h"
114 #include "zypp/base/String.h"
115 #include "zypp/base/Sysconfig.h"
116 
117 #include "QY2ComboTabWidget.h"
118 #include "YQDialog.h"
119 #include "YQApplication.h"
120 #include "utf8.h"
121 #include "YQUI.h"
122 #include "YEvent.h"
123 #include "YQi18n.h"
124 
125 
126 
127 using std::max;
128 using std::endl;
129 using std::string;
130 using std::map;
131 using std::pair;
132 
133 #define DEFAULT_EXPORT_FILE_NAME "user-packages.xml"
134 #define FAST_SOLVER 1
135 
136 #define SETTINGS_DIR "YaST2"
137 #define PATH_TO_YAST_SYSCONFIG "/etc/sysconfig/yast2"
138 #define OPTION_VERIFY "PKGMGR_VERIFY_SYSTEM"
139 #define OPTION_AUTO_CHECK "PKGMGR_AUTO_CHECK"
140 #define OPTION_RECOMMENDED "PKGMGR_RECOMMENDED"
141 
142 YQPackageSelector::YQPackageSelector( YWidget * parent,
143  long modeFlags )
144  : YQPackageSelectorBase( parent, modeFlags )
145 {
146  _showChangesDialog = true;
147  _autoDependenciesAction = 0;
148  _detailsViews = 0;
149  _filters = 0;
150  _langList = 0;
151  _pkgClassFilterView = 0;
152  _patchFilterView = 0;
153  _patchList = 0;
154  _patternList = 0;
155  _pkgChangeLogView = 0;
156  _pkgDependenciesView = 0;
157  _pkgDescriptionView = 0;
158  _pkgFileListView = 0;
159  _pkgList = 0;
160  _pkgTechnicalDetailsView = 0;
161  _pkgVersionsView = 0;
162  _repoFilterView = 0;
163  _serviceFilterView = 0;
164  _searchFilterView = 0;
165  _statusFilterView = 0;
166  _updateProblemFilterView = 0;
167  _excludeDevelPkgs = 0;
168  _excludeDebugInfoPkgs = 0;
169 
170  yuiMilestone() << "This is libyui-qt-pkg " << VERSION << endl;
171 
172  if ( onlineUpdateMode() ) yuiMilestone() << "Online update mode" << endl;
173  if ( updateMode() ) yuiMilestone() << "Update mode" << endl;
174 
175  basicLayout();
176  addMenus(); // Only after all widgets are created!
177  loadSettings(); // Only after menus are created!
178  makeConnections();
179  emit loadData();
180 
181  _filters->loadSettings();
182  bool pagesRestored = _filters->tabCount() > 0;
183 
184  if ( _pkgList )
185  _pkgList->clear();
186 
187  if ( ! pagesRestored )
188  {
189  yuiDebug() << "No page configuration saved, using fallbacks" << endl;
190 
191  //
192  // Add a number of default tabs in the desired order
193  //
194 
195  if ( _searchFilterView ) _filters->showPage( _searchFilterView );
196 
197  if ( ! searchMode() && ! summaryMode()
198  && _patternList ) _filters->showPage( _patternList );
199 
200  if ( _statusFilterView ) _filters->showPage( _statusFilterView );
201  }
202 
203 
204  //
205  // Move the desired tab to the foreground
206  //
207 
208  if ( _patchFilterView && onlineUpdateMode() )
209  {
210  if ( _patchFilterView && _patchList )
211  {
212  _filters->showPage( _patchFilterView );
213  _patchList->filter();
214  }
215  }
216  else if ( _repoFilterView && repoMode() )
217  {
219  {
220  _filters->showPage( _repoFilterView );
221  _repoFilterView->filter();
222  }
223  }
224  else if ( _updateProblemFilterView )
225  {
226  _filters->showPage( _updateProblemFilterView );
227  _updateProblemFilterView->filter();
228  }
229  else if ( searchMode() && _searchFilterView )
230  {
231  if ( _pkgClassFilterView && anyRetractedPkgInstalled() )
232  {
233  // Exceptional case: If the system has any retracted package
234  // installed, switch to that filter view and show those packages.
235  // This should happen only very, very rarely.
236 
237  yuiMilestone() << "Found installed retracted packages; switching to that view" << endl;
238  _filters->showPage( _pkgClassFilterView );
239  _pkgClassFilterView->showPkgClass( YQPkgClassRetractedInstalled );
240 
241  // Also show a pop-up warning?
242  //
243  // This could become very annoying really quickly because you'll
244  // get it with every start of the package selection as long as any
245  // retracted package version is installed (which might be a
246  // deliberate conscious decision by the user). It's also not easy
247  // to add a "Don't show this again" checkbox in such a pop-up;
248  // which retracted packages are installed might change between
249  // program runs, and we'd have to inform the user when such a
250  // change occurs.
251  }
252  else
253  {
254  // Normal case: Show the "Search" filter view.
255 
256  _filters->showPage( _searchFilterView );
257  _searchFilterView->filter();
258  QTimer::singleShot( 0, _searchFilterView, SLOT( setFocus() ) );
259  }
260  }
261  else if ( summaryMode() && _statusFilterView )
262  {
263  _filters->showPage( _statusFilterView );
264  _statusFilterView->filter();
265  _pkgList->selectNextItem();
266  }
267  else if ( _patternList )
268  {
269  _filters->showPage( _patternList );
270  _patternList->filter();
271  }
272 
273 
274  if ( _filters->diskUsageList() )
275  _filters->diskUsageList()->updateDiskUsage();
276 
277  yuiMilestone() << "PackageSelector init done" << endl;
278 
279 
280 #if CHECK_DEPENDENCIES_ON_STARTUP
281 
282  if ( ! testMode() )
283  {
284  // Fire up the first dependency check in the main loop.
285  // Don't do this right away - wait until all initializations are finished.
286  QTimer::singleShot( 0, this, SLOT( resolveDependencies() ) );
287 
288  }
289 #endif
290 
291 }
292 
293 
294 void
295 YQPackageSelector::basicLayout()
296 {
297  QVBoxLayout *layout = new QVBoxLayout();
298  setLayout( layout );
299  layout->setContentsMargins( MARGIN, // left
300  0, // top
301  MARGIN, // right
302  MARGIN ); // bottom
303  layout->setSpacing( SPACING_BELOW_MENU_BAR );
304  layoutMenuBar( this );
305 
306  QString settingsName = "YQPackageSelector";
307 
308  if ( onlineUpdateMode() ) settingsName = "YQOnlineUpdate";
309  if ( updateMode() ) settingsName = "YQSystemUpdate";
310 
311  _filters = new YQPkgFilterTab( this, settingsName );
312  YUI_CHECK_NEW( _filters );
313 
314  layout->addWidget( _filters );
315  layoutFilters( this );
316  layoutRightPane( _filters->rightPane() );
317 }
318 
319 
320 void
321 YQPackageSelector::layoutFilters( QWidget *parent )
322 {
323  //
324  // Update problem view
325  //
326 
327  if ( updateMode() )
328  {
330  || testMode() )
331  {
332  _updateProblemFilterView = new YQPkgUpdateProblemFilterView( parent );
333  YUI_CHECK_NEW( _updateProblemFilterView );
334  _filters->addPage( _( "&Update Problems" ), _updateProblemFilterView, "update_problems" );
335  }
336  }
337 
338 
339  //
340  // Patches view
341  //
342 
343  if ( onlineUpdateMode()
344 #if ALWAYS_SHOW_PATCHES_VIEW_IF_PATCHES_AVAILABLE
345  || ! zyppPool().empty<zypp::Patch>()
346 #endif
347  )
348  {
350  }
351 
352 
353  //
354  // Patterns view
355  //
356 
357  if ( ! zyppPool().empty<zypp::Pattern>() || testMode() )
358  {
359  _patternList = new YQPkgPatternList( parent, true );
360  YUI_CHECK_NEW( _patternList );
361  _filters->addPage( _( "Patter&ns" ), _patternList, "patterns" );
362 
363  connect( _patternList, SIGNAL( statusChanged() ),
364  this, SLOT ( autoResolveDependencies() ) );
365 
366  connect( this, SIGNAL( refresh() ),
367  _patternList, SLOT ( updateItemStates() ) );
368 
369  if ( _pkgConflictDialog )
370  {
371  connect( _pkgConflictDialog, SIGNAL( updatePackages() ),
372  _patternList, SLOT ( updateItemStates() ) );
373  }
374  }
375 
376 
377  //
378  // Package classification view
379  //
380 
381  _pkgClassFilterView = new YQPkgClassFilterView( parent );
382  YUI_CHECK_NEW( _pkgClassFilterView );
383  _filters->addPage( _( "Package &Classification" ), _pkgClassFilterView, "package_classification" );
384 
385  connect( this, SIGNAL( loadData() ),
386  _pkgClassFilterView, SLOT ( filter() ) );
387 
388 
389  //
390  // Languages view
391  //
392 
393  _langList = new YQPkgLangList( parent );
394  YUI_CHECK_NEW( _langList );
395 
396  _filters->addPage( _( "&Languages" ), _langList, "languages" );
397  _langList->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ) ); // hor/vert
398 
399  connect( _langList, SIGNAL( statusChanged() ),
400  this, SLOT ( autoResolveDependencies() ) );
401 
402  connect( this, SIGNAL( refresh() ),
403  _langList, SLOT ( updateItemStates() ) );
404 
405 
406  //
407  // Repository view
408  //
409 
410  _repoFilterView = new YQPkgRepoFilterView( parent );
411  YUI_CHECK_NEW( _repoFilterView );
412  _filters->addPage( _( "&Repositories" ), _repoFilterView, "repos" );
413  // hide and show the upgrade label when tabs change, or when the user
414  // selects repositories
415  connect(_repoFilterView, SIGNAL(filterStart()), this, SLOT(updateRepositoryUpgradeLabel()));
416  connect(this, SIGNAL(refresh()), this, SLOT(updateRepositoryUpgradeLabel()));
417  connect(_filters, &YQPkgFilterTab::currentChanged,
419 
420  // Services view - only if a service is present
422  {
423  _serviceFilterView = new YQPkgServiceFilterView( parent );
424  YUI_CHECK_NEW( _serviceFilterView );
425 
426  // TRANSLATORS: Menu item
427  _filters->addPage( _( "&Services" ), _serviceFilterView, "services" );
428  }
429 
430  //
431  // Package search view
432  //
433 
434  _searchFilterView = new YQPkgSearchFilterView( parent );
435  YUI_CHECK_NEW( _searchFilterView );
436  _filters->addPage( _( "S&earch" ), _searchFilterView, "search" );
437 
438 
439 
440 #if 0
441  // DEBUG
442 
443  _filters->addPage( _( "&Keywords" ), new QLabel( "Keywords\nfilter\n\nfor future use", this ), "keywords" );
444 #endif
445 
446  //
447  // Status change view
448  //
449 
450  _statusFilterView = new YQPkgStatusFilterView( parent );
451  YUI_CHECK_NEW( _statusFilterView );
452  _filters->addPage( _( "&Installation Summary" ), _statusFilterView, "inst_summary" );
453 }
454 
455 
456 YQPackageSelector::~YQPackageSelector()
457 {
458  saveSettings();
459 }
460 
461 
462 QWidget *
463 YQPackageSelector::layoutRightPane( QWidget *parent )
464 {
465  QVBoxLayout *layout = new QVBoxLayout( parent );
466  YUI_CHECK_NEW( layout );
467  layout->setContentsMargins( SPLITTER_HALF_SPACING, // left
468  0, // top
469  0, // right
470  0 ); // bottom
471 
472  QSplitter * splitter = new QSplitter( Qt::Vertical, parent );
473  YUI_CHECK_NEW( splitter );
474  layout->addWidget(splitter);
475 
476  layoutPkgList( splitter );
477  layoutDetailsViews( splitter );
478  layoutButtons( parent );
479 
480  return parent;
481 }
482 
483 
484 void
485 YQPackageSelector::layoutPkgList( QWidget *parent )
486 {
487  // this is made visible when activating the repository
488  // filter
489  QWidget *_notificationsContainer = new QWidget(parent);
490  QVBoxLayout *layout = new QVBoxLayout(_notificationsContainer);
491 
492  _repoUpgradingLabel = new QLabel(_notificationsContainer);
493  _repoUpgradingLabel->setTextFormat(Qt::RichText);
494  _repoUpgradingLabel->setWordWrap(true);
495  _repoUpgradingLabel->setVisible(false);
496 
497  _repoUpgradeLabel = new QLabel(_notificationsContainer);
498  _repoUpgradeLabel->setTextFormat(Qt::RichText);
499  _repoUpgradeLabel->setWordWrap(true);
500  _repoUpgradeLabel->setVisible(false);
501  _repoUpgradeLabel->setObjectName( "RepoUpgradeLabel");
502 
503  layout->addWidget(_repoUpgradingLabel);
504  layout->addWidget(_repoUpgradeLabel);
505 
506  // if the user clicks on a link on the label, we have to check
507  // which repository upgrade job to add or remove, for that
508  // we will encode the links as repoupgradeadd://alias and
509  // repoupgraderemove:://alias
510  connect( _repoUpgradeLabel, SIGNAL( linkActivated ( QString ) ),
511  this, SLOT ( slotRepoUpgradeLabelLinkClicked( QString ) ) );
512 
513  connect(_repoUpgradingLabel, SIGNAL( linkActivated ( QString ) ),
514  this, SLOT ( slotRepoUpgradeLabelLinkClicked( QString ) ) );
515 
517 
518  _pkgList= new YQPkgList( parent );
519  YUI_CHECK_NEW( _pkgList );
520 
521  connect( _pkgList, SIGNAL( statusChanged() ),
522  this, SLOT ( autoResolveDependencies() ) );
523 }
524 
525 
526 void
527 YQPackageSelector::layoutDetailsViews( QWidget *parent )
528 {
529  bool haveInstalledPkgs = YQPkgList::haveInstalledPkgs();
530 
531 
532  _detailsViews = new QTabWidget( parent );
533  YUI_CHECK_NEW( _detailsViews );
534 
535  //
536  // Description
537  //
538 
539  _pkgDescriptionView = new YQPkgDescriptionView( _detailsViews, confirmUnsupported() );
540  YUI_CHECK_NEW( _pkgDescriptionView );
541 
542  _detailsViews->addTab( _pkgDescriptionView, _( "D&escription" ) );
543  _detailsViews->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
544 
545  connect( _pkgList, SIGNAL( currentItemChanged ( ZyppSel ) ),
546  _pkgDescriptionView, SLOT ( showDetailsIfVisible( ZyppSel ) ) );
547 
548  //
549  // Technical details
550  //
551 
552  _pkgTechnicalDetailsView = new YQPkgTechnicalDetailsView( _detailsViews );
553  YUI_CHECK_NEW( _pkgTechnicalDetailsView );
554 
555  _detailsViews->addTab( _pkgTechnicalDetailsView, _( "&Technical Data" ) );
556 
557  connect( _pkgList, SIGNAL( currentItemChanged ( ZyppSel ) ),
558  _pkgTechnicalDetailsView, SLOT ( showDetailsIfVisible( ZyppSel ) ) );
559 
560 
561  //
562  // Dependencies
563  //
564 
565  _pkgDependenciesView = new YQPkgDependenciesView( _detailsViews );
566  YUI_CHECK_NEW( _pkgDependenciesView );
567 
568  _detailsViews->addTab( _pkgDependenciesView, _( "Dependencies" ) );
569  _detailsViews->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
570 
571  connect( _pkgList, SIGNAL( currentItemChanged ( ZyppSel ) ),
572  _pkgDependenciesView, SLOT ( showDetailsIfVisible( ZyppSel ) ) );
573 
574 
575 
576  //
577  // Versions
578  //
579 
580  _pkgVersionsView = new YQPkgVersionsView( _detailsViews );
581  YUI_CHECK_NEW( _pkgVersionsView );
582 
583  _detailsViews->addTab( _pkgVersionsView, _( "&Versions" ) );
584 
585  connect( _pkgList, SIGNAL( currentItemChanged ( ZyppSel ) ),
586  _pkgVersionsView, SLOT ( showDetailsIfVisible( ZyppSel ) ) );
587 
588  connect( _pkgList, SIGNAL( statusChanged() ),
589  _pkgVersionsView, SIGNAL( statusChanged() ) );
590 
591 
592  //
593  // File List
594  //
595 
596  if ( haveInstalledPkgs ) // file list information is only available for installed pkgs
597  {
598  _pkgFileListView = new YQPkgFileListView( _detailsViews );
599  YUI_CHECK_NEW( _pkgFileListView );
600 
601  _detailsViews->addTab( _pkgFileListView, _( "File List" ) );
602  _detailsViews->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
603 
604  connect( _pkgList, SIGNAL( currentItemChanged ( ZyppSel ) ),
605  _pkgFileListView, SLOT ( showDetailsIfVisible( ZyppSel ) ) );
606  }
607 
608 
609  //
610  // Change Log
611  //
612 
613  if ( haveInstalledPkgs ) // change log information is only available for installed pkgs
614  {
615  _pkgChangeLogView = new YQPkgChangeLogView( _detailsViews );
616  YUI_CHECK_NEW( _pkgChangeLogView );
617 
618  _detailsViews->addTab( _pkgChangeLogView, _( "Change Log" ) );
619  _detailsViews->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
620 
621  connect( _pkgList, SIGNAL( currentItemChanged ( ZyppSel ) ),
622  _pkgChangeLogView, SLOT ( showDetailsIfVisible( ZyppSel ) ) );
623  }
624 }
625 
626 
627 void
628 YQPackageSelector::layoutButtons( QWidget *parent )
629 {
630  QWidget * button_box = new QWidget( parent );
631  YUI_CHECK_NEW( button_box );
632  parent->layout()->addWidget( button_box );
633 
634  QHBoxLayout * layout = new QHBoxLayout( button_box );
635  YUI_CHECK_NEW( layout );
636 
637  button_box->setLayout( layout );
638  layout->setContentsMargins( 2, // left
639  2, // top
640  2, // right
641  2 ); // bottom
642  layout->addStretch();
643 
644  QPushButton * cancel_button = new QPushButton( _( "&Cancel" ), button_box );
645  YUI_CHECK_NEW( cancel_button );
646  layout->addWidget(cancel_button);
647 
648  cancel_button->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); // hor/vert
649 
650  connect( cancel_button, SIGNAL( clicked() ),
651  this, SLOT ( reject() ) );
652 
653 
654  QPushButton * accept_button = new QPushButton( _( "&Accept" ), button_box );
655  YUI_CHECK_NEW( accept_button );
656  layout->addWidget(accept_button);
657  accept_button->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); // hor/vert
658 
659  connect( accept_button, SIGNAL( clicked() ),
660  this, SLOT ( accept() ) );
661 
662  button_box->setFixedHeight( button_box->sizeHint().height() );
663 }
664 
665 
666 void
667 YQPackageSelector::layoutMenuBar( QWidget *parent )
668 {
669  _menuBar = new QMenuBar( parent );
670  YUI_CHECK_NEW( _menuBar );
671  parent->layout()->addWidget(_menuBar);
672 
673  _fileMenu = 0;
674  _optionsMenu = 0;
675  _pkgMenu = 0;
676  _patchMenu = 0;
677  _extrasMenu = 0;
678  _configMenu = 0;
679  _dependencyMenu = 0;
680  _helpMenu = 0;
681 
682 }
683 
684 
685 void
687 {
688  //
689  // File menu
690  //
691 
692  _fileMenu = new QMenu( _menuBar );
693  YUI_CHECK_NEW( _fileMenu );
694  QAction * action = _menuBar->addMenu( _fileMenu );
695  action->setText( _( "&File" ));
696 
697  _fileMenu->addAction( _( "&Import..." ), this, SLOT( pkgImport() ) );
698  _fileMenu->addAction( _( "&Export..." ), this, SLOT( pkgExport() ) );
699 
700  _fileMenu->addSeparator();
701 
702  _fileMenu->addAction( _( "E&xit -- Discard Changes" ), this, SLOT( reject() ) );
703  _fileMenu->addAction( _( "&Quit -- Save Changes" ), this, SLOT( accept() ) );
704 
705 
706  if ( _pkgList )
707  {
708  //
709  // Package menu
710  //
711 
712  _pkgMenu = new QMenu( _menuBar );
713  YUI_CHECK_NEW( _pkgMenu );
714  action = _menuBar->addMenu( _pkgMenu );
715  action->setText(_( "&Package" ));
716 
717  _pkgMenu->addAction(_pkgList->actionSetCurrentInstall);
718  _pkgMenu->addAction(_pkgList->actionSetCurrentDontInstall);
719  _pkgMenu->addAction(_pkgList->actionSetCurrentKeepInstalled);
720  _pkgMenu->addAction(_pkgList->actionSetCurrentDelete);
721  _pkgMenu->addAction(_pkgList->actionSetCurrentUpdate);
722  _pkgMenu->addAction(_pkgList->actionSetCurrentUpdateForce);
723  _pkgMenu->addAction(_pkgList->actionSetCurrentTaboo);
724 
725 #if ENABLE_SOURCE_RPMS
726  _pkgMenu->addSeparator();
727 
728  _pkgMenu->addAction(_pkgList->actionInstallSourceRpm);
729  _pkgMenu->addAction(_pkgList->actionDontInstallSourceRpm);
730 #endif
731 
732  _pkgMenu->addSeparator();
733  QMenu * submenu = _pkgList->addAllInListSubMenu( _pkgMenu );
734  YUI_CHECK_NEW( submenu );
735 
736 #if ENABLE_SOURCE_RPMS
737  submenu->addSeparator();
738 
739  _pkgMenu->addAction(_pkgList->actionInstallListSourceRpms);
740  _pkgMenu->addAction(_pkgList->actionDontInstallListSourceRpms);
741 #endif
742 
743  //
744  // Submenu for all packages
745  //
746 
747  submenu = new QMenu( _pkgMenu );
748  YUI_CHECK_NEW( submenu );
749 
750  // Translators: Unlike the "all in this list" submenu, this submenu
751  // refers to all packages globally, not only to those that are
752  // currently visible in the packages list.
753  action = _pkgMenu->addMenu( submenu );
754  action->setText(_( "All Packages" ));
755 
756  submenu->addAction( _( "Update if newer version available" ),
757  this, SLOT( globalUpdatePkg() ) );
758 
759  submenu->addAction( _( "Update unconditionally" ),
760  this, SLOT( globalUpdatePkgForce() ) );
761  }
762 
763 
764  if ( _patchList )
765  {
766  //
767  // Patch menu
768  //
769 
770  _patchMenu = new QMenu( _menuBar );
771  YUI_CHECK_NEW( _patchMenu );
772  action = _menuBar->addMenu( _patchMenu );
773  action->setText(_( "&Patch" ));
774 
775  _patchMenu->addAction(_patchList->actionSetCurrentInstall);
776  _patchMenu->addAction(_patchList->actionSetCurrentDontInstall);
777  _patchMenu->addAction(_patchList->actionSetCurrentKeepInstalled);
778 
779 #if ENABLE_DELETING_PATCHES
780  _patchMenu->addAction(_patchList->actionSetCurrentDelete);
781 #endif
782  _patchMenu->addAction(_patchList->actionSetCurrentUpdate);
783  _patchMenu->addAction(_patchList->actionSetCurrentUpdateForce);
784  _patchMenu->addAction(_patchList->actionSetCurrentTaboo);
785 
786  _patchMenu->addSeparator();
787  _patchList->addAllInListSubMenu( _patchMenu );
788  }
789 
790 
791  //
792  // Configuration menu
793  //
794 
795  if ( repoMgrEnabled() )
796  {
797  _configMenu = new QMenu( _menuBar );
798  YUI_CHECK_NEW( _configMenu );
799  action = _menuBar->addMenu( _configMenu );
800  action->setText(_( "Confi&guration" ));
801  _configMenu->addAction( _( "&Repositories..." ), this, SLOT( repoManager() ), Qt::CTRL + Qt::Key_R );
802  _configMenu->addAction( _( "&Online Update..." ), this, SLOT( onlineUpdateConfiguration() ), Qt::CTRL + Qt::Key_O );
803  }
804 
805 
806  //
807  // Dependency menu
808  //
809 
810  _dependencyMenu = new QMenu( _menuBar );
811  YUI_CHECK_NEW( _dependencyMenu );
812  action = _menuBar->addMenu( _dependencyMenu );
813  action->setText(_( "&Dependencies" ));
814 
815  _dependencyMenu->addAction( _( "&Check Now" ), this, SLOT( manualResolvePackageDependencies() ) );
816 
817  _autoDependenciesAction = new QAction( _( "&Autocheck" ), this );
818  _autoDependenciesAction->setCheckable( true );
819  _dependencyMenu->addAction( _autoDependenciesAction );
820 
821  _installRecommendedAction = _dependencyMenu->addAction(
822  _("Install &Recommended Packages"),
823  this, SLOT (pkgInstallRecommendedChanged(bool)));
824  _installRecommendedAction->setCheckable( true );
825 
826 
827  //
828  // View menu
829  //
830 
831  _optionsMenu = new QMenu( _menuBar );
832  YUI_CHECK_NEW( _optionsMenu );
833  action = _menuBar->addMenu( _optionsMenu );
834  // Translators: Menu for view options (Use a noun, not a verb!)
835  action->setText(_( "&Options" ));
836 
837  // Translators: This is about packages ending in "-devel", so don't translate that "-devel"!
838  _showDevelAction = _optionsMenu->addAction( _( "Show -de&vel Packages" ),
839  this, SLOT( pkgExcludeDevelChanged( bool ) ), Qt::Key_F7 );
840  _showDevelAction->setCheckable(true);
841 
842  _excludeDevelPkgs = new YQPkgObjList::ExcludeRule( _pkgList, QRegExp( ".*(\\d+bit)?-devel(-\\d+bit)?$" ), _pkgList->nameCol() );
843  YUI_CHECK_NEW( _excludeDevelPkgs );
844  _excludeDevelPkgs->enable( false );
845 
846  // Translators: This is about packages ending in "-debuginfo", so don't translate that "-debuginfo"!
847  _showDebugAction = _optionsMenu->addAction( _( "Show -&debuginfo/-debugsource Packages" ),
848  this, SLOT( pkgExcludeDebugChanged( bool ) ), Qt::Key_F8 );
849  _showDebugAction->setCheckable(true);
850  _excludeDebugInfoPkgs = new YQPkgObjList::ExcludeRule( _pkgList, QRegExp( ".*(-\\d+bit)?-(debuginfo|debugsource)(-32bit)?$" ), _pkgList->nameCol() );
851  YUI_CHECK_NEW( _excludeDebugInfoPkgs );
852  _excludeDebugInfoPkgs->enable( false );
853 
854 
855  _verifySystemModeAction = _optionsMenu->addAction( _( "&System Verification Mode" ),
856  this, SLOT( pkgVerifySytemModeChanged( bool ) ) );
857  _verifySystemModeAction->setCheckable(true);
858 
859  // Widget styles can use the text information in the rendering for sections,
860  // or can choose to ignore it and render sections like simple separators.
861  _optionsMenu->addSection( _( "Options for this run only..." ) );
862 
863  _cleanDepsOnRemoveAction = _optionsMenu->addAction( _( "&Cleanup when deleting packages" ),
864  this, SLOT( pkgCleanDepsOnRemoveChanged( bool ) ) );
865  _cleanDepsOnRemoveAction->setCheckable(true);
866 
867  _allowVendorChangeAction = _optionsMenu->addAction( _( "&Allow vendor change" ),
868  this, SLOT( pkgAllowVendorChangeChanged( bool ) ) );
869  _allowVendorChangeAction->setCheckable(true);
870 
871 
872  //
873  // Extras menu
874  //
875 
876  _extrasMenu = new QMenu( _menuBar );
877  YUI_CHECK_NEW( _extrasMenu );
878  action = _menuBar->addMenu( _extrasMenu );
879  action->setText(_( "E&xtras" ));
880 
881  _extrasMenu->addAction( _( "Show &Products" ), this, SLOT( showProducts() ) );
882  _extrasMenu->addAction( _( "Show P&ackage Changes" ), this, SLOT( showAutoPkgList() ), Qt::CTRL + Qt::Key_A );
883  _extrasMenu->addAction( _( "Show &History" ), this, SLOT( showHistory() ) );
884 
885  _extrasMenu->addSeparator();
886 
887 #if BRAINDEAD_LIB_NAMING_SCHEME
888  // See bug #434042: libcddb2 vs. libcddb-devel
889 #else
890  // Translators: This is about packages ending in "-devel", so don't translate that "-devel"!
891  _extrasMenu->addAction( _( "Install All Matching -&devel Packages" ), this, SLOT( installDevelPkgs() ) );
892 #endif
893 
894  // Translators: This is about packages ending in "-debuginfo", so don't translate that "-debuginfo"!
895  _extrasMenu->addAction( _( "Install All Matching -de&buginfo Packages" ), this, SLOT( installDebugInfoPkgs() ) );
896 
897  // Translators: This is about packages ending in "-debugsource", so don't translate that "-debugsource"!
898  _extrasMenu->addAction( _( "Install All Matching -debug&source Packages" ), this, SLOT( installDebugSourcePkgs() ) );
899 
900  _extrasMenu->addAction( _( "Install All Matching &Recommended Packages" ),
901  this, SLOT( installRecommendedPkgs() ) );
902 
903  _extrasMenu->addSeparator();
904 
905  if ( _pkgConflictDialog )
906  _extrasMenu->addAction( _( "Generate Dependency Resolver &Test Case" ),
907  _pkgConflictDialog, SLOT( askCreateSolverTestCase() ) );
908 
909  if ( _actionResetIgnoredDependencyProblems )
910  _extrasMenu->addAction(_actionResetIgnoredDependencyProblems);
911 
912 #ifdef FIXME
913  if ( _patchList )
914  _extrasMenu->addAction(_patchList->actionShowRawPatchInfo);
915 #endif
916 
917  if ( (onlineSearchEnabled()) ) {
918  _extrasMenu->addAction(_("Search &Online"), this, SLOT( onlineSearch() ) );
919  }
920 
921  //
922  // Help menu
923  //
924 
925  _helpMenu = new QMenu( _menuBar );
926  YUI_CHECK_NEW( _helpMenu );
927  _menuBar->addSeparator();
928  action = _menuBar->addMenu( _helpMenu );
929  action->setText(_( "&Help" ));
930 
931  // Note: The help functions and their texts are moved out
932  // to a separate source file YQPackageSelectorHelp.cc
933 
934  // Menu entry for help overview
935  _helpMenu->addAction( _( "&Overview" ), this, SLOT( help() ), Qt::Key_F1 );
936 
937  // Menu entry for help about used symbols ( icons )
938  _helpMenu->addAction( _( "&Symbols" ), this, SLOT( symbolHelp() ), Qt::SHIFT + Qt::Key_F1 );
939 
940  // Menu entry for keyboard help
941  _helpMenu->addAction( _( "&Keys" ), this, SLOT( keyboardHelp() ) );
942 }
943 
944 
945 void
947  QWidget * pkgList,
948  bool hasUpdateSignal )
949 {
950  if ( ! filter ) return;
951  if ( ! pkgList ) return;
952 
953  if ( _filters )
954  {
955  connect( _filters, SIGNAL( currentChanged(QWidget *) ),
956  filter, SLOT ( filterIfVisible() ) );
957  }
958 
959  connect( this, SIGNAL( refresh() ),
960  filter, SLOT ( filterIfVisible() ) );
961 
962  connect( filter, SIGNAL( filterStart() ),
963  pkgList, SLOT ( clear() ) );
964 
965  connect( filter, SIGNAL( filterStart() ),
966  this, SLOT ( busyCursor() ) );
967 
968  connect( filter, SIGNAL( filterMatch( ZyppSel, ZyppPkg ) ),
969  pkgList, SLOT ( addPkgItem ( ZyppSel, ZyppPkg ) ) );
970 
971  connect( filter, SIGNAL( filterFinished() ),
972  pkgList, SLOT ( resort() ) );
973 
974  connect( filter, SIGNAL( filterFinished() ),
975  pkgList, SLOT ( selectSomething() ) );
976 
977  connect( filter, SIGNAL( filterFinished() ),
978  pkgList, SLOT ( logExcludeStatistics() ) );
979 
980  connect( filter, SIGNAL( filterFinished() ),
981  pkgList, SLOT ( setFocus() ) );
982 
983  connect( filter, SIGNAL( filterFinished() ),
984  this, SLOT ( normalCursor() ) );
985 
986 
987  if ( hasUpdateSignal && _filters->diskUsageList() )
988  {
989  connect( filter, SIGNAL( updatePackages() ),
990  pkgList, SLOT ( updateItemStates() ) );
991 
992  if ( _filters->diskUsageList() )
993  {
994  connect( filter, SIGNAL( updatePackages() ),
995  _filters->diskUsageList(), SLOT ( updateDiskUsage() ) );
996  }
997  }
998 }
999 
1000 
1001 void
1003 {
1004  connectFilter( _updateProblemFilterView, _pkgList, false );
1005  connectFilter( _patternList, _pkgList );
1006  connectFilter( _langList, _pkgList );
1007  connectFilter( _repoFilterView, _pkgList, false );
1008  connectFilter( _serviceFilterView, _pkgList, false );
1009  connectFilter( _pkgClassFilterView, _pkgList, false );
1010  connectFilter( _statusFilterView, _pkgList, false );
1011  connectFilter( _searchFilterView, _pkgList, false );
1012 
1013  if ( _searchFilterView && _pkgList )
1014  {
1015  connect( _searchFilterView, SIGNAL( message( const QString & ) ),
1016  _pkgList, SLOT ( message( const QString & ) ) );
1017  }
1018 
1019  if ( _repoFilterView && _pkgList )
1020  {
1021  connect( _repoFilterView, SIGNAL( filterNearMatch ( ZyppSel, ZyppPkg ) ),
1022  _pkgList, SLOT ( addPkgItemDimmed ( ZyppSel, ZyppPkg ) ) );
1023  }
1024 
1025  if ( _serviceFilterView && _pkgList )
1026  {
1027  connect( _serviceFilterView, SIGNAL( filterNearMatch ( ZyppSel, ZyppPkg ) ),
1028  _pkgList, SLOT ( addPkgItemDimmed ( ZyppSel, ZyppPkg ) ) );
1029  }
1030 
1031  if ( _pkgList && _filters->diskUsageList() )
1032  {
1033 
1034  connect( _pkgList, SIGNAL( statusChanged() ),
1035  _filters->diskUsageList(), SLOT ( updateDiskUsage() ) );
1036  }
1037 
1038  connectPatchList();
1039 
1040 
1041  //
1042  // Connect package conflict dialog
1043  //
1044 
1045  if ( _pkgConflictDialog )
1046  {
1047  if (_pkgList )
1048  {
1049  connect( _pkgConflictDialog, SIGNAL( updatePackages() ),
1050  _pkgList, SLOT ( updateItemStates() ) );
1051  }
1052 
1053  if ( _patternList )
1054  {
1055  connect( _pkgConflictDialog, SIGNAL( updatePackages() ),
1056  _patternList, SLOT ( updateItemStates() ) );
1057  }
1058 
1059 
1060  if ( _filters->diskUsageList() )
1061  {
1062  connect( _pkgConflictDialog, SIGNAL( updatePackages() ),
1063  _filters->diskUsageList(), SLOT ( updateDiskUsage() ) );
1064  }
1065  }
1066 
1067 
1068  //
1069  // Connect package versions view
1070  //
1071 
1072  if ( _pkgVersionsView && _pkgList )
1073  {
1074  connect( _pkgVersionsView, SIGNAL( candidateChanged( ZyppObj ) ),
1075  _pkgList, SLOT ( updateItemData() ) );
1076 
1077  connect( _pkgVersionsView, SIGNAL( statusChanged() ),
1078  _pkgList, SLOT ( updateItemData() ) );
1079  }
1080 
1081 
1082  //
1083  // Hotkey to enable "patches" filter view on the fly
1084  //
1085 
1086  QShortcut * accel = new QShortcut( Qt::Key_F2, this, SLOT( hotkeyInsertPatchFilterView() ) );
1087  YUI_CHECK_NEW( accel );
1088 
1089 
1090  //
1091  // Update actions just before opening menus
1092  //
1093 
1094  if ( _pkgMenu && _pkgList )
1095  {
1096  connect( _pkgMenu, SIGNAL( aboutToShow() ),
1097  _pkgList, SLOT ( updateActions() ) );
1098  }
1099 
1100  if ( _patchMenu && _patchList )
1101  {
1102  connect( _patchMenu, SIGNAL( aboutToShow() ),
1103  _patchList, SLOT ( updateActions() ) );
1104  }
1105 }
1106 
1107 
1108 void
1110 {
1111  if ( _autoDependenciesAction && ! _autoDependenciesAction->isChecked() )
1112  return;
1113 
1115 }
1116 
1117 
1118 int
1120 {
1121  if ( ! _pkgConflictDialog )
1122  {
1123  yuiError() << "No package conflict dialog existing" << endl;
1124  return QDialog::Accepted;
1125  }
1126 
1127  busyCursor();
1128  int result = _pkgConflictDialog->solveAndShowConflicts();
1129  normalCursor();
1130 
1131 #if DEPENDENCY_FEEDBACK_IF_OK
1132 
1133  if ( result == QDialog::Accepted )
1134  {
1135  QMessageBox::information( this, "",
1136  _( "All package dependencies are OK." ),
1137  QMessageBox::Ok );
1138  }
1139 #endif
1140 
1141  return result;
1142 }
1143 
1144 
1145 void
1147 {
1148  if ( ! _patchFilterView )
1149  {
1150  _patchFilterView = new YQPkgPatchFilterView( this );
1151  YUI_CHECK_NEW( _patchFilterView );
1152  _filters->addPage( _( "P&atches" ), _patchFilterView, "patches" );
1153 
1154  _patchList = _patchFilterView->patchList();
1155  YUI_CHECK_PTR( _patchList );
1156 
1157  connectPatchList();
1158  }
1159 }
1160 
1161 
1162 void
1164 {
1165  if ( ! _patchFilterView )
1166  {
1167  yuiMilestone() << "Activating patches filter view" << endl;
1168 
1170  connectPatchList();
1171 
1172  _filters->showPage( _patchFilterView );
1173  _pkgList->clear();
1174  _patchList->filter();
1175  }
1176  else
1177  {
1178  _filters->showPage( _patchFilterView );
1179  }
1180 }
1181 
1182 
1183 void
1185 {
1186  if ( _pkgList && _patchList )
1187  {
1188  connectFilter( _patchList, _pkgList );
1189 
1190  connect( _patchList, SIGNAL( filterMatch ( const QString &, const QString &, FSize ) ),
1191  _pkgList, SLOT ( addPassiveItem( const QString &, const QString &, FSize ) ) );
1192 
1193  connect( _patchList, SIGNAL( statusChanged() ),
1194  this, SLOT ( autoResolveDependencies() ) );
1195 
1196  if ( _pkgConflictDialog )
1197  {
1198  connect( _pkgConflictDialog,SIGNAL( updatePackages() ),
1199  _patchList, SLOT ( updateItemStates() ) );
1200  }
1201 
1202  connect( this, SIGNAL( refresh() ),
1203  _patchList, SLOT ( updateItemStates() ) );
1204 
1205  }
1206 }
1207 
1208 
1209 void
1211 {
1212  QString filename = YQApplication::askForSaveFileName( QString( DEFAULT_EXPORT_FILE_NAME ), // startsWith
1213  QString( "*.xml;;*" ), // filter
1214  _( "Save Package List" ) );
1215 
1216  if ( ! filename.isEmpty() )
1217  {
1218  zypp::syscontent::Writer writer;
1219  const zypp::ResPool & pool = zypp::getZYpp()->pool();
1220 
1221  // The ZYPP obfuscated C++ contest proudly presents:
1222 
1223  for_each( pool.begin(), pool.end(),
1224  boost::bind( &zypp::syscontent::Writer::addIf,
1225  boost::ref( writer ),
1226  _1 ) );
1227  // Yuck. What a mess.
1228  //
1229  // Does anybody seriously believe this kind of thing is easier to read,
1230  // let alone use? Get real. This is an argument in favour of all C++
1231  // haters. And it's one that is really hard to counter.
1232  //
1233  // -sh 2006-12-13
1234 
1235  try
1236  {
1237  std::ofstream exportFile( toUTF8( filename ).c_str() );
1238  exportFile.exceptions( std::ios_base::badbit | std::ios_base::failbit );
1239  exportFile << writer;
1240 
1241  yuiMilestone() << "Package list exported to " << filename << endl;
1242  }
1243  catch ( std::exception & exception )
1244  {
1245  yuiWarning() << "Error exporting package list to " << filename << endl;
1246 
1247  // The export might have left over a partially written file.
1248  // Try to delete it. Don't care if it doesn't exist and unlink() fails.
1249  QFile::remove(filename);
1250 
1251  // Post error popup
1252  QMessageBox::warning( this, // parent
1253  _( "Error" ), // caption
1254  _( "Error exporting package list to %1" ).arg( filename ),
1255  QMessageBox::Ok | QMessageBox::Default, // button0
1256  Qt::NoButton, // button1
1257  Qt::NoButton ); // button2
1258  }
1259  }
1260 }
1261 
1262 
1263 void
1265 {
1266  QString filename = QFileDialog::getOpenFileName( this, _( "Load Package List" ), DEFAULT_EXPORT_FILE_NAME,
1267  "*.xml+;;*"// filter
1268  );
1269 
1270  if ( ! filename.isEmpty() )
1271  {
1272  yuiMilestone() << "Importing package list from " << filename << endl;
1273 
1274  try
1275  {
1276  std::ifstream importFile( toUTF8( filename ).c_str() );
1277  zypp::syscontent::Reader reader( importFile );
1278 
1279  //
1280  // Put reader contents into maps
1281  //
1282 
1283  typedef zypp::syscontent::Reader::Entry ZyppReaderEntry;
1284  typedef std::pair<string, ZyppReaderEntry> ImportMapPair;
1285 
1286  map<string, ZyppReaderEntry> importPkg;
1287  map<string, ZyppReaderEntry> importPatterns;
1288 
1289  for ( zypp::syscontent::Reader::const_iterator it = reader.begin();
1290  it != reader.end();
1291  ++ it )
1292  {
1293  string kind = it->kind();
1294 
1295  if ( kind == "package" ) importPkg.insert ( ImportMapPair( it->name(), *it ) );
1296  else if ( kind == "pattern" ) importPatterns.insert( ImportMapPair( it->name(), *it ) );
1297  }
1298 
1299  yuiDebug() << "Found " << importPkg.size()
1300  <<" packages and " << importPatterns.size()
1301  << " patterns in " << filename
1302  << endl;
1303 
1304 
1305  //
1306  // Set status of all patterns and packages according to import map
1307  //
1308 
1309  for ( ZyppPoolIterator it = zyppPatternsBegin();
1310  it != zyppPatternsEnd();
1311  ++it )
1312  {
1313  ZyppSel selectable = *it;
1314  importSelectable( *it, importPatterns.find( selectable->name() ) != importPatterns.end(), "pattern" );
1315  }
1316 
1317  for ( ZyppPoolIterator it = zyppPkgBegin();
1318  it != zyppPkgEnd();
1319  ++it )
1320  {
1321  ZyppSel selectable = *it;
1322  importSelectable( *it, importPkg.find( selectable->name() ) != importPkg.end(), "package" );
1323  }
1324 
1325 
1326  //
1327  // Display result
1328  //
1329 
1330  emit refresh();
1331 
1332  if ( _statusFilterView )
1333  {
1334  // Switch to "Installation Summary" filter view
1335 
1336  _filters->showPage( _statusFilterView );
1337  _statusFilterView->filter();
1338  }
1339 
1340  }
1341  catch ( const zypp::Exception & exception )
1342  {
1343  yuiWarning() << "Error reading package list from " << filename << endl;
1344 
1345  // Post error popup
1346  QMessageBox::warning( this, // parent
1347  _( "Error" ), // caption
1348  _( "Error loading package list from %1" ).arg( filename ),
1349  QMessageBox::Ok | QMessageBox::Default, // button0
1350  QMessageBox::NoButton, // button1
1351  QMessageBox::NoButton ); // button2
1352  }
1353  }
1354 }
1355 
1356 
1357 void
1359  bool isWanted,
1360  const char * kind )
1361 {
1362  ZyppStatus oldStatus = selectable->status();
1363  ZyppStatus newStatus = oldStatus;
1364 
1365  if ( isWanted )
1366  {
1367  //
1368  // Make sure this selectable does not get installed
1369  //
1370 
1371  switch ( oldStatus )
1372  {
1373  case S_Install:
1374  case S_AutoInstall:
1375  case S_KeepInstalled:
1376  case S_Protected:
1377  case S_Update:
1378  case S_AutoUpdate:
1379  newStatus = oldStatus;
1380  break;
1381 
1382  case S_Del:
1383  case S_AutoDel:
1384  newStatus = S_KeepInstalled;
1385  yuiDebug() << "Keeping " << kind << " " << selectable->name() << endl;
1386  break;
1387 
1388  case S_NoInst:
1389  case S_Taboo:
1390 
1391  if ( selectable->hasCandidateObj() )
1392  {
1393  newStatus = S_Install;
1394  yuiDebug() << "Adding " << kind << " " << selectable->name() << endl;
1395  }
1396  else
1397  {
1398  yuiDebug() << "Can't add " << kind << " " << selectable->name()
1399  << ": No candidate" << endl;
1400  }
1401  break;
1402  }
1403  }
1404  else // ! isWanted
1405  {
1406  //
1407  // Make sure this selectable does not get installed
1408  //
1409 
1410  switch ( oldStatus )
1411  {
1412  case S_Install:
1413  case S_AutoInstall:
1414  case S_KeepInstalled:
1415  case S_Protected:
1416  case S_Update:
1417  case S_AutoUpdate:
1418  newStatus = S_Del;
1419  yuiDebug() << "Deleting " << kind << " " << selectable->name() << endl;
1420  break;
1421 
1422  case S_Del:
1423  case S_AutoDel:
1424  case S_NoInst:
1425  case S_Taboo:
1426  newStatus = oldStatus;
1427  break;
1428  }
1429  }
1430 
1431  if ( oldStatus != newStatus )
1432  selectable->setStatus( newStatus );
1433 }
1434 
1435 
1436 void
1438 {
1439  if ( ! _pkgList )
1440  return;
1441 
1442  int count = _pkgList->globalSetPkgStatus( S_Update, force,
1443  true ); // countOnly
1444  yuiMilestone() << count << " pkgs found for update" << endl;
1445 
1446  if ( count >= GLOBAL_UPDATE_CONFIRMATION_THRESHOLD )
1447  {
1448  if ( QMessageBox::question( this, "", // caption
1449  // Translators: %1 is the number of affected packages
1450  _( "%1 packages will be updated" ).arg( count ),
1451  _( "&Continue" ), _( "C&ancel" ),
1452  0, // defaultButtonNumber (from 0)
1453  1 ) // escapeButtonNumber
1454  == 1 ) // "Cancel"?
1455  {
1456  return;
1457  }
1458  }
1459 
1460  (void) _pkgList->globalSetPkgStatus( S_Update, force,
1461  false ); // countOnly
1462 
1463  if ( _statusFilterView )
1464  {
1465  _filters->showPage( _statusFilterView );
1466  _statusFilterView->clear();
1467  _statusFilterView->showTransactions();
1468  _statusFilterView->filter();
1469  }
1470 }
1471 
1472 
1473 void
1475 {
1476  zypp::ResPool::repository_iterator it;
1477  _repoUpgradeLabel->setText("");
1478  _repoUpgradingLabel->setText("");
1479 
1480  // we iterate twice to show first the repo upgrades that
1481  // can be cancelled, and then the repo that can be added
1482  for ( it = zypp::getZYpp()->pool().knownRepositoriesBegin();
1483  it != zypp::getZYpp()->pool().knownRepositoriesEnd();
1484  ++it )
1485  {
1486  zypp::Repository repo(*it);
1487  // add the option to cancel the upgrade job against this
1488  // repository if there is a job for it
1489  if ( zypp::getZYpp()->resolver()->upgradingRepo(repo) )
1490  {
1491  _repoUpgradingLabel->setText(_repoUpgradingLabel->text() + _("<p><small><a href=\"repoupgraderemove:///%1\">Cancel switching</a> system packages to versions in repository %2</small></p>")
1492  .arg(fromUTF8(repo.alias().c_str()))
1493  .arg(fromUTF8(repo.name().c_str()))
1494  );
1495  }
1496  }
1497 
1498  for ( it = zypp::getZYpp()->pool().knownRepositoriesBegin();
1499  it != zypp::getZYpp()->pool().knownRepositoriesEnd();
1500  ++it )
1501  {
1502  zypp::Repository repo(*it);
1503  // add the option to upgrade to this repo packages if it is not the system
1504  // repository and there is no upgrade job in the solver for it
1505  // and the repo is the one selected right now
1506  if ( ! zypp::getZYpp()->resolver()->upgradingRepo(repo) &&
1507  ! repo.isSystemRepo() &&
1508  _repoFilterView->selectedRepo() == repo )
1509  {
1510  _repoUpgradeLabel->setText(_repoUpgradeLabel->text() + _("<p><a href=\"repoupgradeadd:///%1\">Switch system packages</a> to the versions in this repository (%2)</p>")
1511  .arg(fromUTF8(repo.alias().c_str()))
1512  .arg(fromUTF8(repo.name().c_str()))
1513  );
1514  }
1515  }
1516  _repoUpgradeLabel->setVisible(!_repoUpgradeLabel->text().isEmpty() &&
1517  _repoFilterView->isVisible() );
1518  _repoUpgradingLabel->setVisible(!_repoUpgradingLabel->text().isEmpty());
1519 }
1520 
1521 
1522 void
1524 {
1525  yuiDebug() << "link " << link << " clicked on label" << endl;
1526 
1527  QUrl url(link);
1528  if (url.scheme() == "repoupgradeadd")
1529  {
1530  yuiDebug() << "looking for repo " << url.path() << endl;
1531  std::string alias(url.path().remove(0,1).toStdString());
1532  zypp::Repository repo(zypp::getZYpp()->pool().reposFind(alias));
1533  yuiDebug() << repo << endl;
1534 
1535  if ( repo != zypp::Repository::noRepository )
1536  {
1537  zypp::getZYpp()->resolver()->addUpgradeRepo(repo);
1538  // Do not complain about vendor change when switching repos (bsc##1149391)
1539  zypp::getZYpp()->resolver()->dupSetAllowVendorChange(true);
1540  }
1541  }
1542  else if (url.scheme() == "repoupgraderemove")
1543  {
1544  std::string alias(url.path().remove(0,1).toStdString());
1545  zypp::Repository repo(zypp::getZYpp()->pool().reposFind(alias));
1546 
1547  if ( repo != zypp::Repository::noRepository )
1548  zypp::getZYpp()->resolver()->removeUpgradeRepo(repo);
1549  }
1550  else
1551  yuiDebug() << "unknown link operation " << url.scheme() << endl;
1552 
1554  emit refresh();
1555 }
1556 
1557 
1558 void
1560 {
1562 }
1563 
1564 
1565 void
1567 {
1569 }
1570 
1571 
1572 void
1574 {
1575  installSubPkgs( "-devel" );
1576 }
1577 
1578 
1579 void
1581 {
1582  installSubPkgs( "-debuginfo" );
1583 }
1584 
1585 
1586 void
1588 {
1589  installSubPkgs( "-debugsource" );
1590 }
1591 
1592 
1593 void
1595 {
1596  zypp::getZYpp()->resolver()->setIgnoreAlreadyRecommended( false );
1598 
1599  if ( _filters && _statusFilterView )
1600  {
1601  _filters->showPage( _statusFilterView );
1602  _statusFilterView->filter();
1603  }
1604 
1606  _( "Added Subpackages:" ),
1607  _( "&OK" ),
1608  QString(), // rejectButtonLabel
1609  YQPkgChangesDialog::FilterAutomatic,
1610  YQPkgChangesDialog::OptionNone ); // showIfEmpty
1611 }
1612 
1613 
1614 void
1616 {
1617  if ( _optionsMenu && _pkgList )
1618  {
1619  if ( _excludeDebugInfoPkgs )
1620  _excludeDebugInfoPkgs->enable( ! on );
1621 
1622  _pkgList->applyExcludeRules();
1623  }
1624 }
1625 
1626 
1627 void
1628 YQPackageSelector::pkgExcludeDevelChanged( bool on )
1629 {
1630  if ( _optionsMenu && _pkgList )
1631  {
1632  if ( _excludeDevelPkgs )
1633  _excludeDevelPkgs->enable( ! on );
1634 
1635  _pkgList->applyExcludeRules();
1636  }
1637 }
1638 
1639 
1640 void
1641 YQPackageSelector::pkgVerifySytemModeChanged( bool on )
1642 {
1643  zypp::getZYpp()->resolver()->setSystemVerification( on );
1644 }
1645 
1646 
1647 void
1648 YQPackageSelector::pkgInstallRecommendedChanged( bool on )
1649 {
1650  zypp::getZYpp()->resolver()->setOnlyRequires( !on );
1652 }
1653 
1654 
1655 void
1656 YQPackageSelector::pkgCleanDepsOnRemoveChanged( bool on )
1657 {
1658  zypp::getZYpp()->resolver()->setCleandepsOnRemove( on );
1660 }
1661 
1662 
1663 void
1664 YQPackageSelector::pkgAllowVendorChangeChanged( bool on )
1665 {
1666  zypp::getZYpp()->resolver()->setAllowVendorChange( on );
1667  zypp::getZYpp()->resolver()->dupSetAllowVendorChange( on ); // bsc#1170521
1669 }
1670 
1671 
1672 void
1673 YQPackageSelector::installSubPkgs( const QString & suffix )
1674 {
1675  // Find all matching packages and put them into a QMap
1676 
1677  QMap<QString, ZyppSel> subPkgs;
1678 
1679  for ( ZyppPoolIterator it = zyppPkgBegin();
1680  it != zyppPkgEnd();
1681  ++it )
1682  {
1683  QString name = (*it)->name().c_str();
1684 
1685  if ( name.endsWith( suffix ) || name.endsWith( suffix + "-32bit" ) )
1686  {
1687  subPkgs[ name ] = *it;
1688 
1689  yuiDebug() << "Found subpackage: " << name << endl;
1690  }
1691  }
1692 
1693 
1694  // Now go through all packages and look if there is a corresponding subpackage in the QMap
1695 
1696  for ( ZyppPoolIterator it = zyppPkgBegin();
1697  it != zyppPkgEnd();
1698  ++it )
1699  {
1700  QString name = (*it)->name().c_str();
1701 
1702  if ( subPkgs.contains( name + suffix ) )
1703  {
1704  QString subPkgName( name + suffix );
1705  ZyppSel subPkg = subPkgs[ subPkgName ];
1706 
1707  switch ( (*it)->status() )
1708  {
1709  case S_AutoDel:
1710  case S_NoInst:
1711  case S_Protected:
1712  case S_Taboo:
1713  case S_Del:
1714  // Don't install the subpackage
1715  yuiMilestone() << "Ignoring unwanted subpackage " << subPkgName << endl;
1716  break;
1717 
1718  case S_AutoInstall:
1719  case S_Install:
1720  case S_KeepInstalled:
1721 
1722  // Install the subpackage, but don't try to update it
1723 
1724  if ( ! subPkg->installedObj() )
1725  {
1726  subPkg->setStatus( S_Install );
1727  yuiMilestone() << "Installing subpackage " << subPkgName << endl;
1728  }
1729  break;
1730 
1731 
1732  case S_Update:
1733  case S_AutoUpdate:
1734 
1735  // Install or update the subpackage
1736 
1737  if ( ! subPkg->installedObj() )
1738  {
1739  subPkg->setStatus( S_Install );
1740  yuiMilestone() << "Installing subpackage " << subPkgName << endl;
1741  }
1742  else
1743  {
1744  subPkg->setStatus( S_Update );
1745  yuiMilestone() << "Updating subpackage " << subPkgName << endl;
1746  }
1747  break;
1748 
1749  // Intentionally omitting 'default' branch so the compiler can
1750  // catch unhandled enum states
1751  }
1752  }
1753  }
1754 
1755 
1756  if ( _filters && _statusFilterView )
1757  {
1758  _filters->showPage( _statusFilterView );
1759  _statusFilterView->filter();
1760  }
1761 
1763  _( "Added Subpackages:" ),
1764  QRegExp( ".*" + suffix + "$" ),
1765  _( "&OK" ),
1766  QString(), // rejectButtonLabel
1767  YQPkgChangesDialog::FilterAutomatic,
1768  YQPkgChangesDialog::OptionNone ); // showIfEmpty
1769 }
1770 
1771 
1772 bool
1774 {
1775  yuiMilestone() << "Checking for retracted installed packages..." << endl;
1776 
1777  for ( ZyppPoolIterator it = zyppPkgBegin(); it != zyppPkgEnd(); ++it )
1778  {
1779  if ( (*it)->hasRetractedInstalled() )
1780  return true;
1781  }
1782 
1783  yuiMilestone() << "No retracted packages installed." << endl;
1784 
1785  return false;
1786 }
1787 
1788 
1789 void
1791 {
1792  QString settingsName = "YQPackageSelector";
1793 
1794  if ( onlineUpdateMode() )
1795  settingsName = "YQOnlineUpdate";
1796 
1797  if ( updateMode() )
1798  settingsName = "YQSystemUpdate";
1799 
1800  QSettings settings( QSettings::UserScope, SETTINGS_DIR, settingsName );
1801 
1802  _showDevelAction->setChecked(settings.value( "Options/showDevelPackages", true ).toBool());
1803  pkgExcludeDevelChanged(_showDevelAction->isChecked());
1804 
1805  _showDebugAction->setChecked(settings.value( "Options/showDebugPackages", true ).toBool());
1806  pkgExcludeDebugChanged(_showDebugAction->isChecked());
1807 
1809 }
1810 
1811 
1812 void
1814 {
1815  map<string, string> sysconfig = zypp::base::sysconfig::read( PATH_TO_YAST_SYSCONFIG );
1816 
1817  bool auto_check = AUTO_CHECK_DEPENDENCIES_DEFAULT;
1818  auto it = sysconfig.find( OPTION_AUTO_CHECK );
1819 
1820  if ( it != sysconfig.end() )
1821  auto_check = it->second == "yes";
1822 
1823  _autoDependenciesAction->setChecked(auto_check);
1824 
1825  bool verify_system = zypp::getZYpp()->resolver()->systemVerification();
1826  it = sysconfig.find( OPTION_VERIFY );
1827 
1828  if ( it != sysconfig.end() )
1829  verify_system = it->second == "yes";
1830 
1831  _verifySystemModeAction->setChecked( verify_system );
1832  pkgVerifySytemModeChanged( verify_system );
1833 
1834  bool install_recommended = ! zypp::getZYpp()->resolver()->onlyRequires();
1835  it = sysconfig.find( OPTION_RECOMMENDED );
1836 
1837  if (it != sysconfig.end())
1838  install_recommended = it->second == "yes";
1839 
1840  _installRecommendedAction->setChecked( install_recommended );
1841  pkgInstallRecommendedChanged(install_recommended);
1842 
1843  bool allow_vendor_change = zypp::getZYpp()->resolver()->allowVendorChange();
1844  _allowVendorChangeAction->setChecked( allow_vendor_change );
1845  pkgAllowVendorChangeChanged( allow_vendor_change );
1846 
1847  bool clean_deps_on_remove = zypp::getZYpp()->resolver()->cleandepsOnRemove();
1848  _cleanDepsOnRemoveAction->setChecked( clean_deps_on_remove );
1849  pkgCleanDepsOnRemoveChanged( clean_deps_on_remove );
1850 }
1851 
1852 
1853 void
1855 {
1856  QString settingsName = "YQPackageSelector";
1857 
1858  if ( onlineUpdateMode() )
1859  settingsName = "YQOnlineUpdate";
1860 
1861  if ( updateMode() )
1862  settingsName = "YQSystemUpdate";
1863 
1864  QSettings settings( QSettings::UserScope, SETTINGS_DIR, settingsName );
1865 
1866  settings.setValue("Options/showDevelPackages", _showDevelAction->isChecked() );
1867  settings.setValue("Options/showDebugPackages", _showDebugAction->isChecked() );
1868 
1870 }
1871 
1872 void
1874 {
1875  try
1876  {
1877  zypp::base::sysconfig::writeStringVal( PATH_TO_YAST_SYSCONFIG,
1878  OPTION_AUTO_CHECK,
1879  ( _autoDependenciesAction->isChecked() ? "yes" : "no" ),
1880  "Automatic dependency checking");
1881  zypp::base::sysconfig::writeStringVal( PATH_TO_YAST_SYSCONFIG,
1882  OPTION_VERIFY,
1883  ( _verifySystemModeAction->isChecked() ? "yes" : "no" ),
1884  "System verification mode");
1885  zypp::base::sysconfig::writeStringVal( PATH_TO_YAST_SYSCONFIG,
1886  OPTION_RECOMMENDED,
1887  ( _installRecommendedAction->isChecked() ? "yes" : "no" ),
1888  "Install recommended packages");
1889  }
1890  catch( const std::exception &e )
1891  {
1892  yuiError() << "Writing " << PATH_TO_YAST_SYSCONFIG << " failed" << endl;
1893  }
1894 }
1895 
1897 {
1898  YQUI::ui()->busyCursor();
1899 }
1900 
1902 {
1903  YQUI::ui()->normalCursor();
1904 }
1905 
1906 
Display the description of a ZyppObj derived object along with its name and summary.
void onlineUpdateConfiguration()
Close processing and request start of the online update configuration.
void addPatchFilterView()
Add the "Patches" filter view, if it is not already there.
void showPage(QWidget *page)
Show a page.
int globalSetPkgStatus(ZyppStatus newStatus, bool force, bool countOnly)
Set the status of all packages in the pool to a new value.
Definition: YQPkgList.cc:678
void loadData()
Emitted once (!) when the dialog is about to be shown, when all widgets are created and all signal/sl...
void globalUpdatePkg()
Set the status of all installed packages (all in the pool, not only those currently displayed in the ...
void connectFilter(QWidget *filter, QWidget *pkgList, bool hasUpdateSignal=true)
Connect a filter view that provides the usual signals with a package list.
void addPage(const QString &pageLabel, QWidget *pageContent, const QString &internalName)
Add a page with a user-visible "pageLabel", a widget with the page content and an internal name (or I...
void normalCursor()
Show the standard cursor (arrow)
Filter view for package classes (categories) like suggested, recommended, orphaned etc...
zypp::Repository selectedRepo() const
Current selected repository, or if nothing is selected.
static bool any_service()
Is any enabled libzypp service present?
static int countEnabledRepositories()
Returns the number of enabled repositories.
YQPkgPatchList * patchList() const
Returns this view&#39;s selections list.
void showProducts()
Show all products in a popup dialog.
void busyCursor()
Show the busy cursor (clock)
Filter view for packages that made problems during update.
void filter()
Filter according to the view&#39;s rules and current selection.
Widget for "tabbed browsing" in packages:
static bool haveInstalledPkgs()
Returns &#39;true&#39; if there are any installed packages.
Definition: YQPkgList.cc:180
void loadCommonSettings()
loads settings that are shared with other frontends
void importSelectable(ZyppSel selectable, bool isWanted, const char *kind)
Import one selectable: Set its status according to &#39;isWanted&#39; based on its old status.
void updateRepositoryUpgradeLabel()
hides or shows the repository upgrade message
YQPkgDiskUsageList * diskUsageList() const
Return the disk usage list widget or 0 if there is none.
QWidget * rightPane() const
Return the right pane.
void currentChanged(QWidget *newPageContent)
Emitted when the current page changes.
void saveSettings()
saves settings of the checkboxes in the option menu
void saveCommonSettings()
saves settings that are shared with other frontends
int manualResolvePackageDependencies()
Resolve package dependencies manually.
bool anyRetractedPkgInstalled()
Return &#39;true&#39; if any selectable has any retracted package version installed.
void keyboardHelp()
Display online help about magic keys.
void enable(bool enable=true)
Enable or disable this exclude rule.
void accept()
Close processing and accept changes.
Display a list of zypp::Patch objects and ( below ) details about the currently selected patch...
void slotRepoUpgradeLabelLinkClicked(const QString &link)
a link in the repo upgrade label was clicked
static bool showChangesDialog(QWidget *parent, const QString &message, const QString &acceptButtonLabel, const QString &rejectButtonLabel=QString(), Filters f=FilterAutomatic, Options o=OptionAutoAcceptIfEmpty)
Static convenience method: Post a changes dialog with text &#39;message&#39;, a list of changed packages and ...
void repoManager()
Close processing and request start of the repository manager.
Display a pkg&#39;s file list.
Display a list of zypp::Package objects.
Definition: YQPkgList.h:54
void onlineSearch()
Close processing and request start of the online search.
Display a list of zypp::Pattern objects.
Filter view for searching within packages.
void symbolHelp()
Display online help about symbols (package status icons).
void installDebugInfoPkgs()
Install available -debuginfo packages for packages that are installed or marked for installation...
void connectPatchList()
Connect the patch list.
Display technical details (very much like &#39;rpm -qi&#39;) for a ZYPP object - the installed instance...
void clear()
Clears the tree-widgets content, resets the optimal column width values.
Definition: YQPkgList.cc:434
void pkgExport()
Export all current selection/package states.
void applyExcludeRules()
Apply all exclude rules of this list to all items, including those that are currently excluded...
Filter view for packages that made problems during update.
void help()
Display (generic) online help.
Package version selector: Display a list of available versions from all the different installation so...
void autoResolveDependencies()
Automatically resolve package dependencies if desired (if the "auto check" checkbox is on)...
static bool haveProblematicPackages()
Check if there are any problematic packages at all, i.e.
void addMenus()
Add pulldown menus to the menu bar.
Display a list of zypp::Selection objects.
Definition: YQPkgLangList.h:52
void clear()
Reset all check boxes (set them all to "off")
void installDevelPkgs()
Install any -devel package for packages that are installed or marked for installation.
void loadSettings()
loads settings for the checkboxes in the option menu
static void showHistoryDialog(QWidget *parent=0)
Static convenience method: Post a History dialog for pkg &#39;pkgName&#39;.
A widget to display a libzypp servic filter view.
void showTransactions()
Set up the check boxes so all pending transactions are displayed.
void refresh()
Emitted when the internal data base might have changed and a refresh of all displayed data might be n...
virtual QMenu * addAllInListSubMenu(QMenu *menu)
Add a submenu "All in this list..." to &#39;menu&#39;.
void installDebugSourcePkgs()
Install available -debugsource packages for packages that are installed or marked for installation...
virtual QMenu * addAllInListSubMenu(QMenu *menu)
Add a submenu "All in this list..." to &#39;menu&#39;.
Definition: YQPkgList.cc:501
Abstract base class for package selectors.
static void showProductDialog(QWidget *parent=0)
Static convenience method: Post a dialog with all products.
void filter()
Filter according to the view&#39;s rules and current selection.
void hotkeyInsertPatchFilterView()
Add the "Patches" filter view upon hotkey (F2).
void installSubPkgs(const QString &suffix)
Install any subpackage that ends with &#39;suffix&#39; for packages that are installed or marked for installa...
void installRecommendedPkgs()
Install recommended packages for packages that are installed.
void makeConnections()
Establish Qt signal / slot connections.
Display technical details ( very much like &#39;rpm -qi&#39; ) for a zypp::Package object - the installed ins...
void showHistory()
Show dialog for pkgmgr history.
void showAutoPkgList()
Display a list of automatically selected packages (excluding packages contained in any selections tha...
void pkgImport()
Import selection/package states.
bool reject()
Close processing and abandon changes.
int resolveDependencies()
Resolve dependencies (unconditionally) for all resolvables.
void pkgExcludeDebugChanged(bool on)
Enable or disable the package exclude rules (show or suppress -debuginfo or -devel packages) accordin...
int solveAndShowConflicts()
Run the package dependency solver for the current package set and open the conflict dialog if there a...
void globalUpdatePkgForce()
Set the status of all installed packages (all in the pool, not only those currently displayed in the ...
Display a pkg&#39;s file list.