Commit 0ee04e22 authored by Christian Mollekopf's avatar Christian Mollekopf
Browse files

Recursive actions for person nodes + some refactoring and cleanup.

parent 88c0e151
......@@ -255,6 +255,7 @@ class SortProxyModel : public QSortFilterProxyModel
explicit SortProxyModel( QObject *parent=0 )
: QSortFilterProxyModel( parent )
{
setDynamicSortFilter(true);
}
bool lessThan(const QModelIndex &left,
......@@ -349,6 +350,85 @@ class CollectionFilter : public QSortFilterProxyModel
}
};
class EnabledModel : public QSortFilterProxyModel
{
public:
explicit EnabledModel(QObject *parent=0)
: QSortFilterProxyModel(parent)
{
}
protected:
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
{
if (role == EnabledRole) {
Akonadi::Collection col = index.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
if (col.shouldList(Akonadi::Collection::ListDisplay)) {
return Qt::Checked;
} else {
return Qt::Unchecked;
}
}
return QSortFilterProxyModel::data(index, role);
}
};
class CalendarDelegateModel : public QSortFilterProxyModel
{
public:
explicit CalendarDelegateModel(QObject *parent=0)
: QSortFilterProxyModel(parent)
{
}
protected:
bool checkChildren(const QModelIndex &index, int role, const QVariant &value) const
{
const QModelIndex sourceIndex = mapToSource(index);
for (int i = 0; i < sourceModel()->rowCount(sourceIndex); i++) {
const QModelIndex child = sourceModel()->index(i, 0, sourceIndex);
if (child.data(role) != value) {
return false;
}
}
return true;
}
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
{
if (role == Qt::CheckStateRole) {
if (sourceModel()->hasChildren(mapToSource(index)) && index.data(NodeTypeRole).toInt() == PersonNodeRole) {
bool allChecked = checkChildren(index, role, Qt::Checked);
bool allUnchecked = checkChildren(index, role, Qt::Unchecked);
if (allChecked) {
return Qt::Checked;
} else if (allUnchecked) {
return Qt::Unchecked;
} else {
return Qt::PartiallyChecked;
}
}
}
if (role == EnabledRole) {
if (sourceModel()->hasChildren(mapToSource(index)) && index.data(NodeTypeRole).toInt() == PersonNodeRole) {
bool allChecked = checkChildren(index, role, Qt::Checked);
bool allUnchecked = checkChildren(index, role, Qt::Unchecked);
// kDebug() << "person node " << index.data().toString() << allChecked << allUnchecked;
if (allChecked) {
return Qt::Checked;
} else if (allUnchecked) {
return Qt::Unchecked;
} else {
return Qt::PartiallyChecked;
}
}
}
return QSortFilterProxyModel::data(index, role);
}
};
} // anonymous namespace
CalendarViewExtension *AkonadiCollectionViewFactory::create( QWidget *parent )
......@@ -403,14 +483,17 @@ AkonadiCollectionView::AkonadiCollectionView( CalendarView *view, bool hasContex
userProxy->setNodeManager(ReparentingModel::NodeManager::Ptr(new PersonNodeManager(*userProxy)));
userProxy->setSourceModel(colorProxy);
EnabledModel *enabledModel = new EnabledModel(this);
enabledModel->setSourceModel(userProxy);
CalendarDelegateModel *calendarDelegateModel = new CalendarDelegateModel(this);
calendarDelegateModel->setSourceModel(enabledModel);
SortProxyModel *sortProxy = new SortProxyModel( this );
// sortProxy->setObjectName( QLatin1String("Show calendar colors") );
sortProxy->setDynamicSortFilter( true );
sortProxy->setSourceModel(userProxy);
sortProxy->setSourceModel(calendarDelegateModel);
//Hide collections that are not required
CollectionFilter *collectionFilter = new CollectionFilter( this );
collectionFilter->setDynamicSortFilter( true );
collectionFilter->setSourceModel( sortProxy );
mCollectionView = new Akonadi::EntityTreeView( this );
......@@ -867,15 +950,24 @@ void AkonadiCollectionView::edit_disable()
{
Akonadi::Collection col = mCollectionView->currentIndex().data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
if (col.isValid()) {
mController->setCollection(col, false, false);
mController->setCollectionState(col, Controller::Disabled);
}
const QVariant var = mCollectionView->currentIndex().data(PersonRole);
if (var.isValid()) {
mController->removePerson(var.value<Person>());
}
}
void AkonadiCollectionView::edit_enable()
{
Akonadi::Collection col = mCollectionView->currentIndex().data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
kDebug() << col.name();
if (col.isValid()) {
mController->setCollection(col, true, false);
mController->setCollectionState(col, Controller::Enabled);
}
const QVariant var = mCollectionView->currentIndex().data(PersonRole);
if (var.isValid()) {
mController->addPerson(var.value<Person>());
}
}
......@@ -886,31 +978,23 @@ void AkonadiCollectionView::onAction(const QModelIndex &index, int a)
case StyledCalendarDelegate::AddToList: {
const Akonadi::Collection col = index.data(CollectionRole).value<Akonadi::Collection>();
if (col.isValid()) {
mController->setCollection(col, false, true);
mController->setCollectionState(col, Controller::Referenced);
} else {
const QVariant var = index.data(PersonRole);
if (var.isValid()) {
mController->setPersonEnabled(var.value<Person>(), true);
mController->addPerson(var.value<Person>());
}
}
}
break;
case StyledCalendarDelegate::RemoveFromList: {
//Disable all child collections
const QAbstractItemModel *model = index.model();
for (int row = 0; row < model->rowCount(index); row++) {
const Akonadi::Collection col = CalendarSupport::collectionFromIndex(model->index(row, 0, index));
if (col.isValid()) {
mController->setCollection(col, false, false);
}
}
const Akonadi::Collection col = CalendarSupport::collectionFromIndex(index);
if (col.isValid()) {
mController->setCollection(col, false, false);
mController->setCollectionState(col, Controller::Disabled);
} else {
const QVariant var = index.data(PersonRole);
if (var.isValid()) {
mController->setPersonEnabled(var.value<Person>(), false);
mController->removePerson(var.value<Person>());
}
}
}
......@@ -918,7 +1002,12 @@ void AkonadiCollectionView::onAction(const QModelIndex &index, int a)
case StyledCalendarDelegate::Enable: {
const Akonadi::Collection col = CalendarSupport::collectionFromIndex(index);
if (col.isValid()) {
mController->setCollection(col, true, false);
mController->setCollectionState(col, Controller::Enabled);
} else {
const QVariant var = index.data(PersonRole);
if (var.isValid()) {
mController->addPerson(var.value<Person>());
}
}
}
break;
......
......@@ -78,24 +78,20 @@ QList<StyledCalendarDelegate::Action> StyledCalendarDelegate::getActions(const Q
const bool isSearchResult = index.data(IsSearchResultRole).toBool();
const bool hover = option.state & QStyle::State_MouseOver;
const Akonadi::Collection col = CalendarSupport::collectionFromIndex(index);
const bool enabled = col.shouldList(Akonadi::Collection::ListDisplay);
const bool referenced = col.referenced();
Qt::CheckState enabled = static_cast<Qt::CheckState>(index.data(EnabledRole).toInt());
// kDebug() << index.data().toString() << enabled;
QList<Action> buttons;
if (isSearchResult) {
buttons << AddToList;
} else {
//Folders that have been pulled in due to a subfolder
// if (!enabled && !referenced) {
// return QList<Action>() << RemoveFromList;
// }
if (hover) {
if (!enabled) {
if (enabled != Qt::Checked) {
buttons << Enable;
}
buttons << RemoveFromList;
} else {
if (enabled) {
if (enabled == Qt::Checked) {
buttons << Enable;
}
}
......@@ -108,6 +104,10 @@ void StyledCalendarDelegate::paint( QPainter * painter, const QStyleOptionViewIt
Q_ASSERT(index.isValid());
const Akonadi::Collection col = CalendarSupport::collectionFromIndex(index);
//We display the toolbuttons while hovering
const bool showButtons = option.state & QStyle::State_MouseOver;
// const bool enabled = col.shouldList(Akonadi::Collection::ListDisplay);
Qt::CheckState enabled = static_cast<Qt::CheckState>(index.data(EnabledRole).toInt());
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
......@@ -121,6 +121,12 @@ void StyledCalendarDelegate::paint( QPainter * painter, const QStyleOptionViewIt
int i = 1;
Q_FOREACH (Action action, getActions(option, index)) {
QStyleOptionButton buttonOption = buttonOpt(opt, mPixmap.value(action), i);
if (action == Enable && showButtons) {
buttonOption.state = QStyle::State_Active;
}
if (action == Enable && !showButtons && enabled == Qt::PartiallyChecked) {
buttonOption.state = QStyle::State_Active;
}
s->drawControl(QStyle::CE_PushButton, &buttonOption, painter, 0);
i++;
}
......
......@@ -88,6 +88,9 @@ QVariant CollectionNode::data(int role) const
if (role == CollectionRole) {
return QVariant::fromValue(mCollection);
}
if (role == NodeTypeRole) {
return CollectionNodeRole;
}
return QVariant();
}
......@@ -162,6 +165,9 @@ QVariant PersonNode::data(int role) const
if (role == IsSearchResultRole) {
return isSearchNode;
}
if (role == NodeTypeRole) {
return PersonNodeRole;
}
return QVariant();
}
......@@ -432,24 +438,6 @@ void Controller::setSearchString(const QString &searchString)
mCollectionSearchJob->start();
}
void Controller::onPersonEnabled(bool enabled, const Person& person)
{
setPersonEnabled(person, enabled);
}
void Controller::onPersonCollectionsFetched(KJob* job)
{
if (job->error()) {
kWarning() << "Failed to fetch collections " << job->errorString();
return;
}
const bool enable = job->property("enable").toBool();
Q_FOREACH(const Akonadi::Collection &col, static_cast<Akonadi::CollectionFetchJob*>(job)->collections()) {
setCollectionReferenced(enable, col);
}
}
void Controller::onCollectionsFound(KJob* job)
{
if (job->error()) {
......@@ -462,7 +450,7 @@ void Controller::onCollectionsFound(KJob* job)
CollectionNode *collectionNode = new CollectionNode(*mSearchModel, col);
collectionNode->isSearchNode = true;
//toggled by the checkbox, results in collection getting monitored
connect(&collectionNode->emitter, SIGNAL(enabled(bool, Akonadi::Collection)), this, SLOT(onCollectionEnabled(bool, Akonadi::Collection)));
// connect(&collectionNode->emitter, SIGNAL(enabled(bool, Akonadi::Collection)), this, SLOT(onCollectionEnabled(bool, Akonadi::Collection)));
mSearchModel->addNode(ReparentingModel::Node::Ptr(collectionNode));
}
mCollectionSearchJob = 0;
......@@ -480,7 +468,7 @@ void Controller::onPersonsFound(KJob* job)
PersonNode *personNode = new PersonNode(*mSearchModel, p);
personNode->isSearchNode = true;
//toggled by the checkbox, results in person getting added to main model
connect(&personNode->emitter, SIGNAL(enabled(bool, Person)), this, SLOT(onPersonEnabled(bool, Person)));
// connect(&personNode->emitter, SIGNAL(enabled(bool, Person)), this, SLOT(onPersonEnabled(bool, Person)));
mSearchModel->addNode(ReparentingModel::Node::Ptr(personNode));
}
mPersonSearchJob = 0;
......@@ -500,65 +488,67 @@ static Akonadi::EntityTreeModel *findEtm(QAbstractItemModel *model)
return qobject_cast<Akonadi::EntityTreeModel*>(model);
}
void Controller::setCollectionReferenced(bool enabled, const Akonadi::Collection& collection)
{
kDebug() << collection.displayName() << "do reference " << enabled;
kDebug() << "current " << collection.referenced();
Akonadi::EntityTreeModel *etm = findEtm(mPersonModel);
Q_ASSERT(etm);
etm->setCollectionReferenced(collection, enabled);
}
void Controller::setCollectionEnabled(bool enabled, const Akonadi::Collection& collection)
void Controller::setCollectionState(const Akonadi::Collection &collection, CollectionState collectionState, bool recursive)
{
kDebug() << collection.displayName() << "do enable " << enabled;
kDebug() << "current " << collection.enabled();
Akonadi::Collection modifiedCollection = collection;
modifiedCollection.setShouldList(Akonadi::Collection::ListDisplay, enabled);
new Akonadi::CollectionModifyJob(modifiedCollection);
}
void Controller::onCollectionEnabled(bool enabled, const Akonadi::Collection& collection)
{
setCollectionReferenced(enabled, collection);
//We removed the children first, so the children in the tree are removed before the parents
if (recursive) {
//We have to include all mimetypes since mimetypes are not available yet (they will be synced once the collectoins are referenced)
Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(collection, Akonadi::CollectionFetchJob::Recursive, this);
fetchJob->setProperty("collectionState", static_cast<int>(collectionState));
fetchJob->fetchScope().setListFilter(Akonadi::CollectionFetchScope::NoFilter);
connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(onPersonCollectionsFetched(KJob*)));
}
{
Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(collection, Akonadi::CollectionFetchJob::Base, this);
fetchJob->setProperty("collectionState", static_cast<int>(collectionState));
fetchJob->fetchScope().setListFilter(Akonadi::CollectionFetchScope::NoFilter);
connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(onPersonCollectionsFetched(KJob*)));
}
}
void Controller::setCollection(const Akonadi::Collection &collection, bool enabled, bool referenced)
void Controller::onPersonCollectionsFetched(KJob* job)
{
if (job->error()) {
kWarning() << "Failed to fetch collections " << job->errorString();
return;
}
Akonadi::EntityTreeModel *etm = findEtm(mPersonModel);
if (!etm) {
kWarning() << "Couldn't find etm";
return;
}
kDebug() << collection.displayName() << "do enable " << enabled;
Akonadi::Collection modifiedCollection = collection;
modifiedCollection.setShouldList(Akonadi::Collection::ListDisplay, enabled);
//HACK: We have no way of getting to the correct session as used by the etm,
//and two concurrent jobs end up overwriting the enabled state of each other.
etm->setCollectionReferenced(modifiedCollection, referenced);
const CollectionState collectionState = static_cast<CollectionState>(job->property("collectionState").toInt());
Q_FOREACH(const Akonadi::Collection &col, static_cast<Akonadi::CollectionFetchJob*>(job)->collections()) {
// kDebug() << col.displayName() << "do enable " << enabled;
Akonadi::Collection modifiedCollection = col;
if (collectionState == Enabled) {
modifiedCollection.setShouldList(Akonadi::Collection::ListDisplay, true);
}
if (collectionState == Disabled) {
modifiedCollection.setShouldList(Akonadi::Collection::ListDisplay, false);
}
//HACK: We have no way of getting to the correct session as used by the etm,
//and two concurrent jobs end up overwriting the enabled state of each other.
etm->setCollectionReferenced(modifiedCollection, collectionState == Referenced);
}
}
void Controller::setPersonEnabled(const Person &person, bool enabled)
void Controller::addPerson(const Person &person)
{
// kDebug() << person.name << enabled;
if (enabled) {
PersonNode *personNode = new PersonNode(*mPersonModel, person);
personNode->setChecked(true);
mPersonModel->addNode(ReparentingModel::Node::Ptr(personNode));
} else {
mPersonModel->removeNode(PersonNode(*mPersonModel, person));
}
kDebug() << person.name;
PersonNode *personNode = new PersonNode(*mPersonModel, person);
personNode->setChecked(true);
mPersonModel->addNode(ReparentingModel::Node::Ptr(personNode));
Akonadi::Collection rootCollection(person.rootCollection);
// kDebug() << rootCollection.id();
if (rootCollection.isValid()) {
//Reference the persons collections if available
//We have to include all mimetypes since mimetypes are not available yet (they will be synced once the collectoins are referenced)
Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(rootCollection, Akonadi::CollectionFetchJob::Recursive, this);
fetchJob->setProperty("enable", enabled);
fetchJob->fetchScope().setListFilter(Akonadi::CollectionFetchScope::NoFilter);
connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(onPersonCollectionsFetched(KJob*)));
}
setCollectionState(Akonadi::Collection(person.rootCollection), Referenced, true);
}
void Controller::removePerson(const Person &person)
{
kDebug() << person.name;
mPersonModel->removeNode(PersonNode(*mPersonModel, person));
setCollectionState(Akonadi::Collection(person.rootCollection), Disabled, true);
}
......@@ -29,10 +29,18 @@
#include <Akonadi/Collection>
#include "reparentingmodel.h"
enum DataRole {
enum DataRoles {
PersonRole = Akonadi::EntityTreeModel::UserRole + 1,
IsSearchResultRole,
CollectionRole
CollectionRole,
NodeTypeRole,
EnabledRole
};
enum NodeTypeRoles {
SourceNodeRole,
PersonNodeRole,
CollectionNodeRole
};
struct Person
......@@ -175,10 +183,15 @@ public:
*/
void setEntityTreeModel(Akonadi::EntityTreeModel *etm);
void setCollectionReferenced(bool enabled, const Akonadi::Collection &collection);
void setCollectionEnabled(bool enabled, const Akonadi::Collection &collection);
void setCollection(const Akonadi::Collection &collection, bool enabled, bool referenced);
void setPersonEnabled(const Person &person, bool enabled);
enum CollectionState {
Disabled,
Referenced,
Enabled
};
void setCollectionState(const Akonadi::Collection &collection, CollectionState collectionState, bool recursive = false);
void addPerson(const Person &person);
void removePerson(const Person &person);
Q_SIGNALS:
void searchIsActive(bool);
......@@ -189,9 +202,7 @@ public Q_SLOTS:
private Q_SLOTS:
void onCollectionsFound(KJob *job);
void onPersonsFound(KJob *job);
void onPersonEnabled(bool enabled, const Person &person);
void onPersonCollectionsFetched(KJob *job);
void onCollectionEnabled(bool enabled, const Akonadi::Collection &collection);
private:
ReparentingModel *mPersonModel;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment