You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

229 lines
7.8 KiB

/*
* Copyright (c) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "incompleteindexdialog.h"
#include "ui_incompleteindexdialog.h"
#include "kmkernel.h"
#include <QProgressDialog>
#include <KDescendantsProxyModel>
#include <KLocalizedString>
#include <AkonadiCore/EntityTreeModel>
#include <AkonadiCore/EntityMimeTypeFilterModel>
#include <PimCommon/PimUtil>
#include <PimCommonAkonadi/MailUtil>
#include <QDBusInterface>
#include <QDBusReply>
#include <QDBusMetaType>
#include <QTimer>
#include <QHBoxLayout>
#include <QDialogButtonBox>
Q_DECLARE_METATYPE(Qt::CheckState)
Q_DECLARE_METATYPE(QVector<qint64>)
class SearchCollectionProxyModel : public QSortFilterProxyModel
{
public:
explicit SearchCollectionProxyModel(const QVector<qint64> &unindexedCollections, QObject *parent = nullptr)
: QSortFilterProxyModel(parent)
{
mFilterCollections.reserve(unindexedCollections.size());
for (qint64 col : unindexedCollections) {
mFilterCollections.insert(col, true);
}
}
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE
{
if (role == Qt::CheckStateRole) {
if (index.isValid() && index.column() == 0) {
const qint64 colId = collectionIdForIndex(index);
return mFilterCollections.value(colId) ? Qt::Checked : Qt::Unchecked;
}
}
return QSortFilterProxyModel::data(index, role);
}
bool setData(const QModelIndex &index, const QVariant &data, int role) Q_DECL_OVERRIDE {
if (role == Qt::CheckStateRole)
{
if (index.isValid() && index.column() == 0) {
const qint64 colId = collectionIdForIndex(index);
mFilterCollections[colId] = data.value<Qt::CheckState>();
return true;
}
}
return QSortFilterProxyModel::setData(index, data, role);
}
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE
{
if (index.isValid() && index.column() == 0) {
return QSortFilterProxyModel::flags(index) | Qt::ItemIsUserCheckable;
} else {
return QSortFilterProxyModel::flags(index);
}
}
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const Q_DECL_OVERRIDE
{
const QModelIndex source_idx = sourceModel()->index(source_row, 0, source_parent);
const qint64 colId = sourceModel()->data(source_idx, Akonadi::EntityTreeModel::CollectionIdRole).toLongLong();
return mFilterCollections.contains(colId);
}
private:
qint64 collectionIdForIndex(const QModelIndex &index) const
{
return data(index, Akonadi::EntityTreeModel::CollectionIdRole).toLongLong();
}
private:
QHash<qint64, bool> mFilterCollections;
};
IncompleteIndexDialog::IncompleteIndexDialog(const QVector<qint64> &unindexedCollections, QWidget *parent)
: QDialog(parent)
, mUi(new Ui::IncompleteIndexDialog)
, mProgressDialog(nullptr)
, mIndexer(nullptr)
{
QHBoxLayout *mainLayout = new QHBoxLayout(this);
mainLayout->setMargin(0);
QWidget *w = new QWidget(this);
mainLayout->addWidget(w);
qDBusRegisterMetaType<QVector<qint64> >();
mUi->setupUi(w);
Akonadi::EntityTreeModel *etm = KMKernel::self()->entityTreeModel();
Akonadi::EntityMimeTypeFilterModel *mimeProxy = new Akonadi::EntityMimeTypeFilterModel(this);
mimeProxy->addMimeTypeInclusionFilter(Akonadi::Collection::mimeType());
mimeProxy->setSourceModel(etm);
KDescendantsProxyModel *flatProxy = new KDescendantsProxyModel(this);
flatProxy->setDisplayAncestorData(true);
flatProxy->setAncestorSeparator(QStringLiteral(" / "));
flatProxy->setSourceModel(mimeProxy);
SearchCollectionProxyModel *proxy = new SearchCollectionProxyModel(unindexedCollections, this);
proxy->setSourceModel(flatProxy);
mUi->collectionView->setModel(proxy);
connect(mUi->selectAllBtn, &QPushButton::clicked, this, &IncompleteIndexDialog::selectAll);
connect(mUi->unselectAllBtn, &QPushButton::clicked, this, &IncompleteIndexDialog::unselectAll);
mUi->buttonBox->button(QDialogButtonBox::Ok)->setText(i18n("Reindex"));
mUi->buttonBox->button(QDialogButtonBox::Cancel)->setText(i18n("Search Anyway"));
connect(mUi->buttonBox, &QDialogButtonBox::accepted, this, &IncompleteIndexDialog::waitForIndexer);
connect(mUi->buttonBox, &QDialogButtonBox::rejected, this, &IncompleteIndexDialog::reject);
}
IncompleteIndexDialog::~IncompleteIndexDialog()
{
}
void IncompleteIndexDialog::selectAll()
{
updateAllSelection(true);
}
void IncompleteIndexDialog::unselectAll()
{
updateAllSelection(false);
}
void IncompleteIndexDialog::updateAllSelection(bool select)
{
QAbstractItemModel *model = mUi->collectionView->model();
for (int i = 0, cnt = model->rowCount(); i < cnt; ++i) {
const QModelIndex idx = model->index(i, 0, QModelIndex());
model->setData(idx, select ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
}
}
QList<qlonglong> IncompleteIndexDialog::collectionsToReindex() const
{
QList<qlonglong> res;
QAbstractItemModel *model = mUi->collectionView->model();
for (int i = 0, cnt = model->rowCount(); i < cnt; ++i) {
const QModelIndex idx = model->index(i, 0, QModelIndex());
if (model->data(idx, Qt::CheckStateRole).toInt() == Qt::Checked) {
res.push_back(model->data(idx, Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>().id());
}
}
return res;
}
void IncompleteIndexDialog::waitForIndexer()
{
mIndexer = new QDBusInterface(PimCommon::MailUtil::indexerServiceName(), QLatin1String("/"),
QStringLiteral("org.freedesktop.Akonadi.Indexer"),
QDBusConnection::sessionBus(), this);
if (!mIndexer->isValid()) {
accept();
return;
}
mIndexingQueue = collectionsToReindex();
if (mIndexingQueue.isEmpty()) {
accept();
return;
}
mProgressDialog = new QProgressDialog(this);
mProgressDialog->setMaximum(mIndexingQueue.size());
mProgressDialog->setValue(0);
mProgressDialog->setLabelText(i18n("Indexing Collections..."));
connect(mProgressDialog, &QDialog::rejected, this, &IncompleteIndexDialog::slotStopIndexing);
connect(mIndexer, SIGNAL(currentCollectionChanged(qlonglong)),
this, SLOT(slotCurrentlyIndexingCollectionChanged(qlonglong)));
mIndexer->asyncCall(QStringLiteral("reindexCollections"), QVariant::fromValue(mIndexingQueue));
mProgressDialog->show();
}
void IncompleteIndexDialog::slotStopIndexing()
{
mProgressDialog->close();
reject();
}
void IncompleteIndexDialog::slotCurrentlyIndexingCollectionChanged(qlonglong colId)
{
const int idx = mIndexingQueue.indexOf(colId);
if (idx > -1) {
mIndexingQueue.removeAll(idx);
mProgressDialog->setValue(mProgressDialog->maximum() - mIndexingQueue.size());
if (mIndexingQueue.isEmpty()) {
QTimer::singleShot(1000, this, &IncompleteIndexDialog::accept);
}
}
}