diff --git a/src/kjotsedit.cpp b/src/kjotsedit.cpp index fa79176..7e8a436 100644 --- a/src/kjotsedit.cpp +++ b/src/kjotsedit.cpp @@ -1,494 +1,494 @@ /* kjots Copyright (C) 1997 Christoph Neerfeld Copyright (C) 2002, 2003 Aaron J. Seigo Copyright (C) 2003 Stanislav Kljuhhin Copyright (C) 2005-2006 Jaison Lee Copyright (C) 2007-2008 Stephen Kelly This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //Own Header #include "kjotsedit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kjotslinkdialog.h" #include "kjotsmodel.h" #include "noteshared/noteeditorutils.h" #include "noteshared/notelockattribute.h" Q_DECLARE_METATYPE(QTextCursor) Q_DECLARE_METATYPE(KPIMTextEdit::ImageList) using namespace Akonadi; using namespace KPIMTextEdit; class Q_DECL_HIDDEN KJotsEdit::Private { public: Private() = default; ~Private() = default; QAbstractItemModel *model = nullptr; - std::unique_ptr index; + QPersistentModelIndex index; QAction *action_copy_into_title = nullptr; QAction *action_manage_link = nullptr; QAction *action_auto_bullet = nullptr; QAction *action_auto_decimal = nullptr; QAction *action_insert_date = nullptr; QVector richTextActionList; }; KJotsEdit::KJotsEdit(QWidget *parent, KActionCollection *actionCollection) : RichTextComposer(parent) , d(new Private) , m_actionCollection(actionCollection) , allowAutoDecimal(false) { setMouseTracking(true); setAcceptRichText(true); setWordWrapMode(QTextOption::WordWrap); setCheckSpellingEnabled(true); setFocusPolicy(Qt::StrongFocus); createActions(m_actionCollection); activateRichText(); } KJotsEdit::~KJotsEdit() = default; void KJotsEdit::createActions(KActionCollection *ac) { RichTextComposer::createActions(ac); d->action_copy_into_title = new QAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18nc("@action", "Copy &Into Page Title"), this); connect(d->action_copy_into_title, &QAction::triggered, this, &KJotsEdit::copySelectionIntoTitle); connect(this, &KJotsEdit::copyAvailable, d->action_copy_into_title, &QAction::setEnabled); d->action_copy_into_title->setEnabled(false); d->richTextActionList.append(d->action_copy_into_title); if (ac) { ac->addAction(QStringLiteral("copy_into_title"), d->action_copy_into_title); } d->action_manage_link = new QAction(QIcon::fromTheme(QStringLiteral("insert-link")), i18nc("@action creates and manages hyperlinks", "Link"), this); connect(d->action_manage_link, &QAction::triggered, this, &KJotsEdit::onLinkify); d->richTextActionList.append(d->action_manage_link); if (ac) { ac->addAction(QStringLiteral("manage_note_link"), d->action_manage_link); } d->action_auto_bullet = new QAction(QIcon::fromTheme(QStringLiteral("format-list-unordered")), i18nc("@action", "Auto Bullet List"), this); d->action_auto_bullet->setCheckable(true); connect(d->action_auto_bullet, &QAction::triggered, this, &KJotsEdit::onAutoBullet); d->richTextActionList.append(d->action_auto_bullet); if (ac) { ac->addAction(QStringLiteral("auto_bullet"), d->action_auto_bullet); } d->action_auto_decimal = new QAction(QIcon::fromTheme(QStringLiteral("format-list-ordered")), i18nc("@action", "Auto Decimal List"), this); d->action_auto_decimal->setCheckable(true); connect(d->action_auto_decimal, &QAction::triggered, this, &KJotsEdit::onAutoDecimal); d->richTextActionList.append(d->action_auto_decimal); if (ac) { ac->addAction(QStringLiteral("auto_decimal"), d->action_auto_decimal); } d->action_insert_date = new QAction(QIcon::fromTheme(QStringLiteral("view-calendar-time-spent")), i18nc("@action", "Insert Date"), this); connect(d->action_insert_date, &QAction::triggered, this, &KJotsEdit::insertDate); d->richTextActionList.append(d->action_insert_date); if (ac) { ac->addAction(QStringLiteral("insert_date"), d->action_insert_date); ac->setDefaultShortcut(d->action_insert_date, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I)); } } void KJotsEdit::setEnableActions(bool enable) { // FIXME: RichTextComposer::setEnableActions(enable) messes with indent actions // due to bug in KPIMTextEdit (should be fixed in 20.08?) composerActions()->setActionsEnabled(enable); for (QAction *action : qAsConst(d->richTextActionList)) { action->setEnabled(enable); } } void KJotsEdit::contextMenuEvent(QContextMenuEvent *event) { QMenu *popup = mousePopupMenu(event->pos()); if (popup) { const QList actionList = popup->actions(); if (!qApp->clipboard()->text().isEmpty()) { QAction *act = m_actionCollection->action(QStringLiteral("paste_without_formatting")); act->setIcon(QIcon::fromTheme(QStringLiteral("edit-paste"))); act->setEnabled(!isReadOnly()); // HACK: menu actions are following: Undo, Redo, Separator, Cut, Copy, Paste, Delete, Clear // We want to insert "Paste Without Formatting" right after standard Paste (which is at pos 6) // Let's hope QTextEdit and KPIMTextEdit::RichTextEditor doesn't break it // (and we don't break anything either) const int pasteActionPosition = 6; if (actionList.count() >= pasteActionPosition) { popup->insertAction(popup->actions().at(pasteActionPosition), act); } else { popup->addAction(act); } } popup->addSeparator(); popup->addAction(d->action_copy_into_title); if (!anchorAt(event->pos()).isNull()) { popup->addAction(d->action_manage_link); } popup->exec(event->globalPos()); delete popup; } } bool KJotsEdit::modified() { return document()->isModified(); } void KJotsEdit::insertDate() { NoteShared::NoteEditorUtils::insertDate(this); } bool KJotsEdit::setModelIndex(const QModelIndex &index) { // Mapping index to ETM QModelIndex etmIndex = index; const QAbstractProxyModel *proxy = qobject_cast(index.model()); while (proxy) { etmIndex = proxy->mapToSource(etmIndex); proxy = qobject_cast(etmIndex.model()); } // Saving the old document, if it was changed - bool newDocument = d->index && (*d->index != etmIndex); + bool newDocument = d->index.isValid() && (d->index != etmIndex); if (newDocument) { savePage(); } d->model = const_cast(etmIndex.model()); - d->index = std::make_unique(etmIndex); + d->index = QPersistentModelIndex(etmIndex); // Loading document - auto *doc = d->index->data(KJotsModel::DocumentRole).value(); + auto *doc = d->index.data(KJotsModel::DocumentRole).value(); if (!doc) { setReadOnly(true); return false; } disconnect(document(), &QTextDocument::modificationChanged, this, &KJotsEdit::documentModified); setDocument(doc); connect(doc, &QTextDocument::modificationChanged, this, &KJotsEdit::documentModified); // Setting cursor auto cursor = doc->property("textCursor").value(); if (!cursor.isNull()) { setTextCursor(cursor); } else { // This is a work-around for QTextEdit bug. If the first letter of the document is formatted, // QTextCursor doesn't follow this format. One can either move the cursor 1 symbol to the right // and then 1 symbol to the left as a workaround, or just explicitly move it to the start. // Submitted to qt-bugs, id 192886. // -- (don't know the fate of this bug, as for April 2020 it is inaccessible) moveCursor(QTextCursor::Start); } // Setting focus if document was changed if (newDocument) { setFocus(); } // Setting ReadOnly - auto item = d->index->data(EntityTreeModel::ItemRole).value(); + auto item = d->index.data(EntityTreeModel::ItemRole).value(); if (!item.isValid()) { setReadOnly(true); return false; } else if (item.hasAttribute()) { setReadOnly(true); return true; } else { setReadOnly(false); return true; } } void KJotsEdit::onAutoBullet() { KTextEdit::AutoFormatting currentFormatting = autoFormatting(); //TODO: set line spacing properly. if (currentFormatting == KTextEdit::AutoBulletList) { setAutoFormatting(KTextEdit::AutoNone); d->action_auto_bullet->setChecked(false); } else { setAutoFormatting(KTextEdit::AutoBulletList); d->action_auto_bullet->setChecked(true); } } void KJotsEdit::createAutoDecimalList() { //this is an adaptation of Qt's createAutoBulletList() function for creating a bulleted list, except in this case I use it to create a decimal list. QTextCursor cursor = textCursor(); cursor.beginEditBlock(); QTextBlockFormat blockFmt = cursor.blockFormat(); QTextListFormat listFmt; listFmt.setStyle(QTextListFormat::ListDecimal); listFmt.setIndent(blockFmt.indent() + 1); blockFmt.setIndent(0); cursor.setBlockFormat(blockFmt); cursor.createList(listFmt); cursor.endEditBlock(); setTextCursor(cursor); } void KJotsEdit::DecimalList() { QTextCursor cursor = textCursor(); if (cursor.currentList()) { return; } QString blockText = cursor.block().text(); if (blockText.length() == 2 && blockText == QLatin1String("1.")) { cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); cursor.removeSelectedText(); createAutoDecimalList(); } } void KJotsEdit::onAutoDecimal() { if (allowAutoDecimal) { allowAutoDecimal = false; disconnect(this, &KJotsEdit::textChanged, this, &KJotsEdit::DecimalList); d->action_auto_decimal->setChecked(false); } else { allowAutoDecimal = true; connect(this, &KJotsEdit::textChanged, this, &KJotsEdit::DecimalList); d->action_auto_decimal->setChecked(true); } } void KJotsEdit::onLinkify() { // Nothing is yet opened, ignoring - if (!d->index) { + if (d->index.isValid()) { return; } composerControler()->selectLinkText(); auto linkDialog = std::make_unique(d->model, this); linkDialog->setLinkText(composerControler()->currentLinkText()); linkDialog->setLinkUrl(composerControler()->currentLinkUrl()); if (linkDialog->exec()) { composerControler()->updateLink(linkDialog->linkUrl(), linkDialog->linkText()); } } void KJotsEdit::copySelectionIntoTitle() { - if (!d->index) { + if (!d->index.isValid()) { return; } const QString newTitle(textCursor().selectedText()); - d->model->setData(*d->index, newTitle); + d->model->setData(d->index, newTitle); } bool KJotsEdit::canInsertFromMimeData(const QMimeData *source) const { if (source->hasUrls()) { return true; } else { return RichTextComposer::canInsertFromMimeData(source); } } void KJotsEdit::insertFromMimeData(const QMimeData *source) { // Nothing is opened, ignoring - if (!d->index) { + if (!d->index.isValid()) { return; } if (source->hasUrls()) { const QList urls = source->urls(); for (const QUrl &url : urls) { if (url.scheme() == QStringLiteral("akonadi")) { QModelIndex idx = KJotsModel::modelIndexForUrl(d->model, url); if (idx.isValid()) { insertHtml(QStringLiteral("%2").arg(idx.data(KJotsModel::EntityUrlRole).toString(), idx.data().toString())); } } else { QString text = source->hasText() ? source->text() : url.toString(QUrl::RemovePassword); insertHtml(QStringLiteral("%2").arg(QString::fromUtf8(url.toEncoded()), text)); } } } else if (source->hasHtml()) { // Don't have an action to set top and bottom margins on paragraphs yet. // Remove the margins for all inserted html. QTextDocument dummy; dummy.setHtml(source->html()); QTextCursor c(&dummy); QTextBlockFormat fmt = c.blockFormat(); fmt.setTopMargin(0); fmt.setBottomMargin(0); fmt.setLeftMargin(0); fmt.setRightMargin(0); c.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); c.mergeBlockFormat(fmt); textCursor().insertFragment(QTextDocumentFragment(c)); ensureCursorVisible(); } else { RichTextComposer::insertFromMimeData(source); } } void KJotsEdit::mouseMoveEvent(QMouseEvent *event) { if ((event->modifiers() & Qt::ControlModifier) && !anchorAt(event->pos()).isEmpty()) { if (!m_cursorChanged) { QApplication::setOverrideCursor(Qt::PointingHandCursor); m_cursorChanged = true; } } else { if (m_cursorChanged) { QApplication::restoreOverrideCursor(); m_cursorChanged = false; } } RichTextComposer::mouseMoveEvent(event); } void KJotsEdit::leaveEvent(QEvent *event) { if (m_cursorChanged) { QApplication::restoreOverrideCursor(); m_cursorChanged = false; } RichTextComposer::leaveEvent(event); } void KJotsEdit::mousePressEvent(QMouseEvent *event) { QUrl url = anchorAt(event->pos()); if ((event->modifiers() & Qt::ControlModifier) && (event->button() & Qt::LeftButton) && !url.isEmpty()) { Q_EMIT linkClicked(url); } else { RichTextComposer::mousePressEvent(event); } } bool KJotsEdit::event(QEvent *event) { if (event->type() == QEvent::WindowDeactivate) { savePage(); } else if (event->type() == QEvent::ToolTip) { tooltipEvent(static_cast(event)); } return RichTextComposer::event(event); } void KJotsEdit::tooltipEvent(QHelpEvent *event) { // Nothing is opened, ignoring - if (!d->index) { + if (!d->index.isValid()) { return; } QUrl url(anchorAt(event->pos())); QString message; if (url.isValid()) { if (url.scheme() == QStringLiteral("akonadi")) { const QModelIndex idx = KJotsModel::modelIndexForUrl(d->model, url); if (idx.data(EntityTreeModel::ItemRole).value().isValid()) { message = i18nc("@info:tooltip %1 is a full path to note (i.e. Notes / Notebook / Note)", "Ctrl+click to open note: %1", KJotsModel::itemPath(idx)); } else if (idx.data(EntityTreeModel::CollectionRole).value().isValid()) { message = i18nc("@info:tooltip %1 is a full path to book (i.e. Notes / Notebook)", "Ctrl+click to open book: %1", KJotsModel::itemPath(idx)); } } else { message = i18nc("@info:tooltip %1 is hyperlink address", "Ctrl+click to follow the hyperlink: %1", url.toString(QUrl::RemovePassword)); } } if (!message.isEmpty()) { QToolTip::showText(event->globalPos(), message); } else { QToolTip::hideText(); } } void KJotsEdit::focusOutEvent(QFocusEvent *event) { savePage(); RichTextComposer::focusOutEvent(event); } void KJotsEdit::prepareDocumentForSaving() { document()->setModified(false); document()->setProperty("textCursor", QVariant::fromValue(textCursor())); document()->setProperty("images", QVariant::fromValue(composerControler()->composerImages()->embeddedImages())); } void KJotsEdit::savePage() { - if (!document()->isModified() || !d->index) { + if (!document()->isModified() || !d->index.isValid()) { return; } prepareDocumentForSaving(); - d->model->setData(*d->index, QVariant::fromValue(document()), KJotsModel::DocumentRole); + d->model->setData(d->index, QVariant::fromValue(document()), KJotsModel::DocumentRole); } /* ex: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/kjotsmodel.cpp b/src/kjotsmodel.cpp index 109219e..a30b108 100644 --- a/src/kjotsmodel.cpp +++ b/src/kjotsmodel.cpp @@ -1,393 +1,393 @@ /* This file is part of KJots. Copyright (c) 2009 Stephen Kelly 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 "kjotsmodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "noteshared/notelockattribute.h" Q_DECLARE_METATYPE(QTextDocument *) Q_DECLARE_METATYPE(KPIMTextEdit::ImageList) using namespace Akonadi; KJotsEntity::KJotsEntity(const QModelIndex &index, QObject *parent) : QObject(parent) , m_index(index) { } void KJotsEntity::setIndex(const QModelIndex &index) { m_index = QPersistentModelIndex(index); } QString KJotsEntity::title() const { return m_index.data().toString(); } QString KJotsEntity::content() const { auto *document = m_index.data(KJotsModel::DocumentRole).value(); if (!document) { return QString(); } Grantlee::TextHTMLBuilder builder; Grantlee::MarkupDirector director(&builder); director.processDocument(document); QString result = builder.getResult(); return result; } QString KJotsEntity::plainContent() const { auto *document = m_index.data(KJotsModel::DocumentRole).value(); if (!document) { return QString(); } Grantlee::PlainTextMarkupBuilder builder; Grantlee::MarkupDirector director(&builder); director.processDocument(document); QString result = builder.getResult(); return result; } QString KJotsEntity::url() const { return m_index.data(KJotsModel::EntityUrlRole).toString(); } qint64 KJotsEntity::entityId() const { Item item = m_index.data(EntityTreeModel::ItemRole).value(); if (!item.isValid()) { Collection col = m_index.data(EntityTreeModel::CollectionRole).value(); if (!col.isValid()) { return -1; } return col.id(); } return item.id(); } bool KJotsEntity::isBook() const { Collection col = m_index.data(EntityTreeModel::CollectionRole).value(); if (col.isValid()) { return col.contentMimeTypes().contains(Akonadi::NoteUtils::noteMimeType()); } return false; } bool KJotsEntity::isPage() const { Item item = m_index.data(EntityTreeModel::ItemRole).value(); if (item.isValid()) { return item.hasPayload(); } return false; } QVariantList KJotsEntity::entities() const { const QAbstractItemModel *model = m_index.model(); QVariantList list; int row = 0; const int column = 0; QModelIndex childIndex = model->index(row++, column, m_index); while (childIndex.isValid()) { auto *obj = new KJotsEntity(childIndex); list << QVariant::fromValue(obj); childIndex = model->index(row++, column, m_index); } return list; } QVariantList KJotsEntity::breadcrumbs() const { QVariantList list; QModelIndex parent = m_index.parent(); while (parent.isValid()) { QObject *obj = new KJotsEntity(parent); list << QVariant::fromValue(obj); parent = parent.parent(); } return list; } KJotsModel::KJotsModel(ChangeRecorder *monitor, QObject *parent) : EntityTreeModel(monitor, parent) { } KJotsModel::~KJotsModel() { qDeleteAll(m_documents); } bool KJotsModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role == Qt::EditRole) { Item item = index.data(ItemRole).value(); if (!item.isValid()) { Collection col = index.data(CollectionRole).value(); col.setName(value.toString()); if (col.hasAttribute()) { auto *eda = col.attribute(); eda->setDisplayName(value.toString()); } return EntityTreeModel::setData(index, QVariant::fromValue(col), CollectionRole); } NoteUtils::NoteMessageWrapper note(item.payload()); note.setTitle(value.toString()); item.setPayload(note.message()); if (item.hasAttribute()) { auto *displayAttribute = item.attribute(); displayAttribute->setDisplayName(value.toString()); } return EntityTreeModel::setData(index, QVariant::fromValue(item), ItemRole); } if (role == KJotsModel::DocumentRole) { - Item item = updateItem(index.data(ItemIdRole).value(), value.value()); + Item item = updateItem(index.data(ItemRole).value(), value.value()); return EntityTreeModel::setData(index, QVariant::fromValue(item), ItemRole); } return EntityTreeModel::setData(index, value, role); } QVariant KJotsModel::data(const QModelIndex &index, int role) const { if (GrantleeObjectRole == role) { auto *obj = new KJotsEntity(index); obj->setIndex(index); return QVariant::fromValue(obj); } if (role == KJotsModel::DocumentRole) { const Item item = index.data(ItemRole).value(); Item::Id itemId = item.id(); if (m_documents.contains(itemId)) { return QVariant::fromValue(m_documents.value(itemId)); } if (!item.hasPayload()) { return QVariant(); } NoteUtils::NoteMessageWrapper note(item.payload()); const QString doc = note.text(); auto *document = new QTextDocument(); if (note.textFormat() == Qt::RichText || doc.startsWith(u"")) { document->setHtml(doc); } else { document->setPlainText(doc); } document->setModified(false); // Loading embedded images const QVector attachments = note.attachments(); for (const auto &attachment : attachments) { if (attachment.mimetype() == QStringLiteral("image/png") && !attachment.contentID().isEmpty()) { QImage img = QImage::fromData(attachment.data(), "PNG"); document->addResource(QTextDocument::ImageResource, QUrl(QStringLiteral("cid:")+attachment.contentID()), img); } } m_documents.insert(itemId, document); return QVariant::fromValue(document); } if (role == Qt::DecorationRole) { const Item item = index.data(ItemRole).value(); if (item.isValid() && item.hasAttribute()) { return QIcon::fromTheme(QStringLiteral("emblem-locked")); } const Collection col = index.data(CollectionRole).value(); if (col.isValid() && col.hasAttribute()) { return QIcon::fromTheme(QStringLiteral("emblem-locked")); } } return EntityTreeModel::data(index, role); } QVariant KJotsModel::entityData(const Akonadi::Item &item, int column, int role) const { if (item.hasPayload()) { auto message = item.payload(); NoteUtils::NoteMessageWrapper note(message); if (role == Qt::DisplayRole) { switch (column) { case Title: return note.title(); case ModificationTime: return KFormat().formatRelativeDateTime(note.lastModifiedDate(), QLocale::ShortFormat); case CreationTime: return KFormat().formatRelativeDateTime(note.creationDate(), QLocale::ShortFormat); case Size: return KFormat().formatByteSize(message->storageSize()); } } else if (role == Qt::EditRole) { switch (column) { case Title: return note.title(); case ModificationTime: return note.lastModifiedDate(); case CreationTime: return note.creationDate(); case Size: return message->size(); } } } return EntityTreeModel::entityData(item, column, role); } QVariant KJotsModel::entityHeaderData(int section, Qt::Orientation orientation, int role, HeaderGroup headerGroup) const { if (role != Qt::DisplayRole || orientation != Qt::Horizontal) { return EntityTreeModel:: entityHeaderData(section, orientation, role, headerGroup); } if (headerGroup == EntityTreeModel::CollectionTreeHeaders) { return i18nc("@title:column", "Name"); } else if (headerGroup == EntityTreeModel::ItemListHeaders) { switch (section) { case Title: return i18nc("@title:column title of a note", "Title"); case CreationTime: return i18nc("@title:column creation date and time of a note", "Created"); case ModificationTime: return i18nc("@title:column last modification date and time of a note", "Modified"); case Size: return i18nc("@title:column size of a note", "Size"); } } return EntityTreeModel::entityHeaderData(section, orientation, role, headerGroup); } int KJotsModel::entityColumnCount(HeaderGroup headerGroup) const { if (headerGroup == EntityTreeModel::CollectionTreeHeaders) { return 1; } else if (headerGroup == EntityTreeModel::ItemListHeaders) { return 4; } else { return EntityTreeModel::entityColumnCount(headerGroup); } } QModelIndex KJotsModel::modelIndexForUrl(const QAbstractItemModel *model, const QUrl &url) { if (url.scheme() != QStringLiteral("akonadi")) { return {}; } const auto item = Item::fromUrl(url); const auto col = Collection::fromUrl(url); if (item.isValid()) { const QModelIndexList idxs = EntityTreeModel::modelIndexesForItem(model, item); if (!idxs.isEmpty()) { return idxs.first(); } } else if (col.isValid()) { return EntityTreeModel::modelIndexForCollection(model, col); } return {}; } Item KJotsModel::updateItem(const Item &item, QTextDocument *document) { Item newItem = item; if (!item.hasPayload()) { return Item(); } NoteUtils::NoteMessageWrapper note(item.payload()); // Saving embedded images const auto images = document->property("images").value(); QVector &attachments = note.attachments(); attachments.clear(); attachments.reserve(images.count()); std::transform(images.cbegin(), images.cend(), std::back_inserter(attachments), [](const QSharedPointer &img) { NoteUtils::Attachment attachment(img->image, QStringLiteral("image/png")); attachment.setDataBase64Encoded(true); attachment.setContentID(img->contentID); return attachment; }); // Setting text bool isRichText = KPIMTextEdit::TextUtils::containsFormatting(document); if (isRichText) { const QByteArray html = KPIMTextEdit::RichTextComposerImages::imageNamesToContentIds( document->toHtml().toUtf8(), images); note.setText( QString::fromUtf8(html), Qt::RichText ); } else { note.setText( document->toPlainText(), Qt::PlainText ); } note.setLastModifiedDate(QDateTime::currentDateTime()); newItem.setPayload(note.message()); return newItem; } QString KJotsModel::itemPath(const QModelIndex &index, const QString &sep) { QString caption; QModelIndex curIndex = index; while (curIndex.isValid()) { QModelIndex parentBook = curIndex.parent(); if (parentBook.isValid()) { caption = sep + curIndex.data().toString() + caption; } else { caption = curIndex.data().toString() + caption; } curIndex = parentBook; } return caption; }