diff --git a/src/akonadicollectionview.cpp b/src/akonadicollectionview.cpp index 4f156853..ebdbf990 100644 --- a/src/akonadicollectionview.cpp +++ b/src/akonadicollectionview.cpp @@ -1,964 +1,964 @@ /* This file is part of KOrganizer. Copyright (c) 2003,2004 Cornelius Schumacher Copyright (C) 2003-2004 Reinhold Kainhofer Copyright (C) 2009 Sebastian Sauer Copyright (c) 2010-2020 Laurent Montel Copyright (C) 2012 Sérgio Martins 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. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include "akonadicollectionview.h" #include "kocore.h" #include "kohelper.h" #include "prefs/koprefs.h" #include "koglobals.h" #include "manageshowcollectionproperties.h" #include "views/collectionview/reparentingmodel.h" #include "views/collectionview/calendardelegate.h" #include "views/collectionview/quickview.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "PimCommonAkonadi/MailUtil" #include #include #include #include #include #include "korganizer_debug.h" #include #include #include #include #include #include static Akonadi::EntityTreeModel *findEtm(QAbstractItemModel *model) { QAbstractProxyModel *proxyModel = nullptr; while (model) { proxyModel = qobject_cast(model); if (proxyModel && proxyModel->sourceModel()) { model = proxyModel->sourceModel(); } else { break; } } return qobject_cast(model); } /** * Automatically checks new calendar entries */ class NewCalendarChecker : public QObject { Q_OBJECT public: NewCalendarChecker(QAbstractItemModel *model) : QObject(model) , mCheckableProxy(model) { connect(model, &QAbstractItemModel::rowsInserted, this, &NewCalendarChecker::onSourceRowsInserted); qRegisterMetaType("QPersistentModelIndex"); } private Q_SLOTS: void onSourceRowsInserted(const QModelIndex &parent, int start, int end) { Akonadi::EntityTreeModel *etm = findEtm(mCheckableProxy); //Only check new collections and not during initial population if (!etm || !etm->isCollectionTreeFetched()) { return; } for (int i = start; i <= end; ++i) { qCDebug(KORGANIZER_LOG) << "checking " << i << parent << mCheckableProxy->index(i, 0, parent). data().toString(); const QModelIndex index = mCheckableProxy->index(i, 0, parent); QMetaObject::invokeMethod(this, "setCheckState", Qt::QueuedConnection, QGenericReturnArgument(), Q_ARG(QPersistentModelIndex, index)); } } void setCheckState(const QPersistentModelIndex &index) { mCheckableProxy->setData(index, Qt::Checked, Qt::CheckStateRole); if (mCheckableProxy->hasChildren(index)) { onSourceRowsInserted(index, 0, mCheckableProxy->rowCount(index) - 1); } } private: QAbstractItemModel *mCheckableProxy = nullptr; }; /** * Handles expansion state of a treeview * * Persists state, and automatically expands new entries. * With expandAll enabled this class simply ensures that all indexes are fully expanded. */ class NewNodeExpander : public QObject { Q_OBJECT public: NewNodeExpander(QTreeView *view, bool expandAll, const QString &treeStateConfig) : QObject(view) , mTreeView(view) , mExpandAll(expandAll) , mTreeStateConfig(treeStateConfig) { connect( view->model(), &QAbstractItemModel::rowsInserted, this, &NewNodeExpander::onSourceRowsInserted); connect( view->model(), &QAbstractItemModel::layoutChanged, this, &NewNodeExpander::onLayoutChanged); connect(view->model(), &QAbstractItemModel::modelReset, this, &NewNodeExpander::onModelReset); restoreTreeState(); } virtual ~NewNodeExpander() { //Ideally we'd automatically save the treestate of the parent view here, //but that unfortunately doesn't seem to work } public Q_SLOTS: void saveState() { saveTreeState(); } private Q_SLOTS: void onSourceRowsInserted(const QModelIndex &parent, int start, int end) { //The initial expansion is handled by the state saver if (!mExpandAll) { Akonadi::EntityTreeModel *etm = findEtm(mTreeView->model()); if (!etm || !etm->isCollectionTreeFetched()) { restoreTreeState(); return; } } for (int i = start; i <= end; ++i) { const QModelIndex index = mTreeView->model()->index(i, 0, parent); // qCDebug(KORGANIZER_LOG) << "expanding " << index.data().toString(); mTreeView->expand(index); if (mTreeView->model()->hasChildren(index)) { onSourceRowsInserted(index, 0, mTreeView->model()->rowCount(index) - 1); } } } void onLayoutChanged() { if (mExpandAll) { onSourceRowsInserted(QModelIndex(), 0, mTreeView->model()->rowCount(QModelIndex()) - 1); } } void onModelReset() { if (mExpandAll) { onSourceRowsInserted(QModelIndex(), 0, mTreeView->model()->rowCount(QModelIndex()) - 1); } } private: void saveTreeState() { Akonadi::ETMViewStateSaver treeStateSaver; KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(mTreeStateConfig); treeStateSaver.setView(mTreeView); treeStateSaver.setSelectionModel(nullptr); // we only save expand state treeStateSaver.saveState(group); } void restoreTreeState() { if (mTreeStateConfig.isEmpty()) { return; } //Otherwise ETMViewStateSaver crashes if (!findEtm(mTreeView->model())) { return; } if (treeStateRestorer) { // We don't need more than one to be running at the same time delete treeStateRestorer; } qCDebug(KORGANIZER_LOG) << "Restore tree state"; treeStateRestorer = new Akonadi::ETMViewStateSaver(); // not a leak KConfigGroup group(KSharedConfig::openConfig(), mTreeStateConfig); treeStateRestorer->setView(mTreeView); treeStateRestorer->setSelectionModel(nullptr); // we only restore expand state treeStateRestorer->restoreState(group); } QPointer treeStateRestorer; QTreeView *mTreeView = nullptr; bool mExpandAll = false; QString mTreeStateConfig; }; AkonadiCollectionViewFactory::AkonadiCollectionViewFactory(CalendarView *view) : mView(view) , mAkonadiCollectionView(nullptr) { } static bool hasCompatibleMimeTypes(const Akonadi::Collection &collection) { static QStringList goodMimeTypes; if (goodMimeTypes.isEmpty()) { goodMimeTypes << QStringLiteral("text/calendar") << KCalendarCore::Event::eventMimeType() << KCalendarCore::Todo::todoMimeType() << KCalendarCore::Journal::journalMimeType(); } for (int i = 0; i < goodMimeTypes.count(); ++i) { if (collection.contentMimeTypes().contains(goodMimeTypes.at(i))) { return true; } } return false; } namespace { class ColorProxyModel : public QSortFilterProxyModel { public: explicit ColorProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) , mInitDefaultCalendar(false) { } QVariant data(const QModelIndex &index, int role) const override { if (!index.isValid()) { return QVariant(); } if (role == Qt::DecorationRole) { const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index); if (hasCompatibleMimeTypes(collection)) { if (collection.hasAttribute() && !collection.attribute()->iconName().isEmpty()) { return collection.attribute()->icon(); } } } else if (role == Qt::FontRole) { const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index); if (!collection.contentMimeTypes().isEmpty() && KOHelper::isStandardCalendar(collection.id()) && collection.rights() & Akonadi::Collection::CanCreateItem) { QFont font = qvariant_cast(QSortFilterProxyModel::data(index, Qt::FontRole)); font.setBold(true); if (!mInitDefaultCalendar) { mInitDefaultCalendar = true; CalendarSupport::KCalPrefs::instance()->setDefaultCalendarId(collection.id()); } return font; } } else if (role == Qt::DisplayRole) { const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index); const Akonadi::Collection::Id colId = collection.id(); if (colId == CalendarSupport::KCalPrefs::instance()->defaultCalendarId()) { - return i18nc("this is the default calendar", "%1 (Default Calendar)", collection.displayName()); + return i18nc("this is the default calendar", "%1 (Default)", collection.displayName()); } } return QSortFilterProxyModel::data(index, role); } Qt::ItemFlags flags(const QModelIndex &index) const override { return Qt::ItemIsSelectable | QSortFilterProxyModel::flags(index); } private: mutable bool mInitDefaultCalendar; }; class CollectionFilter : public QSortFilterProxyModel { public: explicit CollectionFilter(QObject *parent = nullptr) : QSortFilterProxyModel(parent) { setDynamicSortFilter(true); } protected: bool filterAcceptsRow(int row, const QModelIndex &sourceParent) const override { const QModelIndex sourceIndex = sourceModel()->index(row, 0, sourceParent); Q_ASSERT(sourceIndex.isValid()); const Akonadi::Collection &col = sourceIndex.data(Akonadi::EntityTreeModel::CollectionRole).value(); const Akonadi::CollectionIdentificationAttribute *attr = col.attribute(); //We filter the user folders because we insert person nodes for user folders. if ((attr && attr->collectionNamespace().startsWith("usertoplevel")) || col.name().contains(QLatin1String("Other Users"))) { return false; } return true; } }; class CalendarDelegateModel : public QSortFilterProxyModel { public: explicit CalendarDelegateModel(QObject *parent = nullptr) : 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; } void setChildren(const QModelIndex &sourceIndex, const QVariant &value, int role) const { if (!sourceIndex.isValid()) { return; } for (int i = 0; i < sourceModel()->rowCount(sourceIndex); ++i) { const QModelIndex child = sourceModel()->index(i, 0, sourceIndex); sourceModel()->setData(child, value, role); setChildren(child, value, role); } } }; } CalendarViewExtension *AkonadiCollectionViewFactory::create(QWidget *parent) { mAkonadiCollectionView = new AkonadiCollectionView(view(), true, parent); QObject::connect(mAkonadiCollectionView, &AkonadiCollectionView::resourcesChanged, mView, &CalendarView::resourcesChanged); QObject::connect(mAkonadiCollectionView, &AkonadiCollectionView::resourcesAddedRemoved, mView, &CalendarView::resourcesChanged); return mAkonadiCollectionView; } CalendarView *AkonadiCollectionViewFactory::view() const { return mView; } AkonadiCollectionView *AkonadiCollectionViewFactory::collectionView() const { return mAkonadiCollectionView; } AkonadiCollectionView::AkonadiCollectionView(CalendarView *view, bool hasContextMenu, QWidget *parent) : CalendarViewExtension(parent) , mActionManager(nullptr) , mCollectionView(nullptr) , mBaseModel(nullptr) , mSelectionProxyModel(nullptr) , mAssignColor(nullptr) , mDisableColor(nullptr) , mDefaultCalendar(nullptr) , mServerSideSubscription(nullptr) , mNotSendAddRemoveSignal(false) , mWasDefaultCalendar(false) , mHasContextMenu(hasContextMenu) { mManagerShowCollectionProperties = new ManageShowCollectionProperties(this, this); QVBoxLayout *topLayout = new QVBoxLayout(this); topLayout->setContentsMargins(0, 0, 0, 0); QLineEdit *searchCol = new QLineEdit(this); searchCol->setToolTip(i18nc("info:tooltip", "Set search keyword")); searchCol->setClearButtonEnabled(true); searchCol->setPlaceholderText(i18nc("@info/plain Displayed grayed-out inside the " "textbox, verb to search", "Search...")); topLayout->addWidget(searchCol); ColorProxyModel *colorProxy = new ColorProxyModel(this); colorProxy->setObjectName(QStringLiteral("Show calendar colors")); colorProxy->setDynamicSortFilter(true); mBaseModel = colorProxy; CalendarDelegateModel *calendarDelegateModel = new CalendarDelegateModel(this); calendarDelegateModel->setSourceModel(mBaseModel); //Hide collections that are not required CollectionFilter *collectionFilter = new CollectionFilter(this); collectionFilter->setSourceModel(calendarDelegateModel); mCollectionView = new Akonadi::EntityTreeView(this); mCollectionView->header()->hide(); mCollectionView->setRootIsDecorated(true); // mCollectionView->setSorting( true ); { StyledCalendarDelegate *delegate = new StyledCalendarDelegate(mCollectionView); connect(delegate, &StyledCalendarDelegate::action, this, &AkonadiCollectionView::onAction); mCollectionView->setItemDelegate(delegate); } mCollectionView->setModel(collectionFilter); connect( mCollectionView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &AkonadiCollectionView::updateMenu); mNewNodeExpander = new NewNodeExpander(mCollectionView, false, QStringLiteral("CollectionTreeView")); //Filter tree view. ReparentingModel *searchProxy = new ReparentingModel(this); searchProxy->setSourceModel(collectionFilter); searchProxy->setObjectName(QStringLiteral("searchProxy")); QSortFilterProxyModel *filterTreeViewModel = new QSortFilterProxyModel(this); filterTreeViewModel->setFilterCaseSensitivity(Qt::CaseInsensitive); filterTreeViewModel->setRecursiveFilteringEnabled(true); filterTreeViewModel->setDynamicSortFilter(true); filterTreeViewModel->setSourceModel(searchProxy); connect(searchCol, &QLineEdit::textChanged, filterTreeViewModel, &QSortFilterProxyModel::setFilterWildcard); Akonadi::EntityTreeView *mSearchView = new Akonadi::EntityTreeView(this); mSearchView->header()->hide(); mSearchView->setRootIsDecorated(true); { StyledCalendarDelegate *delegate = new StyledCalendarDelegate(mCollectionView); connect(delegate, &StyledCalendarDelegate::action, this, &AkonadiCollectionView::onAction); mSearchView->setItemDelegate(delegate); } mSearchView->setModel(filterTreeViewModel); new NewNodeExpander(mSearchView, true, QString()); mStackedWidget = new QStackedWidget(this); mStackedWidget->addWidget(mCollectionView); mStackedWidget->addWidget(mSearchView); mStackedWidget->setCurrentWidget(mCollectionView); topLayout->addWidget(mStackedWidget); connect(mBaseModel, &QAbstractProxyModel::rowsInserted, this, &AkonadiCollectionView::rowsInserted); KXMLGUIClient *xmlclient = KOCore::self()->xmlguiClient(view); if (xmlclient) { mCollectionView->setXmlGuiClient(xmlclient); mActionManager = new Akonadi::StandardCalendarActionManager( xmlclient->actionCollection(), mCollectionView); QList standardActions; standardActions << Akonadi::StandardActionManager::CreateCollection << Akonadi::StandardActionManager::DeleteCollections << Akonadi::StandardActionManager::SynchronizeCollections << Akonadi::StandardActionManager::CollectionProperties << Akonadi::StandardActionManager::CopyItems << Akonadi::StandardActionManager::Paste << Akonadi::StandardActionManager::DeleteItems << Akonadi::StandardActionManager::CutItems << Akonadi::StandardActionManager::CreateResource << Akonadi::StandardActionManager::DeleteResources << Akonadi::StandardActionManager::ResourceProperties << Akonadi::StandardActionManager::SynchronizeResources << Akonadi::StandardActionManager::SynchronizeCollectionTree << Akonadi::StandardActionManager::CopyCollectionToMenu << Akonadi::StandardActionManager::MoveCollectionToMenu; for (Akonadi::StandardActionManager::Type standardAction : qAsConst(standardActions)) { mActionManager->createAction(standardAction); } QList calendarActions; calendarActions << Akonadi::StandardCalendarActionManager::CreateEvent << Akonadi::StandardCalendarActionManager::CreateTodo << Akonadi::StandardCalendarActionManager::CreateSubTodo << Akonadi::StandardCalendarActionManager::CreateJournal << Akonadi::StandardCalendarActionManager::EditIncidence; for (Akonadi::StandardCalendarActionManager::Type calendarAction : qAsConst(calendarActions)) { mActionManager->createAction(calendarAction); } mActionManager->setCollectionSelectionModel(mCollectionView->selectionModel()); mActionManager->interceptAction(Akonadi::StandardActionManager::CreateResource); mActionManager->interceptAction(Akonadi::StandardActionManager::DeleteResources); mActionManager->interceptAction(Akonadi::StandardActionManager::DeleteCollections); connect(mActionManager->action( Akonadi::StandardActionManager::CreateResource), &QAction::triggered, this, &AkonadiCollectionView::newCalendar); connect(mActionManager->action( Akonadi::StandardActionManager::DeleteResources), &QAction::triggered, this, &AkonadiCollectionView::deleteCalendar); connect(mActionManager->action( Akonadi::StandardActionManager::DeleteCollections), &QAction::triggered, this, &AkonadiCollectionView::deleteCalendar); mActionManager->setContextText(Akonadi::StandardActionManager::CollectionProperties, Akonadi::StandardActionManager::DialogTitle, ki18nc("@title:window", "Properties of Calendar Folder %1")); mActionManager->action(Akonadi::StandardActionManager::CreateCollection)->setProperty( "ContentMimeTypes", QStringList() << Akonadi::Collection::mimeType() << KCalendarCore::Event::eventMimeType()); mActionManager->interceptAction(Akonadi::StandardActionManager::CollectionProperties); connect(mActionManager->action( Akonadi::StandardActionManager::CollectionProperties), &QAction::triggered, mManagerShowCollectionProperties, &ManageShowCollectionProperties::showCollectionProperties); mDisableColor = new QAction(mCollectionView); mDisableColor->setText(i18n("&Disable Color")); mDisableColor->setEnabled(false); xmlclient->actionCollection()->addAction(QStringLiteral("disable_color"), mDisableColor); connect(mDisableColor, &QAction::triggered, this, &AkonadiCollectionView::disableColor); mAssignColor = new QAction(mCollectionView); mAssignColor->setText(i18n("&Assign Color...")); mAssignColor->setEnabled(false); xmlclient->actionCollection()->addAction(QStringLiteral("assign_color"), mAssignColor); connect(mAssignColor, &QAction::triggered, this, &AkonadiCollectionView::assignColor); mDefaultCalendar = new QAction(mCollectionView); mDefaultCalendar->setText(i18n("Set as &Default Calendar")); mDefaultCalendar->setEnabled(false); xmlclient->actionCollection()->addAction(QStringLiteral("set_standard_calendar"), mDefaultCalendar); connect(mDefaultCalendar, &QAction::triggered, this, &AkonadiCollectionView::setDefaultCalendar); mServerSideSubscription = new QAction(QIcon::fromTheme(QStringLiteral( "folder-bookmarks")), i18n("Serverside Subscription..."), this); xmlclient->actionCollection()->addAction(QStringLiteral( "serverside_subscription"), mServerSideSubscription); connect(mServerSideSubscription, &QAction::triggered, this, &AkonadiCollectionView::slotServerSideSubscription); } } AkonadiCollectionView::~AkonadiCollectionView() { //Necessary because it's apparently impossible to detect in the note expander when to save the state before view get's deleted mNewNodeExpander->saveState(); } void AkonadiCollectionView::onSearchIsActive(bool active) { if (!active) { mStackedWidget->setCurrentIndex(0); } else { mStackedWidget->setCurrentIndex(1); } } void AkonadiCollectionView::slotServerSideSubscription() { const QModelIndex index = mCollectionView->selectionModel()->currentIndex(); //selectedRows() Q_ASSERT(index.isValid()); const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index); if (!collection.isValid()) { return; } PimCommon::ManageServerSideSubscriptionJob *job = new PimCommon::ManageServerSideSubscriptionJob(this); job->setCurrentCollection(collection); job->setParentWidget(this); job->start(); } Akonadi::Collection AkonadiCollectionView::currentCalendar() const { const QModelIndex index = mCollectionView->selectionModel()->currentIndex(); //selectedRows() Q_ASSERT(index.isValid()); Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index); return collection; } void AkonadiCollectionView::setDefaultCalendar() { QModelIndex index = mCollectionView->selectionModel()->currentIndex(); //selectedRows() Q_ASSERT(index.isValid()); const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index); // Ask if they really want to do this const Akonadi::Collection curCol(CalendarSupport::KCalPrefs::instance()->defaultCalendarId()); if (curCol.isValid() && KMessageBox::warningContinueCancel( this, i18nc("@info", "Do you really want replace your current default calendar with \"%1\"?", collection.displayName()), i18nc("@title:window", "Replace Default Calendar?")) != KMessageBox::Continue) { return; } CalendarSupport::KCalPrefs::instance()->setDefaultCalendarId(collection.id()); CalendarSupport::KCalPrefs::instance()->usrSave(); updateMenu(); updateView(); Q_EMIT defaultResourceChanged(collection); } void AkonadiCollectionView::assignColor() { QModelIndex index = mCollectionView->selectionModel()->currentIndex(); //selectedRows() Q_ASSERT(index.isValid()); const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index); Q_ASSERT(collection.isValid()); const QColor defaultColor = KOHelper::resourceColor(collection); QColor myColor; myColor = QColorDialog::getColor(defaultColor); if (myColor.isValid() && myColor != defaultColor) { KOHelper::setResourceColor(collection, myColor); Q_EMIT colorsChanged(); updateMenu(); updateView(); } } void AkonadiCollectionView::disableColor() { QModelIndex index = mCollectionView->selectionModel()->currentIndex(); //selectedRows() Q_ASSERT(index.isValid()); const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index); Q_ASSERT(collection.isValid()); KOHelper::setResourceColor(collection, QColor()); updateMenu(); updateView(); Q_EMIT colorsChanged(); } void AkonadiCollectionView::setCollectionSelectionProxyModel(KCheckableProxyModel *m) { if (mSelectionProxyModel == m) { return; } mSelectionProxyModel = m; if (!mSelectionProxyModel) { return; } new NewCalendarChecker(m); mBaseModel->setSourceModel(mSelectionProxyModel); } KCheckableProxyModel *AkonadiCollectionView::collectionSelectionProxyModel() const { return mSelectionProxyModel; } Akonadi::EntityTreeView *AkonadiCollectionView::view() const { return mCollectionView; } void AkonadiCollectionView::updateView() { Q_EMIT resourcesChanged(mSelectionProxyModel ? mSelectionProxyModel->selectionModel()->hasSelection() : false); } void AkonadiCollectionView::updateMenu() { if (!mHasContextMenu) { return; } bool enableAction = mCollectionView->selectionModel()->hasSelection(); enableAction = enableAction && (KOPrefs::instance()->agendaViewColors() != KOPrefs::CategoryOnly); mAssignColor->setEnabled(enableAction); QModelIndex index = mCollectionView->selectionModel()->currentIndex(); //selectedRows() bool disableStuff = true; if (index.isValid()) { //Returns an invalid collection on person nodes const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index); if (collection.isValid() && !collection.contentMimeTypes().isEmpty()) { const QColor defaultColor = KOHelper::resourceColor(collection); enableAction = enableAction && defaultColor.isValid(); if (collection.remoteId() == QLatin1String("akonadi_birthdays_resource")) { enableAction = false; mAssignColor->setEnabled(enableAction); } mDisableColor->setEnabled(enableAction); mDefaultCalendar->setEnabled( !KOHelper::isStandardCalendar(collection.id()) && (collection.rights() & Akonadi::Collection::CanCreateItem) && !collection.isVirtual() && collection.contentMimeTypes().contains(KCalendarCore::Event::eventMimeType())); disableStuff = false; } bool isOnline; mServerSideSubscription->setEnabled(PimCommon::MailUtil::isImapFolder(collection, isOnline)); } else { mServerSideSubscription->setEnabled(false); } if (disableStuff) { mDisableColor->setEnabled(false); mDefaultCalendar->setEnabled(false); mAssignColor->setEnabled(false); } } void AkonadiCollectionView::newCalendar() { QPointer dlg = new Akonadi::AgentTypeDialog(this); dlg->setWindowTitle(i18nc("@title:window", "Add Calendar")); dlg->agentFilterProxyModel()->addMimeTypeFilter(QStringLiteral("text/calendar")); dlg->agentFilterProxyModel()->addCapabilityFilter(QStringLiteral("Resource")); // show only resources, no agents if (dlg->exec()) { mNotSendAddRemoveSignal = true; const Akonadi::AgentType agentType = dlg->agentType(); if (agentType.isValid()) { Akonadi::AgentInstanceCreateJob *job = new Akonadi::AgentInstanceCreateJob(agentType, this); job->configure(this); connect(job, &Akonadi::AgentInstanceCreateJob::result, this, &AkonadiCollectionView::newCalendarDone); job->start(); } } delete dlg; } void AkonadiCollectionView::newCalendarDone(KJob *job) { Akonadi::AgentInstanceCreateJob *createjob = static_cast(job); if (createjob->error()) { //TODO(AKONADI_PORT) // this should show an error dialog and should be merged // with the identical code in ActionManager qCWarning(KORGANIZER_LOG) << "Create calendar failed:" << createjob->errorString(); mNotSendAddRemoveSignal = false; return; } mNotSendAddRemoveSignal = false; //TODO } void AkonadiCollectionView::deleteCalendar() { QModelIndex index = mCollectionView->selectionModel()->currentIndex(); //selectedRows() Q_ASSERT(index.isValid()); const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index); Q_ASSERT(collection.isValid()); const QString displayname = index.model()->data(index, Qt::DisplayRole).toString(); Q_ASSERT(!displayname.isEmpty()); if (KMessageBox::warningContinueCancel( this, i18n("Do you really want to delete calendar %1?", displayname), i18n("Delete Calendar"), KStandardGuiItem::del(), KStandardGuiItem::cancel(), QString(), KMessageBox::Dangerous) == KMessageBox::Continue) { bool isTopLevel = collection.parentCollection() == Akonadi::Collection::root(); mNotSendAddRemoveSignal = true; mWasDefaultCalendar = KOHelper::isStandardCalendar(collection.id()); if (!isTopLevel) { // deletes contents Akonadi::CollectionDeleteJob *job = new Akonadi::CollectionDeleteJob(collection, this); connect(job, &Akonadi::AgentInstanceCreateJob::result, this, &AkonadiCollectionView::deleteCalendarDone); } else { // deletes the agent, not the contents const Akonadi::AgentInstance instance = Akonadi::AgentManager::self()->instance(collection.resource()); if (instance.isValid()) { Akonadi::AgentManager::self()->removeInstance(instance); } } } } void AkonadiCollectionView::deleteCalendarDone(KJob *job) { Akonadi::CollectionDeleteJob *deletejob = static_cast(job); if (deletejob->error()) { qCWarning(KORGANIZER_LOG) << "Delete calendar failed:" << deletejob->errorString(); mNotSendAddRemoveSignal = false; return; } if (mWasDefaultCalendar) { CalendarSupport::KCalPrefs::instance()->setDefaultCalendarId(Akonadi::Collection().id()); } mNotSendAddRemoveSignal = false; //TODO } void AkonadiCollectionView::rowsInserted(const QModelIndex &, int, int) { if (!mNotSendAddRemoveSignal) { Q_EMIT resourcesAddedRemoved(); } } Akonadi::Collection AkonadiCollectionView::selectedCollection() const { Akonadi::Collection collection; QItemSelectionModel *selectionModel = mCollectionView->selectionModel(); if (!selectionModel) { return collection; } QModelIndexList indexes = selectionModel->selectedIndexes(); if (!indexes.isEmpty()) { collection = indexes.first().data(Akonadi::EntityTreeModel::CollectionRole).value(); } return collection; } Akonadi::Collection::List AkonadiCollectionView::checkedCollections() const { Akonadi::Collection::List collections; if (!mSelectionProxyModel) { return collections; } QItemSelectionModel *selectionModel = mSelectionProxyModel->selectionModel(); if (!selectionModel) { return collections; } const QModelIndexList indexes = selectionModel->selectedIndexes(); for (const QModelIndex &index : indexes) { if (index.isValid()) { const Akonadi::Collection collection = index.data( Akonadi::EntityTreeModel::CollectionRole).value(); if (collection.isValid()) { collections << collection; } } } return collections; } bool AkonadiCollectionView::isChecked(const Akonadi::Collection &collection) const { if (!mSelectionProxyModel) { return false; } QItemSelectionModel *selectionModel = mSelectionProxyModel->selectionModel(); if (!selectionModel) { return false; } const QModelIndexList indexes = selectionModel->selectedIndexes(); for (const QModelIndex &index : indexes) { if (index.isValid()) { const Akonadi::Collection c = index.data(Akonadi::EntityTreeModel::CollectionRole).value(); if (c.id() == collection.id()) { return true; } } } return false; } Akonadi::EntityTreeModel *AkonadiCollectionView::entityTreeModel() const { QAbstractProxyModel *proxy = qobject_cast(mCollectionView->model()); while (proxy) { Akonadi::EntityTreeModel *etm = qobject_cast( proxy->sourceModel()); if (etm) { return etm; } proxy = qobject_cast(proxy->sourceModel()); } qCWarning(KORGANIZER_LOG) << "Couldn't find EntityTreeModel"; return nullptr; } void AkonadiCollectionView::onAction(const QModelIndex &index, int a) { const StyledCalendarDelegate::Action action = static_cast(a); switch (action) { case StyledCalendarDelegate::Quickview: { Quickview *quickview = new Quickview(CalendarSupport::collectionFromIndex(index)); quickview->setAttribute(Qt::WA_DeleteOnClose, true); quickview->show(); break; } case StyledCalendarDelegate::Total: //TODO: anything to implement here? break; } } #include "akonadicollectionview.moc"