libyui-qt-pkg  2.45.28
YQPkgVersionsView.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: YQPkgVersionsView.cc
35 
36  Author: Stefan Hundhammer <sh@suse.de>
37 
38  Textdomain "qt-pkg"
39 
40 /-*/
41 
42 #define YUILogComponent "qt-pkg"
43 
44 #include <YQZypp.h>
45 #include <zypp/Repository.h>
46 #include "YUILog.h"
47 #include <QTabWidget>
48 #include <QRegExp>
49 #include <QHeaderView>
50 #include <QStylePainter>
51 #include <QStyleOptionButton>
52 #include <QMessageBox>
53 #include <QApplication>
54 
55 
56 #include "YQPkgVersionsView.h"
57 #include "YQPkgRepoList.h"
58 #include "YQIconPool.h"
59 #include "YQSignalBlocker.h"
60 #include "YQi18n.h"
61 #include "utf8.h"
62 
63 using std::endl;
64 
66  : QScrollArea( parent )
67  , _content(0)
68  , _layout(0)
69 {
70  _selectable = 0;
71  _isMixedMultiVersion = false;
72  _parentTab = dynamic_cast<QTabWidget *> (parent);
73 
74  _buttons = new QButtonGroup(this);
75 
76  if ( _parentTab )
77  {
78  connect( _parentTab, SIGNAL( currentChanged( int ) ),
79  this, SLOT ( reload ( int ) ) );
80  }
81 }
82 
83 
85 {
86  // NOP
87 }
88 
89 
90 void
91 YQPkgVersionsView::reload( int newCurrent )
92 {
93  if ( _parentTab && _parentTab->widget( newCurrent ) == this )
94  showDetailsIfVisible( _selectable );
95 }
96 
97 
98 void
100 {
101  _selectable = selectable;
102  _isMixedMultiVersion = isMixedMultiVersion( selectable );
103 
104  if ( _parentTab ) // Is this view embedded into a tab widget?
105  {
106  if ( _parentTab->currentWidget() == this ) // Is this page the topmost?
107  showDetails( selectable );
108  }
109  else // No tab parent - simply show data unconditionally.
110  {
111  showDetails( selectable );
112  }
113 }
114 
115 
116 void
117 YQPkgVersionsView::showDetails( ZyppSel selectable )
118 {
119  _selectable = selectable;
120  _isMixedMultiVersion = isMixedMultiVersion( selectable );
121 
122  if ( ! selectable )
123  {
124  // Delete all installed items
125  qDeleteAll( _installed );
126  _installed.clear();
127 
128  _content = new QWidget( this );
129  setWidget( _content );
130  _content->show();
131  return;
132  }
133 
134  // old widget is autodestroyed by setWidget later
135  _content = new QWidget( this );
136  _layout = new QVBoxLayout( _content );
137  _content->setLayout( _layout );
138 
139  QLabel * pkgNameLabel = new QLabel( this );
140 
141  if ( ! selectable->theObj() )
142  return;
143 
144  _layout->addWidget( pkgNameLabel );
145 
146  QFont font = pkgNameLabel->font();
147  font.setBold( true );
148 
149  QFontMetrics fm( font) ;
150  font.setPixelSize( (int) ( fm.height() * 1.1 ) );
151 
152  pkgNameLabel->setFont( font );
153  pkgNameLabel->setText( fromUTF8(selectable->theObj()->name().c_str()) );
154 
155  // New scope
156  {
157  QListIterator<QAbstractButton*> it( _buttons->buttons() );
158 
159  while ( it.hasNext() )
160  {
161  delete it.next();
162  }
163  }
164 
165  // Delete all installed items
166  qDeleteAll( _installed );
167  _installed.clear();
168 
169  if ( selectable->multiversionInstall() ) // at least one (!) PoolItem is multiversion
170  {
171  //
172  // Find installed and available objects (for multiversion view)
173  //
174  {
175  zypp::ui::Selectable::picklist_iterator it = selectable->picklistBegin();
176 
177  while ( it != selectable->picklistEnd() )
178  {
179  YQPkgMultiVersion * version = new YQPkgMultiVersion( this, selectable, *it );
180 
181  _installed.push_back( version );
182  _layout->addWidget( version );
183 
184  connect( version, SIGNAL( statusChanged() ),
185  this, SIGNAL( statusChanged() ) );
186 
187  connect( this, SIGNAL( statusChanged() ),
188  version, SLOT ( update() ) );
189 
190  ++it;
191  }
192 
193  }
194  }
195  else
196  {
197  //
198  // Fill installed objects
199  //
200  {
201  zypp::ui::Selectable::installed_iterator it = selectable->installedBegin();
202 
203  while ( it != selectable->installedEnd() )
204  {
205  QString text = _( "%1-%2 from vendor %3 (installed)" )
206  .arg( fromUTF8( (*it)->edition().asString().c_str() ) )
207  .arg( fromUTF8( (*it)->arch().asString().c_str() ) )
208  .arg( fromUTF8( (*it)->vendor().c_str() ) ) ;
209 
210  QWidget * installedVersion = new QWidget( this );
211  QHBoxLayout * instLayout = new QHBoxLayout( installedVersion );
212  instLayout->setContentsMargins( 0, 0, 0, 0 );
213 
214  QLabel * icon = new QLabel( installedVersion );
215  icon->setPixmap( YQIconPool::pkgSatisfied() );
216  instLayout->addWidget( icon );
217 
218  QLabel * textLabel = new QLabel( text, installedVersion );
219  instLayout->addWidget( textLabel );
220  instLayout->addStretch();
221 
222  _installed.push_back( installedVersion );
223  _layout->addWidget( installedVersion );
224 
225  ++it;
226  }
227  }
228 
229 
230  //
231  // Fill available objects
232  //
233 
234  {
235  zypp::ui::Selectable::available_iterator it = selectable->availableBegin();
236 
237  while ( it != selectable->availableEnd() )
238  {
239  QRadioButton *radioButton = new YQPkgVersion( this, selectable, *it );
240  connect( radioButton, SIGNAL( clicked( bool ) ),
241  this, SLOT ( checkForChangedCandidate() ) );
242 
243  _buttons->addButton( radioButton );
244  _layout->addWidget( radioButton );
245 
246 
247  if ( selectable->hasCandidateObj() &&
248  selectable->candidateObj()->edition() == (*it)->edition() &&
249  selectable->candidateObj()->arch() == (*it)->arch() )
250  {
251  radioButton->setChecked(true);
252  }
253 
254  ++it;
255  }
256  }
257  }
258 
259  _layout->addStretch();
260  setWidget( _content );
261  _content->show();
262 }
263 
264 
265 void
267 {
268  QListIterator<QAbstractButton*> it( _buttons->buttons() );
269 
270  while ( it.hasNext() )
271  {
272  YQPkgVersion * versionItem = dynamic_cast<YQPkgVersion *> (it.next());
273 
274  if ( versionItem && versionItem->isChecked() )
275  {
276  ZyppObj newCandidate = versionItem->zyppObj();
277 
278  if ( _selectable && *newCandidate != _selectable->candidateObj() )
279  {
280  yuiMilestone() << "Candidate changed" << endl;
281 
282  // Change status of selectable
283 
284  ZyppStatus status = _selectable->status();
285 
286  if ( !_selectable->installedEmpty() &&
287  _selectable->installedObj()->arch() == newCandidate->arch() &&
288  _selectable->installedObj()->edition() == newCandidate->edition() )
289  {
290  // Switch back to the original instance -
291  // the version that was previously installed
292  status = S_KeepInstalled;
293  }
294  else
295  {
296  switch ( status )
297  {
298  case S_KeepInstalled:
299  case S_Protected:
300  case S_AutoDel:
301  case S_AutoUpdate:
302  case S_Del:
303  case S_Update:
304 
305  status = S_Update;
306  break;
307 
308  case S_NoInst:
309  case S_Taboo:
310  case S_Install:
311  case S_AutoInstall:
312  status = S_Install;
313  break;
314  }
315  }
316 
317  _selectable->setStatus( status );
318 
319 
320  // Set candidate
321 
322  _selectable->setCandidate( newCandidate );
323  emit candidateChanged( newCandidate );
324  return;
325  }
326  }
327  }
328 }
329 
330 
331 QSize
333 {
334  return QSize( 0, 0 );
335 }
336 
337 
338 bool
340 {
341  ZyppPoolItem poolItem = newSelected->zyppPoolItem();
342  Q_CHECK_PTR( poolItem );
343 
344  bool multiVersion = poolItem->multiversionInstall();
345 
346  yuiMilestone() << "Selected: "
347  << ( multiVersion ? "Multiversion " : "Non-Multiversion " )
348  << newSelected->text()
349  << endl;
350 
351  if ( anyMultiVersionToInstall( !multiVersion ) )
352  {
353  yuiMilestone() << "Multiversion and non-multiversion conflict!" << endl;
354  bool forceContinue = mixedMultiVersionPopup( multiVersion );
355 
356  if ( forceContinue )
357  {
358  _selectable->setPickStatus( poolItem, S_Install );
359  emit statusChanged(); // update status icons for all versions
360  }
361  else
362  {
363  // Nothing to do here: The status of this item was not changed yet;
364  // simply leave it like it was.
365  }
366 
367  return true; // handled here
368  }
369  else
370  {
371  return false; // Not handled here
372  }
373 }
374 
375 
376 bool
378 {
379  // Translators: Popup dialog text. Try to keep the lines about the same length.
380  QString msg = _( "You are trying to install multiversion-capable\n"
381  "and non-multiversion-capable versions of this\n"
382  "package at the same time." );
383  msg += "\n\n";
384 
385  if ( multiversion )
386  {
387  msg +=
388  _( "This version is multiversion-capable.\n"
389  "\n"
390  "Press \"Continue\" to install this version\n"
391  "and unselect the non-multiversion-capable version,\n"
392  "\"Cancel\" to unselect this version and keep the other one." );
393  }
394  else
395  {
396  msg +=
397  _( "This version is not multiversion-capable.\n"
398  "\n"
399  "Press \"Continue\" to install only this version\n"
400  "and unselect all other versions,\n"
401  "\"Cancel\" to unselect this version and keep the other ones." );
402  }
403 
404  // Dialog heading
405  QString heading = _( "Incompatible Package Versions" );
406 
407  int buttonNo = QMessageBox::question( 0, // parent
408  heading,
409  msg,
410  _( "C&ontinue" ), // button #0
411  _( "&Cancel" ) ); // button #1
412  yuiMilestone() << "User hit " << (buttonNo == 0 ? "[Continue]" : "[Cancel]" ) << endl;
413 
414  return buttonNo == 0;
415 }
416 
417 
418 
419 bool
421 {
422  if ( ! _selectable )
423  return false;
424 
425  zypp::ui::Selectable::available_iterator it = _selectable->availableBegin();
426 
427  while ( it != _selectable->availableEnd() )
428  {
429  if ( it->multiversionInstall() == multiversion )
430  {
431  switch ( _selectable->pickStatus( *it ) )
432  {
433  case S_Install:
434  case S_AutoInstall:
435  yuiMilestone() << "Found " << ( multiversion ? "multiversion" : "non-multiversion" )
436  << " to install" << endl;
437  return true;
438 
439  default:
440  break;
441  }
442  }
443 
444  ++it;
445  }
446 
447  yuiMilestone() << "No " << ( multiversion ? "multiversion" : "non-multiversion" )
448  << " to install" << endl;
449  return false;
450 }
451 
452 
453 void
455 {
456  if ( ! _selectable )
457  return;
458 
459  zypp::ui::Selectable::available_iterator it = _selectable->availableBegin();
460 
461  while ( it != _selectable->availableEnd() )
462  {
463  if ( it->multiversionInstall() )
464  {
465  switch ( _selectable->pickStatus( *it ) )
466  {
467  case S_Install:
468  case S_AutoInstall:
469  _selectable->setPickStatus( *it, S_NoInst );
470  yuiMilestone() << "Unselecting " << *it << endl;
471  break;
472 
473  default:
474  break;
475  }
476  }
477 
478  ++it;
479  }
480 }
481 
482 
483 bool
485 {
486  if ( ! selectable )
487  return false;
488 
489  zypp::ui::Selectable::available_iterator it = selectable->availableBegin();
490 
491  if ( it == selectable->availableEnd() )
492  return false;
493 
494  bool multiversion = it->multiversionInstall();
495 
496  while ( it != selectable->availableEnd() )
497  {
498  if ( it->multiversionInstall() != multiversion )
499  {
500  yuiMilestone() << "Mixed multiversion" << endl;
501  return true;
502  }
503 
504  ++it;
505  }
506 
507  return false;
508 }
509 
510 
511 
512 
513 
514 
515 YQPkgVersion::YQPkgVersion( QWidget * parent,
516  ZyppSel selectable,
517  ZyppObj zyppObj )
518  : QRadioButton( parent )
519  , _selectable( selectable )
520  , _zyppObj( zyppObj )
521 {
522  // Translators: %1 is a package version, %2 the package architecture,
523  // %3 describes the repository where it comes from,
524  // %4 is the repository's priority
525  // %5 is the vendor of the package
526  // Examples:
527  // 2.5.23-i568 from Packman with priority 100 and vendor openSUSE
528  // 3.17.4-i386 from openSUSE-11.1 update repository with priority 20 and vendor openSUSE
529  // ^^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^^^^^^^
530  // %1 %2 %3 %4 %5
531  setText( _( "%1-%2 from %3 with priority %4 and vendor %5" )
532  .arg( fromUTF8( zyppObj->edition().asString().c_str() ) )
533  .arg( fromUTF8( zyppObj->arch().asString().c_str() ) )
534  .arg( fromUTF8( zyppObj->repository().info().name().c_str() ) )
535  .arg( zyppObj->repository().info().priority() )
536  .arg( fromUTF8( zyppObj->vendor().c_str() ) ) );
537 }
538 
539 
541 {
542  // NOP
543 }
544 
545 
546 QString
548 {
549  QString tip;
550 
551  if ( *zyppObj() == selectable()->installedObj() )
552  tip = _( "This version is installed in your system." );
553 
554  return tip;
555 }
556 
557 
558 
559 
561  ZyppSel selectable,
562  ZyppPoolItem zyppPoolItem )
563  : QCheckBox( parent )
564  , _parent( parent )
565  , _selectable( selectable )
566  , _zyppPoolItem( zyppPoolItem )
567 {
568  setText (_( "%1-%2 from %3 with priority %4 and vendor %5" )
569  .arg( fromUTF8( zyppPoolItem->edition().asString().c_str() ) )
570  .arg( fromUTF8( zyppPoolItem->arch().asString().c_str() ) )
571  .arg( fromUTF8( zyppPoolItem->repository().info().name().c_str() ) )
572  .arg( zyppPoolItem->repository().info().priority() )
573  .arg( fromUTF8( zyppPoolItem->vendor().c_str() ) ));
574 
575  connect( this, SIGNAL( toggled( bool) ),
576  this, SLOT ( slotIconClicked() ) );
577 }
578 
579 
581 {
582  // NOP
583 }
584 
585 
586 void YQPkgMultiVersion::slotIconClicked()
587 {
588  {
589  YQSignalBlocker sigBlocker( this ); // prevent checkmark, we draw the status icons ourselves
590  setChecked( false );
591  }
592  cycleStatus();
593 }
594 
595 
597 {
598 
599  ZyppStatus oldStatus = _selectable->pickStatus( _zyppPoolItem );
600  ZyppStatus newStatus = oldStatus;
601 
602  switch ( oldStatus )
603  {
604  case S_Install:
605  case S_AutoInstall:
606  case S_Protected:
607  newStatus = S_NoInst;
608  break;
609 
610  case S_KeepInstalled:
611  case S_Update:
612  case S_AutoUpdate:
613  newStatus = S_Del;
614  break;
615 
616 
617  case S_Del:
618  case S_AutoDel:
619  newStatus = S_KeepInstalled;
620  break;
621 
622  case S_NoInst:
623  case S_Taboo:
624  newStatus = S_Install;
625  break;
626  }
627 
628  bool handled = false;
629 
630  if ( _parent->isMixedMultiVersion() &&
631  newStatus == S_Install &&
632  oldStatus != newStatus )
633  {
634  handled = _parent->handleMixedMultiVersion( this );
635  }
636 
637  if ( ! handled )
638  setStatus( newStatus );
639 
640  yuiMilestone() << "oldStatus: " << oldStatus << endl;
641  ZyppStatus actualStatus = _selectable->pickStatus( _zyppPoolItem );
642 
643  if ( actualStatus != newStatus )
644  yuiWarning() << "FAILED to set new status: " << newStatus
645  << " actual Status: " << actualStatus << endl;
646  else
647  yuiMilestone() << "newStatus:" << newStatus << endl;
648 
649  if ( oldStatus != actualStatus )
650  {
651  update();
652  emit statusChanged();
653  }
654 }
655 
656 
657 void YQPkgMultiVersion::setStatus( ZyppStatus newStatus )
658 {
659  yuiMilestone() << "Setting pick status to " << newStatus << endl;
660  _selectable->setPickStatus( _zyppPoolItem, newStatus );
661 }
662 
663 
664 void YQPkgMultiVersion::paintEvent(QPaintEvent *)
665 {
666  // draw the usual checkbox
667  QStylePainter p(this);
668  QStyleOptionButton opt;
669  initStyleOption(&opt);
670  p.drawControl(QStyle::CE_CheckBox, opt);
671 
672 
673  // calculate position and draw the status icon
674  QRect elementRect = style()->subElementRect ( QStyle::SE_CheckBoxIndicator, &opt);
675  QPixmap icon = statusIcon( _selectable->pickStatus(_zyppPoolItem) );
676 
677  QPoint start = elementRect.center() - icon.rect().center();
678  QRect rect = QRect(start.x(), start.y(), icon.width(), icon.height());
679 
680  p.drawItemPixmap( rect, 0, icon );
681 }
682 
683 
684 QPixmap YQPkgMultiVersion::statusIcon( ZyppStatus status )
685 {
686  QPixmap icon = YQIconPool::pkgNoInst();
687 
688  switch ( status )
689  {
690  case S_Del: icon = YQIconPool::pkgDel(); break;
691  case S_Install: icon = YQIconPool::pkgInstall(); break;
692  case S_KeepInstalled: icon = YQIconPool::pkgKeepInstalled(); break;
693  case S_NoInst: icon = QPixmap(); break;
694  case S_Protected: icon = YQIconPool::pkgProtected(); break;
695  case S_Taboo: icon = YQIconPool::pkgTaboo(); break;
696  case S_Update: icon = YQIconPool::pkgUpdate(); break;
697 
698  case S_AutoDel: icon = YQIconPool::pkgAutoDel(); break;
699  case S_AutoInstall: icon = YQIconPool::pkgAutoInstall(); break;
700  case S_AutoUpdate: icon = YQIconPool::pkgAutoUpdate(); break;
701 
702  // Intentionally omitting 'default' branch so the compiler can
703  // catch unhandled enum states
704  }
705  return icon;
706 }
707 
708 
709 
ZyppPoolItem zyppPoolItem() const
Returns the original ZYPP object.
ZyppObj zyppObj() const
Returns the original ZYPP object.
virtual QString toolTip(int column)
Returns a tool tip text for a specific column of this item.
bool isMixedMultiVersion() const
Return the cached value for the current selectable.
YQPkgMultiVersion(YQPkgVersionsView *parent, ZyppSel selectable, ZyppPoolItem zyppPoolItem)
Constructor.
YQPkgVersion(QWidget *parent, ZyppSel selectable, ZyppObj zyppObj)
Constructor.
void showDetailsIfVisible(ZyppSel selectable)
Show details for the specified package.
virtual ~YQPkgVersion()
Destructor.
virtual ~YQPkgMultiVersion()
Destructor.
YQPkgVersionsView(QWidget *parent)
Constructor.
Package version selector: Display a list of available versions from all the different installation so...
virtual QSize minimumSizeHint() const
Returns the minimum size required for this widget.
void paintEvent(QPaintEvent *)
Paints checkboxes with status icons instead of a checkmark.
void checkForChangedCandidate()
Check for changed candidates.
bool anyMultiVersionToInstall(bool multiversion) const
Check if any package version is marked for installation where its &#39;multiversion&#39; flag is set to &#39;mult...
bool mixedMultiVersionPopup(bool multiversion) const
Ask user if he really wants to install incompatible package versions.
void unselectAllMultiVersion()
Unselect all multiversion package versions.
void candidateChanged(ZyppObj newCandidate)
Emitted when the user changes the candidate.
virtual ~YQPkgVersionsView()
Destructor.
bool handleMixedMultiVersion(YQPkgMultiVersion *newSelected)
Negotiate between multiversion and non-multiversion packages if there are both kinds in that selectab...
ZyppSel selectable() const
Returns the original ZYPP selectable.
void statusChanged()
Emitted when the status of this package version is changed.
void cycleStatus()
Cycle the package status to the next valid value.
static bool isMixedMultiVersion(ZyppSel selectable)
Return &#39;true&#39; if &#39;selectable&#39; has mixed multiversion flags, &#39;false&#39; if all its pool items are of the ...
void statusChanged()
Emitted when the status of any package changed.
void reload(int newCurrent)
Show data for the current package.
void showDetails(ZyppSel selectable)
Show details for the specified package.