Akonadi Contacts

standardcontactactionmanager.cpp
1/*
2 This file is part of Akonadi Contact.
3
4 Copyright (c) 2009 - 2010 Tobias Koenig <tokoe@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "standardcontactactionmanager.h"
10
11#include "contacteditordialog.h"
12#include "contactgroupeditordialog.h"
13
14#include <Akonadi/EntityTreeModel>
15#include <Akonadi/MimeTypeChecker>
16#include <KContacts/Addressee>
17#include <KContacts/ContactGroup>
18
19#include <KActionCollection>
20#include <KLocalizedString>
21#include <KMessageBox>
22#include <QAction>
23
24#include <QItemSelectionModel>
25#include <QPointer>
26
27using namespace Akonadi;
28using namespace Akonadi;
29class Akonadi::StandardContactActionManagerPrivate
30{
31public:
32 StandardContactActionManagerPrivate(KActionCollection *actionCollection, QWidget *parentWidget, StandardContactActionManager *parent)
33 : mActionCollection(actionCollection)
34 , mParentWidget(parentWidget)
35 , mParent(parent)
36 {
37 mGenericManager = new StandardActionManager(actionCollection, parentWidget);
39
41
42 mGenericManager->setCapabilityFilter(QStringList() << QStringLiteral("Resource"));
43 }
44
45 ~StandardContactActionManagerPrivate()
46 {
47 delete mGenericManager;
48 }
49
50 void updateGenericAllActions()
51 {
52 updateGenericAction(StandardActionManager::CreateCollection);
53 updateGenericAction(StandardActionManager::CopyCollections);
57 updateGenericAction(StandardActionManager::CopyItems);
58 updateGenericAction(StandardActionManager::Paste);
59 updateGenericAction(StandardActionManager::DeleteItems);
65 updateGenericAction(StandardActionManager::CopyItemToMenu);
66 updateGenericAction(StandardActionManager::MoveItemToMenu);
68 updateGenericAction(StandardActionManager::CutItems);
69 updateGenericAction(StandardActionManager::CutCollections);
70 updateGenericAction(StandardActionManager::CreateResource);
71 updateGenericAction(StandardActionManager::DeleteResources);
77 updateGenericAction(StandardActionManager::CopyItemToDialog);
78 updateGenericAction(StandardActionManager::MoveItemToDialog);
81 updateGenericAction(StandardActionManager::MoveItemsToTrash);
89 }
90
91 void updateGenericAction(StandardActionManager::Type type)
92 {
93 switch (type) {
95 mGenericManager->action(Akonadi::StandardActionManager::CreateCollection)->setText(i18n("Add Address Book Folder..."));
96
98 ->setWhatsThis(i18n("Add a new address book folder to the currently selected address book folder."));
101 i18nc("@title:window", "New Address Book Folder"));
102
105 ki18n("Could not create address book folder: %1"));
106
109 i18n("Address book folder creation failed"));
111 ->setProperty("ContentMimeTypes", QStringList() << QStringLiteral("application/x-vnd.kde.contactgroup") << QStringLiteral("text/directory"));
112
113 break;
115 mGenericManager->setActionText(Akonadi::StandardActionManager::CopyCollections, ki18np("Copy Address Book Folder", "Copy %1 Address Book Folders"));
117 ->setWhatsThis(i18n("Copy the selected address book folders to the clipboard."));
118 break;
121 ki18np("Delete Address Book Folder", "Delete %1 Address Book Folders"));
123 ->setWhatsThis(i18n("Delete the selected address book folders from the address book."));
124
127 ki18np("Do you really want to delete this address book folder and all its sub-folders?",
128 "Do you really want to delete %1 address book folders and all their sub-folders?"));
131 ki18ncp("@title:window", "Delete address book folder?", "Delete address book folders?"));
132
135 ki18n("Could not delete address book folder: %1"));
136
139 i18n("Address book folder deletion failed"));
140 break;
143 ki18np("Update Address Book Folder", "Update %1 Address Book Folders"));
145 ->setWhatsThis(i18n("Update the content of the selected address book folders."));
146 break;
148 mGenericManager->setActionText(Akonadi::StandardActionManager::CutCollections, ki18np("Cut Address Book Folder", "Cut %1 Address Book Folders"));
150 ->setWhatsThis(i18n("Cut the selected address book folders from the address book."));
151 break;
153 mGenericManager->action(Akonadi::StandardActionManager::CollectionProperties)->setText(i18n("Folder Properties..."));
155 ->setWhatsThis(i18n("Open a dialog to edit the properties of the selected address book folder."));
158 ki18nc("@title:window", "Properties of Address Book Folder %1"));
159 break;
161 mGenericManager->setActionText(Akonadi::StandardActionManager::CopyItems, ki18np("Copy Contact", "Copy %1 Contacts"));
162 mGenericManager->action(Akonadi::StandardActionManager::CopyItems)->setWhatsThis(i18n("Copy the selected contacts to the clipboard."));
163 break;
165 mGenericManager->setActionText(Akonadi::StandardActionManager::DeleteItems, ki18np("Delete Contact", "Delete %1 Contacts"));
166 mGenericManager->action(Akonadi::StandardActionManager::DeleteItems)->setWhatsThis(i18n("Delete the selected contacts from the address book."));
169 ki18np("Do you really want to delete the selected contact?", "Do you really want to delete %1 contacts?"));
170
173 ki18ncp("@title:window", "Delete Contact?", "Delete Contacts?"));
174
176
178 break;
180 mGenericManager->setActionText(Akonadi::StandardActionManager::CutItems, ki18np("Cut Contact", "Cut %1 Contacts"));
181 mGenericManager->action(Akonadi::StandardActionManager::CutItems)->setWhatsThis(i18n("Cut the selected contacts from the address book."));
182 break;
184 mGenericManager->action(Akonadi::StandardActionManager::CreateResource)->setText(i18n("Add &Address Book..."));
186 ->setWhatsThis(i18n("Add a new address book<p>"
187 "You will be presented with a dialog where you can select "
188 "the type of the address book that shall be added.</p>"));
191 i18nc("@title:window", "Add Address Book"));
192
195 ki18n("Could not create address book: %1"));
196
199 i18n("Address book creation failed"));
200 break;
202
203 mGenericManager->setActionText(Akonadi::StandardActionManager::DeleteResources, ki18np("&Delete Address Book", "&Delete %1 Address Books"));
205 ->setWhatsThis(i18n("Delete the selected address books<p>"
206 "The currently selected address books will be deleted, "
207 "along with all the contacts and contact groups they contain.</p>"));
210 ki18np("Do you really want to delete this address book?", "Do you really want to delete %1 address books?"));
211
214 ki18ncp("@title:window", "Delete Address Book?", "Delete Address Books?"));
215
216 break;
218
219 mGenericManager->action(Akonadi::StandardActionManager::ResourceProperties)->setText(i18n("Address Book Properties..."));
221 ->setWhatsThis(i18n("Open a dialog to edit properties of the selected address book."));
222 break;
224 mGenericManager->setActionText(Akonadi::StandardActionManager::SynchronizeResources, ki18np("Update Address Book", "Update %1 Address Books"));
225
227 ->setWhatsThis(i18n("Updates the content of all folders of the selected address books."));
228
229 break;
231 mGenericManager->setContextText(StandardActionManager::Paste, StandardActionManager::ErrorMessageText, ki18n("Could not paste contact: %1"));
232
234 break;
235 default:
236 break;
237 }
238 }
239
240 static bool hasWritableCollection(const QModelIndex &index, const QString &mimeType)
241 {
243 if (collection.isValid()) {
244 if (collection.contentMimeTypes().contains(mimeType) && (collection.rights() & Akonadi::Collection::CanCreateItem)) {
245 return true;
246 }
247 }
248
249 const QAbstractItemModel *model = index.model();
250 if (!model) {
251 return false;
252 }
253
254 for (int row = 0; row < model->rowCount(index); ++row) {
255 if (hasWritableCollection(model->index(row, 0, index), mimeType)) {
256 return true;
257 }
258 }
259
260 return false;
261 }
262
263 bool hasWritableCollection(const QString &mimeType) const
264 {
265 if (!mCollectionSelectionModel) {
266 return false;
267 }
268
269 const QAbstractItemModel *collectionModel = mCollectionSelectionModel->model();
270 for (int row = 0; row < collectionModel->rowCount(); ++row) {
271 if (hasWritableCollection(collectionModel->index(row, 0, QModelIndex()), mimeType)) {
272 return true;
273 }
274 }
275
276 return false;
277 }
278
279 void updateActions()
280 {
281 int itemCount = 0;
282 if (mItemSelectionModel) {
283 itemCount = mItemSelectionModel->selectedRows().count();
284 if (itemCount == 1) {
285 const QModelIndex index = mItemSelectionModel->selectedRows().first();
286 if (index.isValid()) {
288 if (mimeType == KContacts::Addressee::mimeType()) {
290 mGenericManager->setActionText(Akonadi::StandardActionManager::CopyItems, ki18np("Copy Contact", "Copy %1 Contacts"));
291 }
293 if (act) {
294 act->setText(i18n("Copy Contact To"));
295 }
297 if (act) {
298 act->setText(i18n("Copy Contact To"));
299 }
301 mGenericManager->setActionText(Akonadi::StandardActionManager::DeleteItems, ki18np("Delete Contact", "Delete %1 Contacts"));
302 }
303 if (mGenericManager->action(Akonadi::StandardActionManager::CutItems)) {
304 mGenericManager->setActionText(Akonadi::StandardActionManager::CutItems, ki18np("Cut Contact", "Cut %1 Contacts"));
305 }
307 if (act) {
308 act->setText(i18n("Move Contact To"));
309 }
311 if (act) {
312 act->setText(i18n("Move Contact To"));
313 }
315 if (act) {
316 act->setText(i18n("Edit Contact..."));
317 }
318 } else if (mimeType == KContacts::ContactGroup::mimeType()) {
320 mGenericManager->setActionText(Akonadi::StandardActionManager::CopyItems, ki18np("Copy Group", "Copy %1 Groups"));
321 }
323 if (act) {
324 act->setText(i18n("Copy Group To"));
325 }
327 if (act) {
328 act->setText(i18n("Copy Group To"));
329 }
331 mGenericManager->setActionText(Akonadi::StandardActionManager::DeleteItems, ki18np("Delete Group", "Delete %1 Groups"));
332 }
333 if (mGenericManager->action(Akonadi::StandardActionManager::CutItems)) {
334 mGenericManager->setActionText(Akonadi::StandardActionManager::CutItems, ki18np("Cut Group", "Cut %1 Groups"));
335 }
337 if (act) {
338 act->setText(i18n("Move Group To"));
339 }
341 if (act) {
342 act->setText(i18n("Move Group To"));
343 }
345 if (act) {
346 act->setText(i18n("Edit Group..."));
347 }
348 }
349 }
350 }
351 }
352
354 mActions[StandardContactActionManager::CreateContact]->setEnabled(hasWritableCollection(KContacts::Addressee::mimeType()));
355 }
357 mActions[StandardContactActionManager::CreateContactGroup]->setEnabled(hasWritableCollection(KContacts::ContactGroup::mimeType()));
358 }
359
361 bool canEditItem = true;
362
363 // only one selected item can be edited
364 canEditItem = canEditItem && (itemCount == 1);
365
366 // check whether parent collection allows changing the item
367 const QModelIndexList rows = mItemSelectionModel->selectedRows();
368 if (rows.count() == 1) {
369 const QModelIndex index = rows.first();
370 const auto parentCollection = index.data(EntityTreeModel::ParentCollectionRole).value<Collection>();
371 if (parentCollection.isValid()) {
372 canEditItem = canEditItem && (parentCollection.rights() & Collection::CanChangeItem);
373 }
374 }
375
376 mActions.value(StandardContactActionManager::EditItem)->setEnabled(canEditItem);
377 }
378
379 Q_EMIT mParent->actionStateUpdated();
380 }
381
382 Collection selectedCollection() const
383 {
384 if (!mCollectionSelectionModel) {
385 return {};
386 }
387
388 if (mCollectionSelectionModel->selectedIndexes().isEmpty()) {
389 return {};
390 }
391
392 const QModelIndex index = mCollectionSelectionModel->selectedIndexes().first();
393 if (!index.isValid()) {
394 return {};
395 }
396
398 }
399
400 void slotCreateContact()
401 {
402 if (mInterceptedActions.contains(StandardContactActionManager::CreateContact)) {
403 return;
404 }
405
407 dlg->setDefaultAddressBook(selectedCollection());
408 dlg->exec();
409 delete dlg;
410 }
411
412 void slotCreateContactGroup()
413 {
415 return;
416 }
417
419 dlg->setDefaultAddressBook(selectedCollection());
420 dlg->exec();
421 delete dlg;
422 }
423
424 void slotEditItem()
425 {
426 if (mInterceptedActions.contains(StandardContactActionManager::EditItem)) {
427 return;
428 }
429
430 if (!mItemSelectionModel) {
431 return;
432 }
433
434 if (mItemSelectionModel->selectedIndexes().isEmpty()) {
435 return;
436 }
437
438 const QModelIndex index = mItemSelectionModel->selectedIndexes().first();
439 if (!index.isValid()) {
440 return;
441 }
442
443 const Item item = index.data(EntityTreeModel::ItemRole).value<Item>();
444 if (!item.isValid()) {
445 return;
446 }
447
450 QObject::connect(dlg.data(), &Akonadi::ContactEditorDialog::error, mParent, [this](const QString &error) {
451 slotContactEditorError(error);
452 });
453 dlg->setContact(item);
454 dlg->exec();
455 delete dlg;
458 dlg->setContactGroup(item);
459 dlg->exec();
460 delete dlg;
461 }
462 }
463
464 void slotContactEditorError(const QString &error)
465 {
466 KMessageBox::error(mParentWidget, i18n("Contact cannot be stored: %1", error), i18nc("@title:window", "Failed to store contact"));
467 }
468
469 KActionCollection *const mActionCollection;
470 QWidget *const mParentWidget;
471 StandardActionManager *mGenericManager = nullptr;
472 QItemSelectionModel *mCollectionSelectionModel = nullptr;
473 QItemSelectionModel *mItemSelectionModel = nullptr;
476 StandardContactActionManager *const mParent;
477};
478
480 : QObject(parent)
481 , d(new StandardContactActionManagerPrivate(actionCollection, parent, this))
482{
483}
484
486
488{
489 d->mCollectionSelectionModel = selectionModel;
490 d->mGenericManager->setCollectionSelectionModel(selectionModel);
491
492 connect(selectionModel->model(), &QAbstractItemModel::rowsInserted, this, [this]() {
493 d->updateActions();
494 });
495 connect(selectionModel->model(), &QAbstractItemModel::rowsRemoved, this, [this]() {
496 d->updateActions();
497 });
498 connect(selectionModel, &QItemSelectionModel::selectionChanged, this, [this]() {
499 d->updateActions();
500 });
501
502 d->updateActions();
503}
504
506{
507 d->mItemSelectionModel = selectionModel;
508 d->mGenericManager->setItemSelectionModel(selectionModel);
509
510 connect(selectionModel, &QItemSelectionModel::selectionChanged, this, [this]() {
511 d->updateActions();
512 });
513
514 d->updateActions();
515}
516
518{
519 QAction *action = d->mActions.value(type);
520 if (action) {
521 return action;
522 }
523
524 switch (type) {
525 case CreateContact:
526 action = new QAction(d->mParentWidget);
527 action->setIcon(QIcon::fromTheme(QStringLiteral("contact-new")));
528 action->setText(i18n("New &Contact..."));
530 "Create a new contact<p>You will be presented with a dialog where you can add data about a person, including addresses and phone numbers.</p>"));
531 d->mActions.insert(CreateContact, action);
532 d->mActionCollection->addAction(QStringLiteral("akonadi_contact_create"), action);
533 d->mActionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::Key_N));
534 connect(action, &QAction::triggered, this, [this]() {
535 d->slotCreateContact();
536 });
537 break;
539 action = new QAction(d->mParentWidget);
540 action->setIcon(QIcon::fromTheme(QStringLiteral("user-group-new")));
541 action->setText(i18n("New &Group..."));
542 action->setWhatsThis(i18n("Create a new group<p>You will be presented with a dialog where you can add a new group of contacts.</p>"));
543 d->mActions.insert(CreateContactGroup, action);
544 d->mActionCollection->addAction(QStringLiteral("akonadi_contact_group_create"), action);
545 d->mActionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::Key_G));
546 connect(action, &QAction::triggered, this, [this]() {
547 d->slotCreateContactGroup();
548 });
549 break;
550 case EditItem:
551 action = new QAction(d->mParentWidget);
552 action->setIcon(QIcon::fromTheme(QStringLiteral("document-edit")));
553 action->setText(i18n("Edit Contact..."));
555 i18n("Edit the selected contact<p>You will be presented with a dialog where you can edit the data stored about a person, including addresses and "
556 "phone numbers.</p>"));
557 action->setEnabled(false);
558 d->mActions.insert(EditItem, action);
559 d->mActionCollection->addAction(QStringLiteral("akonadi_contact_item_edit"), action);
560 d->mActionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::Key_E));
561
562 connect(action, &QAction::triggered, this, [this]() {
563 d->slotEditItem();
564 });
565 break;
566 default:
567 Q_ASSERT(false); // should never happen
568 break;
569 }
570
571 return action;
572}
573
575{
576 QAction *act = d->mGenericManager->action(type);
577 if (!act) {
578 act = d->mGenericManager->createAction(type);
579 }
580 d->updateGenericAction(type);
581 return act;
582}
583
585{
589
590 d->mGenericManager->createAllActions();
591 d->updateGenericAllActions();
592
593 d->updateActions();
594}
595
597{
598 if (d->mActions.contains(type)) {
599 return d->mActions.value(type);
600 }
601
602 return nullptr;
603}
604
606{
607 return d->mGenericManager->action(type);
608}
609
611{
612 d->mGenericManager->setActionText(type, text);
613}
614
616{
617 if (intercept) {
618 d->mInterceptedActions.insert(type);
619 } else {
620 d->mInterceptedActions.remove(type);
621 }
622}
623
625{
626 d->mGenericManager->interceptAction(type, intercept);
627}
628
630{
631 return d->mGenericManager->selectedCollections();
632}
633
635{
636 return d->mGenericManager->selectedItems();
637}
638
640{
641 d->mGenericManager->setCollectionPropertiesPageNames(names);
642}
643
644#include "moc_standardcontactactionmanager.cpp"
A dialog for creating or editing a contact in Akonadi.
@ EditMode
Edits an existing contact.
@ CreateMode
Creates a new contact.
void error(const QString &errMsg)
This signal is emitted whenever a contact is not updated or stored.
A dialog for creating or editing a contact group in Akonadi.
@ CreateMode
Creates a new contact group.
@ EditMode
Edits an existing contact group.
bool isWantedItem(const Item &item) const
void setActionText(Type type, const KLocalizedString &text)
void setCapabilityFilter(const QStringList &capabilities)
void setMimeTypeFilter(const QStringList &mimeTypes)
void setContextText(Type type, TextContext context, const KLocalizedString &text)
QAction * action(Type type) const
Manages contact specific actions for collection and item views.
@ EditItem
Edits the selected contact resp. contact group.
void setCollectionPropertiesPageNames(const QStringList &names)
StandardContactActionManager(KActionCollection *actionCollection, QWidget *parent=nullptr)
Creates a new standard contact action manager.
QAction * action(Type type) const
Returns the action of the given type, 0 if it has not been created (yet).
void setCollectionSelectionModel(QItemSelectionModel *selectionModel)
Sets the collection selection model based on which the collection related actions should operate.
Akonadi::Item::List selectedItems() const
Returns the list of items that are currently selected.
Akonadi::Collection::List selectedCollections() const
Returns the list of collections that are currently selected.
void actionStateUpdated()
This signal is emitted whenever the action state has been updated.
void createAllActions()
Convenience method to create all standard actions.
~StandardContactActionManager() override
Destroys the standard contact action manager.
QAction * createAction(Type type)
Creates the action of the given type and adds it to the action collection specified in the constructo...
void setItemSelectionModel(QItemSelectionModel *selectionModel)
Sets the item selection model based on which the item related actions should operate.
void interceptAction(Type type, bool intercept=true)
Sets whether the default implementation for the given action type shall be executed when the action i...
void setActionText(Akonadi::StandardActionManager::Type type, const KLocalizedString &text)
Sets the label of the action type to text, which is used during updating the action state and substit...
static QString mimeType()
static QString mimeType()
KLocalizedString KI18N_EXPORT ki18np(const char *singular, const char *plural)
KLocalizedString KI18N_EXPORT ki18n(const char *text)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
KLocalizedString KI18N_EXPORT ki18ncp(const char *context, const char *singular, const char *plural)
KLocalizedString KI18N_EXPORT ki18nc(const char *context, const char *text)
QString i18n(const char *text, const TYPE &arg...)
A widget for editing the display name of a contact.
KCALUTILS_EXPORT QString mimeType()
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
virtual int rowCount(const QModelIndex &parent) const const=0
void rowsInserted(const QModelIndex &parent, int first, int last)
void rowsRemoved(const QModelIndex &parent, int first, int last)
void setEnabled(bool)
void setIcon(const QIcon &icon)
void setText(const QString &text)
void triggered(bool checked)
void setWhatsThis(const QString &what)
bool contains(const Key &key) const const
T value(const Key &key) const const
QIcon fromTheme(const QString &name)
QAbstractItemModel * model()
QModelIndexList selectedRows(int column) const const
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
QVariant data(int role) const const
bool isValid() const const
const QAbstractItemModel * model() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool setProperty(const char *name, QVariant &&value)
T * data() const const
bool contains(const QSet< T > &other) const const
QString toString() const const
T value() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:08:08 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.