0.7.1
[fapman] / packageselector.cpp
1 /*
2         This file is part of Faster Application Manager.
3
4         Faster Application Manager is free software: you can redistribute it and/or modify
5         it under the terms of the GNU General Public License as published by
6         the Free Software Foundation, either version 3 of the License, or
7         (at your option) any later version.
8
9         Faster Application Manager is distributed in the hope that it will be useful,
10         but WITHOUT ANY WARRANTY; without even the implied warranty of
11         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12         GNU General Public License for more details.
13
14         You should have received a copy of the GNU General Public License
15         along with Faster Application Manager.  If not, see <http://www.gnu.org/licenses/>.
16
17         (C) Heikki Holstila 2010
18 */
19
20 #include <Qt>
21 #include <QDBusConnection>
22 #include <QDBusInterface>
23
24 #include "packageselector.h"
25 #include "ui_packageselector.h"
26 #include "package.h"
27 #include "packageview.h"
28 #include "repository.h"
29 #include "blacklistselect.h"
30 #include "aaptinterface.h"
31 #include "settings.h"
32 #include "mainwindow.h"
33
34 PackageSelector::PackageSelector(Package* pkg, AAptInterface* apt, Settings* set, MainWindow* mw, QWidget *parent) :
35     QDialog(parent),
36         ui(new Ui::PackageSelector), iNetworkAccessManager(0), iChangelogFetched(false), iFetchInProgress(false)
37 {
38         ui->setupUi(this);
39         iPkg = pkg;
40         iAptInterface = apt;
41         iSettings = set;
42         iMainWindow = mw;
43         iChangelog = "";
44
45         ui->pushButton_website->setIcon(QPixmap("/usr/share/icons/hicolor/48x48/hildon/general_web.png"));
46         if( getMaemoOrgUrl(pkg).isEmpty() && getMaemoOrgUrl(pkg->availablePackage()).isEmpty() ) {
47                 ui->pushButton_website->setEnabled(false);
48         }
49         if( pkg->isMarkedForOperation() )
50                 ui->pushButton_blacklist->setEnabled(false);
51
52         if( pkg->icon() && !pkg->icon()->isNull() ) {
53                 QPixmap aicon( *pkg->icon() );
54                 ui->label_appicon->setPixmap( aicon.scaled(48,48) );
55         } else {
56                 ui->label_appicon->setPixmap( QPixmap(":/icons/icons/appdefault.png") );
57         }
58         this->setWindowTitle( pkg->name() );
59
60         if( pkg->maemoDisplayName() != "" )
61                 ui->label_header->setText("<b>" + pkg->maemoDisplayName() + "</b>");
62         else
63                 ui->label_header->setText("<b>" + pkg->name() + "</b>");
64
65         ui->radioTabBasic->setChecked(true);
66         updateInfo();
67
68         // switch to shorter button labels for portait mode
69         if( QApplication::desktop()->width() < QApplication::desktop()->height() )
70         {
71                 ui->radioTabBasic->setText("Info");
72                 ui->radioTabChanges->setText("Chgs");
73                 ui->radioTabDepends->setText("Deps");
74         ui->scrollAreaWidgetContents->setMaximumWidth( QApplication::desktop()->width() - 15 );
75         }
76
77         Package* upg_pkg = iPkg->availablePackage();
78         if( !upg_pkg )
79                 upg_pkg = iPkg;
80         if( (!pkg->isUpgradeable() || (upg_pkg && upg_pkg->upgradeDescription().isEmpty())) && (getMaemoOrgUrl(upg_pkg).isEmpty()) )
81                 ui->radioTabChanges->hide();
82
83         if( pkg->isUpgradeable() )
84                 ui->radioInstall->setText("Upgrade");
85         else
86                 ui->radioInstall->setText("Install");
87
88         if( pkg->markedOperation() == Package::PkgOpNone )
89         {
90                 if( pkg->isInstalled() && pkg->isUpgradeable() )
91                         ui->label_statusicon->setPixmap(QPixmap(":/icons/icons/pkg_nop_instupgr.png"));
92                 else if( pkg->isInstalled() )
93                         ui->label_statusicon->setPixmap(QPixmap(":/icons/icons/pkg_nop_installed.png"));
94                 else if( !pkg->isInstalled() )
95                         ui->label_statusicon->setPixmap(QPixmap(":/icons/icons/pkg_nop_notinstalled.png"));
96
97                 ui->radioNothing->setChecked(true);
98         } else if( pkg->markedOperation() == Package::PkgOpInstallUpgrade ) {
99                 if( pkg->isUpgradeable() )
100                         ui->label_statusicon->setPixmap(QPixmap(":/icons/icons/pkg_upgrade.png"));
101                 else
102                         ui->label_statusicon->setPixmap(QPixmap(":/icons/icons/pkg_install.png"));
103                 ui->radioInstall->setChecked(true);
104         } else if( pkg->markedOperation() == Package::PkgOpRemove ) {
105                 ui->label_statusicon->setPixmap(QPixmap(":/icons/icons/pkg_remove.png"));
106                 ui->radioRemove->setChecked(true);
107         }
108
109         if( !getMaemoOrgUrl(upg_pkg).isEmpty() && !iChangelogFetched && !iFetchInProgress &&
110                 iSettings->qsettings()->value("always_fetch_changes",false).toBool() )
111         {
112                 queryChangelog();
113         }
114 }
115
116 PackageSelector::~PackageSelector()
117 {
118         if( iNetworkAccessManager ) {
119                 delete iNetworkAccessManager;
120                 iNetworkAccessManager = 0;
121         }
122     delete ui;
123 }
124
125 void PackageSelector::changeEvent(QEvent *e)
126 {
127     QDialog::changeEvent(e);
128     switch (e->type()) {
129     case QEvent::LanguageChange:
130         ui->retranslateUi(this);
131         break;
132     default:
133         break;
134     }
135 }
136
137 Package::operation PackageSelector::selectedOperation()
138 {
139         if( ui->radioInstall->isChecked() )
140                 return Package::PkgOpInstallUpgrade;
141         if( ui->radioRemove->isChecked() )
142                 return Package::PkgOpRemove;
143
144         return Package::PkgOpNone;
145 }
146
147 void PackageSelector::on_pushButton_blacklist_clicked()
148 {
149         Package* pkg = iPkg;
150         /*if( iPkg->isUpgradeable() && iPkg->availablePackage() )
151                 pkg = iPkg->availablePackage();*/
152
153         if( pkg->isInstalled() && pkg->isUpgradeable() )
154         {
155                 Package* upg = pkg->availablePackage();
156                 if( upg )
157                         pkg = upg;
158         }
159
160         BlacklistSelect s(pkg, this);
161         BlacklistSelect::blackList old = pkg->blacklisted();
162         if( s.exec() ) {                
163                 if( old != pkg->blacklisted() ) {
164                         Package* p1 = iAptInterface->packagesInstalled()->value(pkg->name(),0);
165                         Package* p2 = iAptInterface->packagesAvailable()->value(pkg->name(),0);
166                         if( p1 ) {
167                                 iAptInterface->removeFromBlacklist(p1,old);
168                                 if( pkg->blacklisted()==BlacklistSelect::BlacklistAll || pkg->blacklisted()==BlacklistSelect::BlacklistNone )
169                                         p1->setBlacklisted( pkg->blacklisted() );
170                                 else if( pkg->blacklisted()==BlacklistSelect::BlacklistThis && pkg->version()==p1->version() )
171                                         p1->setBlacklisted( pkg->blacklisted() );
172                                 else
173                                         p1->setBlacklisted( BlacklistSelect::BlacklistNone );
174                         }
175                         if( p2 ) {
176                                 iAptInterface->removeFromBlacklist(p2,old);
177                                 if( pkg->blacklisted()==BlacklistSelect::BlacklistAll || pkg->blacklisted()==BlacklistSelect::BlacklistNone )
178                                         p2->setBlacklisted( pkg->blacklisted() );
179                                 else if( pkg->blacklisted()==BlacklistSelect::BlacklistThis && pkg->version()==p2->version() )
180                                         p2->setBlacklisted( pkg->blacklisted() );
181                                 else
182                                         p2->setBlacklisted( BlacklistSelect::BlacklistNone );
183                         }
184                         iAptInterface->writeBlacklist();
185                 }
186                 updateInfo();
187         }
188 }
189
190 QString PackageSelector::getMaemoOrgUrl(Package* pkg)
191 {
192         QString url = "";
193
194         if( !pkg )
195                 return url;
196
197         if( pkg->repositories().count() == 0 )
198                 return url;
199
200         for( int i=0; i<pkg->repositories().count(); i++ )
201         {
202                 if( pkg->repositories().at(i) && pkg->repositories().at(i)->url().startsWith("http://repository.maemo.org") )
203                         url = "http://maemo.org/packages/view/" + pkg->name() + "/";
204         }
205         return url;
206 }
207
208 void PackageSelector::updateInfo()
209 {
210         if( ui->radioTabBasic->isChecked() )
211                 on_radioTabBasic_clicked();
212         else if( ui->radioTabChanges->isChecked() )
213                 on_radioTabChanges_clicked();
214         else if( ui->radioTabDepends->isChecked() )
215                 on_radioTabDepends_clicked();
216
217         ui->radioInstall->setEnabled(true);
218         ui->radioRemove->setEnabled(true);
219         ui->radioInstall->show();
220         ui->radioRemove->show();
221
222         Package* upg_pkg = iPkg->availablePackage();
223
224         if( iPkg->isInstalled() && !iPkg->isUpgradeable() )
225         {
226                 ui->radioInstall->setEnabled(false);
227         ui->radioInstall->hide();
228         } else if( !iPkg->isInstalled() ) {
229                 ui->radioRemove->setEnabled(false);
230                 ui->radioRemove->hide();
231         }
232
233         if( iPkg->isBlacklisted() ) {
234                 ui->radioInstall->setEnabled(false);
235                 //ui->radioRemove->setEnabled(false);
236         }
237         if( iPkg->isInstalled() && upg_pkg && upg_pkg->isBlacklisted() ) {
238                 ui->radioInstall->setEnabled(false);
239         }
240 }
241
242 void PackageSelector::on_pushButton_website_clicked()
243 {
244         QString url = getMaemoOrgUrl(iPkg);
245         if( url == "" ) {
246                 url = getMaemoOrgUrl(iPkg->availablePackage());
247                 if( url == "")
248                         return;
249         }
250
251         QDBusConnection conn = QDBusConnection::connectToBus(QDBusConnection::SessionBus, "faster_application_manager");
252
253         QString service = "com.nokia.osso_browser";
254         QString path = "/com/nokia/osso_browser/request";
255         QString method = "open_new_window";
256
257         QDBusInterface browser(service, path, service, conn, this);
258         browser.call(method, url);
259 }
260
261 void PackageSelector::on_radioTabBasic_clicked()
262 {
263         ui->label_header2->show();
264         QString header2;
265
266         Package* upg_pkg = iPkg->availablePackage();
267
268         if( iPkg->isInstalled() ) {
269                 header2 += "Installed, version <b>" + iPkg->version() + "</b>";
270         } else {
271                 header2 += "Not installed";
272         }
273         header2 += "<br>";
274
275         if( iPkg->markedOperation() == Package::PkgOpInstallUpgrade )
276         {
277                 if( iPkg->isUpgradeable() )
278                         header2 += "Marked for <b>upgrade</b><br>";
279                 else
280                         header2 += "Marked for <b>installation</b><br>";
281         } else if(iPkg->markedOperation() == Package::PkgOpRemove)
282         {
283                 header2 += "Marked for <b>removal</b><br>";
284         }
285
286         if( iPkg->isBlacklisted() && !iPkg->isUpgradeable() ) {
287                 header2 += "BLACKLISTED";
288                 if( iPkg->blacklisted() == BlacklistSelect::BlacklistAll )
289                         header2 += " (all)";
290                 else if( iPkg->blacklisted() == BlacklistSelect::BlacklistThis )
291                         header2 += " (this)";
292                 iPkg->setMarkedForOperation(Package::PkgOpNone);
293                 header2 += "<br>";
294         } else if( upg_pkg && upg_pkg->isBlacklisted() ) {
295                 header2 += "BLACKLISTED";
296                 if( upg_pkg->blacklisted() == BlacklistSelect::BlacklistAll )
297                         header2 += " (all)";
298                 else if( upg_pkg->blacklisted() == BlacklistSelect::BlacklistThis )
299                         header2 += " (" + upg_pkg->version() + ")";
300                 iPkg->setMarkedForOperation(Package::PkgOpNone);
301                 upg_pkg->setMarkedForOperation(Package::PkgOpNone);
302                 header2 += "<br>";
303         }
304
305         ui->label_header2->setText(header2);
306
307
308         QString longtext;
309         longtext += "Category: " + iPkg->section() + "<br>";
310
311         if( iPkg->isInstalled() ) {
312                 longtext += "Installation date: ";
313                 if( iPkg->date().isValid() )
314                         longtext += iPkg->date().toString("yyyy-MM-dd hh:mm");
315                 else
316                         longtext += "Unknown";
317                 longtext += "<br>";
318         }
319
320         if( iPkg->isInstalled() && iPkg->installedSize() > 0 )
321                 longtext += QString("Size: %L1 kB<br>").arg(iPkg->installedSize() );
322
323
324         if( !iPkg->isInstalled() ){
325                 longtext += "Available version <b>" + iPkg->version() + "</b>";
326                 if( iPkg->size() > 0 )
327                         longtext += QString(" (%L1 kB)").arg(iPkg->size()/1024 );
328                 longtext += "<br>";
329         }
330         else if( iPkg->isUpgradeable() ){
331                 longtext += "Available version <b>" + iPkg->upgradeableVersion() + "</b>";
332                 if( iPkg->size() > 0 )
333                         longtext += QString(" (%L1 kB)").arg(iPkg->size()/1024 );
334                 longtext += "<br>";
335         }
336
337         if( !iPkg->isInstalled() ) {
338                 longtext += "Available package date: ";
339                 if( iPkg->date().isValid() )
340                         longtext += iPkg->date().toString("yyyy-MM-dd hh:mm");
341                 else
342                         longtext += "Unknown";
343                 longtext += "<br>";
344         } else if( iPkg->isUpgradeable() ) {
345                 longtext += "Available package date: ";
346                 if( iPkg->availablePackage() && iPkg->availablePackage()->date().isValid() )
347                         longtext += iPkg->availablePackage()->date().toString("yyyy-MM-dd hh:mm");
348                 else
349                         longtext += "Unknown";
350                 longtext += "<br>";
351         }
352
353         if( !iPkg->isInstalled() )
354         {
355                 longtext += "Repositories: ";
356                 if( iPkg->repositories().count()>0 ) {
357                         for(int i=0; i<iPkg->repositories().count(); i++ ) {
358                                 if( iPkg->repositories().at(i) )
359                                         longtext += iPkg->repositories().at(i)->name();
360                                 else
361                                         longtext += "unknown";
362                                 if( i<iPkg->repositories().count()-1 )
363                                         longtext += ", ";
364                         }
365                         longtext += "<br>";
366                 } else {
367                         longtext += "unknown<br>";
368                 }
369         }
370
371         if( iPkg->isUpgradeable() )
372         {
373                 longtext += "Repositories: ";
374                 if( upg_pkg && upg_pkg->repositories().count()>0 ) {
375                         for(int i=0; i<upg_pkg->repositories().count(); i++ ) {
376                                 if( upg_pkg->repositories().at(i) )
377                                         longtext += upg_pkg->repositories().at(i)->name();
378                                 else
379                                         longtext += "unknown";
380                                 if( i<upg_pkg->repositories().count()-1 )
381                                         longtext += ", ";
382                         }
383                         longtext += "<br>";
384                 } else {
385                         longtext += "unknown<br>";
386                 }
387         }
388
389         if( !iPkg->maintainerRichText().isEmpty() ) {
390                 longtext +="Maintainer: " + iPkg->maintainerRichText() + "<br>";
391         }
392
393         longtext += "<br>" + iPkg->descShort();
394         QString descLong = iPkg->descLong();
395         if( descLong.length()>0 ) {
396                 descLong.replace('\n',"<br>");
397                 longtext += "<font size=\"-1\"><br><br>" + descLong + "</font>";
398         }
399
400         ui->label_text->setText( longtext );
401 }
402
403 void PackageSelector::on_radioTabChanges_clicked()
404 {
405         ui->label_header2->hide();
406         ui->label_header2->setText("");
407
408         QString text;
409
410         Package* upg_pkg = iPkg->availablePackage();
411         if( !upg_pkg )
412                 upg_pkg = iPkg;
413
414         if( iPkg->isUpgradeable() && upg_pkg && !upg_pkg->upgradeDescription().isEmpty() )
415         {
416                 text += "<u><b>Upgrade description:</b></u>";
417                 text += "<font size=\"-1\"><br>";
418                 text += upg_pkg->upgradeDescription();
419                 text += "</font><br>";
420                 text.replace('\n',"<br>");
421         }
422
423         QString changelog;
424         if( !getMaemoOrgUrl(upg_pkg).isEmpty() && !iChangelogFetched && !iFetchInProgress ) {
425                 queryChangelog();
426                 changelog = "Fetching changelog...";
427         } else {
428                 changelog = iChangelog;
429                 if( iFetchInProgress )
430                         changelog = "Fetching changelog...";
431                 else if( changelog == "" )
432                         changelog = "Not available";
433         }
434
435         text += "<u><b>Debian changelog:</b></u><font size=\"-1\"><br>";
436         text += changelog;
437         text += "</font>";
438
439         ui->label_text->setText(text);
440 }
441
442 void PackageSelector::on_radioTabDepends_clicked()
443 {
444         ui->label_header2->hide();
445         ui->label_header2->setText("");
446         ui->label_text->setText("");
447
448         QStringList deps = Package::toTrimmedRichTextList( iPkg->depends() );
449         QStringList confl = Package::toTrimmedRichTextList( iPkg->conflicts() );
450         QStringList predeps = Package::toTrimmedRichTextList( iPkg->preDepends() );
451         QStringList repl = Package::toTrimmedRichTextList( iPkg->replaces() );
452         QStringList prov = Package::toTrimmedRichTextList( iPkg->provides() );
453         QStringList brks = Package::toTrimmedRichTextList( iPkg->breaks() );
454         QStringList recs = Package::toTrimmedRichTextList( iPkg->recommends() );
455         QStringList sugs = Package::toTrimmedRichTextList( iPkg->suggests() );
456
457         QString text;
458
459         if( deps.count()>0 )
460         {
461                 text += "<b><u>Depends:</u></b><br><font size=\"-1\">";
462                 text += deps.join(", ");
463                 text += "</font><br>";
464         }
465
466         if( predeps.count()>0 )
467         {
468                 text += "<b><u>Pre-Depends:</u></b><br><font size=\"-1\">";
469                 text += predeps.join(", ");
470                 text += "</font><br>";
471         }
472
473         if( confl.count()>0 )
474         {
475                 text += "<b><u>Conflicts:</u></b><br><font size=\"-1\">";
476                 text += confl.join(", ");
477                 text += "</font><br>";
478         }
479
480         if( prov.count()>0 )
481         {
482                 text += "<b><u>Provides:</u></b><br><font size=\"-1\">";
483                 text += prov.join(", ");
484                 text += "</font><br>";
485         }
486
487         if( repl.count()>0 )
488         {
489                 text += "<b><u>Replaces:</u></b><br><font size=\"-1\">";
490                 text += repl.join(", ");
491                 text += "</font><br>";
492         }
493
494         if( brks.count()>0 )
495         {
496                 text += "<b><u>Breaks:</u></b><br><font size=\"-1\">";
497                 text += brks.join(", ");
498                 text += "</font><br>";
499         }
500
501         if( recs.count()>0 )
502         {
503                 text += "<b><u>Recommends:</u></b><br><font size=\"-1\">";
504                 text += recs.join(", ");
505                 text += "</font><br>";
506         }
507
508         if( sugs.count()>0 )
509         {
510                 text += "<b><u>Suggests:</u></b><br><font size=\"-1\">";
511                 text += sugs.join(", ");
512                 text += "</font><br>";
513         }
514
515         if( deps.count()==0 && predeps.count()==0 && confl.count()==0 && prov.count()==0 &&
516                 repl.count()==0 && brks.count()==0 && recs.count()==0 && sugs.count()==0 )
517         {
518                 text = "Package has no dependencies listed";
519         }
520
521         ui->label_text->setText(text);
522 }
523
524 void PackageSelector::queryChangelog()
525 {
526         if( iChangelogFetched || iFetchInProgress )
527                 return;
528
529         if( iMainWindow )
530                 iMainWindow->openNetworkConnection();
531
532         iChangelogFetched = false;
533         iFetchInProgress = true;
534         iChangelog = "";
535
536         Package* pkg = iPkg->availablePackage();
537         if( !pkg )
538                 pkg = iPkg;
539
540         if( getMaemoOrgUrl(pkg) == "" ) {
541                 iChangelogFetched = true;
542                 return;
543         }
544
545         if( !iNetworkAccessManager ) {
546                 iNetworkAccessManager = new QNetworkAccessManager(this);
547         connect(iNetworkAccessManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(changelogFetchNetworkReply(QNetworkReply*)));
548
549                 if( iSettings->qsettings()->value("use_proxies").toBool() && !iSettings->qsettings()->value("http_proxy").toString().isEmpty() )
550                 {
551                          QNetworkProxy proxy = Settings::createProxyFromString( iSettings->qsettings()->value("http_proxy").toString() );
552                          iNetworkAccessManager->setProxy(proxy);
553                 }
554         }
555
556         QUrl url( getMaemoOrgUrl(pkg) );
557         QNetworkRequest req(url);
558
559         qDebug() << "fetching changelog";
560
561         iNetworkAccessManager->get(req);
562 }
563
564 void PackageSelector::changelogFetchNetworkReply(QNetworkReply* reply)
565 {
566         if( reply->error() == QNetworkReply::NoError ) {
567                 QByteArray data = reply->readAll();
568
569                 int pos = data.indexOf("<div class=\"changelog\">");
570                 int pos2 = data.indexOf("</div>", pos);
571
572                 if( pos!=-1 && pos2!=-1 ) {
573                         iChangelog = parseChangeTable( QString::fromUtf8( data.mid(pos,pos2-pos+6) ) );
574                 } else {
575                         iChangelog = "";
576                 }
577
578                 qDebug() << "changelog fetched";
579         } else {
580                 iChangelog = "Not available ( error)";
581                 qDebug() << "changelog fetch error:" << reply->error() << reply->errorString();
582         }
583
584         reply->deleteLater();
585         iFetchInProgress = false;
586         iChangelogFetched = true;
587
588         if( this->isVisible() && ui->radioTabChanges->isChecked() )
589                 on_radioTabChanges_clicked();
590 }
591
592 QString PackageSelector::parseChangeTable(QString tabledata)
593 {
594         tabledata.remove("<strong>");
595         tabledata.remove("</strong>");
596         tabledata.remove('\n');
597
598         //qDebug() << tabledata;
599
600         QString newdata = "<table><tbody>";
601
602         int pos = tabledata.indexOf("<tr>", tabledata.indexOf("<tbody>") );
603         while( pos != -1 ) {
604                 int pos2 = tabledata.indexOf("</td>",pos);
605                 pos2 = tabledata.indexOf("</td>",pos2+5);
606
607                 if( pos2 != -1 )
608                         newdata += tabledata.mid(pos, pos2-pos+5) + "</tr>";
609
610                 pos = tabledata.indexOf("<tr>",pos+4);
611         }
612
613         newdata += "</tbody></table>";
614
615         //qDebug() << newdata;
616
617         return newdata;
618 }