2 This file is part of Faster Application Manager.
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.
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.
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/>.
17 (C) Heikki Holstila 2010
20 #ifdef MYDEF_GTK_EXISTS
27 #include <QDBusConnection>
28 #include <QDBusInterface>
29 #include <phonon/AudioOutput>
30 #include <phonon/MediaObject>
38 #include "mainwindow.h"
40 #include "ui_mainwindow.h"
41 #include "aaptinterface.h"
42 #include "packageview.h"
43 #include "confirmdialog.h"
49 #include "rotatingbackground.h"
50 #include "dpkginterface.h"
53 MainWindow::MainWindow(QWidget *parent) :
55 ui(new Ui::MainWindow)
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);
71 iWinPackageView->setSortOrder( (PackageView::sortOrder)iSettings->qsettings()->value("default_sort_order",0).toInt() );
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() );
79 this->setAttribute(Qt::WA_Maemo5StackedWindow);
80 if( !iSettings->qsettings()->value("disable_autorotation",false).toBool() ) {
81 this->setAttribute(Qt::WA_Maemo5AutoOrientation);
83 this->setAttribute(Qt::WA_Maemo5LandscapeOrientation);
87 iDimmer = new dimmer(this);
89 iReposAutoUpdating = false;
90 iUpgradeAutoUpdate = true;
91 iNextOperation = OpNone;
93 connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(orientationChanged()));
95 ui->centralWidget->loadWallpaper();
98 QString stylesheet_mainscreen =
100 "border-radius: 16px;"
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);"
109 "QPushButton:pressed {"
110 "border-style: inset;"
111 "background-color: rgba(255,255,255,150);"
115 if( ((QApplication*)QApplication::instance())->styleSheet().isEmpty() )
117 QString stylesheet_file;
118 QFile f("/root/.fapman/style.css");
119 if( f.open(QIODevice::ReadOnly | QIODevice::Text ) )
122 stylesheet_file += f.readLine().trimmed();
127 if( stylesheet_file.isEmpty() ) {
128 //ui->centralWidget->setStyleSheet(stylesheet_mainscreen);
130 ((QApplication*)QApplication::instance())->setStyleSheet(stylesheet_file);
138 QDBusConnection conn = QDBusConnection::connectToBus(QDBusConnection::SystemBus, "faster_application_manager");
140 QString service = "com.nokia.icd";
141 QString path = "/com/nokia/icd";
142 QString method = "connect";
144 QDBusInterface net(service, path, service, conn, this);
145 net.call(method,"[ANY]",0);
148 iMediaObject = new Phonon::MediaObject(this);
149 Phonon::AudioOutput* aout = new Phonon::AudioOutput(Phonon::NotificationCategory, this);
150 Phonon::createPath(iMediaObject, aout);
155 orientationChanged();
158 MainWindow::~MainWindow()
160 // save "need repo refresh" status
161 iSettings->qsettings()->setValue("need_repo_refresh", iAptInterface->needRepoRefresh());
163 delete iWinPackageView;
165 delete iAptInterface;
166 delete iDpkgInterface;
172 void MainWindow::changeEvent(QEvent *e)
174 QMainWindow::changeEvent(e);
176 case QEvent::LanguageChange:
177 ui->retranslateUi(this);
184 void MainWindow::on_btnRepos_clicked()
186 iWinRepoView->openWin();
189 void MainWindow::on_btnUpdate_clicked()
193 busyDialog(true, tr("Operation in progress"), tr("Updating catalogs"));
195 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetUpdate);
196 iAptInterface->run(iDimmer);
200 int MainWindow::top_application()
209 void MainWindow::dateFetchAsk()
211 if( !iSettings->qsettings()->value("firstrun_asked_fetch_dates",false).toBool() &&
212 !iSettings->qsettings()->value("fetch_dates",false).toBool() )
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.");
220 iSettings->qsettings()->setValue("fetch_dates", true);
222 if( iSettings->qsettings()->value("fetch_dates",false).toBool() )
224 iSettings->qsettings()->setValue("firstrun_asked_fetch_dates", true); // don't ask if the option has already been enabled
225 if( !iAptInterface->dateCacheExists() )
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.");
231 iAptInterface->addQueuedOperation(AAptInterface::ModeFetchDates);
235 void MainWindow::on_btnListInstallable_clicked()
241 if( iAptInterface->lastListUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
243 if( iAptInterface->lastDpkgUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
245 iAptInterface->setNeedRefresh(-1,listupd,dpkgupd,listupd);
247 iWinPackageView->setStatFilter( Package::PkgStatNotInstalled );
249 if( iAptInterface->needRepoRefresh() && !iSettings->qsettings()->value("no_catalogs_autoupdate",false).toBool() )
250 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetUpdate);
252 busyDialog(true, tr("Operation in progress"), tr("Reading package lists"));
254 iNextOperation = OpOpenPkgView;
255 iAptInterface->addQueuedOperation(AAptInterface::ModeReadPackages);
259 iAptInterface->run(iDimmer);
262 void MainWindow::on_btnUpgrade_clicked()
268 if( iAptInterface->lastListUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
270 if( iAptInterface->lastDpkgUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
272 iAptInterface->setNeedRefresh(-1,listupd,dpkgupd,listupd);
274 iWinPackageView->setStatFilter( Package::PkgStatUpgradeable );
276 if( iAptInterface->needRepoRefresh() && !iSettings->qsettings()->value("no_catalogs_autoupdate",false).toBool() )
277 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetUpdate);
279 busyDialog(true, tr("Operation in progress"), tr("Reading package lists"));
281 iNextOperation = OpOpenPkgView;
282 iAptInterface->addQueuedOperation(AAptInterface::ModeReadPackages);
286 iAptInterface->run(iDimmer);
289 void MainWindow::on_btnListInstalled_clicked()
293 if( !iSettings->qsettings()->value("remove_readfull",false).toBool() )
294 iAptInterface->setSkipListAndDates();
297 if( iAptInterface->lastDpkgUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
299 iAptInterface->setNeedRefresh(-1,-1,dpkgupd,-1);
301 iWinPackageView->setStatFilter( Package::PkgStatInstalled );
303 busyDialog(true, tr("Operation in progress"), tr("Reading package lists"));
305 iNextOperation = OpOpenPkgView;
306 iAptInterface->addQueuedOperation(AAptInterface::ModeReadPackages);
310 iAptInterface->run(iDimmer);
313 void MainWindow::operationQueueFinished(QList<AAptInterface::interfaceMode> lastModes, bool success, QString title, QStringList msgs)
315 if( lastModes.contains(AAptInterface::ModeAptGetSimulate) && success ) {
316 iNextOperation = OpPromptSimulated;
318 if( lastModes.contains(AAptInterface::ModeAptGetInstall) && success ) {
319 iWinPackageView->clearSelections();
321 iWinPackageView->close();
322 iNextOperation = OpNone;
324 GdkEventIconThemeReload();
327 QWidget* dialogParent = this;
328 if( iWinPackageView->isVisible() )
329 dialogParent = iWinPackageView;
331 if( iNextOperation == OpOpenPkgView && success )
333 iWinPackageView->openWin();
335 iNextOperation = OpNone;
336 } else if( iNextOperation == OpPromptSimulated && success )
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++)
343 if( all.at(zyx).endsWith('-') )
345 remv.append( all.at(zyx).left( all.at(zyx).size()-1 ) );
346 if( vers.count()>zyx )
347 remvver.append( vers.at(zyx) );
349 inst.append( all.at(zyx) );
350 if( vers.count()>zyx )
351 instver.append( vers.at(zyx) );
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);
359 total_dl_size += pkg->size()/1024;
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());
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;
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);
378 qDebug() << "Warning: unknown package" << remv.at(i);
379 pkglist += "<font color=\"red\">***UNKNOWN***</font>";
383 if( pkg && pkg->maemoDisplayName()=="Maemo 5" ) {
384 warn_system_package_remove = true;
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);
392 pkglist += " <font color=\"red\">***TRYING TO REMOVE " + pkg->version() + "***</font> ";
395 if( pkg && pkg->installedSize()>0 )
396 pkglist += QString(" (%L1 kB)").arg(pkg->installedSize());
400 pkglist += "</font>";
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);
409 qDebug() << "Warning: unknown package" << inst.at(i);
410 pkglist += "<font color=\"red\">***NEW/UNKNOWN***</font>";
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;
419 if( pkg && pkg->maemoDisplayName()=="Maemo 5" ) {
420 warn_system_package_install = true;
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);
428 pkglist += " <font color=\"red\">***TRYING TO INSTALL " + pkg->version() + "***</font> ";
431 if( pkg && pkg->size()>0 ) {
432 pkglist += QString(" (%L1 kB)").arg(pkg->size()/1024);
437 pkglist += "</font>";
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.");
445 if( installing_blacklisted ) {
446 ConfirmDialog b(false, dialogParent);
447 b.setText("Warning","Blacklisted package(s) will be installed");
450 if( warn_system_package_remove ) {
451 ConfirmDialog s(false, dialogParent);
452 s.setText("Warning","You are about to remove a critical system package.");
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.");
463 ConfirmDialog d(true, dialogParent);
464 if( inst.count()==0 && remv.count()==0 )
466 pkglist = "None of the packages can be installed";
469 d.setText("Confirmation",pkglist);
471 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetInstall);
473 if( iSettings->qsettings()->value("enable_autoclean",true).toBool() && inst.count()>0 )
474 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetClean);
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);
484 // "run" really does nothing here since the previous item should still be running
485 if( iWinPackageView->isVisible() ) {
486 iAptInterface->run(iWinPackageView->mydimmer());
488 iAptInterface->run(iDimmer);
491 iNextOperation = OpNone;
495 iNextOperation = OpNone;
497 if( iSettings->qsettings()->value("sound_notify",false).toBool() )
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();
504 QString text = "<br><b><u>Faster Application Manager</u></b><br>"
505 "<b>"+title+"</b><br>" + msgs.join("<br>") + "<br>";
507 QRect r = QApplication::desktop()->rect();
508 if(r.width() < r.height()) {
509 ConfirmDialog d(false, dialogParent);
510 d.setText(title,msgs.join("<br>"));
514 QMaemo5InformationBox::information(0, text, QMaemo5InformationBox::NoTimeout);
516 ConfirmDialog d(false, dialogParent);
517 d.setText(title,msgs.join("<br>"));
527 void MainWindow::busyDialog(bool show_, QString title, QString text)
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);
540 iWinPackageView->mydimmer()->undim();
541 ui->menuMenu->setEnabled(true);
542 ui->centralWidget->setEnabled(true);
543 iWinPackageView->enableMenu();
547 void MainWindow::on_actionAbout_triggered()
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¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted\">PayPal</a>");
558 void MainWindow::on_actionClean_triggered()
560 //if( iOperation != OpNone ) return;
561 //iOperation = OpClean;
562 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetClean);
563 iAptInterface->run(iDimmer);
566 void MainWindow::closeEvent(QCloseEvent *event)
568 if( iDimmer->busy() ) {
569 iAptInterface->cancel();
576 void MainWindow::on_actionView_log_triggered()
578 QByteArray log = iAptInterface->readLogFile();
579 LogView l(log, this);
583 void MainWindow::on_actionOptions_triggered()
585 iSettings->openWin();
588 void MainWindow::notifyDialog(QString title, QString msg)
590 QWidget* dialogParent = this;
591 if( iWinPackageView->isVisible() )
592 dialogParent = iWinPackageView;
594 ConfirmDialog d(false, dialogParent);
595 d.setText(title, msg);
599 bool MainWindow::confirmDialog(QString title, QString msg)
601 QWidget* dialogParent = this;
602 if( iWinPackageView->isVisible() )
603 dialogParent = iWinPackageView;
605 ConfirmDialog d(true, dialogParent);
606 d.setText(title, msg);
610 void MainWindow::GdkEventIconThemeReload()
612 // DOES NOT EVEN WORK (at least not reliably) - disabled from the project file
614 #ifdef MYDEF_GTK_EXISTS
615 qDebug() << "Sending GDK icon theme reload event";
617 gdk_init((int*)QApplication::argc(),(gchar***)QApplication::argv());
619 // taken from hildon application manager
621 ev.type = GDK_CLIENT_EVENT;
623 ev.send_event = TRUE;
624 ev.message_type = gdk_atom_intern_static_string("_GTK_LOAD_ICONTHEMES");
626 gdk_event_send_clientmessage_toall((GdkEvent*)&ev);
628 while(gdk_events_pending()) {
629 g_main_context_iteration(NULL, true);
635 void MainWindow::on_actionLoad_file_triggered()
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");
648 iDpkgInterface->loadDebFiles(debs);
649 else if( installs.count()>0 )
650 iAptInterface->loadInstallFiles(installs);
654 void MainWindow::orientationChanged()
656 if( QApplication::desktop()->width() > QApplication::desktop()->height() )
657 ui->listWidget->setGridSize( QSize((ui->listWidget->width()-12)/5, (ui->listWidget->height()-12)/2) );
659 ui->listWidget->setGridSize( QSize((ui->listWidget->width()-12)/3, (ui->listWidget->height()-12)/3) );
663 void MainWindow::showFreeSpace()
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";
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);
681 ui->label->setText("<font size=\"-1\">" + rootstr + "<br>" + optstr + "</font>");
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);
692 if( free_root < warn_limit_root || free_opt < warn_limit_opt )
694 ConfirmDialog d(false, this);
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);
706 void MainWindow::on_listWidget_itemClicked(QListWidgetItem* item)
708 qDebug() << "main menu:" << item->statusTip();
710 if( item->statusTip() == "manage_repos" ) {
711 on_btnRepos_clicked();
713 else if( item->statusTip() == "update_catalogs" ) {
714 on_btnUpdate_clicked();
716 else if( item->statusTip() == "install_apps" ) {
717 on_btnListInstallable_clicked();
719 else if( item->statusTip() == "remove_apps" ) {
720 on_btnListInstalled_clicked();
722 else if( item->statusTip() == "upgrade_apps" ) {
723 on_btnUpgrade_clicked();
726 qDebug() << "Warning: Unhandled main menu item";
728 item->setSelected(false);