Warning, file /pim/mailcommon/src/snippets/snippetsmodel.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.net>
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 "snippetsmodel.h"
0011 
0012 #include <KConfigGroup>
0013 #include <KLocalizedString>
0014 #include <KMessageBox>
0015 #include <KSharedConfig>
0016 #include <QDataStream>
0017 #include <QIODevice>
0018 #include <QMimeData>
0019 #include <QStringList>
0020 
0021 using namespace MailCommon;
0022 
0023 class MailCommon::SnippetItem
0024 {
0025 public:
0026     explicit SnippetItem(bool isGroup = false, SnippetItem *parent = nullptr);
0027     ~SnippetItem();
0028 
0029     [[nodiscard]] bool isGroup() const;
0030 
0031     void setName(const QString &name);
0032     [[nodiscard]] QString name() const;
0033 
0034     void setText(const QString &text);
0035     [[nodiscard]] QString text() const;
0036 
0037     void setKeyword(const QString &text);
0038     [[nodiscard]] QString keyword() const;
0039 
0040     void setKeySequence(const QString &sequence);
0041     [[nodiscard]] QString keySequence() const;
0042 
0043     void appendChild(SnippetItem *child);
0044     void removeChild(SnippetItem *child);
0045     [[nodiscard]] SnippetItem *child(int row) const;
0046     [[nodiscard]] int childCount() const;
0047     [[nodiscard]] int row() const;
0048     [[nodiscard]] SnippetItem *parent() const;
0049 
0050     [[nodiscard]] QString subject() const;
0051     void setSubject(const QString &subject);
0052 
0053     [[nodiscard]] QString to() const;
0054     void setTo(const QString &to);
0055 
0056     [[nodiscard]] QString cc() const;
0057     void setCc(const QString &cc);
0058 
0059     [[nodiscard]] QString bcc() const;
0060     void setBcc(const QString &bcc);
0061 
0062     [[nodiscard]] QString attachment() const;
0063     void setAttachment(const QString &attachment);
0064 
0065 private:
0066     QList<SnippetItem *> mChildItems;
0067     SnippetItem *mParentItem = nullptr;
0068 
0069     bool mIsGroup = false;
0070     QString mName;
0071     QString mText;
0072     QString mKeySequence;
0073     QString mKeyword;
0074     QString mSubject;
0075     QString mTo;
0076     QString mCc;
0077     QString mBcc;
0078     QString mAttachment;
0079 };
0080 
0081 SnippetItem::SnippetItem(bool isGroup, SnippetItem *parent)
0082     : mParentItem(parent)
0083     , mIsGroup(isGroup)
0084 {
0085 }
0086 
0087 SnippetItem::~SnippetItem()
0088 {
0089     qDeleteAll(mChildItems);
0090     mChildItems.clear();
0091 }
0092 
0093 bool SnippetItem::isGroup() const
0094 {
0095     return mIsGroup;
0096 }
0097 
0098 void SnippetItem::setName(const QString &name)
0099 {
0100     mName = name;
0101 }
0102 
0103 QString SnippetItem::name() const
0104 {
0105     return mName;
0106 }
0107 
0108 void SnippetItem::setText(const QString &text)
0109 {
0110     mText = text;
0111 }
0112 
0113 QString SnippetItem::text() const
0114 {
0115     return mText;
0116 }
0117 
0118 void SnippetItem::setKeyword(const QString &text)
0119 {
0120     mKeyword = text;
0121 }
0122 
0123 QString SnippetItem::keyword() const
0124 {
0125     return mKeyword;
0126 }
0127 
0128 void SnippetItem::setKeySequence(const QString &sequence)
0129 {
0130     mKeySequence = sequence;
0131 }
0132 
0133 QString SnippetItem::keySequence() const
0134 {
0135     return mKeySequence;
0136 }
0137 
0138 void SnippetItem::appendChild(SnippetItem *item)
0139 {
0140     mChildItems.append(item);
0141 }
0142 
0143 void SnippetItem::removeChild(SnippetItem *item)
0144 {
0145     mChildItems.removeAll(item);
0146     delete item;
0147 }
0148 
0149 SnippetItem *SnippetItem::child(int row) const
0150 {
0151     return mChildItems.value(row);
0152 }
0153 
0154 int SnippetItem::childCount() const
0155 {
0156     return mChildItems.count();
0157 }
0158 
0159 SnippetItem *SnippetItem::parent() const
0160 {
0161     return mParentItem;
0162 }
0163 
0164 QString SnippetItem::subject() const
0165 {
0166     return mSubject;
0167 }
0168 
0169 void SnippetItem::setSubject(const QString &subject)
0170 {
0171     mSubject = subject;
0172 }
0173 
0174 QString SnippetItem::to() const
0175 {
0176     return mTo;
0177 }
0178 
0179 void SnippetItem::setTo(const QString &to)
0180 {
0181     mTo = to;
0182 }
0183 
0184 QString SnippetItem::cc() const
0185 {
0186     return mCc;
0187 }
0188 
0189 void SnippetItem::setCc(const QString &cc)
0190 {
0191     mCc = cc;
0192 }
0193 
0194 QString SnippetItem::bcc() const
0195 {
0196     return mBcc;
0197 }
0198 
0199 void SnippetItem::setBcc(const QString &bcc)
0200 {
0201     mBcc = bcc;
0202 }
0203 
0204 QString SnippetItem::attachment() const
0205 {
0206     return mAttachment;
0207 }
0208 
0209 void SnippetItem::setAttachment(const QString &attachment)
0210 {
0211     mAttachment = attachment;
0212 }
0213 
0214 int SnippetItem::row() const
0215 {
0216     if (mParentItem) {
0217         return mParentItem->mChildItems.indexOf(const_cast<SnippetItem *>(this));
0218     }
0219 
0220     return 0;
0221 }
0222 
0223 SnippetsModel *SnippetsModel::instance()
0224 {
0225     static SnippetsModel s_self;
0226     return &s_self;
0227 }
0228 
0229 SnippetsModel::SnippetsModel(QObject *parent)
0230     : QAbstractItemModel(parent)
0231 {
0232     mRootItem = new SnippetItem(true);
0233     load();
0234 }
0235 
0236 SnippetsModel::~SnippetsModel()
0237 {
0238     delete mRootItem;
0239 }
0240 
0241 int SnippetsModel::columnCount(const QModelIndex &) const
0242 {
0243     return 1;
0244 }
0245 
0246 bool SnippetsModel::setData(const QModelIndex &index, const QVariant &value, int role)
0247 {
0248     if (!index.isValid()) {
0249         return false;
0250     }
0251 
0252     auto item = static_cast<SnippetItem *>(index.internalPointer());
0253     Q_ASSERT(item);
0254 
0255     switch (role) {
0256     case NameRole:
0257         item->setName(value.toString());
0258         Q_EMIT dataChanged(index, index);
0259         return true;
0260     case TextRole:
0261         item->setText(value.toString());
0262         Q_EMIT dataChanged(index, index);
0263         return true;
0264     case KeySequenceRole:
0265         item->setKeySequence(value.toString());
0266         Q_EMIT dataChanged(index, index);
0267         return true;
0268     case KeywordRole:
0269         item->setKeyword(value.toString());
0270         Q_EMIT dataChanged(index, index);
0271         return true;
0272     case SubjectRole:
0273         item->setSubject(value.toString());
0274         Q_EMIT dataChanged(index, index);
0275         return true;
0276     case ToRole:
0277         item->setTo(value.toString());
0278         Q_EMIT dataChanged(index, index);
0279         return true;
0280     case CcRole:
0281         item->setCc(value.toString());
0282         Q_EMIT dataChanged(index, index);
0283         return true;
0284     case BccRole:
0285         item->setBcc(value.toString());
0286         Q_EMIT dataChanged(index, index);
0287         return true;
0288     case AttachmentRole:
0289         item->setAttachment(value.toString());
0290         Q_EMIT dataChanged(index, index);
0291         return true;
0292     }
0293 
0294     return false;
0295 }
0296 
0297 QVariant SnippetsModel::data(const QModelIndex &index, int role) const
0298 {
0299     if (!index.isValid()) {
0300         return {};
0301     }
0302 
0303     auto item = static_cast<SnippetItem *>(index.internalPointer());
0304 
0305     switch (role) {
0306     case Qt::DisplayRole:
0307         return item->name();
0308     case IsGroupRole:
0309         return item->isGroup();
0310     case NameRole:
0311         return item->name();
0312     case TextRole:
0313         return item->text();
0314     case KeySequenceRole:
0315         return item->keySequence();
0316     case KeywordRole:
0317         return item->keyword();
0318     case SubjectRole:
0319         return item->subject();
0320     case ToRole:
0321         return item->to();
0322     case CcRole:
0323         return item->cc();
0324     case BccRole:
0325         return item->bcc();
0326     case AttachmentRole:
0327         return item->attachment();
0328     }
0329 
0330     return {};
0331 }
0332 
0333 Qt::ItemFlags SnippetsModel::flags(const QModelIndex &index) const
0334 {
0335     Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
0336 
0337     if (index.isValid()) {
0338         const SnippetItem *item = static_cast<SnippetItem *>(index.internalPointer());
0339         if (!item->isGroup()) {
0340             return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
0341         }
0342     }
0343 
0344     return Qt::ItemIsDropEnabled | defaultFlags;
0345 }
0346 
0347 QModelIndex SnippetsModel::index(int row, int column, const QModelIndex &parent) const
0348 {
0349     if (!hasIndex(row, column, parent)) {
0350         return {};
0351     }
0352 
0353     SnippetItem *parentItem = nullptr;
0354 
0355     if (!parent.isValid()) {
0356         parentItem = mRootItem;
0357     } else {
0358         parentItem = static_cast<SnippetItem *>(parent.internalPointer());
0359     }
0360 
0361     SnippetItem *childItem = parentItem->child(row);
0362     if (childItem) {
0363         return createIndex(row, column, childItem);
0364     } else {
0365         return {};
0366     }
0367 }
0368 
0369 QModelIndex SnippetsModel::parent(const QModelIndex &index) const
0370 {
0371     if (!index.isValid()) {
0372         return {};
0373     }
0374 
0375     auto childItem = static_cast<SnippetItem *>(index.internalPointer());
0376     SnippetItem *parentItem = childItem->parent();
0377 
0378     if (parentItem == mRootItem) {
0379         return {};
0380     }
0381 
0382     return createIndex(parentItem->row(), 0, parentItem);
0383 }
0384 
0385 int SnippetsModel::rowCount(const QModelIndex &parent) const
0386 {
0387     SnippetItem *parentItem = nullptr;
0388     if (parent.column() > 0) {
0389         return 0;
0390     }
0391 
0392     if (!parent.isValid()) {
0393         parentItem = mRootItem;
0394     } else {
0395         parentItem = static_cast<SnippetItem *>(parent.internalPointer());
0396     }
0397 
0398     return parentItem->childCount();
0399 }
0400 
0401 bool SnippetsModel::insertRows(int row, int count, const QModelIndex &parent)
0402 {
0403     SnippetItem *parentItem = nullptr;
0404 
0405     if (!parent.isValid()) {
0406         parentItem = mRootItem;
0407     } else {
0408         parentItem = static_cast<SnippetItem *>(parent.internalPointer());
0409     }
0410 
0411     beginInsertRows(parent, row, row + count - 1);
0412     for (int i = 0; i < count; ++i) {
0413         auto snippet = new SnippetItem(!parent.isValid(), parentItem);
0414         parentItem->appendChild(snippet);
0415     }
0416     endInsertRows();
0417 
0418     return true;
0419 }
0420 
0421 bool SnippetsModel::removeRows(int row, int count, const QModelIndex &parent)
0422 {
0423     SnippetItem *parentItem = nullptr;
0424 
0425     if (!parent.isValid()) {
0426         parentItem = mRootItem;
0427     } else {
0428         parentItem = static_cast<SnippetItem *>(parent.internalPointer());
0429     }
0430 
0431     beginRemoveRows(parent, row, row + count - 1);
0432     for (int i = 0; i < count; ++i) {
0433         parentItem->removeChild(parentItem->child(row));
0434     }
0435     endRemoveRows();
0436 
0437     return true;
0438 }
0439 
0440 QStringList SnippetsModel::mimeTypes() const
0441 {
0442     return QStringList() << QStringLiteral("text/x-kmail-textsnippet") << QStringLiteral("text/plain");
0443 }
0444 
0445 QMimeData *SnippetsModel::mimeData(const QModelIndexList &indexes) const
0446 {
0447     if (indexes.isEmpty()) {
0448         return nullptr;
0449     }
0450 
0451     const QModelIndex index = indexes.first();
0452 
0453     auto item = static_cast<SnippetItem *>(index.internalPointer());
0454     if (item->isGroup()) {
0455         return nullptr;
0456     }
0457 
0458     auto mimeData = new QMimeData();
0459 
0460     QByteArray encodedData;
0461     QDataStream stream(&encodedData, QIODevice::WriteOnly);
0462     stream << index.parent().internalId() << item->name() << item->text() << item->keySequence() << item->keyword() << item->subject() << item->to()
0463            << item->cc() << item->bcc() << item->attachment();
0464 
0465     mimeData->setData(QStringLiteral("text/x-kmail-textsnippet"), encodedData);
0466     mimeData->setText(item->text());
0467 
0468     return mimeData;
0469 }
0470 
0471 bool SnippetsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
0472 {
0473     Q_UNUSED(row)
0474 
0475     if (action == Qt::IgnoreAction) {
0476         return true;
0477     }
0478 
0479     if (data->hasFormat(QStringLiteral("text/x-kmail-textsnippet"))) {
0480         if (!parent.isValid()) {
0481             return false;
0482         }
0483 
0484         if (column > 1) {
0485             return false;
0486         }
0487 
0488         auto item = static_cast<SnippetItem *>(parent.internalPointer());
0489 
0490         QByteArray encodedData = data->data(QStringLiteral("text/x-kmail-textsnippet"));
0491         QDataStream stream(&encodedData, QIODevice::ReadOnly);
0492 
0493         quintptr id;
0494         QString name;
0495         QString text;
0496         QString keySequence;
0497         QString keyword;
0498         QString subject;
0499         QString to;
0500         QString cc;
0501         QString bcc;
0502         QString attachment;
0503         stream >> id >> name >> text >> keySequence >> keyword >> subject >> to >> cc >> bcc >> attachment;
0504         if (parent.internalId() == id) {
0505             return false;
0506         }
0507         if (item->isGroup()) {
0508             insertRow(rowCount(parent), parent);
0509 
0510             const QModelIndex idx = index(rowCount(parent) - 1, 0, parent);
0511 
0512             setData(idx, name, SnippetsModel::NameRole);
0513             setData(idx, text, SnippetsModel::TextRole);
0514             setData(idx, keySequence, SnippetsModel::KeySequenceRole);
0515             setData(idx, keyword, SnippetsModel::KeywordRole);
0516             setData(idx, subject, SnippetsModel::SubjectRole);
0517             setData(idx, to, SnippetsModel::ToRole);
0518             setData(idx, cc, SnippetsModel::CcRole);
0519             setData(idx, bcc, SnippetsModel::BccRole);
0520             setData(idx, attachment, SnippetsModel::AttachmentRole);
0521             Q_EMIT dndDone();
0522             return true;
0523         } else {
0524             if (KMessageBox::ButtonCode::PrimaryAction
0525                 == KMessageBox::questionTwoActions(nullptr,
0526                                                    i18n("Do you want to update snippet?"),
0527                                                    i18n("Update snippet"),
0528                                                    KGuiItem(i18n("Update")),
0529                                                    KStandardGuiItem::cancel())) {
0530                 item->setText(text);
0531                 item->setSubject(subject);
0532                 item->setTo(to);
0533                 item->setCc(cc);
0534                 item->setBcc(bcc);
0535                 return true;
0536             }
0537             return false;
0538         }
0539     } else if (data->hasFormat(QStringLiteral("text/plain"))) {
0540         if (column > 1) {
0541             return false;
0542         }
0543         const QString encodedData = QString::fromUtf8(data->data(QStringLiteral("text/plain")));
0544         if (!parent.isValid()) {
0545             Q_EMIT addNewDndSnippset(encodedData);
0546             return false;
0547         }
0548         auto item = static_cast<SnippetItem *>(parent.internalPointer());
0549 
0550         if (item->isGroup()) {
0551             Q_EMIT addNewDndSnippset(encodedData);
0552         } else {
0553             if (KMessageBox::ButtonCode::PrimaryAction
0554                 == KMessageBox::questionTwoActions(nullptr,
0555                                                    i18n("Do you want to update snippet?"),
0556                                                    i18n("Update snippet"),
0557                                                    KGuiItem(i18n("Update")),
0558                                                    KStandardGuiItem::cancel())) {
0559                 item->setText(encodedData);
0560             }
0561         }
0562         return false;
0563     }
0564     return false;
0565 }
0566 
0567 Qt::DropActions SnippetsModel::supportedDropActions() const
0568 {
0569     return Qt::CopyAction | Qt::MoveAction;
0570 }
0571 
0572 QModelIndex SnippetsModel::createGroup(const QString &groupName)
0573 {
0574     insertRow(rowCount(), QModelIndex());
0575     const QModelIndex groupIndex = index(rowCount() - 1, 0, QModelIndex());
0576     setData(groupIndex, groupName, SnippetsModel::NameRole);
0577     return groupIndex;
0578 }
0579 
0580 void SnippetsModel::load(const QString &filename)
0581 {
0582     const KSharedConfig::Ptr config = KSharedConfig::openConfig(filename.isEmpty() ? QStringLiteral("kmailsnippetrc") : filename, KConfig::NoGlobals);
0583 
0584     const KConfigGroup snippetPartGroup = config->group("SnippetPart");
0585 
0586     const int groupCount = snippetPartGroup.readEntry("snippetGroupCount", 0);
0587 
0588     for (int i = 0; i < groupCount; ++i) {
0589         const KConfigGroup group = config->group(QStringLiteral("SnippetGroup_%1").arg(i));
0590 
0591         const QString groupName = group.readEntry("Name");
0592 
0593         // create group
0594         const QModelIndex groupIndex = createGroup(groupName);
0595 
0596         const int snippetCount = group.readEntry("snippetCount", 0);
0597         for (int j = 0; j < snippetCount; ++j) {
0598             const QString snippetName = group.readEntry(QStringLiteral("snippetName_%1").arg(j), QString());
0599 
0600             const QString snippetText = group.readEntry(QStringLiteral("snippetText_%1").arg(j), QString());
0601 
0602             const QString snippetKeySequence = group.readEntry(QStringLiteral("snippetKeySequence_%1").arg(j), QString());
0603 
0604             const QString snippetKeyword = group.readEntry(QStringLiteral("snippetKeyword_%1").arg(j), QString());
0605 
0606             const QString snippetSubject = group.readEntry(QStringLiteral("snippetSubject_%1").arg(j), QString());
0607 
0608             const QString to = group.readEntry(QStringLiteral("snippetTo_%1").arg(j), QString());
0609 
0610             const QString cc = group.readEntry(QStringLiteral("snippetCc_%1").arg(j), QString());
0611 
0612             const QString bcc = group.readEntry(QStringLiteral("snippetBcc_%1").arg(j), QString());
0613 
0614             const QString attachment = group.readEntry(QStringLiteral("snippetAttachment_%1").arg(j), QString());
0615             createSnippet(groupIndex, snippetName, snippetText, snippetKeySequence, snippetKeyword, snippetSubject, to, cc, bcc, attachment);
0616         }
0617     }
0618 
0619     const KConfigGroup group = config->group("SavedVariablesPart");
0620     const int variablesCount = group.readEntry("variablesCount", 0);
0621 
0622     for (int i = 0; i < variablesCount; ++i) {
0623         const QString variableKey = group.readEntry(QStringLiteral("variableName_%1").arg(i), QString());
0624 
0625         const QString variableValue = group.readEntry(QStringLiteral("variableValue_%1").arg(i), QString());
0626 
0627         mSavedVariables.insert(variableKey, variableValue);
0628     }
0629 }
0630 
0631 void SnippetsModel::createSnippet(const QModelIndex &groupIndex,
0632                                   const QString &snippetName,
0633                                   const QString &snippetText,
0634                                   const QString &snippetKeySequence,
0635                                   const QString &snippetKeyword,
0636                                   const QString &snippetSubject,
0637                                   const QString &to,
0638                                   const QString &cc,
0639                                   const QString &bcc,
0640                                   const QString &attachment)
0641 {
0642     insertRow(rowCount(groupIndex), groupIndex);
0643     const QModelIndex modelIndex = index(rowCount(groupIndex) - 1, 0, groupIndex);
0644 
0645     setData(modelIndex, snippetName, SnippetsModel::NameRole);
0646     setData(modelIndex, snippetText, SnippetsModel::TextRole);
0647     setData(modelIndex, snippetKeySequence, SnippetsModel::KeySequenceRole);
0648     setData(modelIndex, snippetKeyword, SnippetsModel::KeywordRole);
0649     setData(modelIndex, snippetSubject, SnippetsModel::SubjectRole);
0650 
0651     setData(modelIndex, to, SnippetsModel::ToRole);
0652     setData(modelIndex, cc, SnippetsModel::CcRole);
0653     setData(modelIndex, bcc, SnippetsModel::BccRole);
0654     setData(modelIndex, attachment, SnippetsModel::AttachmentRole);
0655 
0656     Q_EMIT updateActionCollection(QString(), snippetName, QKeySequence::fromString(snippetKeySequence), snippetText, snippetSubject, to, cc, bcc, attachment);
0657 }
0658 
0659 void SnippetsModel::setSavedVariables(const QMap<QString, QString> &savedVariables)
0660 {
0661     mSavedVariables = savedVariables;
0662 }
0663 
0664 QList<SnippetsInfo> SnippetsModel::snippetsInfo() const
0665 {
0666     QList<SnippetsInfo> infos;
0667     const int groupCount = rowCount();
0668 
0669     for (int i = 0; i < groupCount; ++i) {
0670         const QModelIndex groupIndex = index(i, 0, QModelIndex());
0671         const int snippetCount = rowCount(groupIndex);
0672         for (int j = 0; j < snippetCount; ++j) {
0673             SnippetsInfo info;
0674             const QModelIndex modelIndex = index(j, 0, groupIndex);
0675 
0676             const QString snippetName = modelIndex.data(SnippetsModel::NameRole).toString();
0677             if (!snippetName.isEmpty()) {
0678                 const QString snippetText = modelIndex.data(SnippetsModel::TextRole).toString();
0679                 const QString snippetKeySequence = modelIndex.data(SnippetsModel::KeySequenceRole).toString();
0680                 const QString snippetKeyword = modelIndex.data(SnippetsModel::KeywordRole).toString();
0681                 const QString snippetSubject = modelIndex.data(SnippetsModel::SubjectRole).toString();
0682                 const QString snippetTo = modelIndex.data(SnippetsModel::ToRole).toString();
0683                 const QString snippetCc = modelIndex.data(SnippetsModel::CcRole).toString();
0684                 const QString snippetBcc = modelIndex.data(SnippetsModel::BccRole).toString();
0685                 const QString snippetAttachment = modelIndex.data(SnippetsModel::AttachmentRole).toString();
0686                 info.text = snippetText;
0687                 info.newName = snippetName;
0688                 info.keyword = snippetKeyword;
0689                 info.keySequence = QKeySequence::fromString(snippetKeySequence);
0690                 info.subject = snippetSubject;
0691                 info.to = snippetTo;
0692                 info.cc = snippetCc;
0693                 info.bcc = snippetBcc;
0694                 info.attachment = snippetAttachment;
0695                 infos.append(info);
0696             }
0697         }
0698     }
0699     return infos;
0700 }
0701 
0702 QMap<QString, QString> SnippetsModel::savedVariables() const
0703 {
0704     return mSavedVariables;
0705 }
0706 
0707 void SnippetsModel::save(const QString &filename)
0708 {
0709     KSharedConfig::Ptr config = KSharedConfig::openConfig(filename.isEmpty() ? QStringLiteral("kmailsnippetrc") : filename, KConfig::NoGlobals);
0710 
0711     // clear everything
0712     const QStringList lst = config->groupList();
0713     for (const QString &group : lst) {
0714         config->deleteGroup(group);
0715     }
0716 
0717     // write number of snippet groups
0718     KConfigGroup group = config->group("SnippetPart");
0719 
0720     const int groupCount = rowCount();
0721     group.writeEntry("snippetGroupCount", groupCount);
0722 
0723     for (int i = 0; i < groupCount; ++i) {
0724         const QModelIndex groupIndex = index(i, 0, QModelIndex());
0725         const QString groupName = groupIndex.data(SnippetsModel::NameRole).toString();
0726 
0727         KConfigGroup group = config->group(QStringLiteral("SnippetGroup_%1").arg(i));
0728         group.writeEntry("Name", groupName);
0729 
0730         const int snippetCount = rowCount(groupIndex);
0731 
0732         group.writeEntry("snippetCount", snippetCount);
0733         for (int j = 0; j < snippetCount; ++j) {
0734             const QModelIndex modelIndex = index(j, 0, groupIndex);
0735 
0736             const QString snippetName = modelIndex.data(SnippetsModel::NameRole).toString();
0737             if (!snippetName.isEmpty()) {
0738                 const QString snippetText = modelIndex.data(SnippetsModel::TextRole).toString();
0739                 const QString snippetKeySequence = modelIndex.data(SnippetsModel::KeySequenceRole).toString();
0740                 const QString snippetKeyword = modelIndex.data(SnippetsModel::KeywordRole).toString();
0741                 const QString snippetSubject = modelIndex.data(SnippetsModel::SubjectRole).toString();
0742                 const QString snippetTo = modelIndex.data(SnippetsModel::ToRole).toString();
0743                 const QString snippetCc = modelIndex.data(SnippetsModel::CcRole).toString();
0744                 const QString snippetBcc = modelIndex.data(SnippetsModel::BccRole).toString();
0745                 const QString snippetAttachment = modelIndex.data(SnippetsModel::AttachmentRole).toString();
0746 
0747                 group.writeEntry(QStringLiteral("snippetName_%1").arg(j), snippetName);
0748                 if (!snippetText.isEmpty()) {
0749                     group.writeEntry(QStringLiteral("snippetText_%1").arg(j), snippetText);
0750                 }
0751                 if (!snippetKeySequence.isEmpty()) {
0752                     group.writeEntry(QStringLiteral("snippetKeySequence_%1").arg(j), snippetKeySequence);
0753                 }
0754                 if (!snippetKeyword.isEmpty()) {
0755                     group.writeEntry(QStringLiteral("snippetKeyword_%1").arg(j), snippetKeyword);
0756                 }
0757                 if (!snippetSubject.isEmpty()) {
0758                     group.writeEntry(QStringLiteral("snippetSubject_%1").arg(j), snippetSubject);
0759                 }
0760                 if (!snippetTo.isEmpty()) {
0761                     group.writeEntry(QStringLiteral("snippetTo_%1").arg(j), snippetTo);
0762                 }
0763                 if (!snippetCc.isEmpty()) {
0764                     group.writeEntry(QStringLiteral("snippetCc_%1").arg(j), snippetCc);
0765                 }
0766                 if (!snippetBcc.isEmpty()) {
0767                     group.writeEntry(QStringLiteral("snippetBcc_%1").arg(j), snippetBcc);
0768                 }
0769                 if (!snippetAttachment.isEmpty()) {
0770                     group.writeEntry(QStringLiteral("snippetAttachment_%1").arg(j), snippetAttachment);
0771                 }
0772             }
0773         }
0774     }
0775 
0776     {
0777         KConfigGroup group = config->group("SavedVariablesPart");
0778 
0779         const int variablesCount = mSavedVariables.count();
0780         group.writeEntry("variablesCount", variablesCount);
0781 
0782         int counter = 0;
0783         QMap<QString, QString>::const_iterator it = mSavedVariables.cbegin();
0784         const QMap<QString, QString>::const_iterator itEnd = mSavedVariables.cend();
0785         for (; it != itEnd; ++it) {
0786             group.writeEntry(QStringLiteral("variableName_%1").arg(counter), it.key());
0787             group.writeEntry(QStringLiteral("variableValue_%1").arg(counter), it.value());
0788             counter++;
0789         }
0790     }
0791     config->sync();
0792 }
0793 
0794 #include "moc_snippetsmodel.cpp"