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
30 #include <QDBusConnection>
31 #include <QDBusInterface>
32 #include <phonon/AudioOutput>
33 #include <phonon/MediaObject>
44 #include "mainwindow.h"
46 #include "ui_mainwindow.h"
47 #include "aaptinterface.h"
48 #include "packageview.h"
49 #include "confirmdialog.h"
55 #include "rotatingbackground.h"
56 #include "dpkginterface.h"
59 MainWindow::MainWindow(QWidget *parent) :
61 ui(new Ui::MainWindow)
65 iAptInterface = new AAptInterface(this);
66 iWinPackageView = new PackageView(this);
67 iWinPackageView->setAptInterface(iAptInterface);
68 iWinRepoView = new RepoView(this);
69 iWinRepoView->setAptInterface(iAptInterface);
70 iSettings = new Settings(this);
71 iSettings->setAptInterface(iAptInterface);
72 iSettings->setPackageView(iWinPackageView);
73 iWinPackageView->setSettings(iSettings);
74 iAptInterface->setSettings(iSettings);
75 iDpkgInterface = new DpkgInterface(this);
77 iWinPackageView->setSortOrder( (PackageView::sortOrder)iSettings->qsettings()->value("default_sort_order",0).toInt() );
79 iWinPackageView->setSearchOptions( iSettings->qsettings()->value("search_pkgnames",true).toBool(),
80 iSettings->qsettings()->value("search_displaynames",true).toBool(),
81 iSettings->qsettings()->value("search_descshort",true).toBool(),
82 iSettings->qsettings()->value("search_desclong",false).toBool() );
85 if( !iSettings->qsettings()->value("disable_autorotation",false).toBool() ) {
86 this->setAttribute(Qt::WA_Maemo5AutoOrientation);
88 this->setAttribute(Qt::WA_Maemo5LandscapeOrientation);
90 this->setAttribute(Qt::WA_Maemo5StackedWindow);
93 iDimmer = new dimmer(this);
95 iReposAutoUpdating = false;
96 iUpgradeAutoUpdate = true;
97 iNextOperation = OpNone;
99 connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(orientationChanged()));
101 ui->centralWidget->loadWallpaper();
104 QString stylesheet_mainscreen =
106 "border-radius: 16px;"
108 "border-color: palette(light);"
109 "border-style: outset;"
110 "padding-right: 10px;"
111 "padding-left: 10px;"
112 "color: palette(buttontext);"
113 "background: rgba(255,255,255,80);"
115 "QPushButton:pressed {"
116 "border-style: inset;"
117 "background-color: rgba(255,255,255,150);"
121 if( ((QApplication*)QApplication::instance())->styleSheet().isEmpty() )
123 QString stylesheet_file;
124 QFile f("/root/.fapman/style.css");
125 if( f.open(QIODevice::ReadOnly | QIODevice::Text ) )
128 stylesheet_file += f.readLine().trimmed();
133 if( stylesheet_file.isEmpty() ) {
134 //ui->centralWidget->setStyleSheet(stylesheet_mainscreen);
136 ((QApplication*)QApplication::instance())->setStyleSheet(stylesheet_file);
141 iMediaObject = new Phonon::MediaObject(this);
142 Phonon::AudioOutput* aout = new Phonon::AudioOutput(Phonon::NotificationCategory, this);
143 Phonon::createPath(iMediaObject, aout);
147 iNetworkConfigurationManager = new QNetworkConfigurationManager(this);
148 iNetworkSession = new QNetworkSession(iNetworkConfigurationManager->defaultConfiguration(),this);
154 MainWindow::~MainWindow()
156 // save "need repo refresh" status
157 iSettings->qsettings()->setValue("need_repo_refresh", iAptInterface->needRepoRefresh());
159 if( iNetworkSession && iNetworkSession->isOpen() ) {
160 iNetworkSession->close();
162 // iNetworkSession automatically deleted by parent
164 delete iWinPackageView; iWinPackageView=0;
165 delete iWinRepoView; iWinRepoView=0;
166 delete iAptInterface; iAptInterface=0;
167 delete iDpkgInterface; iDpkgInterface=0;
168 delete iDimmer; iDimmer=0;
169 delete iSettings; iSettings=0;
171 //iMediaObject and aout automatically deleted by their parent
174 void MainWindow::openNetworkConnection()
176 if( iNetworkSession->isOpen() )
179 iNetworkSession->open();
180 if( !iNetworkSession->waitForOpened(20000) )
182 ConfirmDialog d(false, this);
183 d.setText("Network error","Unable to open a network connection");
188 void MainWindow::changeEvent(QEvent *e)
190 QMainWindow::changeEvent(e);
192 case QEvent::LanguageChange:
193 ui->retranslateUi(this);
200 void MainWindow::on_btnRepos_clicked()
202 iWinRepoView->openWin();
205 void MainWindow::on_btnUpdate_clicked()
209 openNetworkConnection();
211 busyDialog(true, tr("Operation in progress"), tr("Updating catalogs"));
213 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetUpdate);
214 iAptInterface->run(iDimmer);
218 int MainWindow::top_application()
227 void MainWindow::dateFetchAsk()
229 if( !iSettings->qsettings()->value("firstrun_asked_fetch_dates",false).toBool() &&
230 !iSettings->qsettings()->value("fetch_dates",false).toBool() )
232 iSettings->qsettings()->setValue("firstrun_asked_fetch_dates", true);
233 ConfirmDialog d(true, this);
234 d.setText("Fetch date information?","Enable date information fetching for packages? You have to enable it in order to be "
235 "able to sort packages by date. The first fetch can be slow but the dates are cached for later use. You can later "
236 "change this selection from the options menu.");
238 iSettings->qsettings()->setValue("fetch_dates", true);
240 if( iSettings->qsettings()->value("fetch_dates",false).toBool() )
242 iSettings->qsettings()->setValue("firstrun_asked_fetch_dates", true); // don't ask if the option has already been enabled
243 if( !iAptInterface->dateCacheExists() )
245 ConfirmDialog d(false, this);
246 d.setText("Notice","Date information will be fetched only for packages from maemo.org and only for user categories.");
249 iAptInterface->addQueuedOperation(AAptInterface::ModeFetchDates);
253 void MainWindow::on_btnListInstallable_clicked()
257 openNetworkConnection();
261 if( iAptInterface->lastListUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
263 if( iAptInterface->lastDpkgUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
265 iAptInterface->setNeedRefresh(-1,listupd,dpkgupd,listupd);
267 iWinPackageView->setStatFilter( Package::PkgStatNotInstalled );
269 if( iAptInterface->needRepoRefresh() && !iSettings->qsettings()->value("no_catalogs_autoupdate",false).toBool() )
270 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetUpdate);
272 busyDialog(true, tr("Operation in progress"), tr("Reading package lists"));
274 iNextOperation = OpOpenPkgView;
275 iAptInterface->addQueuedOperation(AAptInterface::ModeReadPackages);
279 iAptInterface->run(iDimmer);
282 void MainWindow::on_btnUpgrade_clicked()
286 openNetworkConnection();
290 if( iAptInterface->lastListUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
292 if( iAptInterface->lastDpkgUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
294 iAptInterface->setNeedRefresh(-1,listupd,dpkgupd,listupd);
296 iWinPackageView->setStatFilter( Package::PkgStatUpgradeable );
298 if( iAptInterface->needRepoRefresh() && !iSettings->qsettings()->value("no_catalogs_autoupdate",false).toBool() )
299 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetUpdate);
301 busyDialog(true, tr("Operation in progress"), tr("Reading package lists"));
303 iNextOperation = OpOpenPkgView;
304 iAptInterface->addQueuedOperation(AAptInterface::ModeReadPackages);
308 iAptInterface->run(iDimmer);
311 void MainWindow::on_btnListInstalled_clicked()
315 if( !iSettings->qsettings()->value("remove_readfull",false).toBool() )
316 iAptInterface->setSkipListAndDates();
319 if( iAptInterface->lastDpkgUpdate() < QDateTime::currentDateTime().addSecs(-KListExpireTime) )
321 iAptInterface->setNeedRefresh(-1,-1,dpkgupd,-1);
323 iWinPackageView->setStatFilter( Package::PkgStatInstalled );
325 busyDialog(true, tr("Operation in progress"), tr("Reading package lists"));
327 iNextOperation = OpOpenPkgView;
328 iAptInterface->addQueuedOperation(AAptInterface::ModeReadPackages);
332 iAptInterface->run(iDimmer);
335 void MainWindow::operationQueueFinished(QList<AAptInterface::interfaceMode> lastModes, bool success, QString title, QStringList msgs)
337 if( lastModes.contains(AAptInterface::ModeAptGetSimulate) && success ) {
338 iNextOperation = OpPromptSimulated;
340 if( lastModes.contains(AAptInterface::ModeAptGetInstall) && success ) {
341 iWinPackageView->clearSelections();
343 iWinPackageView->close();
344 iNextOperation = OpNone;
346 GdkEventIconThemeReload();
349 QWidget* dialogParent = this;
350 if( iWinPackageView->isVisible() )
351 dialogParent = iWinPackageView;
353 if( iNextOperation == OpOpenPkgView && success )
355 iWinPackageView->openWin();
357 iNextOperation = OpNone;
358 } else if( iNextOperation == OpPromptSimulated && success )
360 QStringList inst,remv,instver,remvver;
361 QStringList all = iAptInterface->processPackages();
362 QStringList vers = iAptInterface->processPackageVersions();
363 for(int zyx=0; zyx<all.count(); zyx++)
365 if( all.at(zyx).endsWith('-') )
367 remv.append( all.at(zyx).left( all.at(zyx).size()-1 ) );
368 if( vers.count()>zyx )
369 remvver.append( vers.at(zyx) );
371 inst.append( all.at(zyx) );
372 if( vers.count()>zyx )
373 instver.append( vers.at(zyx) );
377 int total_dl_size = 0;
378 for( int i=0; i<inst.count(); i++ ) {
379 Package* pkg = iAptInterface->packagesAvailable()->value(inst.at(i),0);
381 total_dl_size += pkg->size()/1024;
386 pkglist = QString("<b>The following operations will be performed:</b><br>"
387 "%1 to install/upgrade, %2 to remove<br>").arg(inst.count()).arg(remv.count());
389 pkglist += QString("Total download size: %L1 kB<br>").arg(total_dl_size);
390 bool mismatch = false;
391 bool warn_system_package_remove = false;
392 bool warn_system_package_install = false;
394 if( remv.count()>0 ) {
395 pkglist += "<br><b><u>REMOVE:</u></b><br><font size=\"-1\">";
396 for( int i=0; i<remv.count(); i++ ) {
397 pkglist += "<b>" + remv.at(i) + "</b>";
398 Package* pkg = iAptInterface->packagesInstalled()->value(remv.at(i),0);
400 qDebug() << "Warning: unknown package" << remv.at(i);
401 pkglist += "<font color=\"red\">***UNKNOWN***</font>";
405 if( pkg && pkg->maemoDisplayName()=="Maemo 5" ) {
406 warn_system_package_remove = true;
409 if( remvver.count()>i ) {
410 pkglist += " " + remvver.at(i);
411 if( pkg && remvver.at(i) != pkg->version() ) {
412 qDebug() << "Version mismatch, database version is" << pkg->version() << "but removing" << remvver.at(i);
414 pkglist += " <font color=\"red\">***TRYING TO REMOVE " + pkg->version() + "***</font> ";
417 if( pkg && pkg->installedSize()>0 )
418 pkglist += QString(" (%L1 kB)").arg(pkg->installedSize());
422 pkglist += "</font>";
424 bool installing_blacklisted = false;
425 if( inst.count()>0 ) {
426 pkglist += "<br><b><u>INSTALL/UPGRADE:</u></b><br><font size=\"-1\">";
427 for( int i=0; i<inst.count(); i++ ) {
428 pkglist += "<b>" + inst.at(i) + "</b>";
429 Package* pkg = iAptInterface->packagesAvailable()->value(inst.at(i),0);
431 qDebug() << "Warning: unknown package" << inst.at(i);
432 pkglist += "<font color=\"red\">***NEW/UNKNOWN***</font>";
435 if( pkg && pkg->isBlacklisted() ) {
436 qDebug() << "Warning: installing blacklisted package" << inst.at(i);
437 pkglist += "<font color=\"red\">***BLACKLISTED***</font>";
438 installing_blacklisted = true;
441 if( pkg && pkg->maemoDisplayName()=="Maemo 5" ) { // unreliable?
442 warn_system_package_install = true;
445 if( instver.count()>i ) {
446 pkglist += " " + instver.at(i);
447 if( pkg && instver.at(i) != pkg->version() ) {
448 qDebug() << "Version mismatch, database version is" << pkg->version() << "but installing" << instver.at(i);
450 pkglist += " <font color=\"red\">***TRYING TO INSTALL " + pkg->version() + "***</font> ";
453 if( pkg && pkg->size()>0 ) {
454 pkglist += QString(" (%L1 kB)").arg(pkg->size()/1024);
459 pkglist += "</font>";
462 ConfirmDialog m(false, dialogParent);
463 m.setText("Warning", "There is a version mismatch between your original package selections and some of the packages being installed " \
464 "from the repositories. This could be due to your application catalogs being out of date.");
467 if( installing_blacklisted ) {
468 ConfirmDialog b(false, dialogParent);
469 b.setText("Warning","Blacklisted package(s) will be installed");
472 if( warn_system_package_remove ) {
473 ConfirmDialog s(false, dialogParent);
474 s.setText("Warning","You are about to remove a critical system package.");
477 if( warn_system_package_install ) {
478 ConfirmDialog s(false, dialogParent);
479 s.setText("Warning","You are trying to perform an install/upgrade operation on a critical system package. Doing a system upgrade with " \
480 "Faster Application Manager has not been tested and it could result in a horrible failure. You have been warned.");
485 ConfirmDialog d(true, dialogParent);
486 if( inst.count()==0 && remv.count()==0 )
488 pkglist = "None of the packages can be installed";
491 d.setText("Confirmation",pkglist);
493 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetInstall);
495 if( iSettings->qsettings()->value("enable_autoclean",true).toBool() && inst.count()>0 )
496 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetClean);
499 if( remv.count() > 0 )
500 busytext += QString("Remove %1 package(s)<br>").arg(remv.count());
501 if( inst.count() > 0 )
502 busytext += QString("Install %1 package(s)<br>").arg(inst.count());
503 busytext += "Preparing...";
504 busyDialog(true, "Operation in progress", busytext);
506 // "run" really does nothing here since the previous item should still be running
507 if( iWinPackageView->isVisible() ) {
508 iAptInterface->run(iWinPackageView->mydimmer());
510 iAptInterface->run(iDimmer);
513 iNextOperation = OpNone;
517 iNextOperation = OpNone;
519 if( iSettings->qsettings()->value("sound_notify",false).toBool() )
521 qDebug() << "playing sound";
522 iMediaObject->setCurrentSource( Phonon::MediaSource(iSettings->qsettings()->value("sound_file","/usr/share/sounds/ui-operation_ready.wav").toString()) );
523 iMediaObject->play();
526 QString text = "<br><b><u>Faster Application Manager</u></b><br>"
527 "<b>"+title+"</b><br>" + msgs.join("<br>") + "<br>";
529 QRect r = QApplication::desktop()->rect();
530 if(r.width() < r.height()) {
531 ConfirmDialog d(false, dialogParent);
532 d.setText(title,msgs.join("<br>"));
536 QMaemo5InformationBox::information(0, text, QMaemo5InformationBox::NoTimeout);
538 ConfirmDialog d(false, dialogParent);
539 d.setText(title,msgs.join("<br>"));
549 void MainWindow::busyDialog(bool show_, QString title, QString text)
552 iDimmer->setProgress(-1);
553 ui->menuMenu->setEnabled(false);
554 ui->centralWidget->setEnabled(false);
555 iWinPackageView->disableMenu();
556 iDimmer->resizeEvent(0);
557 iDimmer->dim(title, text);
558 iWinPackageView->mydimmer()->resizeEvent(0);
559 iWinPackageView->mydimmer()->dim(title, text);
562 iWinPackageView->mydimmer()->undim();
563 ui->menuMenu->setEnabled(true);
564 ui->centralWidget->setEnabled(true);
565 iWinPackageView->enableMenu();
569 void MainWindow::on_actionAbout_triggered()
571 ConfirmDialog d(false, this);
572 d.setText("About","Faster Application Manager<br>"
573 "<font size=\"-1\">Version " + PROGRAM_VERSION + "</font><br><br>"
574 "(C) Heikki Holstila 2010<br>Donate using "
575 "<a href=\"https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=6ZKRY5QFHL42A&lc=FI&item_name=Faster%20Application%20Manager"
576 "%20for%20Maemo5¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted\">PayPal</a>");
580 void MainWindow::on_actionClean_triggered()
582 //if( iOperation != OpNone ) return;
583 //iOperation = OpClean;
584 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetClean);
585 iAptInterface->run(iDimmer);
588 void MainWindow::closeEvent(QCloseEvent *event)
590 if( iDimmer->busy() ) {
591 iAptInterface->cancel();
598 void MainWindow::on_actionView_log_triggered()
600 QByteArray log = iAptInterface->readLogFile();
601 LogView l(log, this);
605 void MainWindow::on_actionOptions_triggered()
607 iSettings->openWin();
610 void MainWindow::notifyDialog(QString title, QString msg)
612 QWidget* dialogParent = this;
613 if( iWinPackageView->isVisible() )
614 dialogParent = iWinPackageView;
616 ConfirmDialog d(false, dialogParent);
617 d.setText(title, msg);
621 bool MainWindow::confirmDialog(QString title, QString msg)
623 QWidget* dialogParent = this;
624 if( iWinPackageView->isVisible() )
625 dialogParent = iWinPackageView;
627 ConfirmDialog d(true, dialogParent);
628 d.setText(title, msg);
632 void MainWindow::GdkEventIconThemeReload()
634 // DOES NOT EVEN WORK (at least not reliably) - disabled from the project file
636 #ifdef MYDEF_GTK_EXISTS
637 qDebug() << "Sending GDK icon theme reload event";
639 gdk_init((int*)QApplication::argc(),(gchar***)QApplication::argv());
641 // taken from hildon application manager
643 ev.type = GDK_CLIENT_EVENT;
645 ev.send_event = TRUE;
646 ev.message_type = gdk_atom_intern_static_string("_GTK_LOAD_ICONTHEMES");
648 gdk_event_send_clientmessage_toall((GdkEvent*)&ev);
650 while(gdk_events_pending()) {
651 g_main_context_iteration(NULL, true);
657 void MainWindow::on_actionLoad_file_triggered()
659 QStringList files = QFileDialog::getOpenFileNames(this, "Open files", "/", "Files (*.deb *.install)");
660 if( files.count() > 0 ) {
661 QStringList debs = files.filter(QRegExp(".*\\.deb$"));
662 QStringList installs = files.filter(QRegExp(".*\\.install$"));
663 if( debs.count()>0 && installs.count()>0 ) {
664 ConfirmDialog d(false, this);
665 d.setText("Error", "You can't mix different file types in your selection");
670 iDpkgInterface->loadDebFiles(debs);
671 else if( installs.count()>0 )
672 iAptInterface->loadInstallFiles(installs);
676 void MainWindow::resizeEvent(QResizeEvent* event)
681 iDimmer->resize( this->size() );
684 QMainWindow::resizeEvent(event);
687 void MainWindow::rescaleMenuView()
689 QRect sg = ui->listWidget->rect();
691 if( sg.width() > sg.height() ) {
692 ui->listWidget->setGridSize( QSize((sg.width()-12)/5, (sg.height()-12)/2) );
694 ui->listWidget->setGridSize( QSize((sg.width()-12)/3, (sg.height()-12)/3) );
698 void MainWindow::orientationChanged()
703 void MainWindow::showFreeSpace()
705 quint64 warn_limit_root = 5120;
706 quint64 warn_limit_opt = 51200;
707 struct statfs root_stat;
708 struct statfs opt_stat;
709 statfs("/",&root_stat);
710 statfs("/opt",&opt_stat);
711 quint64 free_root = static_cast<quint64>(root_stat.f_bavail) * static_cast<quint64>(root_stat.f_bsize) / 1024;
712 quint64 free_opt = static_cast<quint64>(opt_stat.f_bavail) * static_cast<quint64>(opt_stat.f_bsize) / 1024;
713 quint64 total_root = static_cast<quint64>(root_stat.f_blocks) * static_cast<quint64>(root_stat.f_bsize) / 1024;
714 quint64 total_opt = static_cast<quint64>(opt_stat.f_blocks) * static_cast<quint64>(opt_stat.f_bsize) / 1024;
715 qDebug() << "rootfs" << free_root << "/" << total_root << "kB free";
716 qDebug() << "opt fs" << free_opt << "/" << total_opt << "kB free";
718 QString rootstr = QString("rootfs: %L1 / %L2 MB free").arg(free_root/1024).arg(total_root/1024);
719 QString optstr = QString("opt: %L1 / %L2 MB free").arg(free_opt/1024).arg(total_opt/1024);
721 ui->label->setText("<font size=\"-1\">" + rootstr + "<br>" + optstr + "</font>");
724 ui->progressBarRoot->setFormat(rootstr);
725 ui->progressBarRoot->setMaximum(total_root/1024);
726 ui->progressBarRoot->setValue(free_root/1024);
727 ui->progressBarOpt->setFormat(optstr);
728 ui->progressBarOpt->setMaximum(total_opt/1024);
729 ui->progressBarOpt->setValue(free_opt/1024);
732 if( free_root < warn_limit_root || free_opt < warn_limit_opt )
734 ConfirmDialog d(false, this);
736 if( free_root < warn_limit_root )
737 t += QString("Root filesystem has %L1 kB available<br>").arg(free_root);
738 if( free_opt < warn_limit_opt )
739 t += QString("Opt (home) filesystem has %L1 kB available<br>").arg(free_opt);
740 t += "<br>You may proceed, but consider freeing up space to prevent problems in the future";
741 d.setText("Warning: Low disk space",t);
746 void MainWindow::on_listWidget_itemClicked(QListWidgetItem* item)
748 qDebug() << "main menu:" << item->statusTip();
750 if( item->statusTip() == "manage_repos" ) {
751 on_btnRepos_clicked();
753 else if( item->statusTip() == "update_catalogs" ) {
754 on_btnUpdate_clicked();
756 else if( item->statusTip() == "install_apps" ) {
757 on_btnListInstallable_clicked();
759 else if( item->statusTip() == "remove_apps" ) {
760 on_btnListInstalled_clicked();
762 else if( item->statusTip() == "upgrade_apps" ) {
763 on_btnUpgrade_clicked();
766 qDebug() << "Warning: Unhandled main menu item";
768 item->setSelected(false);