Warning, file /pim/mailcommon/src/snippets/snippetsmanager.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002   SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
0003   SPDX-FileContributor: Tobias Koenig <tokoe@kdab.com>
0004 
0005   SPDX-FileCopyrightText: 2019-2024 Laurent Montel <montel@kde.org>
0006 
0007   SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "snippetsmanager.h"
0011 #include "mailcommon_debug.h"
0012 #include "snippetdialog.h"
0013 #include "snippetsmodel.h"
0014 #include "snippetvariabledialog.h"
0015 #include <KActionCollection>
0016 #include <KSharedConfig>
0017 
0018 #include <KLocalizedString>
0019 #include <KMessageBox>
0020 #include <QIcon>
0021 
0022 #include <QAction>
0023 #include <QItemSelectionModel>
0024 #include <QPointer>
0025 #include <QRegularExpression>
0026 
0027 using namespace MailCommon;
0028 
0029 class Q_DECL_HIDDEN SnippetsManager::SnippetsManagerPrivate
0030 {
0031 public:
0032     SnippetsManagerPrivate(SnippetsManager *qq, QWidget *parentWidget)
0033         : q(qq)
0034         , mParent(parentWidget)
0035     {
0036     }
0037 
0038     [[nodiscard]] QModelIndex currentGroupIndex() const;
0039 
0040     void selectionChanged();
0041     void dndDone();
0042     void addSnippet();
0043     void editSnippet();
0044     void deleteSnippet();
0045 
0046     void addSnippetGroup();
0047     void editSnippetGroup();
0048     void deleteSnippetGroup();
0049 
0050     void insertSelectedSnippet();
0051     void insertActionSnippet();
0052 
0053     void createSnippet(const QString &text = QString());
0054 
0055     void slotAddNewDndSnippset(const QString &);
0056 
0057     void updateActionCollection(const QString &oldName,
0058                                 const QString &newName,
0059                                 const QKeySequence &keySequence,
0060                                 const QString &text,
0061                                 const QString &subject,
0062                                 const QString &to,
0063                                 const QString &cc,
0064                                 const QString &bcc,
0065                                 const QString &attachment);
0066     void initializeAction(const QString &newName,
0067                           const QKeySequence &keySequence,
0068                           const QString &text,
0069                           const QString &subject,
0070                           const QString &to,
0071                           const QString &cc,
0072                           const QString &bcc,
0073                           const QString &attachment);
0074     void initializeActionCollection();
0075 
0076     QString replaceVariables(const QString &text);
0077 
0078     void save();
0079 
0080     SnippetsManager *const q;
0081     SnippetsModel *mModel = nullptr;
0082     QItemSelectionModel *mSelectionModel = nullptr;
0083     KActionCollection *mActionCollection = nullptr;
0084     QAction *mAddSnippetAction = nullptr;
0085     QAction *mEditSnippetAction = nullptr;
0086     QAction *mDeleteSnippetAction = nullptr;
0087     QAction *mAddSnippetGroupAction = nullptr;
0088     QAction *mEditSnippetGroupAction = nullptr;
0089     QAction *mDeleteSnippetGroupAction = nullptr;
0090     QAction *mInsertSnippetAction = nullptr;
0091     QWidget *mParent = nullptr;
0092     bool mDirty = false;
0093 };
0094 
0095 QModelIndex SnippetsManager::SnippetsManagerPrivate::currentGroupIndex() const
0096 {
0097     if (mSelectionModel->selectedIndexes().isEmpty()) {
0098         return {};
0099     }
0100 
0101     const QModelIndex index = mSelectionModel->selectedIndexes().first();
0102     if (index.data(SnippetsModel::IsGroupRole).toBool()) {
0103         return index;
0104     } else {
0105         return mModel->parent(index);
0106     }
0107 }
0108 
0109 void SnippetsManager::SnippetsManagerPrivate::selectionChanged()
0110 {
0111     const bool itemSelected = !mSelectionModel->selectedIndexes().isEmpty();
0112 
0113     if (itemSelected) {
0114         const QModelIndex index = mSelectionModel->selectedIndexes().first();
0115         const bool isGroup = index.data(SnippetsModel::IsGroupRole).toBool();
0116         if (isGroup) {
0117             mEditSnippetAction->setEnabled(false);
0118             mDeleteSnippetAction->setEnabled(false);
0119             mEditSnippetGroupAction->setEnabled(true);
0120             mDeleteSnippetGroupAction->setEnabled(true);
0121             mInsertSnippetAction->setEnabled(false);
0122         } else {
0123             mEditSnippetAction->setEnabled(true);
0124             mDeleteSnippetAction->setEnabled(true);
0125             mEditSnippetGroupAction->setEnabled(false);
0126             mDeleteSnippetGroupAction->setEnabled(false);
0127             mInsertSnippetAction->setEnabled(true);
0128         }
0129     } else {
0130         mEditSnippetAction->setEnabled(false);
0131         mDeleteSnippetAction->setEnabled(false);
0132         mEditSnippetGroupAction->setEnabled(false);
0133         mDeleteSnippetGroupAction->setEnabled(false);
0134         mInsertSnippetAction->setEnabled(false);
0135     }
0136 }
0137 
0138 void SnippetsManager::SnippetsManagerPrivate::addSnippet()
0139 {
0140     createSnippet();
0141 }
0142 
0143 void SnippetsManager::SnippetsManagerPrivate::createSnippet(const QString &text)
0144 {
0145     const bool noGroupAvailable = (mModel->rowCount() == 0);
0146 
0147     if (noGroupAvailable) {
0148         // create a 'General' snippet group
0149         if (!mModel->insertRow(mModel->rowCount(), QModelIndex())) {
0150             return;
0151         }
0152 
0153         const QModelIndex groupIndex = mModel->index(mModel->rowCount() - 1, 0, QModelIndex());
0154         mModel->setData(groupIndex, i18n("General"), SnippetsModel::NameRole);
0155 
0156         mSelectionModel->select(groupIndex, QItemSelectionModel::ClearAndSelect);
0157     }
0158 
0159     QPointer<SnippetDialog> dlg = new SnippetDialog(mActionCollection, false, mParent);
0160     dlg->setWindowTitle(i18nc("@title:window", "Add Snippet"));
0161     dlg->setGroupModel(mModel);
0162     dlg->setGroupIndex(currentGroupIndex());
0163     dlg->setText(text);
0164 
0165     q->connect(dlg, &SnippetDialog::rejected, q, [dlg]() {
0166         delete dlg;
0167     });
0168 
0169     q->connect(dlg, &SnippetDialog::accepted, q, [dlg, this]() {
0170         const QModelIndex groupIndex = dlg->groupIndex();
0171 
0172         if (!mModel->insertRow(mModel->rowCount(groupIndex), groupIndex)) {
0173             delete dlg;
0174             return;
0175         }
0176 
0177         const QModelIndex index = mModel->index(mModel->rowCount(groupIndex) - 1, 0, groupIndex);
0178         mModel->setData(index, dlg->name(), SnippetsModel::NameRole);
0179         mModel->setData(index, dlg->text(), SnippetsModel::TextRole);
0180         mModel->setData(index, dlg->keySequence().toString(), SnippetsModel::KeySequenceRole);
0181         mModel->setData(index, dlg->keyword(), SnippetsModel::KeywordRole);
0182         mModel->setData(index, dlg->subject(), SnippetsModel::SubjectRole);
0183         mModel->setData(index, dlg->to(), SnippetsModel::ToRole);
0184         mModel->setData(index, dlg->cc(), SnippetsModel::CcRole);
0185         mModel->setData(index, dlg->bcc(), SnippetsModel::BccRole);
0186         mModel->setData(index, dlg->attachment(), SnippetsModel::AttachmentRole);
0187 
0188         Q_EMIT mModel->updateActionCollection(QString(),
0189                                               dlg->name(),
0190                                               dlg->keySequence(),
0191                                               dlg->text(),
0192                                               dlg->subject(),
0193                                               dlg->to(),
0194                                               dlg->cc(),
0195                                               dlg->bcc(),
0196                                               dlg->attachment());
0197         mDirty = true;
0198         save();
0199         delete dlg;
0200     });
0201     dlg->show();
0202 }
0203 
0204 void SnippetsManager::SnippetsManagerPrivate::slotAddNewDndSnippset(const QString &text)
0205 {
0206     createSnippet(text);
0207 }
0208 
0209 void SnippetsManager::SnippetsManagerPrivate::dndDone()
0210 {
0211     mDirty = true;
0212 }
0213 
0214 void SnippetsManager::SnippetsManagerPrivate::editSnippet()
0215 {
0216     QModelIndex index = mSelectionModel->selectedIndexes().first();
0217     if (!index.isValid() || index.data(SnippetsModel::IsGroupRole).toBool()) {
0218         return;
0219     }
0220 
0221     const QModelIndex oldGroupIndex = currentGroupIndex();
0222 
0223     const QString oldSnippetName = index.data(SnippetsModel::NameRole).toString();
0224 
0225     QPointer<SnippetDialog> dlg = new SnippetDialog(mActionCollection, false, mParent);
0226     dlg->setWindowTitle(i18nc("@title:window", "Edit Snippet"));
0227     dlg->setGroupModel(mModel);
0228     dlg->setGroupIndex(oldGroupIndex);
0229     dlg->setName(oldSnippetName);
0230     dlg->setText(index.data(SnippetsModel::TextRole).toString());
0231     dlg->setKeyword(index.data(SnippetsModel::KeywordRole).toString());
0232     dlg->setSubject(index.data(SnippetsModel::SubjectRole).toString());
0233     dlg->setTo(index.data(SnippetsModel::ToRole).toString());
0234     dlg->setCc(index.data(SnippetsModel::CcRole).toString());
0235     dlg->setBcc(index.data(SnippetsModel::BccRole).toString());
0236     dlg->setAttachment(index.data(SnippetsModel::AttachmentRole).toString());
0237     dlg->setKeySequence(QKeySequence::fromString(index.data(SnippetsModel::KeySequenceRole).toString()));
0238     q->connect(dlg, &SnippetDialog::rejected, q, [dlg]() {
0239         delete dlg;
0240     });
0241 
0242     q->connect(dlg, &SnippetDialog::accepted, q, [dlg, this, oldGroupIndex, index, oldSnippetName]() {
0243         const QModelIndex newGroupIndex = dlg->groupIndex();
0244         QModelIndex oldIndex = index;
0245         if (oldGroupIndex != newGroupIndex) {
0246             mModel->removeRow(index.row(), oldGroupIndex);
0247             mModel->insertRow(mModel->rowCount(newGroupIndex), newGroupIndex);
0248 
0249             oldIndex = mModel->index(mModel->rowCount(newGroupIndex) - 1, 0, newGroupIndex);
0250         }
0251 
0252         mModel->setData(oldIndex, dlg->name(), SnippetsModel::NameRole);
0253         mModel->setData(oldIndex, dlg->text(), SnippetsModel::TextRole);
0254         mModel->setData(oldIndex, dlg->keySequence().toString(), SnippetsModel::KeySequenceRole);
0255         mModel->setData(oldIndex, dlg->keyword(), SnippetsModel::KeywordRole);
0256         mModel->setData(oldIndex, dlg->subject(), SnippetsModel::SubjectRole);
0257         mModel->setData(oldIndex, dlg->to(), SnippetsModel::ToRole);
0258         mModel->setData(oldIndex, dlg->cc(), SnippetsModel::CcRole);
0259         mModel->setData(oldIndex, dlg->bcc(), SnippetsModel::BccRole);
0260         mModel->setData(oldIndex, dlg->attachment(), SnippetsModel::AttachmentRole);
0261 
0262         Q_EMIT mModel->updateActionCollection(oldSnippetName,
0263                                               dlg->name(),
0264                                               dlg->keySequence(),
0265                                               dlg->text(),
0266                                               dlg->subject(),
0267                                               dlg->to(),
0268                                               dlg->cc(),
0269                                               dlg->bcc(),
0270                                               dlg->attachment());
0271         mDirty = true;
0272         save();
0273         delete dlg;
0274     });
0275     dlg->show();
0276 }
0277 
0278 void SnippetsManager::SnippetsManagerPrivate::deleteSnippet()
0279 {
0280     const QModelIndex index = mSelectionModel->selectedIndexes().first();
0281 
0282     const QString snippetName = index.data(SnippetsModel::NameRole).toString();
0283 
0284     if (KMessageBox::warningContinueCancel(nullptr,
0285                                            xi18nc("@info",
0286                                                   "Do you really want to remove snippet \"%1\"?<nl/>"
0287                                                   "<warning>There is no way to undo the removal.</warning>",
0288                                                   snippetName),
0289                                            QString(),
0290                                            KStandardGuiItem::remove())
0291         == KMessageBox::Cancel) {
0292         return;
0293     }
0294 
0295     mModel->removeRow(index.row(), currentGroupIndex());
0296 
0297     Q_EMIT mModel->updateActionCollection(snippetName, QString(), QKeySequence(), QString(), QString(), QString(), QString(), QString(), QString());
0298     mDirty = true;
0299     save();
0300 }
0301 
0302 void SnippetsManager::SnippetsManagerPrivate::addSnippetGroup()
0303 {
0304     QPointer<SnippetDialog> dlg = new SnippetDialog(mActionCollection, true, mParent);
0305     dlg->setWindowTitle(i18nc("@title:window", "Add Group"));
0306 
0307     if (dlg->exec()) {
0308         if (!mModel->insertRow(mModel->rowCount(), QModelIndex())) {
0309             qCDebug(MAILCOMMON_LOG) << "unable to insert row";
0310             delete dlg;
0311             return;
0312         }
0313 
0314         const QModelIndex groupIndex = mModel->index(mModel->rowCount() - 1, 0, QModelIndex());
0315         mModel->setData(groupIndex, dlg->name(), SnippetsModel::NameRole);
0316         mDirty = true;
0317         save();
0318     }
0319     delete dlg;
0320 }
0321 
0322 void SnippetsManager::SnippetsManagerPrivate::editSnippetGroup()
0323 {
0324     const QModelIndex groupIndex = currentGroupIndex();
0325     if (!groupIndex.isValid() || !groupIndex.data(SnippetsModel::IsGroupRole).toBool()) {
0326         return;
0327     }
0328 
0329     QPointer<SnippetDialog> dlg = new SnippetDialog(mActionCollection, true, mParent);
0330     dlg->setWindowTitle(i18nc("@title:window", "Edit Group"));
0331     const QString oldGroupName = groupIndex.data(SnippetsModel::NameRole).toString();
0332     dlg->setName(oldGroupName);
0333 
0334     if (dlg->exec()) {
0335         if (oldGroupName == dlg->name()) {
0336             delete dlg;
0337             return;
0338         }
0339 
0340         mModel->setData(groupIndex, dlg->name(), SnippetsModel::NameRole);
0341         mDirty = true;
0342         save();
0343     }
0344     delete dlg;
0345 }
0346 
0347 void SnippetsManager::SnippetsManagerPrivate::deleteSnippetGroup()
0348 {
0349     const QModelIndex groupIndex = currentGroupIndex();
0350     if (!groupIndex.isValid()) {
0351         return;
0352     }
0353 
0354     const QString groupName = groupIndex.data(SnippetsModel::NameRole).toString();
0355 
0356     if (mModel->rowCount(groupIndex) > 0) {
0357         if (KMessageBox::warningContinueCancel(nullptr,
0358                                                xi18nc("@info",
0359                                                       "Do you really want to remove group \"%1\" along with all its snippets?<nl/>"
0360                                                       "<warning>There is no way to undo the removal.</warning>",
0361                                                       groupName),
0362                                                QString(),
0363                                                KStandardGuiItem::remove())
0364             == KMessageBox::Cancel) {
0365             return;
0366         }
0367     } else {
0368         if (KMessageBox::warningContinueCancel(nullptr,
0369                                                i18nc("@info", "Do you really want to remove group \"%1\"?", groupName),
0370                                                QString(),
0371                                                KStandardGuiItem::remove())
0372             == KMessageBox::Cancel) {
0373             return;
0374         }
0375     }
0376 
0377     mModel->removeRow(groupIndex.row(), QModelIndex());
0378     mDirty = true;
0379     save();
0380 }
0381 
0382 void SnippetsManager::SnippetsManagerPrivate::insertSelectedSnippet()
0383 {
0384     if (!mSelectionModel->hasSelection()) {
0385         return;
0386     }
0387 
0388     const QModelIndex index = mSelectionModel->selectedIndexes().first();
0389     if (index.data(SnippetsModel::IsGroupRole).toBool()) {
0390         return;
0391     }
0392 
0393     const QString text = replaceVariables(index.data(SnippetsModel::TextRole).toString());
0394     const QString subject = replaceVariables(index.data(SnippetsModel::SubjectRole).toString());
0395     const QString to = index.data(SnippetsModel::ToRole).toString();
0396     const QString cc = index.data(SnippetsModel::CcRole).toString();
0397     const QString bcc = index.data(SnippetsModel::BccRole).toString();
0398     const QString attachment = index.data(SnippetsModel::AttachmentRole).toString();
0399     Q_EMIT q->insertSnippetInfo({subject, text, to, cc, bcc, attachment});
0400 }
0401 
0402 void SnippetsManager::SnippetsManagerPrivate::insertActionSnippet()
0403 {
0404     auto action = qobject_cast<QAction *>(q->sender());
0405     if (!action) {
0406         return;
0407     }
0408 
0409     const QString text = replaceVariables(action->property("snippetText").toString());
0410     const QString subject = replaceVariables(action->property("snippetSubject").toString());
0411     const QString to = action->property("snippetTo").toString();
0412     const QString cc = action->property("snippetCc").toString();
0413     const QString bcc = action->property("snippetBcc").toString();
0414     const QString attachment = action->property("snippetAttachment").toString();
0415     Q_EMIT q->insertSnippetInfo({subject, text, to, cc, bcc, attachment});
0416 }
0417 
0418 void SnippetsManager::SnippetsManagerPrivate::initializeActionCollection()
0419 {
0420     if (mActionCollection) {
0421         const QList<SnippetsInfo> infos = mModel->snippetsInfo();
0422         for (const SnippetsInfo &info : infos) {
0423             initializeAction(info.newName, info.keySequence, info.text, info.subject, info.to, info.cc, info.bcc, info.attachment);
0424         }
0425     }
0426 }
0427 
0428 void SnippetsManager::SnippetsManagerPrivate::initializeAction(const QString &newName,
0429                                                                const QKeySequence &keySequence,
0430                                                                const QString &text,
0431                                                                const QString &subject,
0432                                                                const QString &to,
0433                                                                const QString &cc,
0434                                                                const QString &bcc,
0435                                                                const QString &attachment)
0436 {
0437     const QString actionName = i18nc("@action", "Snippet %1", newName);
0438     const QString normalizedName = QString(actionName).replace(QLatin1Char(' '), QLatin1Char('_'));
0439 
0440     QAction *action = mActionCollection->addAction(normalizedName, q);
0441     connect(action, &QAction::triggered, q, [this]() {
0442         insertActionSnippet();
0443     });
0444     action->setProperty("snippetText", text);
0445     action->setProperty("snippetSubject", subject);
0446     action->setProperty("snippetTo", to);
0447     action->setProperty("snippetCc", cc);
0448     action->setProperty("snippetBcc", bcc);
0449     action->setProperty("snippetAttachment", attachment);
0450     action->setText(actionName);
0451     mActionCollection->setDefaultShortcut(action, keySequence);
0452 }
0453 
0454 void SnippetsManager::SnippetsManagerPrivate::updateActionCollection(const QString &oldName,
0455                                                                      const QString &newName,
0456                                                                      const QKeySequence &keySequence,
0457                                                                      const QString &text,
0458                                                                      const QString &subject,
0459                                                                      const QString &to,
0460                                                                      const QString &cc,
0461                                                                      const QString &bcc,
0462                                                                      const QString &attachment)
0463 {
0464     // remove previous action in case that the name changed
0465     if (!oldName.isEmpty() && mActionCollection) {
0466         const QString actionName = i18nc("@action", "Snippet %1", oldName);
0467         const QString normalizedName = QString(actionName).replace(QLatin1Char(' '), QLatin1Char('_'));
0468 
0469         QAction *action = mActionCollection->action(normalizedName);
0470         if (action) {
0471             mActionCollection->removeAction(action);
0472         }
0473     }
0474 
0475     if (!newName.isEmpty()) {
0476         initializeAction(newName, keySequence, text, subject, to, cc, bcc, attachment);
0477     }
0478 }
0479 
0480 QString SnippetsManager::SnippetsManagerPrivate::replaceVariables(const QString &text)
0481 {
0482     QString result = text;
0483     QString variableName;
0484     QString variableValue;
0485     QMap<QString, QString> localVariables(SnippetsModel::instance()->savedVariables());
0486     int iFound = -1;
0487     int iEnd = -1;
0488     QMap<QString, QString> tempLocalVariables(localVariables);
0489     do {
0490         // find the next variable by this regex
0491         iFound = text.indexOf(QRegularExpression(QStringLiteral("\\$[A-Za-z\\-_0-9\\s]*\\$")), iEnd + 1);
0492         if (iFound >= 0) {
0493             iEnd = text.indexOf(QLatin1Char('$'), iFound + 1) + 1;
0494 
0495             variableName = text.mid(iFound, iEnd - iFound);
0496 
0497             if (variableName != QLatin1StringView("$$")) { // if not double-delimiter
0498                 if (!localVariables.contains(variableName)) { // and not already in map
0499                     QPointer<SnippetVariableDialog> dlg = new SnippetVariableDialog(variableName, &tempLocalVariables, mParent);
0500                     if (dlg->exec()) {
0501                         if (dlg->saveVariableIsChecked()) {
0502                             mDirty = true;
0503                         }
0504                         variableValue = dlg->variableValue();
0505                     } else {
0506                         delete dlg;
0507                         return {};
0508                     }
0509                     delete dlg;
0510                 } else {
0511                     variableValue = localVariables.value(variableName);
0512                 }
0513             } else {
0514                 variableValue = QLatin1Char('$'); // if double-delimiter -> replace by single character
0515             }
0516 
0517             result.replace(variableName, variableValue);
0518             localVariables[variableName] = variableValue;
0519         }
0520     } while (iFound != -1);
0521     SnippetsModel::instance()->setSavedVariables(tempLocalVariables);
0522 
0523     return result;
0524 }
0525 
0526 void SnippetsManager::SnippetsManagerPrivate::save()
0527 {
0528     if (!mDirty) {
0529         return;
0530     }
0531 
0532     SnippetsModel::instance()->save();
0533     mDirty = false;
0534 }
0535 
0536 SnippetsManager::SnippetsManager(KActionCollection *actionCollection, QObject *parent, QWidget *parentWidget)
0537     : QObject(parent)
0538     , d(new SnippetsManagerPrivate(this, parentWidget))
0539 {
0540     d->mModel = SnippetsModel::instance();
0541     connect(d->mModel,
0542             &SnippetsModel::updateActionCollection,
0543             this,
0544             [this](const QString &oldName,
0545                    const QString &newName,
0546                    const QKeySequence &keySequence,
0547                    const QString &text,
0548                    const QString &subject,
0549                    const QString &to,
0550                    const QString &cc,
0551                    const QString &bcc,
0552                    const QString &attachment) {
0553                 d->updateActionCollection(oldName, newName, keySequence, text, subject, to, cc, bcc, attachment);
0554             });
0555     d->mSelectionModel = new QItemSelectionModel(d->mModel);
0556     d->mActionCollection = actionCollection;
0557 
0558     d->mAddSnippetAction = new QAction(i18n("Add Snippet..."), this);
0559     d->mAddSnippetAction->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
0560     d->mEditSnippetAction = new QAction(i18n("Edit Snippet..."), this);
0561     d->mEditSnippetAction->setIcon(QIcon::fromTheme(QStringLiteral("document-properties")));
0562     d->mDeleteSnippetAction = new QAction(i18n("Remove Snippet"), this);
0563     d->mDeleteSnippetAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
0564 
0565     d->mAddSnippetGroupAction = new QAction(i18n("Add Group..."), this);
0566     d->mAddSnippetGroupAction->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
0567     d->mEditSnippetGroupAction = new QAction(i18n("Rename Group..."), this);
0568     d->mEditSnippetGroupAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-rename")));
0569     d->mDeleteSnippetGroupAction = new QAction(i18n("Remove Group"), this);
0570     d->mDeleteSnippetGroupAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
0571 
0572     d->mInsertSnippetAction = new QAction(i18n("Insert Snippet"), this);
0573     d->mInsertSnippetAction->setIcon(QIcon::fromTheme(QStringLiteral("insert-text")));
0574 
0575     connect(d->mSelectionModel, &QItemSelectionModel::selectionChanged, this, [this]() {
0576         d->selectionChanged();
0577     });
0578     connect(d->mModel, &SnippetsModel::dndDone, this, [this]() {
0579         d->dndDone();
0580     });
0581     connect(d->mModel, &SnippetsModel::addNewDndSnippset, this, [this](const QString &str) {
0582         d->slotAddNewDndSnippset(str);
0583     });
0584 
0585     connect(d->mAddSnippetAction, &QAction::triggered, this, [this]() {
0586         d->addSnippet();
0587     });
0588     connect(d->mEditSnippetAction, &QAction::triggered, this, [this]() {
0589         d->editSnippet();
0590     });
0591     connect(d->mDeleteSnippetAction, &QAction::triggered, this, [this]() {
0592         d->deleteSnippet();
0593     });
0594 
0595     connect(d->mAddSnippetGroupAction, &QAction::triggered, this, [this]() {
0596         d->addSnippetGroup();
0597     });
0598     connect(d->mEditSnippetGroupAction, &QAction::triggered, this, [this]() {
0599         d->editSnippetGroup();
0600     });
0601     connect(d->mDeleteSnippetGroupAction, &QAction::triggered, this, [this]() {
0602         d->deleteSnippetGroup();
0603     });
0604 
0605     connect(d->mInsertSnippetAction, &QAction::triggered, this, [this]() {
0606         d->insertSelectedSnippet();
0607     });
0608 
0609     d->initializeActionCollection();
0610     d->selectionChanged();
0611     connect(this, &SnippetsManager::insertSnippet, this, [this]() {
0612         d->insertSelectedSnippet();
0613     });
0614 }
0615 
0616 SnippetsManager::~SnippetsManager()
0617 {
0618     d->save();
0619 }
0620 
0621 QAbstractItemModel *SnippetsManager::model() const
0622 {
0623     return d->mModel;
0624 }
0625 
0626 QItemSelectionModel *SnippetsManager::selectionModel() const
0627 {
0628     return d->mSelectionModel;
0629 }
0630 
0631 QAction *SnippetsManager::addSnippetAction() const
0632 {
0633     return d->mAddSnippetAction;
0634 }
0635 
0636 QAction *SnippetsManager::editSnippetAction() const
0637 {
0638     return d->mEditSnippetAction;
0639 }
0640 
0641 QAction *SnippetsManager::deleteSnippetAction() const
0642 {
0643     return d->mDeleteSnippetAction;
0644 }
0645 
0646 QAction *SnippetsManager::addSnippetGroupAction() const
0647 {
0648     return d->mAddSnippetGroupAction;
0649 }
0650 
0651 QAction *SnippetsManager::editSnippetGroupAction() const
0652 {
0653     return d->mEditSnippetGroupAction;
0654 }
0655 
0656 QAction *SnippetsManager::deleteSnippetGroupAction() const
0657 {
0658     return d->mDeleteSnippetGroupAction;
0659 }
0660 
0661 QAction *SnippetsManager::insertSnippetAction() const
0662 {
0663     return d->mInsertSnippetAction;
0664 }
0665 
0666 bool SnippetsManager::snippetGroupSelected() const
0667 {
0668     if (d->mSelectionModel->selectedIndexes().isEmpty()) {
0669         return false;
0670     }
0671 
0672     return d->mSelectionModel->selectedIndexes().first().data(SnippetsModel::IsGroupRole).toBool();
0673 }
0674 
0675 QString SnippetsManager::selectedName() const
0676 {
0677     if (d->mSelectionModel->selectedIndexes().isEmpty()) {
0678         return {};
0679     }
0680 
0681     return d->mSelectionModel->selectedIndexes().first().data(SnippetsModel::NameRole).toString();
0682 }
0683 
0684 #include "moc_snippetsmanager.cpp"