diff --git a/src/snippets/snippetsmanager.cpp b/src/snippets/snippetsmanager.cpp index 73eddd3..013fc13 100644 --- a/src/snippets/snippetsmanager.cpp +++ b/src/snippets/snippetsmanager.cpp @@ -1,605 +1,609 @@ /* Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company Author Tobias Koenig This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "snippetsmanager.h" #include "mailcommon_debug.h" #include "snippetdialog.h" #include "snippetsmodel.h" #include "snippetvariabledialog.h" #include #include #include #include #include #include #include #include #include using namespace MailCommon; class Q_DECL_HIDDEN SnippetsManager::Private { public: Private(SnippetsManager *qq, QWidget *parent) : q(qq) , mParent(parent) { } QModelIndex currentGroupIndex() const; void selectionChanged(); void dndDone(); void addSnippet(); void editSnippet(); void deleteSnippet(); void addSnippetGroup(); void editSnippetGroup(); void deleteSnippetGroup(); void insertSelectedSnippet(); void insertActionSnippet(); void createSnippet(const QString &text = QString()); void slotAddNewDndSnippset(const QString &); void updateActionCollection(const QString &oldName, const QString &newName, const QKeySequence &keySequence, const QString &text); QString replaceVariables(const QString &text); void save(); SnippetsManager *q = nullptr; SnippetsModel *mModel = nullptr; QItemSelectionModel *mSelectionModel = nullptr; KActionCollection *mActionCollection = nullptr; QObject *mEditor = nullptr; QByteArray mEditorInsertMethod; QAction *mAddSnippetAction = nullptr; QAction *mEditSnippetAction = nullptr; QAction *mDeleteSnippetAction = nullptr; QAction *mAddSnippetGroupAction = nullptr; QAction *mEditSnippetGroupAction = nullptr; QAction *mDeleteSnippetGroupAction = nullptr; QAction *mInsertSnippetAction = nullptr; QWidget *mParent = nullptr; bool mDirty = false; }; QModelIndex SnippetsManager::Private::currentGroupIndex() const { if (mSelectionModel->selectedIndexes().isEmpty()) { return QModelIndex(); } const QModelIndex index = mSelectionModel->selectedIndexes().first(); if (index.data(SnippetsModel::IsGroupRole).toBool()) { return index; } else { return mModel->parent(index); } } void SnippetsManager::Private::selectionChanged() { const bool itemSelected = !mSelectionModel->selectedIndexes().isEmpty(); if (itemSelected) { const QModelIndex index = mSelectionModel->selectedIndexes().first(); const bool isGroup = index.data(SnippetsModel::IsGroupRole).toBool(); if (isGroup) { mEditSnippetAction->setEnabled(false); mDeleteSnippetAction->setEnabled(false); mEditSnippetGroupAction->setEnabled(true); mDeleteSnippetGroupAction->setEnabled(true); mInsertSnippetAction->setEnabled(false); } else { mEditSnippetAction->setEnabled(true); mDeleteSnippetAction->setEnabled(true); mEditSnippetGroupAction->setEnabled(false); mDeleteSnippetGroupAction->setEnabled(false); mInsertSnippetAction->setEnabled(true); } } else { mEditSnippetAction->setEnabled(false); mDeleteSnippetAction->setEnabled(false); mEditSnippetGroupAction->setEnabled(false); mDeleteSnippetGroupAction->setEnabled(false); mInsertSnippetAction->setEnabled(false); } } void SnippetsManager::Private::addSnippet() { createSnippet(); } void SnippetsManager::Private::createSnippet(const QString &text) { const bool noGroupAvailable = (mModel->rowCount() == 0); if (noGroupAvailable) { // create a 'General' snippet group if (!mModel->insertRow(mModel->rowCount(), QModelIndex())) { return; } const QModelIndex groupIndex = mModel->index(mModel->rowCount() - 1, 0, QModelIndex()); mModel->setData(groupIndex, i18n("General"), SnippetsModel::NameRole); mSelectionModel->select(groupIndex, QItemSelectionModel::ClearAndSelect); } QPointer dlg = new SnippetDialog(mActionCollection, false, mParent); dlg->setWindowTitle(i18nc("@title:window", "Add Snippet")); dlg->setGroupModel(mModel); dlg->setGroupIndex(currentGroupIndex()); dlg->setText(text); if (dlg->exec()) { const QModelIndex groupIndex = dlg->groupIndex(); if (!mModel->insertRow(mModel->rowCount(groupIndex), groupIndex)) { delete dlg; return; } const QModelIndex index = mModel->index(mModel->rowCount(groupIndex) - 1, 0, groupIndex); mModel->setData(index, dlg->name(), SnippetsModel::NameRole); mModel->setData(index, dlg->text(), SnippetsModel::TextRole); mModel->setData(index, dlg->keySequence().toString(), SnippetsModel::KeySequenceRole); - updateActionCollection(QString(), dlg->name(), dlg->keySequence(), dlg->text()); + Q_EMIT mModel->updateActionCollection(QString(), dlg->name(), dlg->keySequence(), dlg->text()); mDirty = true; save(); } delete dlg; } void SnippetsManager::Private::slotAddNewDndSnippset(const QString &text) { createSnippet(text); } void SnippetsManager::Private::dndDone() { mDirty = true; } void SnippetsManager::Private::editSnippet() { QModelIndex index = mSelectionModel->selectedIndexes().first(); if (!index.isValid() || index.data(SnippetsModel::IsGroupRole).toBool()) { return; } const QModelIndex oldGroupIndex = currentGroupIndex(); const QString oldSnippetName = index.data(SnippetsModel::NameRole).toString(); QPointer dlg = new SnippetDialog(mActionCollection, false, mParent); dlg->setWindowTitle(i18nc("@title:window", "Edit Snippet")); dlg->setGroupModel(mModel); dlg->setGroupIndex(oldGroupIndex); dlg->setName(oldSnippetName); dlg->setText(index.data(SnippetsModel::TextRole).toString()); dlg->setKeySequence( QKeySequence::fromString( index.data(SnippetsModel::KeySequenceRole).toString())); if (dlg->exec()) { const QModelIndex newGroupIndex = dlg->groupIndex(); if (oldGroupIndex != newGroupIndex) { mModel->removeRow(index.row(), oldGroupIndex); mModel->insertRow(mModel->rowCount(newGroupIndex), newGroupIndex); index = mModel->index(mModel->rowCount(newGroupIndex) - 1, 0, newGroupIndex); } mModel->setData(index, dlg->name(), SnippetsModel::NameRole); mModel->setData(index, dlg->text(), SnippetsModel::TextRole); mModel->setData(index, dlg->keySequence().toString(), SnippetsModel::KeySequenceRole); - updateActionCollection(oldSnippetName, dlg->name(), dlg->keySequence(), dlg->text()); + Q_EMIT mModel->updateActionCollection(oldSnippetName, dlg->name(), dlg->keySequence(), dlg->text()); mDirty = true; save(); } delete dlg; } void SnippetsManager::Private::deleteSnippet() { const QModelIndex index = mSelectionModel->selectedIndexes().first(); const QString snippetName = index.data(SnippetsModel::NameRole).toString(); if (KMessageBox::warningContinueCancel( nullptr, xi18nc("@info", "Do you really want to remove snippet \"%1\"?" "There is no way to undo the removal.", snippetName), QString(), KStandardGuiItem::remove()) == KMessageBox::Cancel) { return; } mModel->removeRow(index.row(), currentGroupIndex()); - updateActionCollection(snippetName, QString(), QKeySequence(), QString()); + Q_EMIT mModel->updateActionCollection(snippetName, QString(), QKeySequence(), QString()); mDirty = true; save(); } void SnippetsManager::Private::addSnippetGroup() { QPointer dlg = new SnippetDialog(mActionCollection, true, mParent); dlg->setWindowTitle(i18nc("@title:window", "Add Group")); if (dlg->exec()) { if (!mModel->insertRow(mModel->rowCount(), QModelIndex())) { qCDebug(MAILCOMMON_LOG) << "unable to insert row"; delete dlg; return; } const QModelIndex groupIndex = mModel->index(mModel->rowCount() - 1, 0, QModelIndex()); mModel->setData(groupIndex, dlg->name(), SnippetsModel::NameRole); mDirty = true; save(); } delete dlg; } void SnippetsManager::Private::editSnippetGroup() { const QModelIndex groupIndex = currentGroupIndex(); if (!groupIndex.isValid() || !groupIndex.data(SnippetsModel::IsGroupRole).toBool()) { return; } QPointer dlg = new SnippetDialog(mActionCollection, true, mParent); dlg->setWindowTitle(i18nc("@title:window", "Edit Group")); const QString oldGroupName = groupIndex.data(SnippetsModel::NameRole).toString(); dlg->setName(oldGroupName); if (dlg->exec()) { if (oldGroupName == dlg->name()) { delete dlg; return; } mModel->setData(groupIndex, dlg->name(), SnippetsModel::NameRole); mDirty = true; save(); } delete dlg; } void SnippetsManager::Private::deleteSnippetGroup() { const QModelIndex groupIndex = currentGroupIndex(); if (!groupIndex.isValid()) { return; } const QString groupName = groupIndex.data(SnippetsModel::NameRole).toString(); if (mModel->rowCount(groupIndex) > 0) { if (KMessageBox::warningContinueCancel( nullptr, xi18nc("@info", "Do you really want to remove group \"%1\" along with all its snippets?" "There is no way to undo the removal.", groupName), QString(), KStandardGuiItem::remove()) == KMessageBox::Cancel) { return; } } else { if (KMessageBox::warningContinueCancel( nullptr, i18nc("@info", "Do you really want to remove group \"%1\"?", groupName), QString(), KStandardGuiItem::remove()) == KMessageBox::Cancel) { return; } } mModel->removeRow(groupIndex.row(), QModelIndex()); mDirty = true; save(); } void SnippetsManager::Private::insertSelectedSnippet() { if (!mEditor) { return; } if (!mSelectionModel->hasSelection()) { return; } const QModelIndex index = mSelectionModel->selectedIndexes().first(); if (index.data(SnippetsModel::IsGroupRole).toBool()) { return; } const QString text = replaceVariables(index.data(SnippetsModel::TextRole).toString()); QMetaObject::invokeMethod(mEditor, mEditorInsertMethod.constData(), Qt::DirectConnection, Q_ARG(QString, text)); } void SnippetsManager::Private::insertActionSnippet() { if (!mEditor) { return; } QAction *action = qobject_cast(q->sender()); if (!action) { return; } const QString text = replaceVariables(action->property("snippetText").toString()); QMetaObject::invokeMethod(mEditor, mEditorInsertMethod.constData(), Qt::DirectConnection, Q_ARG(QString, text)); } void SnippetsManager::Private::updateActionCollection(const QString &oldName, const QString &newName, const QKeySequence &keySequence, const QString &text) { // remove previous action in case that the name changed if (!oldName.isEmpty()) { const QString actionName = i18nc("@action", "Snippet %1", oldName); const QString normalizedName = QString(actionName).replace(QLatin1Char(' '), QLatin1Char('_')); QAction *action = mActionCollection->action(normalizedName); if (action) { mActionCollection->removeAction(action); } } if (!newName.isEmpty()) { const QString actionName = i18nc("@action", "Snippet %1", newName); const QString normalizedName = QString(actionName).replace(QLatin1Char(' '), QLatin1Char('_')); QAction *action = mActionCollection->addAction(normalizedName, q); connect(action, &QAction::triggered, q, [this]() { insertActionSnippet(); }); action->setProperty("snippetText", text); action->setText(actionName); mActionCollection->setDefaultShortcut(action, keySequence); } } QString SnippetsManager::Private::replaceVariables(const QString &text) { QString result = text; QString variableName; QString variableValue; QMap localVariables(SnippetsModel::instance()->savedVariables()); int iFound = -1; int iEnd = -1; QMap tempLocalVariables(localVariables); do { //find the next variable by this QRegExp iFound = text.indexOf(QRegExp(QLatin1String("\\$[A-Za-z-_0-9\\s]*\\$")), iEnd + 1); if (iFound >= 0) { iEnd = text.indexOf(QLatin1Char('$'), iFound + 1) + 1; variableName = text.mid(iFound, iEnd - iFound); if (variableName != QLatin1String("$$")) { // if not double-delimiter if (!localVariables.contains(variableName)) { // and not already in map QPointer dlg = new SnippetVariableDialog(variableName, &tempLocalVariables, mParent); if (dlg->exec()) { if (dlg->saveVariableIsChecked()) { mDirty = true; } variableValue = dlg->variableValue(); } else { delete dlg; return QString(); } delete dlg; } else { variableValue = localVariables.value(variableName); } } else { variableValue = QLatin1Char('$'); //if double-delimiter -> replace by single character } result.replace(variableName, variableValue); localVariables[ variableName ] = variableValue; } } while (iFound != -1); SnippetsModel::instance()->setSavedVariables(tempLocalVariables); return result; } void SnippetsManager::Private::save() { if (!mDirty) { return; } SnippetsModel::instance()->save(); mDirty = false; } SnippetsManager::SnippetsManager(KActionCollection *actionCollection, QObject *parent, QWidget *widget) : QObject(parent) , d(new Private(this, widget)) { d->mModel = SnippetsModel::instance(); + connect(d->mModel, &SnippetsModel::updateActionCollection, this, [this] (const QString &oldName, const QString &newName, const QKeySequence &keySequence, const QString &text) { + d->updateActionCollection(oldName, newName, keySequence, text); + }); d->mSelectionModel = new QItemSelectionModel(d->mModel); d->mActionCollection = actionCollection; d->mAddSnippetAction = new QAction(i18n("Add Snippet..."), this); d->mAddSnippetAction->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); d->mEditSnippetAction = new QAction(i18n("Edit Snippet..."), this); d->mEditSnippetAction->setIcon(QIcon::fromTheme(QStringLiteral("document-properties"))); d->mDeleteSnippetAction = new QAction(i18n("Remove Snippet"), this); d->mDeleteSnippetAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); d->mAddSnippetGroupAction = new QAction(i18n("Add Group..."), this); d->mAddSnippetGroupAction->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); d->mEditSnippetGroupAction = new QAction(i18n("Rename Group..."), this); d->mEditSnippetGroupAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-rename"))); d->mDeleteSnippetGroupAction = new QAction(i18n("Remove Group"), this); d->mDeleteSnippetGroupAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); d->mInsertSnippetAction = new QAction(i18n("Insert Snippet"), this); connect(d->mSelectionModel, &QItemSelectionModel::selectionChanged, this, [this]() { d->selectionChanged(); }); connect(d->mModel, &SnippetsModel::dndDone, this, [this]() { d->dndDone(); }); connect(d->mModel, &SnippetsModel::addNewDndSnippset, this, [this](const QString &str) { d->slotAddNewDndSnippset(str); }); connect(d->mAddSnippetAction, &QAction::triggered, this, [this]() { d->addSnippet(); }); connect(d->mEditSnippetAction, &QAction::triggered, this, [this]() { d->editSnippet(); }); connect(d->mDeleteSnippetAction, &QAction::triggered, this, [this]() { d->deleteSnippet(); }); connect(d->mAddSnippetGroupAction, &QAction::triggered, this, [this]() { d->addSnippetGroup(); }); connect(d->mEditSnippetGroupAction, &QAction::triggered, this, [this]() { d->editSnippetGroup(); }); connect(d->mDeleteSnippetGroupAction, &QAction::triggered, this, [this]() { d->deleteSnippetGroup(); }); connect(d->mInsertSnippetAction, &QAction::triggered, this, [this]() { d->insertSelectedSnippet(); }); d->selectionChanged(); + //TODO initialize QKeySequence } SnippetsManager::~SnippetsManager() { d->save(); delete d; } void SnippetsManager::setEditor(QObject *editor, const char *insertSnippetMethod, const char *dropSignal) { d->mEditor = editor; d->mEditorInsertMethod = insertSnippetMethod; if (dropSignal) { const int index = editor->metaObject()->indexOfSignal( QMetaObject::normalizedSignature(dropSignal + 1).data()); // skip the leading '2' if (index != -1) { connect(editor, dropSignal, this, SLOT(insertSelectedSnippet())); } } } QAbstractItemModel *SnippetsManager::model() const { return d->mModel; } QItemSelectionModel *SnippetsManager::selectionModel() const { return d->mSelectionModel; } QAction *SnippetsManager::addSnippetAction() const { return d->mAddSnippetAction; } QAction *SnippetsManager::editSnippetAction() const { return d->mEditSnippetAction; } QAction *SnippetsManager::deleteSnippetAction() const { return d->mDeleteSnippetAction; } QAction *SnippetsManager::addSnippetGroupAction() const { return d->mAddSnippetGroupAction; } QAction *SnippetsManager::editSnippetGroupAction() const { return d->mEditSnippetGroupAction; } QAction *SnippetsManager::deleteSnippetGroupAction() const { return d->mDeleteSnippetGroupAction; } QAction *SnippetsManager::insertSnippetAction() const { return d->mInsertSnippetAction; } bool SnippetsManager::snippetGroupSelected() const { if (d->mSelectionModel->selectedIndexes().isEmpty()) { return false; } return d->mSelectionModel->selectedIndexes().first().data(SnippetsModel::IsGroupRole).toBool(); } QString SnippetsManager::selectedName() const { if (d->mSelectionModel->selectedIndexes().isEmpty()) { return QString(); } return d->mSelectionModel->selectedIndexes().first().data(SnippetsModel::NameRole).toString(); } #include "moc_snippetsmanager.cpp" diff --git a/src/snippets/snippetsmodel.cpp b/src/snippets/snippetsmodel.cpp index c793d98..a9babb3 100644 --- a/src/snippets/snippetsmodel.cpp +++ b/src/snippets/snippetsmodel.cpp @@ -1,585 +1,584 @@ /* Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net, Author: Tobias Koenig This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "snippetsmodel.h" #include #include #include #include #include #include #include using namespace MailCommon; class MailCommon::SnippetItem { public: SnippetItem(bool isGroup = false, SnippetItem *parent = nullptr); ~SnippetItem(); bool isGroup() const; void setName(const QString &name); QString name() const; void setText(const QString &text); QString text() const; void setKeySequence(const QString &sequence); QString keySequence() const; void appendChild(SnippetItem *child); void removeChild(SnippetItem *child); SnippetItem *child(int row) const; int childCount() const; int row() const; SnippetItem *parent() const; private: QList mChildItems; SnippetItem *mParentItem = nullptr; bool mIsGroup = false; QString mName; QString mText; QString mKeySequence; }; SnippetItem::SnippetItem(bool isGroup, SnippetItem *parent) : mParentItem(parent) , mIsGroup(isGroup) { } SnippetItem::~SnippetItem() { qDeleteAll(mChildItems); mChildItems.clear(); } bool SnippetItem::isGroup() const { return mIsGroup; } void SnippetItem::setName(const QString &name) { mName = name; } QString SnippetItem::name() const { return mName; } void SnippetItem::setText(const QString &text) { mText = text; } QString SnippetItem::text() const { return mText; } void SnippetItem::setKeySequence(const QString &sequence) { mKeySequence = sequence; } QString SnippetItem::keySequence() const { return mKeySequence; } void SnippetItem::appendChild(SnippetItem *item) { mChildItems.append(item); } void SnippetItem::removeChild(SnippetItem *item) { mChildItems.removeAll(item); delete item; } SnippetItem *SnippetItem::child(int row) const { return mChildItems.value(row); } int SnippetItem::childCount() const { return mChildItems.count(); } SnippetItem *SnippetItem::parent() const { return mParentItem; } int SnippetItem::row() const { if (mParentItem) { return mParentItem->mChildItems.indexOf(const_cast(this)); } return 0; } SnippetsModel *SnippetsModel::instance() { static SnippetsModel s_self; return &s_self; } SnippetsModel::SnippetsModel(QObject *parent) : QAbstractItemModel(parent) { mRootItem = new SnippetItem(true); load(); } SnippetsModel::~SnippetsModel() { delete mRootItem; } int SnippetsModel::columnCount(const QModelIndex &) const { return 1; } bool SnippetsModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid()) { return false; } SnippetItem *item = static_cast(index.internalPointer()); Q_ASSERT(item); switch (role) { case NameRole: item->setName(value.toString()); Q_EMIT dataChanged(index, index); return true; case TextRole: item->setText(value.toString()); Q_EMIT dataChanged(index, index); return true; case KeySequenceRole: item->setKeySequence(value.toString()); Q_EMIT dataChanged(index, index); return true; default: return false; } return false; } QVariant SnippetsModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } SnippetItem *item = static_cast(index.internalPointer()); switch (role) { case Qt::DisplayRole: return item->name(); case IsGroupRole: return item->isGroup(); case NameRole: return item->name(); case TextRole: return item->text(); case KeySequenceRole: return item->keySequence(); } return QVariant(); } Qt::ItemFlags SnippetsModel::flags(const QModelIndex &index) const { Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index); if (index.isValid()) { const SnippetItem *item = static_cast(index.internalPointer()); if (!item->isGroup()) { return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; } } return Qt::ItemIsDropEnabled | defaultFlags; } QModelIndex SnippetsModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) { return QModelIndex(); } SnippetItem *parentItem = nullptr; if (!parent.isValid()) { parentItem = mRootItem; } else { parentItem = static_cast(parent.internalPointer()); } SnippetItem *childItem = parentItem->child(row); if (childItem) { return createIndex(row, column, childItem); } else { return QModelIndex(); } } QModelIndex SnippetsModel::parent(const QModelIndex &index) const { if (!index.isValid()) { return QModelIndex(); } SnippetItem *childItem = static_cast(index.internalPointer()); SnippetItem *parentItem = childItem->parent(); if (parentItem == mRootItem) { return QModelIndex(); } return createIndex(parentItem->row(), 0, parentItem); } int SnippetsModel::rowCount(const QModelIndex &parent) const { SnippetItem *parentItem = nullptr; if (parent.column() > 0) { return 0; } if (!parent.isValid()) { parentItem = mRootItem; } else { parentItem = static_cast(parent.internalPointer()); } return parentItem->childCount(); } bool SnippetsModel::insertRows(int row, int count, const QModelIndex &parent) { SnippetItem *parentItem = nullptr; if (!parent.isValid()) { parentItem = mRootItem; } else { parentItem = static_cast(parent.internalPointer()); } beginInsertRows(parent, row, row + count - 1); for (int i = 0; i < count; ++i) { SnippetItem *snippet = new SnippetItem(!parent.isValid(), parentItem); parentItem->appendChild(snippet); } endInsertRows(); return true; } bool SnippetsModel::removeRows(int row, int count, const QModelIndex &parent) { SnippetItem *parentItem = nullptr; if (!parent.isValid()) { parentItem = mRootItem; } else { parentItem = static_cast(parent.internalPointer()); } beginRemoveRows(parent, row, row + count - 1); for (int i = 0; i < count; ++i) { parentItem->removeChild(parentItem->child(row)); } endRemoveRows(); return true; } QStringList SnippetsModel::mimeTypes() const { return QStringList() << QStringLiteral("text/x-kmail-textsnippet") << QStringLiteral("text/plain"); } QMimeData *SnippetsModel::mimeData(const QModelIndexList &indexes) const { if (indexes.isEmpty()) { return nullptr; } const QModelIndex index = indexes.first(); SnippetItem *item = static_cast(index.internalPointer()); if (item->isGroup()) { return nullptr; } QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); stream << index.parent().internalId() << item->name() << item->text() << item->keySequence(); mimeData->setData(QStringLiteral("text/x-kmail-textsnippet"), encodedData); mimeData->setText(item->text()); return mimeData; } bool SnippetsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { Q_UNUSED(row); if (action == Qt::IgnoreAction) { return true; } if (data->hasFormat(QStringLiteral("text/plain"))) { if (column > 1) { return false; } const QString encodedData = QString::fromUtf8(data->data(QStringLiteral("text/plain"))); if (!parent.isValid()) { Q_EMIT addNewDndSnippset(encodedData); return false; } SnippetItem *item = static_cast(parent.internalPointer()); if (item->isGroup()) { Q_EMIT addNewDndSnippset(encodedData); } else { if (KMessageBox::Yes == KMessageBox::questionYesNo(nullptr, i18n("Do you want to update snippet?"), i18n("Update snippet"))) { item->setText(encodedData); } } return false; } else { if (!parent.isValid()) { return false; } if (!data->hasFormat(QStringLiteral("text/x-kmail-textsnippet"))) { return false; } if (column > 1) { return false; } SnippetItem *item = static_cast(parent.internalPointer()); if (!item->isGroup()) { return false; } QByteArray encodedData = data->data(QStringLiteral("text/x-kmail-textsnippet")); QDataStream stream(&encodedData, QIODevice::ReadOnly); quintptr id; QString name; QString text; QString keySequence; stream >> id >> name >> text >> keySequence; if (parent.internalId() == id) { return false; } insertRow(rowCount(parent), parent); const QModelIndex idx = index(rowCount(parent) - 1, 0, parent); setData(idx, name, SnippetsModel::NameRole); setData(idx, text, SnippetsModel::TextRole); setData(idx, keySequence, SnippetsModel::KeySequenceRole); Q_EMIT dndDone(); return true; } } Qt::DropActions SnippetsModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } QModelIndex SnippetsModel::createGroup(const QString &groupName) { insertRow(rowCount(), QModelIndex()); const QModelIndex groupIndex = index(rowCount() - 1, 0, QModelIndex()); setData(groupIndex, groupName, SnippetsModel::NameRole); return groupIndex; } void SnippetsModel::load() { const KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kmailsnippetrc"), KConfig::NoGlobals); const KConfigGroup snippetPartGroup = config->group("SnippetPart"); const int groupCount = snippetPartGroup.readEntry("snippetGroupCount", 0); for (int i = 0; i < groupCount; ++i) { const KConfigGroup group = config->group(QStringLiteral("SnippetGroup_%1").arg(i)); const QString groupName = group.readEntry("Name"); // create group QModelIndex groupIndex = createGroup(groupName); const int snippetCount = group.readEntry("snippetCount", 0); for (int j = 0; j < snippetCount; ++j) { const QString snippetName = group.readEntry(QStringLiteral("snippetName_%1").arg(j), QString()); const QString snippetText = group.readEntry(QStringLiteral("snippetText_%1").arg(j), QString()); const QString snippetKeySequence = group.readEntry(QStringLiteral("snippetKeySequence_%1").arg(j), QString()); createSnippet(groupIndex, snippetName, snippetText, snippetKeySequence); } } mSavedVariables.clear(); const KConfigGroup group = config->group("SavedVariablesPart"); const int variablesCount = group.readEntry("variablesCount", 0); for (int i = 0; i < variablesCount; ++i) { const QString variableKey = group.readEntry(QStringLiteral("variableName_%1").arg(i), QString()); const QString variableValue = group.readEntry(QStringLiteral("variableValue_%1").arg(i), QString()); mSavedVariables.insert(variableKey, variableValue); } } void SnippetsModel::createSnippet(const QModelIndex &groupIndex, const QString &snippetName, const QString &snippetText, const QString &snippetKeySequence) { insertRow(rowCount(groupIndex), groupIndex); const QModelIndex modelIndex = index(rowCount(groupIndex) - 1, 0, groupIndex); setData(modelIndex, snippetName, SnippetsModel::NameRole); setData(modelIndex, snippetText, SnippetsModel::TextRole); setData(modelIndex, snippetKeySequence, SnippetsModel::KeySequenceRole); - //TODO -// updateActionCollection(QString(), -// snippetName, -// QKeySequence::fromString(snippetKeySequence), -// snippetText); + Q_EMIT updateActionCollection(QString(), + snippetName, + QKeySequence::fromString(snippetKeySequence), + snippetText); } void SnippetsModel::setSavedVariables(const QMap &savedVariables) { mSavedVariables = savedVariables; } QMap SnippetsModel::savedVariables() const { return mSavedVariables; } void SnippetsModel::save() { KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kmailsnippetrc"), KConfig::NoGlobals); // clear everything for (const QString &group : config->groupList()) { config->deleteGroup(group); } // write number of snippet groups KConfigGroup group = config->group("SnippetPart"); const int groupCount = rowCount(); group.writeEntry("snippetGroupCount", groupCount); for (int i = 0; i < groupCount; ++i) { const QModelIndex groupIndex = index(i, 0, QModelIndex()); const QString groupName = groupIndex.data(SnippetsModel::NameRole).toString(); KConfigGroup group = config->group(QStringLiteral("SnippetGroup_%1").arg(i)); group.writeEntry("Name", groupName); const int snippetCount = rowCount(groupIndex); group.writeEntry("snippetCount", snippetCount); for (int j = 0; j < snippetCount; ++j) { const QModelIndex modelIndex = index(j, 0, groupIndex); const QString snippetName = modelIndex.data(SnippetsModel::NameRole).toString(); if (!snippetName.isEmpty()) { const QString snippetText = modelIndex.data(SnippetsModel::TextRole).toString(); const QString snippetKeySequence = modelIndex.data(SnippetsModel::KeySequenceRole).toString(); group.writeEntry(QStringLiteral("snippetName_%1").arg(j), snippetName); if (!snippetText.isEmpty()) { group.writeEntry(QStringLiteral("snippetText_%1").arg(j), snippetText); } if (!snippetKeySequence.isEmpty()) { group.writeEntry(QStringLiteral("snippetKeySequence_%1").arg(j), snippetKeySequence); } } } } { KConfigGroup group = config->group("SavedVariablesPart"); const int variablesCount = mSavedVariables.count(); group.writeEntry("variablesCount", variablesCount); int counter = 0; QMap::const_iterator it = mSavedVariables.cbegin(); const QMap::const_iterator itEnd = mSavedVariables.cend(); for (; it != itEnd; ++it) { group.writeEntry(QStringLiteral("variableName_%1").arg(counter), it.key()); group.writeEntry(QStringLiteral("variableValue_%1").arg(counter), it.value()); counter++; } } config->sync(); } diff --git a/src/snippets/snippetsmodel.h b/src/snippets/snippetsmodel.h index fa6f970..4d00357 100644 --- a/src/snippets/snippetsmodel.h +++ b/src/snippets/snippetsmodel.h @@ -1,89 +1,91 @@ /* Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net, Author: Tobias Koenig This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MAILCOMMON_SNIPPETSMODEL_P_H #define MAILCOMMON_SNIPPETSMODEL_P_H #include namespace MailCommon { class SnippetItem; class SnippetsModel : public QAbstractItemModel { Q_OBJECT public: enum Role { IsGroupRole = Qt::UserRole + 1, ///< Returns whether the index represents a group NameRole, ///< The name of a snippet or group TextRole, ///< The text of a snippet KeySequenceRole ///< The key sequence to activate a snippet }; static SnippetsModel *instance(); explicit SnippetsModel(QObject *parent = nullptr); ~SnippetsModel() override; Q_REQUIRED_RESULT bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; Q_REQUIRED_RESULT QVariant data(const QModelIndex &index, int role) const override; Q_REQUIRED_RESULT Qt::ItemFlags flags(const QModelIndex &index) const override; Q_REQUIRED_RESULT QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; Q_REQUIRED_RESULT QModelIndex parent(const QModelIndex &index) const override; Q_REQUIRED_RESULT int rowCount(const QModelIndex &parent = QModelIndex()) const override; Q_REQUIRED_RESULT int columnCount(const QModelIndex &parent = QModelIndex()) const override; Q_REQUIRED_RESULT QStringList mimeTypes() const override; Q_REQUIRED_RESULT QMimeData *mimeData(const QModelIndexList &indexes) const override; Q_REQUIRED_RESULT bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; Q_REQUIRED_RESULT Qt::DropActions supportedDropActions() const override; void load(); void save(); Q_REQUIRED_RESULT QMap savedVariables() const; void setSavedVariables(const QMap &savedVariables); protected: bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; Q_SIGNALS: void dndDone(); void addNewDndSnippset(const QString &); + void updateActionCollection(const QString &oldName, const QString &newName, const QKeySequence &keySequence, const QString &text); + private: QModelIndex createGroup(const QString &groupName); void createSnippet(const QModelIndex &groupIndex, const QString &snippetName, const QString &snippetText, const QString &snippetKeySequence); SnippetItem *mRootItem = nullptr; QMap mSavedVariables; }; } #endif