test
[fapman] / packageview.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 "packageview.h"
21 #include "ui_packageview.h"
22 #include "package.h"
23 #include "filterselect.h"
24 #include "confirmdialog.h"
25 #include "dimmer.h"
26 #include "packageselector.h"
27 #include "help.h"
28 #include "aaptinterface.h"
29 #include "logview.h"
30 #include "sortselector.h"
31 #include "settings.h"
32 #include "searchoptions.h"
33 #include "blacklistselect.h"
34
35 PackageListWidgetItem::PackageListWidgetItem(Package* p_, QString name_) : QListWidgetItem(name_)
36 {
37         iPackage = p_;
38 }
39
40
41 void ListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
42 {
43         //QTime t;
44         //t.start();
45
46         QString name = index.data(UserRoleName).toString();
47         QString version = index.data(UserRoleVersion).toString();
48         QString desc = index.data(UserRoleDescShort).toString();
49         Package::operation marked = (Package::operation) index.data(UserRoleMarked).toInt();
50         bool installed = index.data(UserRoleInstalled).toBool();
51         bool upgradeable = index.data(UserRoleUpgradeable).toBool();
52         int statfilter = index.data(UserRoleCurrentStatFilter).toInt();
53         int catfilter = index.data(UserRoleCurrentCatFilter).toInt();
54         QString upg_version = index.data(UserRoleAvailVersion).toString();
55         BlacklistSelect::blackList blacklisted = (BlacklistSelect::blackList) index.data(UserRoleBlacklisted).toInt();
56
57         painter->save();
58         QRect r = option.rect;
59
60         QLinearGradient gradientBase(r.topLeft(), r.bottomLeft());
61         QColor base = option.palette.color(QPalette::Window);
62         QColor base2 = base;
63         int r1=base.red()+15;
64         int g1=base.green()+15;
65         int b1=base.blue()+15;
66         if( r1>255 ) r1=255;
67         if( g1>255 ) g1=255;
68         if( b1>255 ) b1=255;
69         int r2=base2.red()-20;
70         int g2=base2.green()-20;
71         int b2=base2.blue()-20;
72         if( r2<0 ) r2=0;
73         if( g2<0 ) g2=0;
74         if( b2<0 ) b2=0;
75         base.setRgb( r1, g1, b1 );
76         base2.setRgb( r2, g2, b2 );
77         gradientBase.setColorAt(0, base);
78         gradientBase.setColorAt(1, base2);
79
80         painter->fillRect(r, gradientBase);
81         painter->drawLine(QPoint(r.left(),r.bottom()), QPoint(r.right(),r.bottom()));
82
83         QPixmap icon = index.data(Qt::DecorationRole).value<QPixmap>();
84         if( icon.isNull() ) {
85                 // use default icon
86                 painter->drawPixmap( r.left(), r.top()+4, 48, 48, iDefaultIcon );
87         } else {
88                 painter->drawPixmap( r.left(), r.top()+4, 48, 48, icon );
89         }
90
91         QPixmap statusicon;
92         if( marked == Package::PkgOpNone )
93         {
94                 if( installed && upgradeable )
95                         statusicon = iIconPkgNoOpInstalledUpgradeable;
96                 else if( installed )
97                         statusicon = iIconPkgNoOpInstalled;
98                 else if( !installed )
99                         statusicon = iIconPkgNoOpNotInstalled;
100         } else if( marked == Package::PkgOpInstallUpgrade ) {
101                 if( upgradeable )
102                         statusicon = iIconPkgUpgrade;
103                 else
104                         statusicon = iIconPkgInstall;
105         } else if( marked == Package::PkgOpRemove ) {
106                 statusicon = iIconPkgRemove;
107         }
108
109         QString showVer = "";
110         if( upgradeable && (statfilter==Package::PkgStatUpgradeable ||
111                                                 (statfilter==Package::PkgStatUnknown && marked==Package::PkgOpInstallUpgrade) ||
112                                                 (catfilter==PackageView::CatFilterAllMarked && marked==Package::PkgOpInstallUpgrade) ))
113         {
114                 showVer = upg_version;
115         } else {
116                 showVer = version;
117         }
118
119         int ver_w = 0;
120         if( QApplication::desktop()->width() > QApplication::desktop()->height() )
121         {
122                 r = option.rect;
123                 r.setRight( r.right()-statusicon.width()-4 );
124
125                 if( catfilter != PackageView::CatFilterBlacklisted ) {
126                         painter->drawText(r, Qt::AlignTop|Qt::AlignRight, showVer, &r);
127                         ver_w = r.width();
128                 } else if( blacklisted==BlacklistSelect::BlacklistThis ) {
129                         if( upgradeable && upg_version!="" ) {
130                                 showVer = upg_version;
131                         } else {
132                                 showVer = version;
133                         }
134                         painter->drawText(r, Qt::AlignTop|Qt::AlignRight, showVer, &r);
135                         ver_w = r.width();
136                 }
137         }
138
139         r = option.rect;
140         r.setRight( r.right()-statusicon.width()-4-ver_w );  //does not work as it should?
141         QFont f = painter->font();
142         f.setBold(true);
143         painter->setFont(f);
144         painter->drawText(r.left()+iDefaultIcon.width()+2, r.top(), r.width(), r.height(), Qt::AlignTop|Qt::AlignLeft, name, &r);
145         f.setBold(false);
146         painter->setFont(f);
147
148         f.setPointSize( f.pointSize()-4 );
149         painter->setFont(f);
150         r = option.rect;
151         painter->drawText(r.left()+iDefaultIcon.width()+2, r.top(), r.width(), r.height(), Qt::AlignBottom|Qt::AlignLeft, desc, &r);
152
153         r = option.rect;
154         painter->drawPixmap(r.right()-statusicon.width()-2, r.top()+4, 24, 24, statusicon);
155
156         painter->restore();
157
158         //if( t.elapsed()>=100 )
159         //qDebug() << name << t.elapsed();
160 }
161
162 void ListItemDelegate::loadIcons()
163 {
164         iDefaultIcon = QPixmap(":/icons/icons/appdefault.png");
165         iIconPkgInstall = QPixmap(":/icons/icons/pkg_install.png");
166         iIconPkgUpgrade = QPixmap(":/icons/icons/pkg_upgrade.png");
167         iIconPkgRemove = QPixmap(":/icons/icons/pkg_remove.png");
168         iIconPkgNoOpInstalled = QPixmap(":/icons/icons/pkg_nop_installed.png");
169         iIconPkgNoOpNotInstalled = QPixmap(":/icons/icons/pkg_nop_notinstalled.png");
170         iIconPkgNoOpInstalledUpgradeable = QPixmap(":/icons/icons/pkg_nop_instupgr.png");
171 }
172
173
174 QSize ListItemDelegate::sizeHint(const QStyleOptionViewItem&, const QModelIndex&) const
175 {
176         return QSize(400, 58);
177 }
178
179
180 PackageView::PackageView(QWidget *parent) : QMainWindow(parent), ui(new Ui::PackageView)
181 {
182         iMainWindow = dynamic_cast<MainWindow*>(parent);
183         ui->setupUi(this);
184 #ifdef Q_WS_MAEMO_5
185         this->setAttribute(Qt::WA_Maemo5StackedWindow);
186         this->setWindowFlags(Qt::Window);
187         this->setAttribute(Qt::WA_Maemo5AutoOrientation);
188 #endif
189         iSettings = 0;
190         iAptInterface = 0;
191
192         connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(orientationChanged()));
193
194         iCatFilterLabels
195                         << tr("All marked packages")    // a special case
196                         << tr("All user categories")
197                         << tr("\tDesktop")
198                         << tr("\tEducation")
199                         << tr("\tGames")
200                         << tr("\tGraphics")
201                         << tr("\tInternet & Networking")
202                         << tr("\tLocation & Navigation")
203                         << tr("\tMultimedia")
204                         << tr("\tOffice")
205                         << tr("\tOther")
206                         << tr("\tProgramming")
207                         << tr("\tScience")
208                         << tr("\tSystem")
209                         << tr("\tUtilities")
210                         << tr("All packages (ADVANCED)")
211                         << tr("Blacklisted packages");  // a special case
212
213         iCatFilterStrings
214                         << ""
215                         << "user/"
216                         << "user/desktop"
217                         << "user/education"
218                         << "user/games"
219                         << "user/graphics"
220                         << "user/network"
221                         << "user/navigation"
222                         << "user/multimedia"
223                         << "user/office"
224                         << "user/other"
225                         << "user/development"
226                         << "user/science"
227                         << "user/system"
228                         << "user/utilities"
229                         << ""
230                         << "";
231
232         iDefaultCatFilter = CatFilterAllUser;
233         iSelectedCatFilter = iDefaultCatFilter;
234
235         iStatFilterLabels
236                         << tr("All")
237                         << tr("Not installed")
238                         << tr("Upgradeable")
239                         << tr("Installed");
240
241         iSelectedStatFilter = Package::PkgStatUnknown;
242         iSortOrder = SortAlpha;
243
244         iDimmer = new dimmer(this);
245
246         ui->searchBar->hide();
247
248         iListCoverLabel = new QLabel(ui->listWidget);
249         iListCoverLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
250         iListCoverLabel->setAlignment(Qt::AlignCenter);
251
252         iKeyFilter = new KeyEventGrabber(this);
253         ui->listWidget->installEventFilter(iKeyFilter);
254
255         iSortNoticeShown = false;
256
257         iSearchPkgName = true;
258         iSearchDisplayName = true;
259         iSearchDescShort = true;
260         iSearchDescLong = false;
261
262         // fine-tune kinetic scrolling parameters
263         QAbstractKineticScroller* listscroller = ui->listWidget->property("kineticScroller").value<QAbstractKineticScroller*>();
264         if( listscroller )
265         {
266                 //qDebug() << listscroller->dragInertia() << listscroller->decelerationFactor()
267                 //              << listscroller->minimumVelocity() << listscroller->maximumVelocity();
268                 listscroller->setDecelerationFactor(0.75); // default is 0.85
269                 listscroller->setDragInertia(0.60);     // default is 0.85
270                 listscroller->setMaximumVelocity(1800); // default is 3500
271
272                 // not good because it alse sets horizontal overshoot:
273                 //listscroller->setOvershootPolicy( QAbstractKineticScroller::OvershootAlwaysOn );
274         }
275 }
276
277 PackageView::~PackageView()
278 {
279         delete iListCoverLabel;
280         delete iKeyFilter;
281         delete iDimmer;
282     delete ui;
283 }
284
285 void PackageView::orientationChanged()
286 {
287         ui->listWidget->scroll(1,1);    // this causes all items to be repainted
288         iListCoverLabel->setGeometry( ui->listWidget->rect() );
289 }
290
291 void PackageView::resizeEvent(QResizeEvent* event)
292 {
293         iListCoverLabel->setGeometry( ui->listWidget->rect() );
294         QWidget::resizeEvent(event);
295 }
296
297 bool PackageView::doFilterCategory(Package* pkg)
298 {
299         if( pkg->section()=="user/hidden" && iSelectedStatFilter!=Package::PkgStatInstalled && iSelectedStatFilter!=Package::PkgStatUnknown )
300                 return false;
301         if( pkg->section()=="user/hidden" && !pkg->isInstalled() )
302                 return false;
303
304         Package* upg_pkg = pkg->availablePackage();
305
306         if( iSelectedStatFilter==Package::PkgStatUpgradeable && iSelectedCatFilter!=CatFilterBlacklisted &&
307                 pkg->isUpgradeable() && upg_pkg && upg_pkg->isBlacklisted() )
308                 return false;
309
310         if( pkg->isBlacklisted() || (upg_pkg && upg_pkg->isBlacklisted()) )
311         {
312                 if( iSelectedCatFilter == CatFilterBlacklisted )
313                         return true;
314                 if( pkg->isInstalled() && (iSelectedStatFilter==Package::PkgStatInstalled || iSelectedStatFilter==Package::PkgStatUnknown) )
315                         return true;
316                 if( pkg->isBlacklisted() && iSelectedCatFilter != CatFilterBlacklisted )
317                         return false;
318         } else if( !pkg->isBlacklisted() && iSelectedCatFilter == CatFilterBlacklisted )
319                 return false;
320
321         if( iSelectedCatFilter==CatFilterAllMarked ) {
322                 if( pkg->isMarkedForOperation() )
323                         return true;
324                 else
325                         return false;
326         }
327         if( pkg->section().startsWith( iCatFilterStrings.at(iSelectedCatFilter) ) )
328                 return true;
329
330         return false;
331 }
332
333 QString PackageView::generateSortString(Package* pkg)
334 {
335         QString sortstr;
336
337         if( iSortOrder==SortAlpha ) {
338                 sortstr = pkg->displayName();
339         }
340         else if( iSortOrder==SortDateDesc ) {
341                 Package* upg = 0;
342                 if( pkg->isUpgradeable() )
343                         upg = pkg->availablePackage();
344
345                 if( (!upg && pkg->date().isValid()) || iSelectedStatFilter==Package::PkgStatInstalled )
346                         sortstr = pkg->date().toString("yyyy-MM-dd hh:mm:ss");
347                 else if( upg && upg->date().isValid() ) {
348                         sortstr = upg->date().toString("yyyy-MM-dd hh:mm:ss");
349                 } else {
350                         sortstr = "";
351                         iPackagesEmptySort++;
352                 }
353         }
354         else if( iSortOrder==SortSizeDesc ) {
355                 if( pkg->isInstalled() )
356                         sortstr = QString("%1").arg(pkg->installedSize()*1024, 12 );
357                 else
358                         sortstr = QString("%1").arg(pkg->size(), 12 );
359         }
360
361         //qDebug() << sortstr;
362
363         return sortstr;
364 }
365
366 void PackageView::openWin()
367 {
368         ui->listWidget->clear();
369         ui->listWidget->setSortingEnabled(true);
370         iPackagesEmptySort = 0;
371
372         if( !isVisible() ) {
373                 iMainWindow->busyDialog(false);
374                 iListCoverLabel->setText("Loading...");
375                 iListCoverLabel->setAutoFillBackground(true);
376                 iListCoverLabel->show();
377                 show();
378                 QApplication::processEvents();
379         }
380
381         if( iSortOrder==SortDateDesc || iSortOrder==SortSizeDesc )
382                 ui->listWidget->sortItems(Qt::DescendingOrder);
383         else
384                 ui->listWidget->sortItems(Qt::AscendingOrder);
385
386         delete ui->listWidget->itemDelegate();
387         ListItemDelegate* delegate = new ListItemDelegate(ui->listWidget);
388         delegate->loadIcons();
389         ui->listWidget->setItemDelegate( delegate );
390
391         if( !ui->searchBar->isVisible() )
392         {
393                 if( iSelectedStatFilter == Package::PkgStatNotInstalled || iSelectedStatFilter == Package::PkgStatUnknown ||
394                         iSelectedCatFilter == CatFilterAllMarked || iSelectedCatFilter == CatFilterBlacklisted )
395                 {
396                         QHashIterator<QString, Package*> i( *iAptInterface->packagesAvailable() );
397                         while (i.hasNext())
398                         {
399                                 i.next();
400                                 Package* inst = iAptInterface->packagesInstalled()->value(i.value()->name(),0);
401                                 if( doFilterCategory(i.value()) && !inst )
402                                         addListItem(i.value(), generateSortString(i.value()));
403                         }
404                 }
405                 if( iSelectedStatFilter == Package::PkgStatInstalled || iSelectedStatFilter == Package::PkgStatUpgradeable ||
406                         iSelectedStatFilter == Package::PkgStatUnknown || iSelectedCatFilter == CatFilterAllMarked ||
407                         iSelectedCatFilter == CatFilterBlacklisted )
408                 {
409                         QHashIterator<QString, Package*> i( *iAptInterface->packagesInstalled() );
410                         while (i.hasNext())
411                         {
412                                 i.next();
413                                 if( iSelectedStatFilter == Package::PkgStatUpgradeable && iSelectedCatFilter != CatFilterBlacklisted ) {
414                                         if( i.value()->isUpgradeable() && doFilterCategory(i.value()) )
415                                                 addListItem(i.value(), generateSortString(i.value()));
416                                 } else {
417                                         if( doFilterCategory(i.value()) )
418                                                 addListItem(i.value(), generateSortString(i.value()));
419                                 }
420                         }
421                 }
422         } else {
423                 for( int j=0; j<iSearchResults.count(); j++ )
424                 {
425                         addListItem(iSearchResults.at(j), generateSortString( iSearchResults.at(j) ));
426                 }
427         }
428
429         iListCoverLabel->hide();
430         iListCoverLabel->setAutoFillBackground(false);
431
432         updateLabel();
433
434         if( iSelectedStatFilter==Package::PkgStatUpgradeable && ui->listWidget->count()>0 &&
435                 iSelectedCatFilter != CatFilterAllMarked && iSelectedCatFilter != CatFilterBlacklisted )
436         {
437                 ui->actionUpgrade_all->setVisible(true);
438         } else {
439                 ui->actionUpgrade_all->setVisible(false);
440         }
441
442         if( iSelectedCatFilter == CatFilterBlacklisted && ui->listWidget->count()>0 ) {
443                 ui->actionRestore_all->setVisible(true);
444         } else {
445                 ui->actionRestore_all->setVisible(false);
446         }
447
448         show();
449
450         if( !ui->searchBar->isVisible() ) {
451                 ui->listWidget->setFocusPolicy(Qt::StrongFocus);
452                 ui->listWidget->setFocus();
453         } else {
454                 ui->listWidget->setFocusPolicy(Qt::NoFocus);
455                 ui->lineEdit->setFocus();
456         }
457
458         if( ui->listWidget->count() == 0 )
459         {
460                 iListCoverLabel->setGeometry( ui->listWidget->rect() );
461                 iListCoverLabel->setText("No packages");
462                 iListCoverLabel->show();
463         }
464
465         if( ui->listWidget->count()>1 && iPackagesEmptySort == ui->listWidget->count() && !iSortNoticeShown ) {
466                 ConfirmDialog d(false, this);
467                 QString msg = "No shown packages currently have the required information for sorting by this criterion. The list is unsorted.";
468                 if( iSortOrder == SortDateDesc && !iSettings->qsettings()->value("fetch_dates",false).toBool() )
469                         msg += " You can enable date fetching in the options menu.";
470                 d.setText("Notice", msg);
471                 d.exec();
472                 iSortNoticeShown = true;
473         }
474 }
475
476 void PackageView::enableMenu()
477 {
478         ui->menuMenu->setEnabled(true);
479 }
480
481 void PackageView::disableMenu()
482 {
483         ui->menuMenu->setEnabled(false);
484 }
485
486 void PackageView::addListItem(Package* pkg_, QString listname_)
487 {
488         PackageListWidgetItem* p = new PackageListWidgetItem( pkg_, listname_ );
489
490         if( pkg_ != 0 )
491         {
492                 QString name = pkg_->name();
493                 if( pkg_->maemoDisplayName()!="" )
494                         name = pkg_->maemoDisplayName();
495                 p->setData(UserRoleName, name);
496         } else {
497                 p->setData(UserRoleName, listname_);
498         }
499
500         if( pkg_ != 0 )
501         {
502                 p->setData(UserRoleDescShort, pkg_->descShort());
503                 p->setData(UserRoleVersion, pkg_->version());
504                 p->setData(UserRoleMarked, (int)pkg_->markedOperation());
505                 p->setData(UserRoleInstalled, pkg_->isInstalled());
506                 p->setData(UserRoleUpgradeable, pkg_->isUpgradeable());
507                 p->setData(UserRoleAvailVersion, pkg_->upgradeableVersion());
508                 p->setData(UserRoleCurrentStatFilter, iSelectedStatFilter);
509                 p->setData(UserRoleCurrentCatFilter, iSelectedCatFilter);
510
511                 if( pkg_->availablePackage() )
512                         p->setData(UserRoleBlacklisted, (int)pkg_->availablePackage()->blacklisted());
513                 else
514                         p->setData(UserRoleBlacklisted, (int)pkg_->blacklisted());
515
516                 //qDebug()<<pkg_->name();
517
518                 pkg_->convertIcon();
519                 p->setData(Qt::DecorationRole, *pkg_->icon());
520         }
521         ui->listWidget->addItem( p );
522 }
523
524 void PackageView::closeEvent(QCloseEvent *event)
525 {
526         if( !iAptInterface ) {
527                 resetWindow();
528                 event->accept();
529         }
530
531         if( iDimmer->busy() )
532         {
533                 iAptInterface->cancel();
534                 event->ignore();
535                 return;
536         }
537
538 #ifdef Q_WS_MAEMO_5
539         if( iAptInterface->numSelectedPackages() == 0 )
540         {               
541                 resetWindow();
542                 event->accept();
543         } else {
544                 QString c;
545                 c.setNum( iAptInterface->numSelectedPackages() );
546                 ConfirmDialog d(true, this);
547                 d.setText("Returning to main menu", QString("Clear %1 package selection(s) and lose all the pending changes?").arg(iAptInterface->numSelectedPackages()));
548                 if( d.exec() ) {
549                         resetWindow();
550                         event->accept();
551                 } else {
552                         event->ignore();
553                 }
554         }
555 #else   // for simulator
556         resetWindow();
557         event->accept();
558 #endif
559 }
560
561 void PackageView::changeEvent(QEvent *e)
562 {
563     QMainWindow::changeEvent(e);
564     switch (e->type()) {
565     case QEvent::LanguageChange:
566         ui->retranslateUi(this);
567         break;
568     default:
569         break;
570     }
571 }
572
573 void PackageView::on_btn_Commit_clicked()
574 {
575         QStringList pkgnames;
576
577         QHashIterator<QString, Package*> i( *iAptInterface->packagesAvailable() );
578         while (i.hasNext())
579         {
580                 i.next();
581
582                 if( i.value()->markedOperation() == Package::PkgOpInstallUpgrade )
583                         pkgnames << i.value()->name();
584                 if( i.value()->markedOperation() == Package::PkgOpRemove ) {
585                         qDebug() << "warning: trying to add package marked from the wrong list";
586                         //pkgnames << i.value()->name() + "-";
587                 }
588         }
589
590         QHashIterator<QString, Package*> r( *iAptInterface->packagesInstalled() );
591         while (r.hasNext())
592         {
593                 r.next();
594
595                 if( r.value()->markedOperation() == Package::PkgOpInstallUpgrade )
596                         pkgnames << r.value()->name();
597                 if( r.value()->markedOperation() == Package::PkgOpRemove )
598                         pkgnames << r.value()->name() + "-";
599         }
600
601         iMainWindow->busyDialog(true, "Operation in progress", "Reading dependencies");
602
603         iAptInterface->setProcessPackages(pkgnames);
604         iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetSimulate);
605         iAptInterface->run(iDimmer);
606 }
607
608 void PackageView::on_actionClear_selections_triggered()
609 {
610         QString c;
611         c.setNum( iAptInterface->numSelectedPackages() );
612         ConfirmDialog d(true, this);
613         d.setText(tr("Confirmation"), tr("Clear ") + c + tr(" package selection(s) and lose all the pending changes?"));
614         if( d.exec() )
615         {
616                 clearSelections();
617                 openWin();
618         }
619 }
620
621 void PackageView::clearSelections()
622 {
623         QHashIterator<QString, Package*> i( *iAptInterface->packagesInstalled() );
624         while (i.hasNext())
625         {
626                 i.next();
627                 i.value()->setMarkedForOperation(Package::PkgOpNone);
628         }
629         QHashIterator<QString, Package*> a( *iAptInterface->packagesAvailable() );
630         while (a.hasNext())
631         {
632                 a.next();
633                 a.value()->setMarkedForOperation(Package::PkgOpNone);
634         }
635         iAptInterface->setNumSelectedPackages(0);
636 }
637
638 void PackageView::on_listWidget_itemClicked(QListWidgetItem* item)
639 {
640         Package* pkg = dynamic_cast<PackageListWidgetItem*>(item)->package();
641         if( !pkg )
642                 return;
643
644         bool bl = pkg->isBlacklisted();
645         bool bl_u = false;
646
647         Package* upg_pkg = pkg->availablePackage();
648         if( upg_pkg )
649                 bl_u = upg_pkg->isBlacklisted();
650
651         PackageSelector s(pkg, iAptInterface, this);
652         s.exec();
653
654         pkg->setMarkedForOperation( s.selectedOperation() );
655         item->setData(UserRoleMarked, (int)s.selectedOperation());
656         updateLabel();
657
658         if( pkg->isBlacklisted() != bl ) {
659                 openWin();
660         }
661         else if( upg_pkg && upg_pkg->isBlacklisted() != bl_u ) {
662                 openWin();
663         }
664 }
665
666 void PackageView::updateLabel()
667 {
668         QString s;
669         s.setNum( iAptInterface->numSelectedPackages() );
670         QString s2;
671         s2.setNum( ui->listWidget->count() );
672         QString statlabel = iStatFilterLabels.at(iSelectedStatFilter);
673         if( iSelectedCatFilter == CatFilterAllMarked || iSelectedCatFilter == CatFilterBlacklisted )
674                 statlabel = "All";
675         ui->label->setText("<font size=\"-2\"><b>" + s + "</b> package(s) marked<br>"
676                                            + "Showing: <b>" + statlabel + "</b><br>"
677                                            + "Filter: " + iCatFilterLabels.at(iSelectedCatFilter) + " - " + s2 + " package(s)</font>");
678
679         if( iAptInterface->numSelectedPackages()==0 ) {
680                 ui->btn_Commit->setEnabled(false);
681                 ui->actionClear_selections->setVisible(false);
682                 ui->actionSave_selections->setVisible(false);
683         } else {
684                 ui->btn_Commit->setEnabled(true);
685                 ui->actionClear_selections->setVisible(true);
686                 ui->actionSave_selections->setVisible(true);
687         }
688 }
689
690 void PackageView::on_btn_CategoryFilter_clicked()
691 {
692         FilterSelect f("Category filter", this);
693         f.setList( iCatFilterLabels, iSelectedCatFilter );
694
695         bool s = f.exec();
696
697         if( s )
698                 iSelectedCatFilter = f.selection();
699
700         if( iSelectedCatFilter == CatFilterAllMarked || iSelectedCatFilter == CatFilterBlacklisted ) {
701                 ui->btn_StatusFilter->setEnabled(false);
702         } else {
703                 ui->btn_StatusFilter->setEnabled(true);
704         }
705
706         if( s ) {
707                 iListCoverLabel->setText("Loading...");
708                 iListCoverLabel->setAutoFillBackground(true);
709                 iListCoverLabel->show();
710                 QApplication::processEvents();
711                 iSortNoticeShown = false;
712
713                 openWin();
714         }
715 }
716
717 void PackageView::setStatFilter(Package::packageStatus f_)
718 {
719         iSelectedStatFilter = f_;
720 }
721
722 void PackageView::on_btn_StatusFilter_clicked()
723 {
724         FilterSelect f("Status filter", this);
725         f.setList( iStatFilterLabels, iSelectedStatFilter );
726
727         int oldfilter = iSelectedStatFilter;
728
729         bool s = f.exec();
730
731         if( s ) {
732                 iSelectedStatFilter = (Package::packageStatus)f.selection();
733
734                 iListCoverLabel->setText("Loading...");
735                 iListCoverLabel->setAutoFillBackground(true);
736                 iListCoverLabel->show();
737                 QApplication::processEvents();
738                 iSortNoticeShown = false;
739
740                 openWin();
741
742                 if( oldfilter==Package::PkgStatInstalled && iSelectedStatFilter!=Package::PkgStatInstalled &&
743                         iAptInterface->needListOrDateRefresh() )
744                 {
745                         iMainWindow->setNextOperation(MainWindow::OpOpenPkgView);
746                         iMainWindow->busyDialog(true,"Operation in progress","Reading the rest of the package lists");
747
748                         if( iAptInterface->needRepoRefresh() )
749                                 iAptInterface->addQueuedOperation(AAptInterface::ModeAptGetUpdate);
750
751                         iAptInterface->addQueuedOperation(AAptInterface::ModeReadPackages);
752                         iAptInterface->addQueuedOperation(AAptInterface::ModeFetchDates);
753                         iAptInterface->run(iDimmer);
754                 }
755         }
756 }
757
758 void PackageView::resetWindow()
759 {
760         iMainWindow->resetIdlingTime();
761
762         iAptInterface->writeBlacklist();
763
764         ui->btn_StatusFilter->setEnabled(true);
765         //iSelectedCatFilter = iDefaultCatFilter;
766         //iSortOrder = SortAlpha;
767         iSortNoticeShown = false;
768
769         clearSelections();
770         clearSearch();
771 }
772
773 void PackageView::on_actionHelp_triggered()
774 {
775         Help h(this);
776         h.exec();
777 }
778
779 void PackageView::on_btn_searchClose_clicked()
780 {
781         clearSearch();
782
783         iListCoverLabel->setText("Loading...");
784         iListCoverLabel->setAutoFillBackground(true);
785         iListCoverLabel->show();
786         QApplication::processEvents();
787
788         openWin();
789 }
790
791 void PackageView::clearSearch()
792 {
793         ui->lineEdit->clear();
794         ui->searchBar->hide();
795         ui->toolBar->show();
796         ui->listWidget->setFocusPolicy(Qt::StrongFocus);
797
798         iSearchResults.clear();
799 }
800
801 void PackageView::on_actionSearch_triggered()
802 {
803         if( ui->searchBar->isVisible() )
804                 return;
805
806         ui->listWidget->setFocusPolicy(Qt::NoFocus);
807         ui->searchLabel->setText( QString("%1 results").arg(ui->listWidget->count()) );
808         ui->toolBar->hide();
809         ui->searchBar->show();
810         ui->lineEdit->setFocus();
811         iPrevSearchText = "";
812 }
813
814 void PackageView::on_lineEdit_textEdited(QString text)
815 {
816         if( !ui->searchBar->isVisible() )
817                 return;
818
819         if( text=="" ) {
820                 on_btn_searchClose_clicked();
821                 return;
822         }
823
824         if( iPrevSearchText.length() > text.length() )
825         {
826                 iListCoverLabel->setText("Loading...");
827                 iListCoverLabel->setAutoFillBackground(true);
828                 iListCoverLabel->show();
829                 QApplication::processEvents();
830
831                 ui->searchBar->hide();
832                 openWin();
833                 ui->searchBar->show();
834                 ui->toolBar->hide(); // ensure it stays hidden
835                 ui->lineEdit->setFocus();
836         }
837
838         iPrevSearchText = text;
839
840         QList<Package*> packages;
841         iSearchResults.clear();
842
843         for( int i=0; i<(ui->listWidget->count()); i++ ) {
844                 packages.append( dynamic_cast<PackageListWidgetItem*>( ui->listWidget->item(i) )->package() );
845         }
846
847         if( text.startsWith(":") ) {
848                 for( int i=0; i<packages.count(); i++ ) {
849                         if( packages.at(i) ) {
850                                 if( (iSearchPkgName && packages.at(i)->name().startsWith(text.mid(1), Qt::CaseInsensitive)) ||
851                                         (iSearchDisplayName && packages.at(i)->displayName().startsWith(text.mid(1), Qt::CaseInsensitive)) ||
852                                         (iSearchDescShort && packages.at(i)->descShort().startsWith(text.mid(1), Qt::CaseInsensitive)) ||
853                                         (iSearchDescLong && packages.at(i)->descLong().startsWith(text.mid(1), Qt::CaseInsensitive)) )
854                                 {
855                                         iSearchResults.append( packages.at(i) );
856                                 }
857                         }
858                 }
859         } else {
860                 for( int i=0; i<packages.count(); i++ ) {
861                         if( packages.at(i) ) {
862                                 if( (iSearchPkgName && packages.at(i)->name().contains(text, Qt::CaseInsensitive)) ||
863                                         (iSearchDisplayName && packages.at(i)->displayName().contains(text, Qt::CaseInsensitive)) ||
864                                         (iSearchDescShort && packages.at(i)->descShort().contains(text, Qt::CaseInsensitive)) ||
865                                         (iSearchDescLong && packages.at(i)->descLong().contains(text, Qt::CaseInsensitive)) )
866                                 {
867                                         iSearchResults.append( packages.at(i) );
868                                 }
869                         }
870                 }
871         }
872
873         ui->searchLabel->setText( QString("%1 results").arg( iSearchResults.count()) );
874
875         openWin();
876 }
877
878 void PackageView::setSearchText(QString text)
879 {
880         ui->lineEdit->setText(text);
881         on_lineEdit_textEdited(text);
882 }
883
884 KeyEventGrabber::KeyEventGrabber(QObject* parent) : QObject(parent)
885 {
886 }
887
888 bool KeyEventGrabber::eventFilter(QObject *obj, QEvent *event)
889 {
890         if( event->type() == QEvent::KeyPress ) {
891                 QString text = dynamic_cast<QKeyEvent*>(event)->text();
892                 int key = dynamic_cast<QKeyEvent*>(event)->key();
893                 if( (text.trimmed() != "" || text==" ") && key!=Qt::Key_Backspace ) {
894                         dynamic_cast<PackageView*>(this->parent())->on_actionSearch_triggered();
895                         dynamic_cast<PackageView*>(this->parent())->setSearchText( text );
896                         return true;
897                 }
898         }
899         return QObject::eventFilter(obj, event);
900 }
901
902 void PackageView::on_pushButton_searchOptions_clicked()
903 {
904         SearchOptions s(this);
905         s.setSelections(iSearchPkgName, iSearchDisplayName, iSearchDescShort, iSearchDescLong);
906         if( s.exec() )
907         {
908                 iSearchPkgName = s.searchPkgName();
909                 iSearchDisplayName = s.searchDisplayName();
910                 iSearchDescShort = s.searchDescShort();
911                 iSearchDescLong = s.searchDescLong();
912
913                 iPrevSearchText += " ";
914                 on_lineEdit_textEdited( ui->lineEdit->text() );
915         }
916 }
917
918 void PackageView::setSearchOptions(bool pkgname, bool dispname, bool dshort, bool dlong)
919 {
920         iSearchPkgName = pkgname;
921         iSearchDisplayName = dispname;
922         iSearchDescShort = dshort;
923         iSearchDescLong = dlong;
924 }
925
926 void PackageView::on_actionUpgrade_all_triggered()
927 {
928         for( int i=0; i<ui->listWidget->count(); i++ )
929         {
930                 Package* pkg = dynamic_cast<PackageListWidgetItem*>(ui->listWidget->item(i))->package();
931                 if( pkg && pkg->isUpgradeable() ) {
932                         pkg->setMarkedForOperation( Package::PkgOpInstallUpgrade );
933                         ui->listWidget->item(i)->setData(UserRoleMarked, (int)Package::PkgOpInstallUpgrade);
934                 }
935         }
936         updateLabel();
937 }
938
939 void PackageView::on_actionView_log_triggered()
940 {
941         QByteArray log = iAptInterface->readLogFile();
942         LogView l(log, this);
943         l.exec();
944 }
945
946 void PackageView::on_btn_Sort_clicked()
947 {
948         SortSelector s(iSortOrder, this);
949         if( s.exec() ) {
950                 iSortOrder = s.selectedOperation();
951                 iSortNoticeShown = false;
952                 openWin();
953         }
954 }
955
956 void PackageView::on_actionLoad_selections_triggered()
957 {
958         if( iAptInterface->numSelectedPackages() > 0 ) {
959                 ConfirmDialog d(true, this);
960                 d.setText("Confirmation", "Proceed loading selections? All current selections will be cleared.");
961                 if( !d.exec() )
962                         return;
963         }
964
965         clearSelections();
966
967         QStringList unknownList;
968         QStringList wrongverList;
969         int success=0;
970         int errors=0;
971
972         QFile f("/root/.fapman/selections.list");
973         if( f.open(QIODevice::ReadOnly | QIODevice::Text ) )
974         {
975                 while(!f.atEnd()) {
976                         QString line = f.readLine().trimmed();
977                         QStringList parts = line.split(' ');
978                         if( parts.count()==3 ) {
979                                 Package* pkgAv = iAptInterface->packagesAvailable()->value(parts.at(0),0);
980                                 Package* pkgIn = iAptInterface->packagesInstalled()->value(parts.at(0),0);
981                                 if( parts.at(2)=="install" ) {
982                                         if( !pkgAv && !pkgIn ) {
983                                                 unknownList << parts.at(0);
984                                         }
985                                         else if( pkgIn ) {
986                                                 wrongverList << parts.at(0);
987                                         }
988                                         else if( pkgAv ) {
989                                                 if( pkgAv->version() == parts.at(1) && !pkgAv->isInstalled() ) {
990                                                         pkgAv->setMarkedForOperation(Package::PkgOpInstallUpgrade);
991                                                         success++;
992                                                 } else {
993                                                         wrongverList << parts.at(0);
994                                                 }
995                                         }
996
997                                 } else if( parts.at(2)=="upgrade" ) {
998                                         if( !pkgAv && !pkgIn ) {
999                                                 unknownList << parts.at(0);
1000                                         }
1001                                         else if( (pkgAv && !pkgIn) || (pkgIn && !pkgAv) ) {
1002                                                 wrongverList << parts.at(0);
1003                                         }
1004                                         else if( pkgIn && pkgAv ) {
1005                                                 if( pkgIn->version() == parts.at(1) && pkgIn->isInstalled() && pkgIn->isUpgradeable() ) {
1006                                                         pkgIn->setMarkedForOperation(Package::PkgOpInstallUpgrade);
1007                                                         success++;
1008                                                 } else {
1009                                                         wrongverList << parts.at(0);
1010                                                 }
1011                                         }
1012
1013                                 } else if( parts.at(2)=="remove" ) {
1014                                         if( !pkgAv && !pkgIn ) {
1015                                                 unknownList << parts.at(0);
1016                                         }
1017                                         else if( pkgAv && !pkgIn ) {
1018                                                 wrongverList << parts.at(0);
1019                                         }
1020                                         else if( pkgIn ) {
1021                                                 if( pkgIn->version() == parts.at(1) && pkgIn->isInstalled() ) {
1022                                                         pkgIn->setMarkedForOperation(Package::PkgOpRemove);
1023                                                         success++;
1024                                                 } else {
1025                                                         wrongverList << parts.at(0);
1026                                                 }
1027                                         }
1028                                 } else {
1029                                         errors++;
1030                                 }
1031                         } else if( line!="" ){
1032                                 errors++;
1033                         }
1034                 }
1035                 f.close();
1036         }
1037
1038         ConfirmDialog d(false, this);
1039         QString msg;
1040         msg += QString("<b>%1 successful</b><br>").arg(success);
1041         if( wrongverList.count() > 0 ) {
1042                 msg += QString("%1 wrong versions/changed statuses (not selected):<br>").arg(wrongverList.count());
1043                 msg += "<font size=\"-1\">";
1044                 for( int i=0; i<wrongverList.count(); i++ ) {
1045                         msg += wrongverList.at(i) + " ";
1046                 }
1047                 msg += "</font><br>";
1048         }
1049         if( unknownList.count() > 0 ) {
1050                 msg += QString("%1 unknown packages:<br>").arg(unknownList.count());
1051                 msg += "<font size=\"-1\">";
1052                 for( int i=0; i<unknownList.count(); i++ ) {
1053                         msg += unknownList.at(i) + " ";
1054                 }
1055                 msg += "</font><br>";
1056         }
1057         if( errors>0 || (wrongverList.count()==0 && unknownList.count()==0) ) {
1058                 msg += QString("%1 errors<br>").arg(errors);
1059         }
1060         if( success==0 && wrongverList.count()==0 && unknownList.count()==0 )
1061                 msg = "No stored selections";
1062         QString title;
1063         if( success > 0 )
1064                 title = "Selections loaded";
1065         else
1066                 title = "No selections loaded";
1067         d.setText(title, msg);
1068         d.exec();
1069
1070         if( success > 0 ) {
1071                 ui->btn_StatusFilter->setEnabled(false);
1072                 iSelectedCatFilter = CatFilterAllMarked;
1073         }
1074         openWin();
1075 }
1076
1077 void PackageView::on_actionSave_selections_triggered()
1078 {
1079         if( iAptInterface->numSelectedPackages() == 0 )
1080                 return;
1081
1082         QFile f("/root/.fapman/selections.list");
1083         bool fail = false;
1084         int count = 0;
1085         if( f.open(QIODevice::WriteOnly | QIODevice::Text) )
1086         {
1087                 QTextStream out(&f);
1088
1089                 QHashIterator<QString, Package*> i( *iAptInterface->packagesAvailable() );
1090                 while (i.hasNext())
1091                 {
1092                         i.next();
1093
1094                         if( i.value()->markedOperation() == Package::PkgOpInstallUpgrade ) {
1095                                 out << i.value()->name() << " " << i.value()->version() << " install\n";
1096                                 count++;
1097                         }
1098                         if( i.value()->markedOperation() == Package::PkgOpRemove )
1099                                 qDebug() << "Warning: package is marked for removal in the wrong list";
1100                 }
1101
1102                 QHashIterator<QString, Package*> r( *iAptInterface->packagesInstalled() );
1103                 while (r.hasNext())
1104                 {
1105                         r.next();
1106
1107                         if( r.value()->markedOperation() == Package::PkgOpInstallUpgrade ) {
1108                                 out << r.value()->name() << " " << r.value()->version() << " upgrade\n";
1109                                 count++;
1110                         }
1111                         if( r.value()->markedOperation() == Package::PkgOpRemove ) {
1112                                 out << r.value()->name() << " " << r.value()->version() << " remove\n";
1113                                 count++;
1114                         }
1115                 }
1116
1117                 f.close();
1118         } else {
1119                 fail = true;
1120         }
1121
1122         ConfirmDialog d(false, this);
1123         if( fail )
1124                 d.setText( "Error", "Failed to write package selections" );
1125         else
1126                 d.setText( "Selections stored", QString("Stored %1 selections").arg(count) );
1127         d.exec();
1128 }
1129
1130 void PackageView::on_actionRestore_all_triggered()
1131 {
1132         ConfirmDialog d(true, this);
1133         d.setText("Confirmation","Restore all shown blacklisted packages?");
1134         if( !d.exec() )
1135                 return;
1136
1137         for( int i=0; i<ui->listWidget->count(); i++ )
1138         {
1139                 Package* pkg = dynamic_cast<PackageListWidgetItem*>(ui->listWidget->item(i))->package();
1140                 Package* p1 = iAptInterface->packagesInstalled()->value(pkg->name(),0);
1141                 Package* p2 = iAptInterface->packagesAvailable()->value(pkg->name(),0);
1142                 if( p1 && p1->isBlacklisted() ) {
1143                         BlacklistSelect::blackList old = p1->blacklisted();
1144                         p1->setBlacklisted(BlacklistSelect::BlacklistNone);
1145                         iAptInterface->removeFromBlacklist(p1, old);
1146                 }
1147                 if( p2 && p2->isBlacklisted() ) {
1148                         BlacklistSelect::blackList old = p2->blacklisted();
1149                         p2->setBlacklisted(BlacklistSelect::BlacklistNone);
1150                         iAptInterface->removeFromBlacklist(p2, old);
1151                 }
1152         }
1153         iAptInterface->writeBlacklist();
1154         openWin();
1155 }