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