- Don't create layouts with parent. Qt 4.x automatically reparents
[duncan/yast2-qt4.git] / src / pkg / YQPackageSelectorBase.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                        (C) SuSE GmbH |
11 \----------------------------------------------------------------------/
12
13   File:       YQPackageSelectorBase.cc
14
15   Author:     Stefan Hundhammer <sh@suse.de>
16
17   Textdomain "packages-qt"
18
19 /-*/
20
21 #include <QMessageBox>
22 #include <QKeyEvent>
23
24 #define y2log_component "qt-pkg"
25 #include <ycp/y2log.h>
26
27 #include <QAction>
28 #include <QVBoxLayout>
29 #include <QHBoxLayout>
30 #include "QY2LayoutUtils.h"
31
32 #include "YQPackageSelectorBase.h"
33 #include "YQPkgChangesDialog.h"
34 #include "YQPkgConflictDialog.h"
35 #include "YQPkgDiskUsageList.h"
36 #include "YQPkgDiskUsageWarningDialog.h"
37 #include "YQPkgTextDialog.h"
38 #include "YQPkgObjList.h"
39
40 #include "YQDialog.h"
41 #include "utf8.h"
42 #include "YQApplication.h"
43 #include "YQUI.h"
44 #include "YEvent.h"
45 #include "YQi18n.h"
46
47
48 using std::max;
49 using std::string;
50
51
52 YQPackageSelectorBase::YQPackageSelectorBase( YWidget * parent,
53                                               long      modeFlags )
54     : QFrame( (QWidget *) parent->widgetRep() )
55     , YPackageSelector( parent, modeFlags )
56 {
57     setWidgetRep( this );
58
59 //     QHBoxLayout *layout = new QHBoxLayout();
60 //     setLayout(layout);
61
62     _showChangesDialog          = false;
63     _pkgConflictDialog          = 0;
64     _diskUsageList              = 0;
65     _pkgConflictDialog          = 0;
66
67     YQUI::setTextdomain( "packages-qt" );
68     setFont( YQUI::yqApp()->currentFont() );
69
70     _pkgConflictDialog = new YQPkgConflictDialog( this );
71     Q_CHECK_PTR( _pkgConflictDialog );
72
73     QString label = _( "Reset &Ignored Dependency Conflicts" );
74     _actionResetIgnoredDependencyProblems = new QAction( label, this);
75     _actionResetIgnoredDependencyProblems->setShortcut((QKeySequence) 0);
76     //_actionResetIgnoredDependencyProblems->setMenuRole(QAction::TextHeuristicRole);
77     Q_CHECK_PTR( _actionResetIgnoredDependencyProblems );
78
79     connect( _actionResetIgnoredDependencyProblems, SIGNAL( activated() ),
80              this,                                  SLOT  ( resetIgnoredDependencyProblems() ) );
81
82     zyppPool().saveState<zypp::Package  >();
83     zyppPool().saveState<zypp::Pattern  >();
84     zyppPool().saveState<zypp::Selection>();
85     zyppPool().saveState<zypp::Language >();
86     zyppPool().saveState<zypp::Patch    >();
87
88
89     // Install event handler to handle WM_CLOSE like "Cancel"
90     topLevelWidget()->installEventFilter( this );
91
92     y2milestone( "PackageSelectorBase init done" );
93 }
94
95
96 YQPackageSelectorBase::~YQPackageSelectorBase()
97 {
98     y2milestone( "Destroying PackageSelector" );
99 }
100
101
102 int
103 YQPackageSelectorBase::resolveDependencies()
104 {
105     if ( ! _pkgConflictDialog )
106     {
107         y2error( "No package conflict dialog existing" );
108         return QDialog::Accepted;
109     }
110
111
112     YQUI::ui()->busyCursor();
113     emit resolvingStarted();
114
115     int result = _pkgConflictDialog->solveAndShowConflicts();
116
117     emit resolvingFinished();
118     YQUI::ui()->normalCursor();
119
120     return result;
121 }
122
123
124 int
125 YQPackageSelectorBase::verifySystem()
126 {
127     if ( ! _pkgConflictDialog )
128     {
129         y2error( "No package conflict dialog existing" );
130         return QDialog::Accepted;
131     }
132
133
134     YQUI::ui()->busyCursor();
135     int result = _pkgConflictDialog->verifySystem();
136     YQUI::ui()->normalCursor();
137
138     if ( result == QDialog::Accepted )
139     {
140         QMessageBox::information( this, "",
141                                   _( "System dependencies verify OK." ),
142                                   QMessageBox::Ok );
143     }
144
145     return result;
146 }
147
148
149 int
150 YQPackageSelectorBase::checkDiskUsage()
151 {
152     if ( ! _diskUsageList )
153     {
154         return QDialog::Accepted;
155     }
156
157     if ( ! _diskUsageList->overflowWarning.inRange() )
158         return QDialog::Accepted;
159
160     QString msg =
161         // Translators: RichText ( HTML-like ) format
162         "<p><b>" + _( "Error: Out of disk space!" ) + "</b></p>"
163         + _( "<p>"
164              "You can choose to install anyway if you know what you are doing, "
165              "but you risk getting a corrupted system that requires manual repairs. "
166              "If you are not absolutely sure how to handle such a case, "
167              "press <b>Cancel</b> now and deselect some packages."
168              "</p>" );
169
170     return YQPkgDiskUsageWarningDialog::diskUsageWarning( msg,
171                                                           100, _( "C&ontinue Anyway" ), _( "&Cancel" ) );
172
173 }
174
175
176
177 void
178 YQPackageSelectorBase::showAutoPkgList()
179 {
180     resolveDependencies();
181
182     // Show which packages are installed/deleted automatically
183     QString msg =
184         "<p><b>"
185         // Dialog header
186         + _( "Automatic Changes" )
187         + "</b></p>"
188         // Detailed explanation ( automatic word wrap! )
189         + "<p>"
190         + _( "In addition to your manual selections, the following packages"
191              " have been changed to resolve dependencies:" )
192         + "<p>";
193
194     YQPkgChangesDialog::showChangesDialog( msg,
195                                            _( "&OK" ),
196                                            QString::null,       // rejectButtonLabel
197                                            true );              // showIfEmpty
198 }
199
200
201
202 void
203 YQPackageSelectorBase::reject()
204 {
205     bool changes =
206         zyppPool().diffState<zypp::Package  >() ||
207         zyppPool().diffState<zypp::Pattern  >() ||
208         zyppPool().diffState<zypp::Selection>() ||
209         zyppPool().diffState<zypp::Language >() ||
210         zyppPool().diffState<zypp::Patch    >();
211
212     if ( changes )
213     {
214         if ( zyppPool().diffState<zypp::Package>() )
215             y2milestone( "diffState() reports changed packages" );
216
217         if ( zyppPool().diffState<zypp::Pattern>() )
218             y2milestone( "diffState() reports changed patterns" );
219
220         if ( zyppPool().diffState<zypp::Selection>() )
221             y2milestone( "diffState() reports changed selections" );
222
223         if ( zyppPool().diffState<zypp::Language>() )
224             y2milestone( "diffState() reports changed languages" );
225
226         if ( zyppPool().diffState<zypp::Patch>() )
227             y2milestone( "diffState() reports changed patches" );
228     }
229
230     if ( ! changes ||
231          ( QMessageBox::warning( this, "",
232                                  _( "Abandon all changes?" ),
233                                  _( "&OK" ), _( "&Cancel" ), "",
234                                  1, // defaultButtonNumber (from 0)
235                                  1 ) // escapeButtonNumber
236            == 0 )       // Proceed upon button #0 ( OK )
237          )
238     {
239         zyppPool().restoreState<zypp::Package  >();
240         zyppPool().restoreState<zypp::Pattern  >();
241         zyppPool().restoreState<zypp::Selection>();
242         zyppPool().restoreState<zypp::Language >();
243         zyppPool().restoreState<zypp::Patch    >();
244
245         y2milestone( "Closing PackageSelector with \"Cancel\"" );
246         YQUI::ui()->sendEvent( new YCancelEvent() );
247     }
248 }
249
250
251 void
252 YQPackageSelectorBase::accept()
253 {
254     bool confirmedAllLicenses;
255
256     do
257     {
258         // Force final dependency resolving
259         if ( resolveDependencies() == QDialog::Rejected )
260             return;
261
262         confirmedAllLicenses = showPendingLicenseAgreements();
263
264     } while ( ! confirmedAllLicenses ); // Some packages will be set to S_TABOO - need another solver run
265
266     if ( _showChangesDialog )
267     {
268         // Show which packages are installed/deleted automatically
269         QString msg =
270             "<p><b>"
271             // Dialog header
272             + _( "Automatic Changes" )
273             + "</b></p>"
274             // Detailed explanation ( automatic word wrap! )
275             + "<p>"
276             + _( "In addition to your manual selections, the following packages"
277                  " have been changed to resolve dependencies:" )
278             + "<p>";
279
280         if ( YQPkgChangesDialog::showChangesDialog( msg, _( "C&ontinue" ), _( "&Cancel" ) )
281              == QDialog::Rejected )
282             return;
283     }
284
285     // Check disk usage
286     if ( checkDiskUsage() == QDialog::Rejected )
287         return;
288
289     y2milestone( "Closing PackageSelector with \"Accept\"" );
290     YQUI::ui()->sendEvent( new YMenuEvent( YCPSymbol( "accept" ) ) );
291 }
292
293
294 bool
295 YQPackageSelectorBase::showPendingLicenseAgreements()
296 {
297     y2milestone( "Showing all pending license agreements" );
298
299     bool allConfirmed = true;
300
301     if ( onlineUpdateMode() )
302         allConfirmed = showPendingLicenseAgreements( zyppPatchesBegin(), zyppPatchesEnd() );
303
304     allConfirmed = showPendingLicenseAgreements( zyppPkgBegin(), zyppPkgEnd() ) && allConfirmed;
305
306     return allConfirmed;
307 }
308
309
310 bool
311 YQPackageSelectorBase::showPendingLicenseAgreements( ZyppPoolIterator begin, ZyppPoolIterator end )
312 {
313     bool allConfirmed = true;
314
315     for ( ZyppPoolIterator it = begin; it != end; ++it )
316     {
317         ZyppSel sel = (*it);
318
319         switch ( sel->status() )
320         {
321             case S_Install:
322             case S_AutoInstall:
323             case S_Update:
324             case S_AutoUpdate:
325
326                 if ( sel->candidateObj() )
327                 {
328                     string licenseText = sel->candidateObj()->licenseToConfirm();
329
330                     if ( ! licenseText.empty() )
331                     {
332                         y2milestone( "Resolvable %s has a license agreement", sel->name().c_str() );
333
334                         if( ! sel->hasLicenceConfirmed() )
335                         {
336                             y2debug( "Showing license agreement for resolvable %s", sel->name().c_str() );
337                             allConfirmed = YQPkgObjListItem::showLicenseAgreement( sel ) && allConfirmed;
338                         }
339                         else
340                         {
341                             y2milestone( "Resolvable %s's  license is already confirmed", sel->name().c_str() );
342                         }
343                     }
344                 }
345                 break;
346
347             default:
348                 break;
349         }
350     }
351
352     return allConfirmed;
353 }
354
355
356 void
357 YQPackageSelectorBase::notImplemented()
358 {
359     QMessageBox::information( this, "",
360                               _( "Not implemented yet. Sorry." ),
361                               QMessageBox::Ok );
362 }
363
364
365 void
366 YQPackageSelectorBase::resetIgnoredDependencyProblems()
367 {
368     YQPkgConflictDialog::resetIgnoredDependencyProblems();
369 }
370
371
372 void
373 YQPackageSelectorBase::keyPressEvent( QKeyEvent * event )
374 {
375     if ( event )
376     {
377         Qt::KeyboardModifiers special_combo = ( Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier );
378
379         if ( ( event->modifiers() & special_combo ) == special_combo )
380         {
381             if ( event->key() == Qt::Key_A )
382             {
383                 showAutoPkgList();
384                 event->accept();
385                 return;
386             }
387         }
388     }
389
390     QWidget::keyPressEvent( event );
391 }
392
393
394 bool YQPackageSelectorBase::eventFilter( QObject * obj, QEvent * event )
395 {
396     if ( event->type() == QEvent::Close )
397     {
398         // Handle WM_CLOSE like "Cancel"
399         reject();
400
401         return true;    // Stop processing this event
402     }
403
404     return false;       // Don't stop processing this event
405 }
406
407
408 int YQPackageSelectorBase::preferredWidth()
409 {
410     return max( 640, sizeHint().width() );
411 }
412
413
414 int YQPackageSelectorBase::preferredHeight()
415 {
416     return max( 480, sizeHint().height() );
417 }
418
419
420 void
421 YQPackageSelectorBase::setSize( int newWidth, int newHeight )
422 {
423     resize( newWidth, newHeight );
424 }
425
426
427 void
428 YQPackageSelectorBase::setEnabling( bool enabled )
429 {
430     QWidget::setEnabled( enabled );
431 }
432
433
434 bool
435 YQPackageSelectorBase::setKeyboardFocus()
436 {
437     setFocus();
438
439     return true;
440 }
441
442
443 #include "YQPackageSelectorBase.moc"