10#include "snippetsmanager.h"
11#include "mailcommon_debug.h"
12#include "snippetdialog.h"
13#include "snippetsmodel.h"
14#include "snippetvariabledialog.h"
15#include <KActionCollection>
16#include <KSharedConfig>
18#include <KLocalizedString>
23#include <QItemSelectionModel>
25#include <QRegularExpression>
32 SnippetsManagerPrivate(SnippetsManager *qq, QWidget *parentWidget)
34 , mParent(parentWidget)
38 [[nodiscard]] QModelIndex currentGroupIndex()
const;
40 void selectionChanged();
46 void addSnippetGroup();
47 void editSnippetGroup();
48 void deleteSnippetGroup();
50 void insertSelectedSnippet();
51 void insertActionSnippet();
53 void createSnippet(
const QString &text = QString());
55 void slotAddNewDndSnippset(
const QString &);
57 void updateActionCollection(
const QString &oldName,
58 const QString &newName,
59 const QKeySequence &keySequence,
61 const QString &subject,
65 const QString &attachment);
66 void initializeAction(
const QString &newName,
67 const QKeySequence &keySequence,
69 const QString &subject,
73 const QString &attachment);
74 void initializeActionCollection();
76 QString replaceVariables(
const QString &text);
80 SnippetsManager *
const q;
81 SnippetsModel *mModel =
nullptr;
82 QItemSelectionModel *mSelectionModel =
nullptr;
83 KActionCollection *mActionCollection =
nullptr;
84 QAction *mAddSnippetAction =
nullptr;
85 QAction *mEditSnippetAction =
nullptr;
86 QAction *mDeleteSnippetAction =
nullptr;
87 QAction *mAddSnippetGroupAction =
nullptr;
88 QAction *mEditSnippetGroupAction =
nullptr;
89 QAction *mDeleteSnippetGroupAction =
nullptr;
90 QAction *mInsertSnippetAction =
nullptr;
91 QWidget *mParent =
nullptr;
95QModelIndex SnippetsManager::SnippetsManagerPrivate::currentGroupIndex()
const
97 if (mSelectionModel->selectedIndexes().isEmpty()) {
101 const QModelIndex index = mSelectionModel->selectedIndexes().first();
105 return mModel->parent(index);
109void SnippetsManager::SnippetsManagerPrivate::selectionChanged()
111 const bool itemSelected = !mSelectionModel->selectedIndexes().isEmpty();
114 const QModelIndex index = mSelectionModel->selectedIndexes().first();
117 mEditSnippetAction->setEnabled(
false);
118 mDeleteSnippetAction->setEnabled(
false);
119 mEditSnippetGroupAction->setEnabled(
true);
120 mDeleteSnippetGroupAction->setEnabled(
true);
121 mInsertSnippetAction->setEnabled(
false);
123 mEditSnippetAction->setEnabled(
true);
124 mDeleteSnippetAction->setEnabled(
true);
125 mEditSnippetGroupAction->setEnabled(
false);
126 mDeleteSnippetGroupAction->setEnabled(
false);
127 mInsertSnippetAction->setEnabled(
true);
130 mEditSnippetAction->setEnabled(
false);
131 mDeleteSnippetAction->setEnabled(
false);
132 mEditSnippetGroupAction->setEnabled(
false);
133 mDeleteSnippetGroupAction->setEnabled(
false);
134 mInsertSnippetAction->setEnabled(
false);
138void SnippetsManager::SnippetsManagerPrivate::addSnippet()
143void SnippetsManager::SnippetsManagerPrivate::createSnippet(
const QString &text)
145 const bool noGroupAvailable = (mModel->rowCount() == 0);
147 if (noGroupAvailable) {
149 if (!mModel->insertRow(mModel->rowCount(), QModelIndex())) {
153 const QModelIndex groupIndex = mModel->index(mModel->rowCount() - 1, 0, QModelIndex());
159 QPointer<SnippetDialog> dlg =
new SnippetDialog(mActionCollection,
false, mParent);
160 dlg->setWindowTitle(
i18nc(
"@title:window",
"Add Snippet"));
161 dlg->setGroupModel(mModel);
162 dlg->setGroupIndex(currentGroupIndex());
170 const QModelIndex groupIndex = dlg->groupIndex();
172 if (!mModel->insertRow(mModel->rowCount(groupIndex), groupIndex)) {
177 const QModelIndex index = mModel->index(mModel->rowCount(groupIndex) - 1, 0, groupIndex);
188 Q_EMIT mModel->updateActionCollection(QString(),
204void SnippetsManager::SnippetsManagerPrivate::slotAddNewDndSnippset(
const QString &text)
209void SnippetsManager::SnippetsManagerPrivate::dndDone()
214void SnippetsManager::SnippetsManagerPrivate::editSnippet()
216 QModelIndex index = mSelectionModel->selectedIndexes().first();
221 const QModelIndex oldGroupIndex = currentGroupIndex();
225 QPointer<SnippetDialog> dlg =
new SnippetDialog(mActionCollection,
false, mParent);
226 dlg->setWindowTitle(
i18nc(
"@title:window",
"Edit Snippet"));
227 dlg->setGroupModel(mModel);
228 dlg->setGroupIndex(oldGroupIndex);
229 dlg->setName(oldSnippetName);
243 const QModelIndex newGroupIndex = dlg->groupIndex();
244 QModelIndex oldIndex = index;
245 if (oldGroupIndex != newGroupIndex) {
246 mModel->removeRow(index.
row(), oldGroupIndex);
247 mModel->insertRow(mModel->rowCount(newGroupIndex), newGroupIndex);
249 oldIndex = mModel->index(mModel->rowCount(newGroupIndex) - 1, 0, newGroupIndex);
262 Q_EMIT mModel->updateActionCollection(oldSnippetName,
278void SnippetsManager::SnippetsManagerPrivate::deleteSnippet()
280 const QModelIndex index = mSelectionModel->selectedIndexes().first();
286 "Do you really want to remove snippet \"%1\"?<nl/>"
287 "<warning>There is no way to undo the removal.</warning>",
295 mModel->removeRow(index.
row(), currentGroupIndex());
297 Q_EMIT mModel->updateActionCollection(snippetName, QString(), QKeySequence(), QString(), QString(), QString(), QString(), QString(), QString());
302void SnippetsManager::SnippetsManagerPrivate::addSnippetGroup()
304 QPointer<SnippetDialog> dlg =
new SnippetDialog(mActionCollection,
true, mParent);
305 dlg->setWindowTitle(
i18nc(
"@title:window",
"Add Group"));
308 if (!mModel->insertRow(mModel->rowCount(), QModelIndex())) {
309 qCDebug(MAILCOMMON_LOG) <<
"unable to insert row";
314 const QModelIndex groupIndex = mModel->index(mModel->rowCount() - 1, 0, QModelIndex());
322void SnippetsManager::SnippetsManagerPrivate::editSnippetGroup()
324 const QModelIndex groupIndex = currentGroupIndex();
329 QPointer<SnippetDialog> dlg =
new SnippetDialog(mActionCollection,
true, mParent);
330 dlg->setWindowTitle(
i18nc(
"@title:window",
"Edit Group"));
332 dlg->setName(oldGroupName);
335 if (oldGroupName == dlg->name()) {
347void SnippetsManager::SnippetsManagerPrivate::deleteSnippetGroup()
349 const QModelIndex groupIndex = currentGroupIndex();
356 if (mModel->rowCount(groupIndex) > 0) {
359 "Do you really want to remove group \"%1\" along with all its snippets?<nl/>"
360 "<warning>There is no way to undo the removal.</warning>",
369 i18nc(
"@info",
"Do you really want to remove group \"%1\"?", groupName),
377 mModel->removeRow(groupIndex.
row(), QModelIndex());
382void SnippetsManager::SnippetsManagerPrivate::insertSelectedSnippet()
384 if (!mSelectionModel->hasSelection()) {
388 const QModelIndex index = mSelectionModel->selectedIndexes().first();
399 Q_EMIT q->insertSnippetInfo({subject, text, to, cc, bcc, attachment});
402void SnippetsManager::SnippetsManagerPrivate::insertActionSnippet()
409 const QString text = replaceVariables(action->property(
"snippetText").toString());
410 const QString subject = replaceVariables(action->property(
"snippetSubject").toString());
411 const QString to = action->property(
"snippetTo").toString();
412 const QString cc = action->property(
"snippetCc").toString();
413 const QString bcc = action->property(
"snippetBcc").toString();
414 const QString attachment = action->property(
"snippetAttachment").toString();
415 Q_EMIT q->insertSnippetInfo({subject, text, to, cc, bcc, attachment});
418void SnippetsManager::SnippetsManagerPrivate::initializeActionCollection()
420 if (mActionCollection) {
421 const QList<SnippetsInfo> infos = mModel->snippetsInfo();
422 for (
const SnippetsInfo &info : infos) {
423 initializeAction(info.newName, info.keySequence, info.text, info.subject, info.to, info.cc, info.bcc, info.attachment);
428void SnippetsManager::SnippetsManagerPrivate::initializeAction(
const QString &newName,
429 const QKeySequence &keySequence,
431 const QString &subject,
435 const QString &attachment)
437 const QString actionName =
i18nc(
"@action",
"Snippet %1", newName);
438 const QString normalizedName = QString(actionName).replace(QLatin1Char(
' '), QLatin1Char(
'_'));
440 QAction *action = mActionCollection->addAction(normalizedName, q);
442 insertActionSnippet();
449 action->
setProperty(
"snippetAttachment", attachment);
451 mActionCollection->setDefaultShortcut(action, keySequence);
454void SnippetsManager::SnippetsManagerPrivate::updateActionCollection(
const QString &oldName,
455 const QString &newName,
456 const QKeySequence &keySequence,
458 const QString &subject,
462 const QString &attachment)
465 if (!oldName.
isEmpty() && mActionCollection) {
466 const QString actionName =
i18nc(
"@action",
"Snippet %1", oldName);
467 const QString normalizedName = QString(actionName).
replace(QLatin1Char(
' '), QLatin1Char(
'_'));
469 QAction *action = mActionCollection->action(normalizedName);
471 mActionCollection->removeAction(action);
476 initializeAction(newName, keySequence, text, subject, to, cc, bcc, attachment);
480QString SnippetsManager::SnippetsManagerPrivate::replaceVariables(
const QString &text)
482 QString result = text;
483 QString variableName;
484 QString variableValue;
485 QMap<QString, QString> localVariables(SnippetsModel::instance()->savedVariables());
488 QMap<QString, QString> tempLocalVariables(localVariables);
491 iFound = text.
indexOf(QRegularExpression(QStringLiteral(
"\\$[A-Za-z\\-_0-9\\s]*\\$")), iEnd + 1);
493 iEnd = text.
indexOf(QLatin1Char(
'$'), iFound + 1) + 1;
495 variableName = text.
mid(iFound, iEnd - iFound);
497 if (variableName != QLatin1StringView(
"$$")) {
498 if (!localVariables.contains(variableName)) {
499 QPointer<SnippetVariableDialog> dlg =
new SnippetVariableDialog(variableName, &tempLocalVariables, mParent);
501 if (dlg->saveVariableIsChecked()) {
504 variableValue = dlg->variableValue();
511 variableValue = localVariables.value(variableName);
514 variableValue = QLatin1Char(
'$');
517 result.
replace(variableName, variableValue);
518 localVariables[variableName] = variableValue;
520 }
while (iFound != -1);
521 SnippetsModel::instance()->setSavedVariables(tempLocalVariables);
526void SnippetsManager::SnippetsManagerPrivate::save()
532 SnippetsModel::instance()->save();
538 , d(new SnippetsManagerPrivate(this, parentWidget))
540 d->mModel = SnippetsModel::instance();
542 &SnippetsModel::updateActionCollection,
553 d->updateActionCollection(oldName, newName, keySequence, text, subject, to, cc, bcc, attachment);
556 d->mActionCollection = actionCollection;
558 d->mAddSnippetAction =
new QAction(
i18nc(
"@action",
"Add Snippet…"),
this);
559 d->mAddSnippetAction->setIcon(
QIcon::fromTheme(QStringLiteral(
"list-add")));
560 d->mEditSnippetAction =
new QAction(
i18nc(
"@action",
"Edit Snippet…"),
this);
561 d->mEditSnippetAction->setIcon(
QIcon::fromTheme(QStringLiteral(
"document-properties")));
562 d->mDeleteSnippetAction =
new QAction(
i18nc(
"@action",
"Remove Snippet"),
this);
563 d->mDeleteSnippetAction->setIcon(
QIcon::fromTheme(QStringLiteral(
"edit-delete")));
565 d->mAddSnippetGroupAction =
new QAction(
i18nc(
"@action",
"Add Group…"),
this);
566 d->mAddSnippetGroupAction->setIcon(
QIcon::fromTheme(QStringLiteral(
"list-add")));
567 d->mEditSnippetGroupAction =
new QAction(
i18nc(
"@action",
"Rename Group…"),
this);
568 d->mEditSnippetGroupAction->setIcon(
QIcon::fromTheme(QStringLiteral(
"edit-rename")));
569 d->mDeleteSnippetGroupAction =
new QAction(
i18nc(
"@action",
"Remove Group"),
this);
570 d->mDeleteSnippetGroupAction->setIcon(
QIcon::fromTheme(QStringLiteral(
"edit-delete")));
572 d->mInsertSnippetAction =
new QAction(
i18nc(
"@action",
"Insert Snippet"),
this);
573 d->mInsertSnippetAction->setIcon(
QIcon::fromTheme(QStringLiteral(
"insert-text")));
576 d->selectionChanged();
578 connect(d->mModel, &SnippetsModel::dndDone,
this, [
this]() {
581 connect(d->mModel, &SnippetsModel::addNewDndSnippset,
this, [
this](
const QString &str) {
582 d->slotAddNewDndSnippset(str);
596 d->addSnippetGroup();
599 d->editSnippetGroup();
602 d->deleteSnippetGroup();
606 d->insertSelectedSnippet();
609 d->initializeActionCollection();
610 d->selectionChanged();
611 connect(
this, &SnippetsManager::insertSnippet,
this, [
this]() {
612 d->insertSelectedSnippet();
628 return d->mSelectionModel;
633 return d->mAddSnippetAction;
638 return d->mEditSnippetAction;
643 return d->mDeleteSnippetAction;
648 return d->mAddSnippetGroupAction;
653 return d->mEditSnippetGroupAction;
658 return d->mDeleteSnippetGroupAction;
663 return d->mInsertSnippetAction;
668 if (d->mSelectionModel->selectedIndexes().isEmpty()) {
677 if (d->mSelectionModel->selectedIndexes().isEmpty()) {
684#include "moc_snippetsmanager.cpp"
The SnippetsManager class.
QString selectedName() const
Returns the name of the currently selected snippet or snippet group.
QAction * editSnippetAction() const
Returns the action that handles editing the currently selected snippet.
bool snippetGroupSelected() const
Returns whether the currently selected item is a snippet group.
QAction * deleteSnippetAction() const
Returns the action that handles deleting the currently selected snippet.
QAction * addSnippetAction() const
Returns the action that handles adding new snippets.
QAbstractItemModel * model() const
Returns the model that represents the snippets.
QAction * addSnippetGroupAction() const
Returns the action that handles adding new snippet groups.
QAction * insertSnippetAction() const
Returns the action that handles inserting a snippet into the editor.
QAction * deleteSnippetGroupAction() const
Returns the action that handles deleting the currently selected snippet group.
QItemSelectionModel * selectionModel() const
Returns the selection model that is used by the manager to select the snippet or snippet group to wor...
~SnippetsManager() override
Destroys the snippets manager.
QAction * editSnippetGroupAction() const
Returns the action that handles editing the currently selected snippet group.
SnippetsManager(KActionCollection *actionCollection, QObject *parent=nullptr, QWidget *widget=nullptr)
Creates a new snippets manager.
@ AttachmentRole
The Attachment of a snippet.
@ KeywordRole
The keyword which will replace by snippet.
@ CcRole
The Cc of a snippet.
@ SubjectRole
The subject of a snippet.
@ BccRole
The Cc of a snippet.
@ KeySequenceRole
The key sequence to activate a snippet.
@ IsGroupRole
Returns whether the index represents a group.
@ ToRole
The To of a snippet.
@ NameRole
The name of a snippet or group.
@ TextRole
The text of a snippet.
QString xi18nc(const char *context, const char *text, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
QAction * save(const QObject *recvr, const char *slot, QObject *parent)
void setText(const QString &text)
void triggered(bool checked)
QIcon fromTheme(const QString &name)
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
QKeySequence fromString(const QString &str, SequenceFormat format)
QVariant data(int role) const const
bool isValid() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
T qobject_cast(QObject *object)
bool setProperty(const char *name, QVariant &&value)
QString first(qsizetype n) const const
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString mid(qsizetype position, qsizetype n) const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
bool toBool() const const
QString toString() const const