44215ce0b8149df54bc8364ff54d72eb042fdbce
[fapman] / mainwindow.cpp
1 /*
2         This file is part of Faster Application Manager.
3
4         Faster Application Manager is free software: you can redistribute it and/or modify
5         it under the terms of the GNU General Public License as published by
6         the Free Software Foundation, either version 3 of the License, or
7         (at your option) any later version.
8
9         Faster Application Manager is distributed in the hope that it will be useful,
10         but WITHOUT ANY WARRANTY; without even the implied warranty of
11         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12         GNU General Public License for more details.
13
14         You should have received a copy of the GNU General Public License
15         along with Faster Application Manager.  If not, see <http://www.gnu.org/licenses/>.
16
17         (C) Heikki Holstila 2010
18 */
19
20 #ifdef MYDEF_GTK_EXISTS
21 #include <gdk/gdk.h>
22 #include <gtk/gtk.h>
23 #endif
24
25 #include <QtCore>
26 #include <QtGui>
27 #include <QDBusConnection>
28 #include <QDBusInterface>
29 #include <phonon/AudioOutput>
30 #include <phonon/MediaObject>
31
32 #ifdef Q_WS_MAEMO_5
33 #include <QtMaemo5>
34 #endif
35
36 #include <sys/vfs.h>
37
38 #include "mainwindow.h"
39 #include "version.h"
40 #include "ui_mainwindow.h"
41 #include "aaptinterface.h"
42 #include "packageview.h"
43 #include "confirmdialog.h"
44 #include "dimmer.h"
45 #include "repoview.h"
46 #include "help.h"
47 #include "settings.h"
48 #include "logview.h"
49 #include "rotatingbackground.h"
50 #include "dpkginterface.h"
51
52
53 MainWindow::MainWindow(QWidget *parent) :
54     QMainWindow(parent),
55     ui(new Ui::MainWindow)
56 {
57     ui->setupUi(this);
58
59         iAptInterface = new AAptInterface(this);
60         iWinPackageView = new PackageView(this);
61         iWinPackageView->setAptInterface(iAptInterface);
62         iWinRepoView = new RepoView(this);
63         iWinRepoView->setAptInterface(iAptInterface);
64         iSettings = new Settings(this);
65         iSettings->setAptInterface(iAptInterface);
66         iSettings->setPackageView(iWinPackageView);
67         iWinPackageView->setSettings(iSettings);
68         iAptInterface->setSettings(iSettings);
69         iDpkgInterface = new DpkgInterface(this);
70
71         iWinPackageView->setSortOrder( (PackageView::sortOrder)iSettings->qsettings()->value("default_sort_order",0).toInt() );
72
73         iWinPackageView->setSearchOptions( iSettings->qsettings()->value("search_pkgnames",true).toBool(),
74                                                                            iSettings->qsettings()->value("search_displaynames",true).toBool(),
75                                                                            iSettings->qsettings()->value("search_descshort",true).toBool(),
76                                                                            iSettings->qsettings()->value("search_desclong",false).toBool() );
77
78 #ifdef Q_WS_MAEMO_5
79         this->setAttribute(Qt::WA_Maemo5StackedWindow);
80         if( !iSettings->qsettings()->value("disable_autorotation",false).toBool() ) {
81                 this->setAttribute(Qt::WA_Maemo5AutoOrientation);
82         } else {
83                 this->setAttribute(Qt::WA_Maemo5LandscapeOrientation);
84         }
85 #endif
86
87         iDimmer = new dimmer(this);
88
89         iReposAutoUpdating = false;
90         iUpgradeAutoUpdate = true;
91         iNextOperation = OpNone;
92
93         connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(orientationChanged()));
94
95         ui->centralWidget->loadWallpaper();
96
97         /*
98         QString stylesheet_mainscreen =
99                         "QPushButton {"
100                         "border-radius: 16px;"
101                         "border-width: 1px;"
102                         "border-color: palette(light);"
103                         "border-style: outset;"
104                         "padding-right: 10px;"
105                         "padding-left: 10px;"
106                         "color: palette(buttontext);"
107                         "background: rgba(255,255,255,80);"
108                         "}"
109                         "QPushButton:pressed {"
110                         "border-style: inset;"
111                         "background-color: rgba(255,255,255,150);"
112                         "}";
113         */
114
115         if( ((QApplication*)QApplication::instance())->styleSheet().isEmpty() )
116         {
117                 QString stylesheet_file;
118                 QFile f("/root/.fapman/style.css");
119                 if( f.open(QIODevice::ReadOnly | QIODevice::Text ) )
120                 {
121                         while(!f.atEnd()) {
122                                 stylesheet_file += f.readLine().trimmed();
123                         }
124                         f.close();
125                 }
126
127                 if( stylesheet_file.isEmpty() ) {
128                         //ui->centralWidget->setStyleSheet(stylesheet_mainscreen);
129                 } else {
130                         ((QApplication*)QApplication::instance())->setStyleSheet(stylesheet_file);
131                 }
132         }
133
134
135         /*
136         // does not work
137
138         QDBusConnection conn = QDBusConnection::connectToBus(QDBusConnection::SystemBus, "faster_application_manager");
139
140         QString service = "com.nokia.icd";
141         QString path = "/com/nokia/icd";
142         QString method = "connect";
143
144         QDBusInterface net(service, path, service, conn, this);
145         net.call(method,"[ANY]",0);
146         */
147
148         iMediaObject = new Phonon::MediaObject(this);
149         Phonon::AudioOutput* aout = new Phonon::AudioOutput(Phonon::NotificationCategory, this);
150         Phonon::createPath(iMediaObject, aout);
151
152         showFreeSpace();
153
154         show();
155         orientationChanged();
156 }
157
158 MainWindow::~MainWindow()
159 {
160         // save "need repo refresh" status
161         iSettings->qsettings()->setValue("need_repo_refresh", iAptInterface->needRepoRefresh());
162
163         delete iWinPackageView;
164         delete iWinRepoView;
165         delete iAptInterface;
166         delete iDpkgInterface;
167         delete iDimmer;
168         delete iSettings;
169     delete ui;
170 }
171
172 void MainWindow::changeEvent(QEvent *e)
173 {
174     QMainWindow::changeEvent(e);
175     switch (e->type()) {
176     case QEvent::LanguageChange:
177         ui->retranslateUi(this);
178         break;
179     default:
180         break;
181     }
182 }
183
184 void MainWindow::on_btnRepos_clicked()
185 {
186         iWinRepoView->openWin();
187 }
188
189 void MainWindow::on_btnUpdate_clicked()
190 {       
191         // update catalogs
192
193         busyDialog(true, tr("Operation in progress"), tr("Updating catalogs"));
194
195         iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetUpdate);
196         iAptInterface->run(iDimmer);
197 }
198
199 #ifdef Q_WS_MAEMO_5
200 int MainWindow::top_application()
201 {
202         show();
203         activateWindow();
204         raise();
205         return 0;
206 }
207 #endif
208
209 void MainWindow::dateFetchAsk()
210 {
211         if( !iSettings->qsettings()->value("firstrun_asked_fetch_dates",false).toBool() &&
212                 !iSettings->qsettings()->value("fetch_dates",false).toBool() )
213         {
214                 iSettings->qsettings()->setValue("firstrun_asked_fetch_dates", true);
215                 ConfirmDialog d(true, this);
216                 d.setText("Fetch date information?","Enable date information fetching for packages? You have to enable it in order to be "
217                                   "able to sort packages by date. The first fetch can be slow but the dates are cached for later use. You can later "
218                                   "change this selection from the options menu.");
219                 if( d.exec() )
220                         iSettings->qsettings()->setValue("fetch_dates", true);
221         }
222         if( iSettings->qsettings()->value("fetch_dates",false).toBool() )
223         {
224                 iSettings->qsettings()->setValue("firstrun_asked_fetch_dates", true);   // don't ask if the option has already been enabled
225                 if( !iAptInterface->dateCacheExists() )
226                 {
227                         ConfirmDialog d(false, this);
228                         d.setText("Notice","Date information will be fetched only for packages from maemo.org and only for user categories.");
229                         d.exec();
230                 }
231                 iAptInterface->addQueuedOperation(AAptInterface::ModeFetchDates);
232         }
233 }
234
235 void MainWindow::on_btnListInstallable_clicked()
236 {
237         //install
238
239         int listupd = -1;
240         int dpkgupd = -1;
241         if( iAptInterface->lastListUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
242                 listupd = 1;
243         if( iAptInterface->lastDpkgUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
244                 dpkgupd = 1;
245         iAptInterface->setNeedRefresh(-1,listupd,dpkgupd,listupd);
246
247         iWinPackageView->setStatFilter( Package::PkgStatNotInstalled );
248
249         if( iAptInterface->needRepoRefresh() && !iSettings->qsettings()->value("no_catalogs_autoupdate",false).toBool() )
250                 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetUpdate);
251
252         busyDialog(true, tr("Operation in progress"), tr("Reading package lists"));
253
254         iNextOperation = OpOpenPkgView;
255         iAptInterface->addQueuedOperation(AAptInterface::ModeReadPackages);
256
257         dateFetchAsk();
258
259         iAptInterface->run(iDimmer);
260 }
261
262 void MainWindow::on_btnUpgrade_clicked()
263 {
264         // upgrade
265
266         int listupd = -1;
267         int dpkgupd = -1;
268         if( iAptInterface->lastListUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
269                 listupd = 1;
270         if( iAptInterface->lastDpkgUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
271                 dpkgupd = 1;
272         iAptInterface->setNeedRefresh(-1,listupd,dpkgupd,listupd);
273
274         iWinPackageView->setStatFilter( Package::PkgStatUpgradeable );
275
276         if( iAptInterface->needRepoRefresh() && !iSettings->qsettings()->value("no_catalogs_autoupdate",false).toBool() )
277                 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetUpdate);
278
279         busyDialog(true, tr("Operation in progress"), tr("Reading package lists"));
280
281         iNextOperation = OpOpenPkgView;
282         iAptInterface->addQueuedOperation(AAptInterface::ModeReadPackages);
283
284         dateFetchAsk();
285
286         iAptInterface->run(iDimmer);
287 }
288
289 void MainWindow::on_btnListInstalled_clicked()
290 {
291         //remove
292
293         if( !iSettings->qsettings()->value("remove_readfull",false).toBool() )
294                 iAptInterface->setSkipListAndDates();
295
296         int dpkgupd = -1;
297         if( iAptInterface->lastDpkgUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
298                 dpkgupd = 1;
299         iAptInterface->setNeedRefresh(-1,-1,dpkgupd,-1);
300
301         iWinPackageView->setStatFilter( Package::PkgStatInstalled );
302
303         busyDialog(true, tr("Operation in progress"), tr("Reading package lists"));
304
305         iNextOperation = OpOpenPkgView;
306         iAptInterface->addQueuedOperation(AAptInterface::ModeReadPackages);
307
308         dateFetchAsk();
309
310         iAptInterface->run(iDimmer);
311 }
312
313 void MainWindow::operationQueueFinished(QList<AAptInterface::interfaceMode> lastModes, bool success, QString title, QStringList msgs)
314 {
315         if( lastModes.contains(AAptInterface::ModeAptGetSimulate) && success ) {
316                 iNextOperation = OpPromptSimulated;
317         }
318         if( lastModes.contains(AAptInterface::ModeAptGetInstall) && success ) {
319                 iWinPackageView->clearSelections();
320                 busyDialog(false);
321                 iWinPackageView->close();
322                 iNextOperation = OpNone;
323
324                 GdkEventIconThemeReload();
325         }
326
327         QWidget* dialogParent = this;
328         if( iWinPackageView->isVisible() )
329                 dialogParent = iWinPackageView;
330
331         if( iNextOperation == OpOpenPkgView && success )
332         {
333                 iWinPackageView->openWin();
334                 busyDialog(false);
335                 iNextOperation = OpNone;
336         } else if( iNextOperation == OpPromptSimulated && success )
337         {
338                 QStringList inst,remv,instver,remvver;
339                 QStringList all = iAptInterface->processPackages();
340                 QStringList vers = iAptInterface->processPackageVersions();
341                 for(int zyx=0; zyx<all.count(); zyx++)
342                 {
343                         if( all.at(zyx).endsWith('-') )
344                         {
345                                 remv.append( all.at(zyx).left( all.at(zyx).size()-1 ) );
346                                 if( vers.count()>zyx )
347                                         remvver.append( vers.at(zyx) );
348                         } else {
349                                 inst.append( all.at(zyx) );
350                                 if( vers.count()>zyx )
351                                         instver.append( vers.at(zyx) );
352                         }
353                 }
354
355                 int total_dl_size = 0;
356                 for( int i=0; i<inst.count(); i++ ) {
357                         Package* pkg = iAptInterface->packagesAvailable()->value(inst.at(i),0);
358                         if( pkg ) {
359                                 total_dl_size += pkg->size()/1024;
360                         }
361                 }
362
363                 QString pkglist;
364                 pkglist = QString("<b>The following operations will be performed:</b><br>"
365                                   "%1 to install/upgrade, %2 to remove<br>").arg(inst.count()).arg(remv.count());
366                 if( inst.count()>0 )
367                         pkglist += QString("Total download size: %L1 kB<br>").arg(total_dl_size);
368                 bool mismatch = false;
369                 bool warn_system_package_remove = false;
370                 bool warn_system_package_install = false;
371
372                 if( remv.count()>0 ) {
373                         pkglist += "<br><b><u>REMOVE:</u></b><br><font size=\"-1\">";
374                         for( int i=0; i<remv.count(); i++ ) {
375                                 pkglist += "<b>" + remv.at(i) + "</b>";
376                                 Package* pkg = iAptInterface->packagesInstalled()->value(remv.at(i),0);
377                                 if( !pkg ) {
378                                         qDebug() << "Warning: unknown package" << remv.at(i);
379                                         pkglist += "<font color=\"red\">***UNKNOWN***</font>";
380                                         mismatch = true;
381                                 }
382 #ifdef Q_WS_MAEMO_5
383                                 if( pkg && pkg->maemoDisplayName()=="Maemo 5" ) {
384                                         warn_system_package_remove = true;
385                                 }
386 #endif
387                                 if( remvver.count()>i ) {
388                                         pkglist += " " + remvver.at(i);
389                                         if( pkg && remvver.at(i) != pkg->version() ) {
390                                                 qDebug() << "Version mismatch, database version is" << pkg->version() << "but removing" << remvver.at(i);
391                                                 mismatch = true;
392                                                 pkglist += " <font color=\"red\">***TRYING TO REMOVE " + pkg->version() + "***</font> ";
393                                         }
394                                 }
395                                 if( pkg && pkg->installedSize()>0 )
396                                         pkglist += QString(" (%L1 kB)").arg(pkg->installedSize());
397                                 pkglist += "<br>";
398                         }
399                 }
400                 pkglist += "</font>";
401
402                 bool installing_blacklisted = false;
403                 if( inst.count()>0 ) {
404                         pkglist += "<br><b><u>INSTALL/UPGRADE:</u></b><br><font size=\"-1\">";
405                         for( int i=0; i<inst.count(); i++ ) {
406                                 pkglist += "<b>" + inst.at(i) + "</b>";
407                                 Package* pkg = iAptInterface->packagesAvailable()->value(inst.at(i),0);
408                                 if( !pkg ) {
409                                         qDebug() << "Warning: unknown package" << inst.at(i);
410                                         pkglist += "<font color=\"red\">***NEW/UNKNOWN***</font>";
411                                         mismatch = true;
412                                 }
413                                 if( pkg && pkg->isBlacklisted() ) {
414                                         qDebug() << "Warning: installing blacklisted package" << inst.at(i);
415                                         pkglist += "<font color=\"red\">***BLACKLISTED***</font>";
416                                         installing_blacklisted = true;
417                                 }
418 #ifdef Q_WS_MAEMO_5
419                                 if( pkg && pkg->maemoDisplayName()=="Maemo 5" ) {
420                                         warn_system_package_install = true;
421                                 }
422 #endif
423                                 if( instver.count()>i ) {
424                                         pkglist += " " + instver.at(i);
425                                         if( pkg && instver.at(i) != pkg->version() ) {
426                                                 qDebug() << "Version mismatch, database version is" << pkg->version() << "but installing" << instver.at(i);
427                                                 mismatch = true;
428                                                 pkglist += " <font color=\"red\">***TRYING TO INSTALL " + pkg->version() + "***</font> ";
429                                         }
430                                 }
431                                 if( pkg && pkg->size()>0 ) {
432                                         pkglist += QString(" (%L1 kB)").arg(pkg->size()/1024);
433                                 }
434                                 pkglist += "<br>";
435                         }
436                 }
437                 pkglist += "</font>";
438
439                 if( mismatch ) {
440                         ConfirmDialog m(false, dialogParent);
441                         m.setText("Warning", "There is a version mismatch between your original package selections and some of the packages being installed " \
442                                           "from the repositories. This could be due to your application catalogs being out of date.");
443                         m.exec();
444                 }
445                 if( installing_blacklisted ) {
446                         ConfirmDialog b(false, dialogParent);
447                         b.setText("Warning","Blacklisted package(s) will be installed");
448                         b.exec();
449                 }
450                 if( warn_system_package_remove ) {
451                         ConfirmDialog s(false, dialogParent);
452                         s.setText("Warning","You are about to remove a critical system package.");
453                         s.exec();
454                 }
455                 if( warn_system_package_install ) {
456                         ConfirmDialog s(false, dialogParent);
457                         s.setText("Warning","You are trying to perform an install/upgrade operation on a critical system package. Doing a system upgrade with " \
458                                           "Faster Application Manager has not been tested and it could result in a horrible failure. You have been warned.");
459                         s.exec();
460                 }
461
462                 busyDialog(false);
463                 ConfirmDialog d(true, dialogParent);
464                 if( inst.count()==0 && remv.count()==0 )
465                 {
466                         pkglist = "None of the packages can be installed";
467                         d.disableButton();
468                 }
469                 d.setText("Confirmation",pkglist);
470                 if( d.exec() ) {
471                         iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetInstall);
472
473                         if( iSettings->qsettings()->value("enable_autoclean",true).toBool() && inst.count()>0 )
474                                 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetClean);
475
476                         QString busytext;
477                         if( remv.count() > 0 )
478                                 busytext += QString("Remove %1 package(s)<br>").arg(remv.count());
479                         if( inst.count() > 0 )
480                                 busytext += QString("Install %1 package(s)<br>").arg(inst.count());
481                         busytext += "Preparing...";
482                         busyDialog(true, "Operation in progress", busytext);
483
484                         // "run" really does nothing here since the previous item should still be running
485                         if( iWinPackageView->isVisible() ) {
486                                 iAptInterface->run(iWinPackageView->mydimmer());
487                         } else {
488                                 iAptInterface->run(iDimmer);
489                         }
490                 }
491                 iNextOperation = OpNone;
492                 return;
493         } else {
494                 busyDialog(false);
495                 iNextOperation = OpNone;
496
497                 if( iSettings->qsettings()->value("sound_notify",false).toBool() )
498                 {
499                         qDebug() << "playing sound";
500                         iMediaObject->setCurrentSource( Phonon::MediaSource(iSettings->qsettings()->value("sound_file","/usr/share/sounds/ui-operation_ready.wav").toString()) );
501                         iMediaObject->play();
502                 }
503
504                 QString text = "<br><b><u>Faster Application Manager</u></b><br>"
505                                            "<b>"+title+"</b><br>" + msgs.join("<br>") + "<br>";
506
507                 QRect r = QApplication::desktop()->rect();
508                 if(r.width() < r.height()) {
509                         ConfirmDialog d(false, dialogParent);
510                         d.setText(title,msgs.join("<br>"));
511                         d.exec();
512                 } else {
513 #ifdef Q_WS_MAEMO_5
514                         QMaemo5InformationBox::information(0, text, QMaemo5InformationBox::NoTimeout);
515 #else
516                         ConfirmDialog d(false, dialogParent);
517                         d.setText(title,msgs.join("<br>"));
518                         d.exec();
519 #endif
520                 }
521
522                 showFreeSpace();
523         }
524
525 }
526
527 void MainWindow::busyDialog(bool show_, QString title, QString text)
528 {
529         if( show_ ) {
530                 iDimmer->setProgress(-1);
531                 ui->menuMenu->setEnabled(false);
532                 ui->centralWidget->setEnabled(false);
533                 iWinPackageView->disableMenu();
534                 iDimmer->resizeEvent(0);
535                 iDimmer->dim(title, text);
536                 iWinPackageView->mydimmer()->resizeEvent(0);
537                 iWinPackageView->mydimmer()->dim(title, text);
538         } else {
539                 iDimmer->undim();
540                 iWinPackageView->mydimmer()->undim();
541                 ui->menuMenu->setEnabled(true);
542                 ui->centralWidget->setEnabled(true);
543                 iWinPackageView->enableMenu();
544         }
545 }
546
547 void MainWindow::on_actionAbout_triggered()
548 {
549         ConfirmDialog d(false, this);
550         d.setText("About","Faster Application Manager<br>"
551                           "<font size=\"-1\">Version " + PROGRAM_VERSION + "</font><br><br>"
552                           "(C) Heikki Holstila 2010<br>Donate using "
553                           "<a href=\"https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=6ZKRY5QFHL42A&lc=FI&item_name=Faster%20Application%20Manager"
554                           "%20for%20Maemo5&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted\">PayPal</a>");
555         d.exec();
556 }
557
558 void MainWindow::on_actionClean_triggered()
559 {
560         //if( iOperation != OpNone ) return;
561         //iOperation = OpClean;
562         iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetClean);
563         iAptInterface->run(iDimmer);
564 }
565
566 void MainWindow::closeEvent(QCloseEvent *event)
567 {
568         if( iDimmer->busy() ) {
569                 iAptInterface->cancel();
570                 event->ignore();
571         } else {
572                 event->accept();
573         }
574 }
575
576 void MainWindow::on_actionView_log_triggered()
577 {
578         QByteArray log = iAptInterface->readLogFile();
579         LogView l(log, this);
580         l.exec();
581 }
582
583 void MainWindow::on_actionOptions_triggered()
584 {
585         iSettings->openWin();
586 }
587
588 void MainWindow::notifyDialog(QString title, QString msg)
589 {
590         QWidget* dialogParent = this;
591         if( iWinPackageView->isVisible() )
592                 dialogParent = iWinPackageView;
593
594         ConfirmDialog d(false, dialogParent);
595         d.setText(title, msg);
596         d.exec();
597 }
598
599 bool MainWindow::confirmDialog(QString title, QString msg)
600 {
601         QWidget* dialogParent = this;
602         if( iWinPackageView->isVisible() )
603                 dialogParent = iWinPackageView;
604
605         ConfirmDialog d(true, dialogParent);
606         d.setText(title, msg);
607         return d.exec();
608 }
609
610 void MainWindow::GdkEventIconThemeReload()
611 {
612         // DOES NOT EVEN WORK (at least not reliably) - disabled from the project file
613
614 #ifdef MYDEF_GTK_EXISTS
615         qDebug() << "Sending GDK icon theme reload event";
616
617         gdk_init((int*)QApplication::argc(),(gchar***)QApplication::argv());
618
619         // taken from hildon application manager
620         GdkEventClient ev;
621         ev.type = GDK_CLIENT_EVENT;
622         ev.window = NULL;
623         ev.send_event = TRUE;
624         ev.message_type = gdk_atom_intern_static_string("_GTK_LOAD_ICONTHEMES");
625         ev.data_format = 32;
626         gdk_event_send_clientmessage_toall((GdkEvent*)&ev);
627
628         while(gdk_events_pending()) {
629                 g_main_context_iteration(NULL, true);
630         }
631
632 #endif
633 }
634
635 void MainWindow::on_actionLoad_file_triggered()
636 {
637         QStringList files = QFileDialog::getOpenFileNames(this, "Open files", "/", "Files (*.deb *.install)");
638         if( files.count() > 0 ) {
639                 QStringList debs = files.filter(QRegExp(".*\\.deb$"));
640                 QStringList installs = files.filter(QRegExp(".*\\.install$"));
641                 if( debs.count()>0 && installs.count()>0 ) {
642                         ConfirmDialog d(false, this);
643                         d.setText("Error", "You can't mix different file types in your selection");
644                         d.exec();
645                         return;
646                 }
647                 if( debs.count()>0 )
648                         iDpkgInterface->loadDebFiles(debs);
649                 else if( installs.count()>0 )
650                         iAptInterface->loadInstallFiles(installs);
651         }
652 }
653
654 void MainWindow::orientationChanged()
655 {
656         if( QApplication::desktop()->width() > QApplication::desktop()->height() )
657                 ui->listWidget->setGridSize( QSize((ui->listWidget->width()-12)/5, (ui->listWidget->height()-12)/2) );
658         else
659                 ui->listWidget->setGridSize( QSize((ui->listWidget->width()-12)/3, (ui->listWidget->height()-12)/3) );
660 }
661
662
663 void MainWindow::showFreeSpace()
664 {
665         quint64 warn_limit_root = 5120;
666         quint64 warn_limit_opt = 51200;
667         struct statfs root_stat;
668         struct statfs opt_stat;
669         statfs("/",&root_stat);
670         statfs("/opt",&opt_stat);
671         quint64 free_root = root_stat.f_bavail * root_stat.f_bsize / 1024;
672         quint64 free_opt = opt_stat.f_bavail * opt_stat.f_bsize / 1024;
673         quint64 total_root = root_stat.f_blocks * root_stat.f_bsize / 1024;
674         quint64 total_opt = opt_stat.f_blocks * opt_stat.f_bsize / 1024;
675         qDebug() << "rootfs" << free_root << "/" << total_root << "kB free";
676         qDebug() << "opt fs" << free_opt << "/" << total_opt << "kB free";
677
678         QString rootstr = QString("rootfs: %L1 / %L2 MB free").arg(free_root/1024).arg(total_root/1024);
679         QString optstr = QString("opt: %L1 / %L2 MB free").arg(free_opt/1024).arg(total_opt/1024);
680
681         ui->label->setText("<font size=\"-1\">" + rootstr + "<br>" + optstr + "</font>");
682
683         /*
684         ui->progressBarRoot->setFormat(rootstr);
685         ui->progressBarRoot->setMaximum(total_root/1024);
686         ui->progressBarRoot->setValue(free_root/1024);
687         ui->progressBarOpt->setFormat(optstr);
688         ui->progressBarOpt->setMaximum(total_opt/1024);
689         ui->progressBarOpt->setValue(free_opt/1024);
690         */
691
692         if( free_root < warn_limit_root || free_opt < warn_limit_opt )
693         {
694                 ConfirmDialog d(false, this);
695                 QString t;
696                 if( free_root < warn_limit_root )
697                         t += QString("Root filesystem has %L1 kB available<br>").arg(free_root);
698                 if( free_opt < warn_limit_opt )
699                         t += QString("Opt (home) filesystem has %L1 kB available<br>").arg(free_opt);
700                 t += "<br>You may proceed, but consider freeing up space to prevent problems in the future";
701                 d.setText("Warning: Low disk space",t);
702                 d.exec();
703         }
704 }
705
706 void MainWindow::on_listWidget_itemClicked(QListWidgetItem* item)
707 {
708         qDebug() << "main menu:" << item->statusTip();
709
710         if( item->statusTip() == "manage_repos" ) {
711                 on_btnRepos_clicked();
712         }
713         else if( item->statusTip() == "update_catalogs" ) {
714                 on_btnUpdate_clicked();
715         }
716         else if( item->statusTip() == "install_apps" ) {
717                 on_btnListInstallable_clicked();
718         }
719         else if( item->statusTip() == "remove_apps" ) {
720                 on_btnListInstalled_clicked();
721         }
722         else if( item->statusTip() == "upgrade_apps" ) {
723                 on_btnUpgrade_clicked();
724         }
725         else {
726                 qDebug() << "Warning: Unhandled main menu item";
727         }
728         item->setSelected(false);
729 }