diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,4 @@ -# noteshared contains copy of some classes from kdepim/noteshared. This -# is at least until the noteshared library is split out from kdepim -# repository and we can link against it add_subdirectory(noteshared) add_subdirectory(kontact_plugin) @@ -25,7 +22,6 @@ set(kjots_common_SRCS aboutdata.cpp - kjotslockjob.cpp kjotsedit.cpp kjotstreeview.cpp kjotsbookmarks.cpp diff --git a/src/kjotslockjob.h b/src/kjotslockjob.h deleted file mode 100644 --- a/src/kjotslockjob.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright (C) 2010 Klarälvdalens Datakonsult AB, - a KDAB Group company, info@kdab.net, - author Stephen Kelly - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This library 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 Library General Public - License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#ifndef KJOTS_LOCK_JOB_H -#define KJOTS_LOCK_JOB_H - -#include -#include -#include - -class KJotsLockJob : Akonadi::Job -{ - Q_OBJECT -public: - enum Type { - LockJob, - UnlockJob - }; - - explicit KJotsLockJob(const Akonadi::Collection::List &collections, const Akonadi::Item::List &items, Type type = LockJob, QObject *parent = nullptr); - explicit KJotsLockJob(const Akonadi::Collection::List &collections, const Akonadi::Item::List &items, QObject *parent = nullptr); -protected: - void doStart() override; - -protected Q_SLOTS: - void slotResult(KJob *job) override; - -private: - Akonadi::Collection::List m_collections; - Akonadi::Item::List m_items; - Type m_type; -}; - -#endif diff --git a/src/kjotslockjob.cpp b/src/kjotslockjob.cpp deleted file mode 100644 --- a/src/kjotslockjob.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - Copyright (C) 2010 Klarälvdalens Datakonsult AB, - a KDAB Group company, info@kdab.net, - author Stephen Kelly - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This library 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 Library General Public - License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#include "kjotslockjob.h" - -#include -#include - -#include "noteshared/notelockattribute.h" - -KJotsLockJob::KJotsLockJob(const Akonadi::Collection::List &collections, const Akonadi::Item::List &items, KJotsLockJob::Type type, QObject *parent) - : Job(parent), m_collections(collections), m_items(items), m_type(type) -{ -} - -KJotsLockJob::KJotsLockJob(const Akonadi::Collection::List &collections, const Akonadi::Item::List &items, QObject *parent) - : Job(parent), m_collections(collections), m_items(items), m_type(LockJob) -{ -} - -void KJotsLockJob::doStart() -{ - for (const Akonadi::Collection &_col : qAsConst(m_collections)) { - Akonadi::Collection col = _col; - if (m_type == LockJob) { - col.addAttribute(new NoteShared::NoteLockAttribute()); - } else { - col.removeAttribute(); - } - new Akonadi::CollectionModifyJob(col, this); - } - for (const Akonadi::Item &_item : qAsConst(m_items)) { - Akonadi::Item item = _item; - if (m_type == LockJob) { - item.addAttribute(new NoteShared::NoteLockAttribute()); - } else { - item.removeAttribute(); - } - - new Akonadi::ItemModifyJob(item, this); - } -} - -void KJotsLockJob::slotResult(KJob *job) -{ - Akonadi::Job::slotResult(job); - if (!hasSubjobs()) { - emitResult(); - } -} - diff --git a/src/kjotspartui.rc b/src/kjotspartui.rc --- a/src/kjotspartui.rc +++ b/src/kjotspartui.rc @@ -1,16 +1,16 @@ - + - - + + - - + + diff --git a/src/kjotstreeview.h b/src/kjotstreeview.h --- a/src/kjotstreeview.h +++ b/src/kjotstreeview.h @@ -26,28 +26,27 @@ class KXMLGUIClient; +namespace Akonadi { +class StandardNoteActionManager; +} + class KJotsTreeView : public Akonadi::EntityTreeView { Q_OBJECT public: - explicit KJotsTreeView(KXMLGUIClient *xmlGuiClient, QWidget *parent = nullptr); + explicit KJotsTreeView(KXMLGUIClient *xmlGuiClient, + QWidget *parent = nullptr); - void delayedInitialization(); QString captionForSelection(const QString &sep) const; public Q_SLOTS: void renameEntry(); protected: void contextMenuEvent(QContextMenuEvent *event) override; -protected Q_SLOTS: - void copyLinkAddress(); - void changeColor(); - private: KXMLGUIClient *m_xmlGuiClient; - }; #endif diff --git a/src/kjotstreeview.cpp b/src/kjotstreeview.cpp --- a/src/kjotstreeview.cpp +++ b/src/kjotstreeview.cpp @@ -37,64 +37,60 @@ using namespace Akonadi; KJotsTreeView::KJotsTreeView(KXMLGUIClient *xmlGuiClient, QWidget *parent) - : EntityTreeView(xmlGuiClient, parent), m_xmlGuiClient(xmlGuiClient) + : EntityTreeView(xmlGuiClient, parent) + , m_xmlGuiClient(xmlGuiClient) { } void KJotsTreeView::contextMenuEvent(QContextMenuEvent *event) { QMenu *popup = new QMenu(this); - QModelIndexList rows = selectionModel()->selectedRows(); - + const QModelIndexList rows = selectionModel()->selectedRows(); const bool noselection = rows.isEmpty(); const bool singleselection = rows.size() == 1; - const bool multiselection = rows.size() > 1; + const bool itemSelected = singleselection && rows.first().data(EntityTreeModel::ItemRole).value().isValid(); - popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("new_book"))); if (singleselection) { - popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("new_page"))); + popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("akonadi_note_create"))); + popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("akonadi_collection_create"))); popup->addAction(m_xmlGuiClient->actionCollection()->action(QString::fromLatin1(KStandardAction::name(KStandardAction::RenameFile)))); + if (itemSelected) { + popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("akonadi_item_copy"))); + } else { + popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("akonadi_collection_copy"))); + } - popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("copy_link_address"))); - popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("change_color"))); + popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("akonadi_change_color"))); popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("sort_children_alpha"))); popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("sort_children_by_date"))); + } else if (!noselection) { + popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("akonadi_collection_create"))); + popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("akonadi_change_color"))); } if (!noselection) { popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("save_to"))); } popup->addSeparator(); - popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("lock"))); - popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("unlock"))); + popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("akonadi_note_lock"))); + popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("akonadi_note_unlock"))); if (singleselection) { - Item item = rows.at(0).data(KJotsModel::ItemRole).value(); - if (item.isValid()) { - popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("del_page"))); + if (itemSelected) { + popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("akonadi_item_delete"))); } else { - popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("del_folder"))); + popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("akonadi_collection_delete"))); } } - if (multiselection) { - popup->addAction(m_xmlGuiClient->actionCollection()->action(QStringLiteral("del_mult"))); - } - popup->exec(event->globalPos()); delete popup; } -void KJotsTreeView::delayedInitialization() -{ - connect(m_xmlGuiClient->actionCollection()->action(QStringLiteral("copy_link_address")), &QAction::triggered, this, &KJotsTreeView::copyLinkAddress); - connect(m_xmlGuiClient->actionCollection()->action(QStringLiteral("change_color")), &QAction::triggered, this, &KJotsTreeView::changeColor); -} - QString KJotsTreeView::captionForSelection(const QString &sep) const { QString caption; @@ -128,29 +124,3 @@ } edit(rows.first()); } - -void KJotsTreeView::copyLinkAddress() -{ - const QModelIndexList rows = selectionModel()->selectedRows(); - if (rows.size() != 1) { - return; - } - const QModelIndex idx = rows.first(); - QMimeData *mimeData = new QMimeData(); - mimeData->setText(idx.data().toString()); - mimeData->setUrls({idx.data(KJotsModel::EntityUrlRole).toUrl()}); - QApplication::clipboard()->setMimeData(mimeData); -} - -void KJotsTreeView::changeColor() -{ - QColor myColor; - myColor = QColorDialog::getColor(); - if (myColor.isValid()) { - const QModelIndexList rows = selectionModel()->selectedRows(); - for (const QModelIndex &idx : rows) { - model()->setData(idx, myColor, Qt::BackgroundRole); - } - } -} - diff --git a/src/kjotsui.rc b/src/kjotsui.rc --- a/src/kjotsui.rc +++ b/src/kjotsui.rc @@ -1,16 +1,16 @@ - + - - + + - - + + @@ -66,8 +66,8 @@ Main Toolbar - - + + diff --git a/src/kjotswidget.h b/src/kjotswidget.h --- a/src/kjotswidget.h +++ b/src/kjotswidget.h @@ -53,6 +53,7 @@ { class EntityTreeModel; class EntityOrderProxyModel; +class StandardNoteActionManager; } namespace Grantlee @@ -83,10 +84,6 @@ void updateCaption(); void updateMenu(); - void doCreateNewPage(const Akonadi::Collection &collection); - - Q_SCRIPTABLE void newPage(); - Q_SCRIPTABLE void newBook(); Q_SCRIPTABLE bool queryClose(); @@ -126,17 +123,10 @@ void printSelection(); void printPreviewSelection(); - void deletePage(); - void deleteBook(); - void deleteMultiple(); - void openLink(const QUrl &url); private Q_SLOTS: void delayedInitialization(); - void newPageResult(KJob *job); - void newBookResult(KJob *job); - void copySelectionToTitle(); void onShowSearch(); @@ -151,8 +141,6 @@ void onRepeatReplace(); void onEndReplace(); - void actionLock(); - void actionUnlock(); void actionSortChildrenAlpha(); void actionSortChildrenByDate(); @@ -165,6 +153,7 @@ private: KXMLGUIClient *m_xmlGuiClient; + Akonadi::StandardNoteActionManager *m_actionManager = nullptr; KJotsEdit *editor; KJotsBrowser *browser; QStackedWidget *stackedWidget; diff --git a/src/kjotswidget.cpp b/src/kjotswidget.cpp --- a/src/kjotswidget.cpp +++ b/src/kjotswidget.cpp @@ -58,8 +58,6 @@ #include #include -#include "noteshared/notecreatorandselector.h" - // Grantlee #include #include @@ -92,19 +90,19 @@ #include "kjotsconfigdlg.h" #include "kjotsreplacenextdialog.h" #include "KJotsSettings.h" -#include "kjotslockjob.h" #include "kjotsbrowser.h" - #include "noteshared/notelockattribute.h" +#include "noteshared/standardnoteactionmanager.h" #include "localresourcecreator.h" #include using namespace Akonadi; using namespace Grantlee; KJotsWidget::KJotsWidget(QWidget *parent, KXMLGUIClient *xmlGuiClient, Qt::WindowFlags f) - : QWidget(parent, f), m_xmlGuiClient(xmlGuiClient) + : QWidget(parent, f) + , m_xmlGuiClient(xmlGuiClient) { ControlGui::widgetNeedsAkonadi(this); @@ -170,6 +168,11 @@ selProxy = new KSelectionProxyModel(treeview->selectionModel(), this); selProxy->setSourceModel(treeview->model()); + m_actionManager = new StandardNoteActionManager(xmlGuiClient->actionCollection(), this); + m_actionManager->setCollectionSelectionModel(treeview->selectionModel()); + m_actionManager->setItemSelectionModel(treeview->selectionModel()); + m_actionManager->createAllActions(); + // TODO: Write a QAbstractItemView subclass to render kjots selection. // TODO: handle dataChanged properly, i.e. if item was changed from outside @@ -217,34 +220,13 @@ actionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::Key_PageUp)); connect(this, &KJotsWidget::canGoPreviousPageChanged, action, &QAction::setEnabled); - action = actionCollection->addAction(QStringLiteral("new_page")); - action->setText(i18n("&New Page")); - actionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_N)); - action->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); - connect(action, &QAction::triggered, this, &KJotsWidget::newPage); - - action = actionCollection->addAction(QStringLiteral("new_book")); - action->setText(i18n("New &Book...")); - actionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_N)); - action->setIcon(QIcon::fromTheme(QStringLiteral("address-book-new"))); - connect(action, &QAction::triggered, this, &KJotsWidget::newBook); - - action = actionCollection->addAction(QStringLiteral("del_page")); - action->setText(i18n("&Delete Page")); - actionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Delete)); - action->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete-page"))); - connect(action, &QAction::triggered, this, &KJotsWidget::deletePage); - - action = actionCollection->addAction(QStringLiteral("del_folder")); - action->setText(i18n("Delete Boo&k")); - actionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Delete)); - action->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); - connect(action, &QAction::triggered, this, &KJotsWidget::deleteBook); - - action = actionCollection->addAction(QStringLiteral("del_mult")); - action->setText(i18n("Delete Selected")); - action->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); - connect(action, &QAction::triggered, this, &KJotsWidget::deleteMultiple); + actionCollection->setDefaultShortcut(m_actionManager->action(StandardActionManager::CreateCollection), + QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_N)); + actionCollection->setDefaultShortcut(m_actionManager->action(StandardActionManager::DeleteCollections), + QKeySequence(Qt::CTRL + Qt::Key_Delete)); + actionCollection->setDefaultShortcut(m_actionManager->action(StandardActionManager::DeleteItems), + QKeySequence(Qt::CTRL + Qt::Key_Delete)); + KStandardAction::save( editor, &KJotsEdit::savePage, actionCollection); @@ -278,23 +260,6 @@ actionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I)); action->setIcon(QIcon::fromTheme(QStringLiteral("view-calendar-time-spent"))); - action = actionCollection->addAction(QStringLiteral("change_color")); - action->setIcon(QIcon::fromTheme(QStringLiteral("format-fill-color"))); - action->setText(i18n("Change Color...")); - - action = actionCollection->addAction(QStringLiteral("copy_link_address")); - action->setText(i18n("Copy Link Address")); - - action = actionCollection->addAction(QStringLiteral("lock")); - action->setText(i18n("Lock Selected")); - action->setIcon(QIcon::fromTheme(QStringLiteral("emblem-locked"))); - connect(action, &QAction::triggered, this, &KJotsWidget::actionLock); - - action = actionCollection->addAction(QStringLiteral("unlock")); - action->setText(i18n("Unlock Selected")); - action->setIcon(QIcon::fromTheme(QStringLiteral("emblem-unlocked"))); - connect(action, &QAction::triggered, this, &KJotsWidget::actionUnlock); - action = actionCollection->addAction(QStringLiteral("sort_children_alpha")); action->setText(i18n("Sort children alphabetically")); connect(action, &QAction::triggered, this, &KJotsWidget::actionSortChildrenAlpha); @@ -466,42 +431,41 @@ entryActions.insert(actionCollection->action(QString::fromLatin1(KStandardAction::name(KStandardAction::Find)))); entryActions.insert(actionCollection->action(QString::fromLatin1(KStandardAction::name(KStandardAction::Print)))); entryActions.insert(actionCollection->action(QString::fromLatin1(KStandardAction::name(KStandardAction::RenameFile)))); - entryActions.insert(actionCollection->action(QStringLiteral("change_color"))); + entryActions.insert(m_actionManager->action(StandardNoteActionManager::ChangeColor)); entryActions.insert(actionCollection->action(QStringLiteral("save_to"))); - entryActions.insert(actionCollection->action(QStringLiteral("copy_link_address"))); + entryActions.insert(m_actionManager->action(StandardActionManager::CopyItems)); + entryActions.insert(m_actionManager->action(StandardActionManager::CopyCollections)); // Actions that are used only when a page is selected. pageActions.insert(actionCollection->action(QString::fromLatin1(KStandardAction::name(KStandardAction::Cut)))); pageActions.insert(actionCollection->action(QString::fromLatin1(KStandardAction::name(KStandardAction::Paste)))); pageActions.insert(actionCollection->action(QString::fromLatin1(KStandardAction::name(KStandardAction::Replace)))); pageActions.insert(actionCollection->action(QString::fromLatin1(KStandardAction::name(KStandardAction::Save)))); - pageActions.insert(actionCollection->action(QStringLiteral("del_page"))); + pageActions.insert(m_actionManager->action(StandardActionManager::DeleteItems)); pageActions.insert(actionCollection->action(QStringLiteral("insert_date"))); pageActions.insert(actionCollection->action(QStringLiteral("auto_bullet"))); pageActions.insert(actionCollection->action(QStringLiteral("auto_decimal"))); pageActions.insert(actionCollection->action(QStringLiteral("manage_link"))); pageActions.insert(actionCollection->action(QStringLiteral("insert_checkmark"))); // Actions that are used only when a book is selected. bookActions.insert(actionCollection->action(QStringLiteral("save_to_book"))); - bookActions.insert(actionCollection->action(QStringLiteral("del_folder"))); + bookActions.insert(m_actionManager->action(StandardActionManager::DeleteCollections)); bookActions.insert(actionCollection->action(QStringLiteral("sort_children_alpha"))); bookActions.insert(actionCollection->action(QStringLiteral("sort_children_by_date"))); // Actions that are used when multiple items are selected. multiselectionActions.insert(actionCollection->action(QString::fromLatin1(KStandardAction::name(KStandardAction::Find)))); multiselectionActions.insert(actionCollection->action(QString::fromLatin1(KStandardAction::name(KStandardAction::Print)))); - multiselectionActions.insert(actionCollection->action(QStringLiteral("del_mult"))); multiselectionActions.insert(actionCollection->action(QStringLiteral("save_to"))); - multiselectionActions.insert(actionCollection->action(QStringLiteral("change_color"))); + multiselectionActions.insert(m_actionManager->action(StandardNoteActionManager::ChangeColor)); m_autosaveTimer = new QTimer(this); updateConfiguration(); connect(m_autosaveTimer, &QTimer::timeout, editor, &KJotsEdit::savePage); connect(treeview->selectionModel(), &QItemSelectionModel::selectionChanged, m_autosaveTimer, qOverload<>(&QTimer::start)); - treeview->delayedInitialization(); editor->delayedInitialization(m_xmlGuiClient->actionCollection()); browser->delayedInitialization(); @@ -573,14 +537,8 @@ for (QAction *action : qAsConst(pageActions)) { action->setEnabled(false); } - const bool colIsRootCollection = (col.parentCollection() == Collection::root()); for (QAction *action : qAsConst(bookActions)) { - if (action->objectName() == QLatin1String("del_folder") && colIsRootCollection) { - action->setEnabled(false); - } else { - action->setEnabled(true); - } - + action->setEnabled(true); } editor->setActionsEnabled(false); @@ -636,184 +594,6 @@ } } -void KJotsWidget::deleteMultiple() -{ - const QModelIndexList selectedRows = treeview->selectionModel()->selectedRows(); - - if (KMessageBox::questionYesNo(this, - i18n("Do you really want to delete all selected books and pages?"), - i18n("Delete?"), KStandardGuiItem::del(), KStandardGuiItem::cancel(), - QString(), KMessageBox::Dangerous) != KMessageBox::Yes) { - return; - } - - for (const QModelIndex &index : selectedRows) { - bool ok; - qlonglong id = index.data(EntityTreeModel::ItemIdRole).toLongLong(&ok); - Q_ASSERT(ok); - if (id >= 0) { - new ItemDeleteJob(Item(id), this); - } else { - id = index.data(EntityTreeModel::CollectionIdRole).toLongLong(&ok); - Q_ASSERT(ok); - if (id >= 0) { - new CollectionDeleteJob(Collection(id), this); - } - } - } -} - -void KJotsWidget::deletePage() -{ - QModelIndexList selectedRows = treeview->selectionModel()->selectedRows(); - - if (selectedRows.size() != 1) { - return; - } - - const QModelIndex idx = selectedRows.at(0); - Item item = idx.data(EntityTreeModel::ItemRole).value(); - - if (!item.isValid()) { - return; - } - - if (item.hasAttribute()) { - - KMessageBox::information(topLevelWidget(), - i18n("This page is locked. You can only delete it when you first unlock it."), - i18n("Item is locked")); - return; - } - - if (KMessageBox::warningContinueCancel(topLevelWidget(), - i18nc("remove the page, by title", "Are you sure you want to delete the page %1?", idx.data().toString()), - i18n("Delete"), KStandardGuiItem::del(), KStandardGuiItem::cancel(), QStringLiteral("DeletePageWarning")) == KMessageBox::Cancel) { - return; - } - - (void) new ItemDeleteJob(item, this); -} - -void KJotsWidget::deleteBook() -{ - QModelIndexList selectedRows = treeview->selectionModel()->selectedRows(); - - if (selectedRows.size() != 1) { - return; - } - - const QModelIndex idx = selectedRows.at(0); - Collection col = idx.data(EntityTreeModel::CollectionRole).value(); - - if (!col.isValid()) { - return; - } - - if (col.parentCollection() == Collection::root()) { - return; - } - - if (col.hasAttribute()) { - - KMessageBox::information(topLevelWidget(), - i18n("This book is locked. You can only delete it when you first unlock it."), - i18n("Item is locked")); - return; - } - if (KMessageBox::warningContinueCancel(topLevelWidget(), - i18nc("remove the book, by title", "Are you sure you want to delete the book %1?", idx.data().toString()), - i18n("Delete"), KStandardGuiItem::del(), KStandardGuiItem::cancel(), QStringLiteral("DeleteBookWarning")) == KMessageBox::Cancel) { - return; - } - - (void) new CollectionDeleteJob(col, this); -} - -void KJotsWidget::newBook() -{ - QModelIndexList selectedRows = treeview->selectionModel()->selectedRows(); - - if (selectedRows.size() != 1) { - return; - } - - Collection col = selectedRows.at(0).data(EntityTreeModel::CollectionRole).value(); - - if (!col.isValid()) { - return; - } - - Collection newCollection; - newCollection.setParentCollection(col); - - QString title = i18nc("The default name for new books.", "New Book"); - newCollection.setName(KRandom::randomString(10)); - newCollection.setContentMimeTypes({Collection::mimeType(), NoteUtils::noteMimeType()}); - - EntityDisplayAttribute *eda = new EntityDisplayAttribute(); - eda->setIconName(QStringLiteral("x-office-address-book")); - eda->setDisplayName(title); - newCollection.addAttribute(eda); - - CollectionCreateJob *job = new CollectionCreateJob(newCollection); - connect(job, &CollectionCreateJob::result, this, &KJotsWidget::newBookResult); -} - -void KJotsWidget::newPage() -{ - QModelIndexList selectedRows = treeview->selectionModel()->selectedRows(); - - if (selectedRows.size() != 1) { - return; - } - - Item item = selectedRows.at(0).data(EntityTreeModel::ItemRole).value(); - - Collection col; - if (item.isValid()) { - col = selectedRows.at(0).data(EntityTreeModel::ParentCollectionRole).value(); - } else { - col = selectedRows.at(0).data(EntityTreeModel::CollectionRole).value(); - } - - if (!col.isValid()) { - return; - } - doCreateNewPage(col); -} - -void KJotsWidget::doCreateNewPage(const Collection &collection) -{ - auto creatorAndSelector = new NoteShared::NoteCreatorAndSelector(treeview->selectionModel()); - creatorAndSelector->createNote(collection); -} - -void KJotsWidget::newPageResult(KJob *job) -{ - if (job->error()) { - qDebug() << job->errorString(); - } -} - -void KJotsWidget::newBookResult(KJob *job) -{ - if (job->error()) { - qDebug() << job->errorString(); - return; - } - CollectionCreateJob *createJob = qobject_cast(job); - if (!createJob) { - return; - } - const Collection collection = createJob->collection(); - if (!collection.isValid()) { - return; - } - - doCreateNewPage(collection); -} - QString KJotsWidget::renderSelectionToHtml() { QHash hash; @@ -1582,62 +1362,6 @@ return true; } -void KJotsWidget::actionLock() -{ - const QModelIndexList selection = treeview->selectionModel()->selectedRows(); - - if (selection.isEmpty()) { - return; - } - - Collection::List collections; - Item::List items; - for (const QModelIndex &idx : selection) { - Collection col = idx.data(EntityTreeModel::CollectionRole).value(); - if (col.isValid()) { - collections << col; - } else { - Item item = idx.data(EntityTreeModel::ItemRole).value(); - if (item.isValid()) { - items << item; - } - } - } - if (collections.isEmpty() && items.isEmpty()) { - return; - } - - new KJotsLockJob(collections, items, this); -} - -void KJotsWidget::actionUnlock() -{ - const QModelIndexList selection = treeview->selectionModel()->selectedRows(); - - if (selection.isEmpty()) { - return; - } - - Collection::List collections; - Item::List items; - for (const QModelIndex &idx : selection) { - Collection col = idx.data(EntityTreeModel::CollectionRole).value(); - if (col.isValid()) { - collections << col; - } else { - Item item = idx.data(EntityTreeModel::ItemRole).value(); - if (item.isValid()) { - items << item; - } - } - } - if (collections.isEmpty() && items.isEmpty()) { - return; - } - - new KJotsLockJob(collections, items, KJotsLockJob::UnlockJob, this); -} - void KJotsWidget::actionSortChildrenAlpha() { const QModelIndexList selection = treeview->selectionModel()->selectedRows(); diff --git a/src/kontact_plugin/kjots_plugin.cpp b/src/kontact_plugin/kjots_plugin.cpp --- a/src/kontact_plugin/kjots_plugin.cpp +++ b/src/kontact_plugin/kjots_plugin.cpp @@ -78,7 +78,7 @@ QStringList KJotsPlugin::invisibleToolbarActions() const { - return { QStringLiteral("new_page"), QStringLiteral("new_book") }; + return { QStringLiteral("akonadi_note_create"), QStringLiteral("akonadi_collection_create") }; } #if KONTACTINTERFACE_VERSION >= QT_VERSION_CHECK(5, 14, 42) diff --git a/src/noteshared/CMakeLists.txt b/src/noteshared/CMakeLists.txt --- a/src/noteshared/CMakeLists.txt +++ b/src/noteshared/CMakeLists.txt @@ -3,6 +3,7 @@ notelockattribute.cpp noteeditorutils.cpp localresourcecreator.cpp + standardnoteactionmanager.cpp ) ecm_qt_declare_logging_category(noteshared_SRCS @@ -37,6 +38,7 @@ KF5::I18n KF5::AkonadiCore KF5::AkonadiNotes + KF5::XmlGui ) target_include_directories(noteshared PUBLIC $) diff --git a/src/noteshared/notecreatorandselector.cpp b/src/noteshared/notecreatorandselector.cpp --- a/src/noteshared/notecreatorandselector.cpp +++ b/src/noteshared/notecreatorandselector.cpp @@ -38,7 +38,7 @@ NoteCreatorAndSelector::NoteCreatorAndSelector(QItemSelectionModel *primaryModel, QItemSelectionModel *secondaryModel, QObject *parent) : QObject(parent), m_primarySelectionModel(primaryModel), - m_secondarySelectionModel(secondaryModel == 0 ? primaryModel : secondaryModel), + m_secondarySelectionModel(secondaryModel == nullptr ? primaryModel : secondaryModel), m_containerCollectionId(-1), m_newNoteId(-1), m_giveupTimer(new QTimer(this)) diff --git a/src/noteshared/standardnoteactionmanager.h b/src/noteshared/standardnoteactionmanager.h new file mode 100644 --- /dev/null +++ b/src/noteshared/standardnoteactionmanager.h @@ -0,0 +1,189 @@ +/* + This file is part of KJots + + Copyright (c) 2020 Igor Poboiko + 2009 - 2010 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef AKONADI_STANDARDNOTESACTIONMANAGER_H +#define AKONADI_STANDARDNOTESACTIONMANAGER_H + +#include + +#include + +class QAction; +class KActionCollection; +class QItemSelectionModel; +class QWidget; + +namespace Akonadi { +class Item; + +/** + * @short Manages note specific actions for collection and item views. + * + * @author Igor Poboiko + */ +class StandardNoteActionManager : public QObject +{ + Q_OBJECT + +public: + /** + * Describes the supported actions. + */ + enum Type { + CreateNote = StandardActionManager::LastType + 1, ///< Creates a new note + Lock, ///< Locks a note or a note book + Unlock, ///< Unlocks a note or a note book + ChangeColor ///< Changes a color of a note or a note book + }; + + /** + * Creates a new standard note action manager. + * + * @param actionCollection The action collection to operate on. + * @param parent The parent widget. + */ + explicit StandardNoteActionManager(KActionCollection *actionCollection, QWidget *parent = nullptr); + + /** + * Destroys the standard note action manager. + */ + ~StandardNoteActionManager(); + + /** + * Sets the collection selection model based on which the collection + * related actions should operate. If none is set, all collection actions + * will be disabled. + * + * @param selectionModel selection model for collections + */ + void setCollectionSelectionModel(QItemSelectionModel *selectionModel); + + /** + * Sets the item selection model based on which the item related actions + * should operate. If none is set, all item actions will be disabled. + * + * @param selectionModel the selection model for items + */ + void setItemSelectionModel(QItemSelectionModel *selectionModel); + + /** + * Creates the action of the given type and adds it to the action collection + * specified in the constructor if it does not exist yet. The action is + * connected to its default implementation provided by this class. + * + * @param type the type of action to create + */ + Q_REQUIRED_RESULT QAction *createAction(Type type); + + /** + * Creates the action of the given type and adds it to the action collection + * specified in the constructor if it does not exist yet. The action is + * connected to its default implementation provided by this class. + * + * @param type the type of action to create + */ + QAction *createAction(StandardActionManager::Type type); + + /** + * Convenience method to create all standard actions. + * @see createAction() + */ + void createAllActions(); + + /** + * Returns the action of the given type, 0 if it has not been created (yet). + */ + QAction *action(Type type) const; + + /** + * Returns the action of the given type, 0 if it has not been created (yet). + * + * @param type the type of action to return + */ + QAction *action(StandardActionManager::Type type) const; + + /** + * Sets the label of the action @p type to @p text, which is used during + * updating the action state and substituted according to the number of + * selected objects. This is mainly useful to customize the label of actions + * that can operate on multiple objects. + * + * Example: + * @code + * acctMgr->setActionText( Akonadi::StandardActionManager::CopyItems, + * ki18np( "Copy Item", "Copy %1 Items" ) ); + * @endcode + */ + void setActionText(StandardActionManager::Type type, const KLocalizedString &text); + + /** + * Sets whether the default implementation for the given action @p type + * shall be executed when the action is triggered. + * + * @param intercept If @c false, the default implementation will be executed, + * if @c true no action is taken. + */ + void interceptAction(Type type, bool intercept = true); + + /** + * Sets whether the default implementation for the given action @p type + * shall be executed when the action is triggered. + * + * @param intercept If @c false, the default implementation will be executed, + * if @c true no action is taken. + */ + void interceptAction(StandardActionManager::Type type, bool intercept = true); + + /** + * Returns the list of collections that are currently selected. + * The list is empty if no collection is currently selected. + */ + Q_REQUIRED_RESULT Akonadi::Collection::List selectedCollections() const; + + /** + * Returns the list of items that are currently selected. + * The list is empty if no item is currently selected. + */ + Q_REQUIRED_RESULT Akonadi::Item::List selectedItems() const; + + /** + * @param names the list of names to set as collection properties page names + */ + void setCollectionPropertiesPageNames(const QStringList &names); + +Q_SIGNALS: + /** + * This signal is emitted whenever the action state has been updated. + * In case you have special needs for changing the state of some actions, + * connect to this signal and adjust the action state. + */ + void actionStateUpdated(); + +private: + //@cond PRIVATE + class Private; + std::unique_ptr const d; + //@endcond +}; +} + +#endif diff --git a/src/noteshared/standardnoteactionmanager.cpp b/src/noteshared/standardnoteactionmanager.cpp new file mode 100644 --- /dev/null +++ b/src/noteshared/standardnoteactionmanager.cpp @@ -0,0 +1,589 @@ +/* + This file is part of KJots. + + Copyright (c) 2020 Igor Poboiko + 2009 - 2010 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "standardnoteactionmanager.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "notelockattribute.h" +#include "notecreatorandselector.h" + +using namespace Akonadi; + +class Q_DECL_HIDDEN StandardNoteActionManager::Private +{ +public: + Private(KActionCollection *actionCollection, QWidget *parentWidget, StandardNoteActionManager *parent) + : mActionCollection(actionCollection) + , mParentWidget(parentWidget) + , mGenericManager(std::make_unique(actionCollection, parentWidget)) + , mCollectionSelectionModel(nullptr) + , mItemSelectionModel(nullptr) + , mParent(parent) + { + mParent->connect(mGenericManager.get(), &StandardActionManager::actionStateUpdated, + mParent, &StandardNoteActionManager::actionStateUpdated); + + mGenericManager->setMimeTypeFilter({ NoteUtils::noteMimeType() }); + + mGenericManager->setCapabilityFilter({ QStringLiteral("Resource") }); + } + + ~Private() = default; + + void updateGenericAllActions() + { + updateGenericAction(StandardActionManager::CreateCollection); + updateGenericAction(StandardActionManager::CopyCollections); + updateGenericAction(StandardActionManager::DeleteCollections); + updateGenericAction(StandardActionManager::SynchronizeCollections); + updateGenericAction(StandardActionManager::CollectionProperties); + updateGenericAction(StandardActionManager::CopyItems); + updateGenericAction(StandardActionManager::Paste); + updateGenericAction(StandardActionManager::DeleteItems); + updateGenericAction(StandardActionManager::ManageLocalSubscriptions); + updateGenericAction(StandardActionManager::AddToFavoriteCollections); + updateGenericAction(StandardActionManager::RemoveFromFavoriteCollections); + updateGenericAction(StandardActionManager::RenameFavoriteCollection); + updateGenericAction(StandardActionManager::CopyCollectionToMenu); + updateGenericAction(StandardActionManager::CopyItemToMenu); + updateGenericAction(StandardActionManager::MoveItemToMenu); + updateGenericAction(StandardActionManager::MoveCollectionToMenu); + updateGenericAction(StandardActionManager::CutItems); + updateGenericAction(StandardActionManager::CutCollections); + updateGenericAction(StandardActionManager::CreateResource); + updateGenericAction(StandardActionManager::DeleteResources); + updateGenericAction(StandardActionManager::ResourceProperties); + updateGenericAction(StandardActionManager::SynchronizeResources); + updateGenericAction(StandardActionManager::ToggleWorkOffline); + updateGenericAction(StandardActionManager::CopyCollectionToDialog); + updateGenericAction(StandardActionManager::MoveCollectionToDialog); + updateGenericAction(StandardActionManager::CopyItemToDialog); + updateGenericAction(StandardActionManager::MoveItemToDialog); + updateGenericAction(StandardActionManager::SynchronizeCollectionsRecursive); + updateGenericAction(StandardActionManager::MoveCollectionsToTrash); + updateGenericAction(StandardActionManager::MoveItemsToTrash); + updateGenericAction(StandardActionManager::RestoreCollectionsFromTrash); + updateGenericAction(StandardActionManager::RestoreItemsFromTrash); + updateGenericAction(StandardActionManager::MoveToTrashRestoreCollection); + updateGenericAction(StandardActionManager::MoveToTrashRestoreCollectionAlternative); + updateGenericAction(StandardActionManager::MoveToTrashRestoreItem); + updateGenericAction(StandardActionManager::MoveToTrashRestoreItemAlternative); + updateGenericAction(StandardActionManager::SynchronizeFavoriteCollections); + } + + void updateGenericAction(StandardActionManager::Type type) + { + switch (type) { + case StandardActionManager::CreateCollection: + mGenericManager->action(StandardActionManager::CreateCollection)->setText( + i18n("New Note Book...")); + mGenericManager->action(StandardActionManager::CreateCollection)->setIcon( + QIcon::fromTheme(QStringLiteral("address-book-new"))); + + mGenericManager->action(StandardActionManager::CreateCollection)->setWhatsThis( + i18n("Add a new note book to the currently selected bookshelf.")); + mGenericManager->setContextText( + StandardActionManager::CreateCollection, StandardActionManager::DialogTitle, + i18nc("@title:window", "New Note Book")); + + mGenericManager->setContextText( + StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageText, + ki18n("Could not create note book: %1")); + + mGenericManager->setContextText( + StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageTitle, + i18n("Note book creation failed")); + mGenericManager->action(StandardActionManager::CreateCollection)->setProperty("ContentMimeTypes", { NoteUtils::noteMimeType() }); + + break; + case StandardActionManager::CopyCollections: + mGenericManager->setActionText(StandardActionManager::CopyCollections, + ki18np("Copy Note Book", + "Copy %1 Note Books")); + mGenericManager->action(StandardActionManager::CopyCollections)->setWhatsThis( + i18n("Copy the selected note books to the clipboard.")); + break; + case StandardActionManager::DeleteCollections: + mGenericManager->setActionText(StandardActionManager::DeleteCollections, + ki18np("Delete Note Book", + "Delete %1 Note Books")); + mGenericManager->action(StandardActionManager::DeleteCollections)->setWhatsThis( + i18n("Delete the selected note books from the bookshelf.")); + + mGenericManager->setContextText( + StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxText, + ki18np("Do you really want to delete this note book and all its contents?", + "Do you really want to delete %1 note books and all their contents?")); + mGenericManager->setContextText( + StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxTitle, + ki18ncp("@title:window", "Delete note book?", "Delete note books?")); + + mGenericManager->setContextText( + StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageText, + ki18n("Could not delete note book: %1")); + + mGenericManager->setContextText( + StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageTitle, + i18n("Note book deletion failed")); + break; + case StandardActionManager::SynchronizeCollections: + mGenericManager->setActionText(StandardActionManager::SynchronizeCollections, + ki18np("Update Note Book", + "Update %1 Note Books")); + mGenericManager->action(StandardActionManager::SynchronizeCollections)->setWhatsThis( + i18n("Update the content of the selected note books.")); + break; + case StandardActionManager::CutCollections: + mGenericManager->setActionText(StandardActionManager::CutCollections, + ki18np("Cut Note Book", + "Cut %1 Note Books")); + mGenericManager->action(StandardActionManager::CutCollections)->setWhatsThis( + i18n("Cut the selected note books from the bookshelf.")); + break; + case StandardActionManager::CollectionProperties: + mGenericManager->action(StandardActionManager::CollectionProperties)->setText( + i18n("Note Book Properties...")); + mGenericManager->action(StandardActionManager::CollectionProperties)->setWhatsThis( + i18n("Open a dialog to edit the properties of the selected note book.")); + mGenericManager->setContextText( + StandardActionManager::CollectionProperties, StandardActionManager::DialogTitle, + ki18nc("@title:window", "Properties of Note Book %1")); + break; + + case StandardActionManager::CopyItems: + mGenericManager->setActionText(StandardActionManager::CopyItems, + ki18np("Copy Note", "Copy %1 Notes")); + mGenericManager->action(StandardActionManager::CopyItems)->setWhatsThis( + i18n("Copy the selected notes to the clipboard.")); + break; + case StandardActionManager::DeleteItems: + mGenericManager->setActionText(StandardActionManager::DeleteItems, + ki18np("Delete Note", "Delete %1 Notes")); + mGenericManager->action(StandardActionManager::DeleteItems)->setWhatsThis( + i18n("Delete the selected notes from the note book.")); + mGenericManager->setContextText( + StandardActionManager::DeleteItems, StandardActionManager::MessageBoxText, + ki18np("Do you really want to delete the selected note?", + "Do you really want to delete %1 notes?")); + + mGenericManager->setContextText( + StandardActionManager::DeleteItems, StandardActionManager::MessageBoxTitle, + ki18ncp("@title:window", "Delete Note?", "Delete Notes?")); + + mGenericManager->setContextText( + StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageText, + ki18n("Could not delete note: %1")); + + mGenericManager->setContextText( + StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageTitle, + i18n("Note deletion failed")); + break; + case StandardActionManager::CutItems: + mGenericManager->setActionText(StandardActionManager::CutItems, + ki18np("Cut Note", "Cut %1 Notes")); + mGenericManager->action(StandardActionManager::CutItems)->setWhatsThis( + i18n("Cut the selected notes from the note book.")); + break; + case StandardActionManager::CreateResource: + mGenericManager->action(StandardActionManager::CreateResource)->setText( + i18n("Add &Bookshelf...")); + mGenericManager->action(StandardActionManager::CreateResource)->setWhatsThis( + i18n("Add a new bookshelf

