libyui-qt-pkg  2.45.13.1
YQPkgConflictList.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: YQPkgConflictList.cc
35 
36  Author: Stefan Hundhammer <sh@suse.de>
37 
38  Textdomain "qt-pkg"
39 
40 /-*/
41 
42 #include <QPainter>
43 #include <QPixmap>
44 #include <QDateTime>
45 #include <QMessageBox>
46 #include <QRadioButton>
47 #include <QList>
48 #include <QToolTip>
49 #include <QDebug>
50 #include <QVBoxLayout>
51 
52 #include <errno.h>
53 
54 #define YUILogComponent "qt-pkg"
55 #include "YUILog.h"
56 
57 #include <zypp/ZYppFactory.h>
58 #include "YQPkgConflictList.h"
59 #include "YQPkgConflictDialog.h"
60 #include "YQIconPool.h"
61 
62 #include "YQApplication.h"
63 #include "YQUI.h"
64 #include "YQi18n.h"
65 #include "utf8.h"
66 
67 using std::list;
68 using std::string;
69 
70 
71 #define LIST_SPLIT_THRESHOLD 8
72 
73 #define RED QColor( 0xC0, 0, 0 )
74 #define BRIGHT_RED QColor( 0xFF, 0, 0 )
75 #define BLUE QColor( 0, 0, 0xC0 )
76 #define LIGHT_BLUE QColor( 0xE0, 0xE0, 0xF8 )
77 #define LIGHT_GREY QColor( 0xE0, 0xE0, 0xE0 )
78 #define MAGENTA Qt::magenta
79 #define DEEP_ORANGE QColor( 0xFF, 0x80, 0x20 )
80 #define LIGHT_ORANGE QColor( 0xFF, 0xC0, 0x50 )
81 
82 
84  : QScrollArea( parent ), _layout( 0 )
85 {
86  setWidget( new QFrame( this ) );
87  _layout = new QVBoxLayout;
88  widget()->setLayout( _layout );
89  clear();
90 
91  widget()->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred );
92 }
93 
94 
96 {
97  // NOP
98 }
99 
100 void
101 YQPkgConflictList::clear()
102 {
103  YQPkgConflict * conflict;
104 
105  foreach( conflict, _conflicts )
106  {
107  _layout->removeWidget( conflict );
108  delete conflict;
109  }
110  _conflicts.clear();
111 
112  // kill the stretch item, too
113  delete _layout->takeAt( 0 );
114 }
115 
116 void
117 YQPkgConflictList::fill( zypp::ResolverProblemList problemList )
118 {
119  clear();
120  string text;
121 
122  zypp::ResolverProblemList::iterator it = problemList.begin();
123 
124  while ( it != problemList.end() )
125  {
126  YQPkgConflict *conflict = new YQPkgConflict( widget(), *it );
127  Q_CHECK_PTR( conflict );
128 
129  connect( conflict, SIGNAL( expanded() ),
130  SLOT( relayout() ) );
131  _layout->addWidget( conflict );
132  _conflicts.push_back( conflict );
133  ++it;
134  }
135  _layout->addStretch( 1 );
136  relayout();
137 }
138 
139 void YQPkgConflictList::relayout()
140 {
141  // for some weird reason, the layout's minSize is still 18x18 even after 3000 pixels
142  // inserted, so we have to do the math on our own
143  QSize minSize = QSize( _layout->margin() * 2, _layout->margin() * 2 );
144 
145  YQPkgConflict * conflict;
146 
147  foreach( conflict, _conflicts )
148  {
149  minSize = minSize.expandedTo( conflict->minimumSizeHint() );
150  minSize.rheight() += conflict->minimumSizeHint().height() + _layout->spacing();
151  }
152 
153  widget()->resize( minSize );
154 }
155 
156 void
158 {
159  zypp::ProblemSolutionList userChoices;
160  YQPkgConflict * conflict;
161 
162  foreach( conflict, _conflicts )
163  {
164  zypp::ProblemSolution_Ptr userChoice = conflict->userSelectedResolution();
165 
166  if ( userChoice )
167  userChoices.push_back( userChoice );
168  }
169 
170  zypp::getZYpp()->resolver()->applySolutions( userChoices );
171  emit updatePackages();
172 }
173 
174 
175 void
177 {
178  QString filename = YQApplication::askForSaveFileName( "conflicts.txt", // startsWith
179  "*.txt", // filter
180  _( "Save Conflicts List" ) );
181  if ( ! filename.isEmpty() )
182  saveToFile( filename, true );
183 }
184 
185 
186 void
187 YQPkgConflictList::saveToFile( const QString filename, bool interactive ) const
188 {
189  // Open file
190  QFile file(filename);
191 
192  if ( ! file.open(QIODevice::WriteOnly) )
193  {
194  yuiError() << "Can't open file " << filename << std::endl;
195 
196  if ( interactive )
197  {
198  // Post error popup.
199 
200  QMessageBox::warning( 0, // parent
201  _( "Error" ), // caption
202  _( "Cannot open file %1" ).arg( filename ),
203  QMessageBox::Ok | QMessageBox::Default, // button0
204  QMessageBox::NoButton, // button1
205  QMessageBox::NoButton ); // button2
206  }
207  return;
208  }
209 
210 
211  // Write header
212 
213  QString header = "#### YaST2 conflicts list - generated ";
214  header += QDateTime::currentDateTime().toString( "yyyy-MM-dd hh:mm:ss" );
215  header += " ####\n\n";
216 
217  file.write(header.toUtf8());
218 
219  YQPkgConflict * conflict;
220 
221  foreach( conflict, _conflicts )
222  {
223  conflict->saveToFile( file );
224  }
225 
226 
227  // Write footer
228 
229  file.write("\n#### YaST2 conflicts list END ###\n" );
230 
231 
232  // Clean up
233 
234  if ( file.isOpen() )
235  file.close();
236 }
237 
238 
239 
240 
241 
242 
244  zypp::ResolverProblem_Ptr problem )
245  : QFrame( parent )
246  , _problem( problem )
247  , _resolutionsHeader( 0 )
248 {
249  _layout = new QVBoxLayout( this );
250  _layout->setSpacing( 0 );
251  _layout->setMargin( 0 );
252 
253  formatHeading();
254 
255  QLabel * detailsLabel = new QLabel( fromUTF8 ( _problem->details() ), this );
256  _layout->addWidget( detailsLabel );
257 
258  setProperty( "class", "conflict" );
259  addSolutions();
260  setMinimumSize( _layout->minimumSize() );
261  setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
262 }
263 
264 
265 void
267 {
268  QFrame * frame = new QFrame( this );
269  frame->setProperty( "class", "conflict-frame" );
270 
271  QHBoxLayout * hbox = new QHBoxLayout( frame );
272 
273  QLabel * pix = new QLabel( this );
274  pix->setPixmap( YQIconPool::normalPkgConflict() );
275  hbox->addWidget( pix );
276 
277  QString text = fromUTF8( problem()->description() );
278  QLabel * heading = new QLabel( text, this );
279  heading->setProperty( "class", "conflict-heading" );
280  heading->setStyleSheet( "font-size: +2; font: bold;" );
281  hbox->addWidget( heading );
282 
283  hbox->addStretch( 1 );
284 
285  _layout->addWidget( frame );
286 }
287 
288 
289 void
291 {
292  _resolutionsHeader = new QLabel( _( "Conflict Resolution:" ), this );
293  _layout->addWidget( _resolutionsHeader );
294 
295  QHBoxLayout *hbox = new QHBoxLayout();
296  hbox->addSpacing( 20 );
297 
298  QVBoxLayout *vbox = new QVBoxLayout();
299  hbox->addLayout( vbox );
300  _layout->addLayout( hbox );
301 
302  zypp::ProblemSolutionList solutions = problem()->solutions();
303  zypp::ProblemSolutionList::iterator it = solutions.begin();
304 
305  int n=0;
306 
307  while ( it != solutions.end() )
308  {
309  ++n;
310  QString shortcut = "" + QString( (n<10)?"&":"" ) + QString::number(n) + ": ";
311 
312  QRadioButton * solutionButton = new QRadioButton( shortcut + fromUTF8( ( *it )->description() ), this );
313  vbox->addWidget( solutionButton );
314  _solutions[ solutionButton ] = *it;
315 
316  QString details = fromUTF8( ( *it )->details() );
317 
318  if ( ! details.isEmpty() )
319  {
320  QStringList lines = details.split( "\n" );
321 
322  if ( lines.count() > 7 )
323  {
324  details = "<qt>";
325 
326  for ( int i = 0; i < 4; i++ )
327  details += lines[i] + "<br>\n";
328 
329  details += _( "<a href='/'>%1 more...</a>" ).arg( lines.count() - 4 );
330  }
331 
332  QLabel * detailsLabel = new QLabel( details, this );
333 
334  connect( detailsLabel, SIGNAL( linkActivated ( const QString & ) ),
335  this, SLOT ( detailsExpanded() ) );
336 
337  connect( detailsLabel, SIGNAL( linkHovered ( const QString & ) ),
338  this, SLOT ( detailsTooltip() ) );
339 
340  QHBoxLayout * hbox = new QHBoxLayout();
341  hbox->addSpacing( 15 );
342  hbox->addWidget( detailsLabel );
343  vbox->addLayout( hbox );
344  _details[ detailsLabel ] = *it;
345  }
346 
347  ++it;
348  }
349 }
350 
351 void
352 YQPkgConflict::detailsExpanded()
353 {
354  QLabel * obj = qobject_cast<QLabel*>( sender() );
355 
356  if ( !obj || ! _details.contains( obj ) )
357  return;
358 
359  QSize _size = size();
360  int oldHeight = obj->height();
361  obj->setText( fromUTF8( _details[obj]->details() ) );
362 
363  resize( _size.width(), _size.height() + ( obj->minimumSizeHint().height() - oldHeight ) );
364  emit expanded();
365 }
366 
367 
368 zypp::ProblemSolution_Ptr
370 {
371  QMap<QRadioButton*, zypp::ProblemSolution_Ptr>::iterator it;
372 
373  for ( it = _solutions.begin(); it != _solutions.end(); ++it )
374  {
375  QRadioButton *button = it.key();
376  if ( !button->isChecked() )
377  continue;
378  zypp::ProblemSolution_Ptr solution = it.value();
379 
380  yuiMilestone() << "User selected resolution \""<< solution->description()
381  <<"\"" << std::endl;
382  return solution;
383  }
384 
385  return zypp::ProblemSolution_Ptr(); // Null pointer
386 }
387 
388 
389 void
390 YQPkgConflict::saveToFile( QFile &file ) const
391 {
392  if ( ! file.isOpen() )
393  return;
394 
395  // Write item
396 
397  QMap<QRadioButton*, zypp::ProblemSolution_Ptr>::const_iterator it;
398 
399  file.write( problem()->description().c_str() );
400  file.write( "\n" );
401  file.write( problem()->details().c_str() );
402  file.write( "\n" );
403 
404  QString buffer;
405 
406  for ( it = _solutions.begin(); it != _solutions.end(); ++it )
407  {
408  QRadioButton *button = it.key();
409  zypp::ProblemSolution_Ptr solution = it.value();
410  buffer.sprintf( " [%c] %s\n", button->isChecked() ? 'x' : ' ', qPrintable( fromUTF8( solution->description() ) ) );
411  buffer += fromUTF8( solution->details() );
412  buffer += "\n";
413  file.write( buffer.toUtf8() );
414  }
415 
416  file.write( "\n\n" );
417 }
418 
419 #include "YQPkgConflictList.moc"
YQPkgConflictList(QWidget *parent)
Constructor.
void applyResolutions()
Apply the choices the user made.
void saveToFile(const QString filename, bool interactive) const
Save the conflict list in its current state to a file.
void saveToFile(QFile &file) const
save one item to file.
zypp::ResolverProblem_Ptr problem() const
Returns the corresponding ResolverProblem.
zypp::ProblemSolution_Ptr userSelectedResolution()
Returns the resolution the user selected or 0 if he didn&#39;t select one.
void formatHeading()
Format the text heading line for this item.
virtual ~YQPkgConflictList()
Destructor.
void askSaveToFile() const
Ask for a file name and save the current conflict list to file.
void fill(zypp::ResolverProblemList problemList)
Fill the list with the specified problems.
YQPkgConflict(QWidget *parent, zypp::ResolverProblem_Ptr problem)
Constructor.
Root item for each individual conflict.
void updatePackages()
Update package states - they may have changed.
void addSolutions()
Add suggestions how to resolve this conflict.