libyui-qt-pkg  2.42.13
 All Classes Functions Variables Enumerations
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  frame->setStyleSheet( "background-color: " +
271  QApplication::palette().color( QPalette::Active, QPalette::Base ).name() +
272  ";" );
273 
274  QHBoxLayout * hbox = new QHBoxLayout( frame );
275 
276  QLabel * pix = new QLabel( this );
277  pix->setPixmap( YQIconPool::normalPkgConflict() );
278  hbox->addWidget( pix );
279 
280  QString text = fromUTF8( problem()->description() );
281  QLabel * heading = new QLabel( text, this );
282  heading->setProperty( "class", "conflict-heading" );
283  heading->setStyleSheet( "font-size: +2; color: red; font: bold;" );
284  hbox->addWidget( heading );
285 
286  hbox->addStretch( 1 );
287 
288  _layout->addWidget( frame );
289 }
290 
291 
292 void
294 {
295  _resolutionsHeader = new QLabel( _( "Conflict Resolution:" ), this );
296  _layout->addWidget( _resolutionsHeader );
297 
298  QHBoxLayout *hbox = new QHBoxLayout();
299  hbox->addSpacing( 20 );
300 
301  QVBoxLayout *vbox = new QVBoxLayout();
302  hbox->addLayout( vbox );
303  _layout->addLayout( hbox );
304 
305  zypp::ProblemSolutionList solutions = problem()->solutions();
306  zypp::ProblemSolutionList::iterator it = solutions.begin();
307 
308  int n=0;
309 
310  while ( it != solutions.end() )
311  {
312  ++n;
313  QString shortcut = "" + QString( (n<10)?"&":"" ) + QString::number(n) + ": ";
314 
315  QRadioButton * solutionButton = new QRadioButton( shortcut + fromUTF8( ( *it )->description() ), this );
316  vbox->addWidget( solutionButton );
317  _solutions[ solutionButton ] = *it;
318 
319  QString details = fromUTF8( ( *it )->details() );
320 
321  if ( ! details.isEmpty() )
322  {
323  QStringList lines = details.split( "\n" );
324 
325  if ( lines.count() > 7 )
326  {
327  details = "<qt>";
328 
329  for ( int i = 0; i < 4; i++ )
330  details += lines[i] + "<br>\n";
331 
332  details += _( "<a href='/'>%1 more...</a>" ).arg( lines.count() - 4 );
333  }
334 
335  QLabel * detailsLabel = new QLabel( details, this );
336 
337  connect( detailsLabel, SIGNAL( linkActivated ( const QString & ) ),
338  this, SLOT ( detailsExpanded() ) );
339 
340  connect( detailsLabel, SIGNAL( linkHovered ( const QString & ) ),
341  this, SLOT ( detailsTooltip() ) );
342 
343  QHBoxLayout * hbox = new QHBoxLayout();
344  hbox->addSpacing( 15 );
345  hbox->addWidget( detailsLabel );
346  vbox->addLayout( hbox );
347  _details[ detailsLabel ] = *it;
348  }
349 
350  ++it;
351  }
352 }
353 
354 void
355 YQPkgConflict::detailsExpanded()
356 {
357  QLabel * obj = qobject_cast<QLabel*>( sender() );
358 
359  if ( !obj || ! _details.contains( obj ) )
360  return;
361 
362  QSize _size = size();
363  int oldHeight = obj->height();
364  obj->setText( fromUTF8( _details[obj]->details() ) );
365 
366  resize( _size.width(), _size.height() + ( obj->minimumSizeHint().height() - oldHeight ) );
367  emit expanded();
368 }
369 
370 
371 zypp::ProblemSolution_Ptr
373 {
374  QMap<QRadioButton*, zypp::ProblemSolution_Ptr>::iterator it;
375 
376  for ( it = _solutions.begin(); it != _solutions.end(); ++it )
377  {
378  QRadioButton *button = it.key();
379  if ( !button->isChecked() )
380  continue;
381  zypp::ProblemSolution_Ptr solution = it.value();
382 
383  yuiMilestone() << "User selected resolution \""<< solution->description()
384  << "\" for problem \"" << solution->problem()->description()
385  <<"\"" << std::endl;
386  return solution;
387  }
388 
389  return zypp::ProblemSolution_Ptr(); // Null pointer
390 }
391 
392 
393 void
394 YQPkgConflict::saveToFile( QFile &file ) const
395 {
396  if ( ! file.isOpen() )
397  return;
398 
399  // Write item
400 
401  QMap<QRadioButton*, zypp::ProblemSolution_Ptr>::const_iterator it;
402 
403  file.write( problem()->description().c_str() );
404  file.write( "\n" );
405  file.write( problem()->details().c_str() );
406  file.write( "\n" );
407 
408  QString buffer;
409 
410  for ( it = _solutions.begin(); it != _solutions.end(); ++it )
411  {
412  QRadioButton *button = it.key();
413  zypp::ProblemSolution_Ptr solution = it.value();
414  buffer.sprintf( " [%c] %s\n", button->isChecked() ? 'x' : ' ', qPrintable( fromUTF8( solution->description() ) ) );
415  buffer += fromUTF8( solution->details() );
416  buffer += "\n";
417  file.write( buffer.toUtf8() );
418  }
419 
420  file.write( "\n\n" );
421 }
422 
423 #include "YQPkgConflictList.moc"
YQPkgConflictList(QWidget *parent)
void saveToFile(const QString filename, bool interactive) const
void saveToFile(QFile &file) const
zypp::ResolverProblem_Ptr problem() const
zypp::ProblemSolution_Ptr userSelectedResolution()
virtual ~YQPkgConflictList()
void askSaveToFile() const
void fill(zypp::ResolverProblemList problemList)
YQPkgConflict(QWidget *parent, zypp::ResolverProblem_Ptr problem)
Root item for each individual conflict.