" + "You will be presented with a dialog where you can select " + "the type of the bookshelf that shall be added.

")); + mGenericManager->setContextText( + StandardActionManager::CreateResource, StandardActionManager::DialogTitle, + i18nc("@title:window", "Add Bookshelf")); + + mGenericManager->setContextText( + StandardActionManager::CreateResource, StandardActionManager::ErrorMessageText, + ki18n("Could not create bookshelf: %1")); + + mGenericManager->setContextText( + StandardActionManager::CreateResource, StandardActionManager::ErrorMessageTitle, + i18n("Bookshelf creation failed")); + break; + case StandardActionManager::DeleteResources: + + mGenericManager->setActionText(StandardActionManager::DeleteResources, + ki18np("&Delete Bookshelf", + "&Delete %1 Bookshelfs")); + mGenericManager->action(StandardActionManager::DeleteResources)->setWhatsThis( + i18n("Delete the selected bookshelfs

" + "The currently selected bookshelfs will be deleted, " + "along with all the notes they contain.

")); + mGenericManager->setContextText( + StandardActionManager::DeleteResources, StandardActionManager::MessageBoxText, + ki18np("Do you really want to delete this bookshelf?", + "Do you really want to delete %1 bookshelfs?")); + + mGenericManager->setContextText( + StandardActionManager::DeleteResources, StandardActionManager::MessageBoxTitle, + ki18ncp("@title:window", "Delete Bookshelf?", "Delete Bookshelfs?")); + + break; + case StandardActionManager::ResourceProperties: + + mGenericManager->action(StandardActionManager::ResourceProperties)->setText( + i18n("Bookshelf Properties...")); + mGenericManager->action(StandardActionManager::ResourceProperties)->setWhatsThis( + i18n("Open a dialog to edit properties of the selected bookshelf.")); + break; + case StandardActionManager::SynchronizeResources: + mGenericManager->setActionText(StandardActionManager::SynchronizeResources, + ki18np("Update Bookshelf", + "Update %1 Bookshelfs")); + + mGenericManager->action(StandardActionManager::SynchronizeResources)->setWhatsThis + (i18n("Updates the content of all note books of the selected bookshelfs.")); + + break; + case StandardActionManager::Paste: + mGenericManager->setContextText( + StandardActionManager::Paste, StandardActionManager::ErrorMessageText, + ki18n("Could not paste note: %1")); + + mGenericManager->setContextText( + StandardActionManager::Paste, StandardActionManager::ErrorMessageTitle, + i18n("Paste failed")); + break; + default: + break; + } + } + + void updateActions() + { + if (mItemSelectionModel && mCollectionSelectionModel) { + const Collection::List collections = mParent->selectedCollections(); + const Item::List items = mParent->selectedItems(); + QAction *action = mActions.value(StandardNoteActionManager::Lock); + if (action) { + bool canLock = std::any_of(collections.cbegin(), collections.cend(), [](const Collection &collection){ + return collection.isValid() && !collection.hasAttribute(); + }); + canLock = canLock || std::any_of(items.cbegin(), items.cend(), [](const Item &item){ + return item.isValid() && !item.hasAttribute(); + }); + action->setEnabled(canLock); + } + + action = mActions.value(StandardNoteActionManager::Unlock); + if (action) { + const bool hasLockedCollection = std::any_of(collections.cbegin(), collections.cend(), [](const Collection &collection){ + return collection.isValid() && collection.hasAttribute(); + }); + if (hasLockedCollection) { + mGenericManager->action(StandardActionManager::DeleteCollections)->setEnabled(false); + } + const bool hasLockedItems = std::any_of(items.cbegin(), items.cend(), [](const Item &item){ + return item.isValid() && item.hasAttribute(); + }); + if (hasLockedItems) { + mGenericManager->action(StandardActionManager::DeleteItems)->setEnabled(false); + } + action->setEnabled(hasLockedItems || hasLockedCollection); + } + } else { + if (mActions.contains(StandardNoteActionManager::Lock)) { + mActions[StandardNoteActionManager::Lock]->setEnabled(false); + } + if (mActions.contains(StandardNoteActionManager::Unlock)) { + mActions[StandardNoteActionManager::Unlock]->setEnabled(false); + } + } + + Q_EMIT mParent->actionStateUpdated(); + } + + void slotLockUnlock(bool lock) { + if (!mItemSelectionModel || !mCollectionSelectionModel) { + return; + } + if ((lock && mInterceptedActions.contains(Lock)) || + (!lock && mInterceptedActions.contains(Unlock))) + { + return; + } + const Item::List items = mParent->selectedItems(); + for (auto item : items) { + if (item.isValid()) { + if (lock) { + item.addAttribute(new NoteShared::NoteLockAttribute); + } else { + item.removeAttribute(); + } + new ItemModifyJob(item, mParent); + } + } + const Collection::List collections = mParent->selectedCollections(); + for (auto collection : collections) { + if (collection.isValid()) { + if (lock) { + collection.addAttribute(new NoteShared::NoteLockAttribute); + } else { + collection.removeAttribute(); + } + new CollectionModifyJob(collection, mParent); + } + } + } + + void slotCreateNote() { + if (mInterceptedActions.contains(CreateNote)) { + return; + } + const Collection::List collections = mParent->selectedCollections(); + if (collections.count() != 1) { + return; + } + Collection collection = collections.first(); + auto creatorAndSelector = new NoteShared::NoteCreatorAndSelector(mCollectionSelectionModel, mItemSelectionModel, mParent); + creatorAndSelector->createNote(collection); + } + + void slotChangeColor() { + if (mInterceptedActions.contains(ChangeColor)) { + return; + } + QColor color = Qt::white; + const Collection::List collections = mParent->selectedCollections(); + const Item::List items = mParent->selectedItems(); + if (collections.size() + items.size() == 1) { + const EntityDisplayAttribute *attr = (collections.size() == 1) + ? collections.first().attribute() + : items.first().attribute();; + + if (attr) { + color = attr->backgroundColor(); + } + } + color = QColorDialog::getColor(color, mParentWidget); + if (!color.isValid()) { + return; + } + for (auto item : items) { + item.attribute(Item::AddIfMissing)->setBackgroundColor(color); + new ItemModifyJob(item, mParent); + } + for (auto collection : collections) { + collection.attribute(Collection::AddIfMissing)->setBackgroundColor(color); + new CollectionModifyJob(collection, mParent); + } + } + + KActionCollection *mActionCollection = nullptr; + QWidget *mParentWidget = nullptr; + std::unique_ptr mGenericManager; + QItemSelectionModel *mCollectionSelectionModel = nullptr; + QItemSelectionModel *mItemSelectionModel = nullptr; + QHash mActions; + QSet mInterceptedActions; + StandardNoteActionManager *mParent = nullptr; +}; + +StandardNoteActionManager::StandardNoteActionManager(KActionCollection *actionCollection, QWidget *parent) + : QObject(parent) + , d(std::make_unique(actionCollection, parent, this)) +{ +} + +StandardNoteActionManager::~StandardNoteActionManager() = default; + +void StandardNoteActionManager::setCollectionSelectionModel(QItemSelectionModel *selectionModel) +{ + d->mCollectionSelectionModel = selectionModel; + d->mGenericManager->setCollectionSelectionModel(selectionModel); + + connect(selectionModel->model(), &QAbstractItemModel::dataChanged, this, [this]() { + d->updateActions(); + }); + connect(selectionModel->model(), &QAbstractItemModel::rowsInserted, this, [this]() { + d->updateActions(); + }); + connect(selectionModel->model(), &QAbstractItemModel::rowsRemoved, this, [this]() { + d->updateActions(); + }); + connect(selectionModel, &QItemSelectionModel::selectionChanged, this, [this]() { + d->updateActions(); + }); + + d->updateActions(); +} + +void StandardNoteActionManager::setItemSelectionModel(QItemSelectionModel *selectionModel) +{ + d->mItemSelectionModel = selectionModel; + d->mGenericManager->setItemSelectionModel(selectionModel); + + connect(selectionModel->model(), &QAbstractItemModel::dataChanged, this, [this]() { + d->updateActions(); + }); + connect(selectionModel, &QItemSelectionModel::selectionChanged, this, [this]() { + d->updateActions(); + }); + + d->updateActions(); +} + +QAction *StandardNoteActionManager::createAction(Type type) +{ + QAction *action = d->mActions.value(type); + if (action) { + return action; + } + + switch (type) { + case CreateNote: + action = new QAction(d->mParentWidget); + action->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); + action->setText(i18n("&New Note")); + action->setWhatsThis(i18n("Add a new note to a selected note book")); + d->mActions.insert(CreateNote, action); + d->mActionCollection->addAction(QStringLiteral("akonadi_note_create"), action); + d->mActionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_N)); + connect(action, &QAction::triggered, this, [this](){ + d->slotCreateNote(); + }); + break; + case Lock: + action = new QAction(d->mParentWidget); + action->setIcon(QIcon::fromTheme(QStringLiteral("emblem-locked"))); + action->setText(i18n("Lock Selected")); + action->setWhatsThis(i18n("Lock selected note book or notes")); + d->mActions.insert(Lock, action); + d->mActionCollection->addAction(QStringLiteral("akonadi_note_lock"), action); + connect(action, &QAction::triggered, this, [this]() { + d->slotLockUnlock(true); + }); + break; + case Unlock: + action = new QAction(d->mParentWidget); + action->setIcon(QIcon::fromTheme(QStringLiteral("emblem-unlocked"))); + action->setText(i18n("Unlock Selected")); + action->setWhatsThis(i18n("Unlock selected note books or notes")); + d->mActions.insert(Unlock, action); + d->mActionCollection->addAction(QStringLiteral("akonadi_note_unlock"), action); + connect(action, &QAction::triggered, this, [this]() { + d->slotLockUnlock(false); + }); + break; + case ChangeColor: + action = new QAction(d->mParentWidget); + action->setIcon(QIcon::fromTheme(QStringLiteral("format-fill-color"))); + action->setText(i18n("Change Color...")); + action->setWhatsThis(i18n("Changes the color of a selected note books or notes")); + d->mActions.insert(ChangeColor, action); + d->mActionCollection->addAction(QStringLiteral("akonadi_change_color"), action); + connect(action, &QAction::triggered, this, [this](){ + d->slotChangeColor(); + }); + break; + default: + Q_ASSERT(false); // should never happen + break; + } + + return action; +} + +QAction *StandardNoteActionManager::createAction(StandardActionManager::Type type) +{ + QAction *act = d->mGenericManager->action(type); + if (!act) { + act = d->mGenericManager->createAction(type); + } + d->updateGenericAction(type); + return act; +} + +void StandardNoteActionManager::createAllActions() +{ + (void)createAction(CreateNote); + (void)createAction(Lock); + (void)createAction(Unlock); + (void)createAction(ChangeColor); + + d->mGenericManager->createAllActions(); + d->updateGenericAllActions(); + d->updateActions(); +} + +QAction *StandardNoteActionManager::action(Type type) const +{ + if (d->mActions.contains(type)) { + return d->mActions.value(type); + } + + return nullptr; +} + +QAction *StandardNoteActionManager::action(StandardActionManager::Type type) const +{ + return d->mGenericManager->action(type); +} + +void StandardNoteActionManager::setActionText(StandardActionManager::Type type, const KLocalizedString &text) +{ + d->mGenericManager->setActionText(type, text); +} + +void StandardNoteActionManager::interceptAction(Type type, bool intercept) +{ + if (intercept) { + d->mInterceptedActions.insert(type); + } else { + d->mInterceptedActions.remove(type); + } +} + +void StandardNoteActionManager::interceptAction(StandardActionManager::Type type, bool intercept) +{ + d->mGenericManager->interceptAction(type, intercept); +} + +Collection::List StandardNoteActionManager::selectedCollections() const +{ + return d->mGenericManager->selectedCollections(); +} + +Item::List StandardNoteActionManager::selectedItems() const +{ + return d->mGenericManager->selectedItems(); +} + +void StandardNoteActionManager::setCollectionPropertiesPageNames(const QStringList &names) +{ + d->mGenericManager->setCollectionPropertiesPageNames(names); +}