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