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