diff --git a/src/kjotsbookmarks.h b/src/kjotsbookmarks.h --- a/src/kjotsbookmarks.h +++ b/src/kjotsbookmarks.h @@ -36,9 +36,13 @@ explicit KJotsBookmarks(KJotsTreeView *treeView); QUrl currentUrl() const override; + QString currentIcon() const override; QString currentTitle() const override; void openBookmark(const KBookmark &bm, Qt::MouseButtons mb, Qt::KeyboardModifiers km) override; +Q_SIGNALS: + void openLink(const QUrl &url); + private: KJotsTreeView *m_treeView; }; diff --git a/src/kjotsbookmarks.cpp b/src/kjotsbookmarks.cpp --- a/src/kjotsbookmarks.cpp +++ b/src/kjotsbookmarks.cpp @@ -35,34 +35,38 @@ void KJotsBookmarks::openBookmark(const KBookmark &bookmark, Qt::MouseButtons, Qt::KeyboardModifiers) { -#if 0 - QModelIndexList rows = m_treeView->model()->match(QModelIndex(), KJotsModel::EntityUrlRole, bookmark.url().url()); - - if (rows.isEmpty()) { + if (bookmark.url().scheme() != QStringLiteral("kjots")) { return; } - - // Arbitrarily chooses the first one if multiple are returned. - return m_treeView->selectionModel()->select(rows.at(0), QItemSelectionModel::ClearAndSelect); -#endif + Q_EMIT openLink(bookmark.url()); } -QUrl KJotsBookmarks::currentUrl() const +QString KJotsBookmarks::currentIcon() const { -#if 0 //QT5 - QModelIndexList rows = m_treeView->selectionModel()->selectedRows(); - + const QModelIndexList rows = m_treeView->selectionModel()->selectedRows(); if (rows.size() != 1) { return QString(); } -#if 0 - return rows.at(0).data(EntityTreeModel::EntityUrlRole).toString(); -#else + const QModelIndex idx = rows.first(); + auto collection = idx.data(EntityTreeModel::CollectionRole).value(); + if (collection.isValid()) { + return QStringLiteral("x-office-address-book"); + } + auto item = idx.data(EntityTreeModel::ItemRole).value(); + if (item.isValid()) { + return QStringLiteral("x-office-document"); + } return QString(); -#endif -#else - return QUrl(); -#endif +} + +QUrl KJotsBookmarks::currentUrl() const +{ + const QModelIndexList rows = m_treeView->selectionModel()->selectedRows(); + if (rows.size() != 1) { + return QUrl(); + } else { + return QUrl(rows.first().data(KJotsModel::UrlRole).value()); + } } QString KJotsBookmarks::currentTitle() const diff --git a/src/kjotsbrowser.h b/src/kjotsbrowser.h --- a/src/kjotsbrowser.h +++ b/src/kjotsbrowser.h @@ -35,7 +35,7 @@ void delayedInitialization(); -protected Q_SLOTS: +Q_SIGNALS: void linkClicked(const QUrl &); private: diff --git a/src/kjotsbrowser.cpp b/src/kjotsbrowser.cpp --- a/src/kjotsbrowser.cpp +++ b/src/kjotsbrowser.cpp @@ -26,8 +26,6 @@ #include -#include - #include #include @@ -39,45 +37,14 @@ void KJotsBrowser::delayedInitialization() { - connect(this, &KJotsBrowser::anchorClicked, this, &KJotsBrowser::linkClicked); -} - -/*! - \brief Handle link clicks. -*/ -void KJotsBrowser::linkClicked(const QUrl &link) -{ - //Stop QTextBrowser from being stupid by giving it an invalid url. - QUrl url; - setSource(url); - - QString anchor = link.fragment(); - - if (link.toString().startsWith(QLatin1String("#")) && (anchor.startsWith(QLatin1String("book_")) - || anchor.startsWith(QLatin1String("page_")))) { - scrollToAnchor(anchor); - return; - } - - if (link.scheme() == QLatin1String("kjots")) { - const quint64 targetId = link.path().mid(1).toULongLong(); - if (link.host().endsWith(QLatin1String("book"))) { - const QModelIndex colIndex = Akonadi::EntityTreeModel::modelIndexForCollection(m_itemSelectionModel->model(), Akonadi::Collection(targetId)); - if (!colIndex.isValid()) { - return; - } - m_itemSelectionModel->select(colIndex, QItemSelectionModel::ClearAndSelect); - } else { - Q_ASSERT(link.host().endsWith(QLatin1String("page"))); - const QModelIndexList itemIndexes = Akonadi::EntityTreeModel::modelIndexesForItem(m_itemSelectionModel->model(), Akonadi::Item(targetId)); - if (itemIndexes.size() != 1) { - return; - } - m_itemSelectionModel->select(itemIndexes.first(), QItemSelectionModel::ClearAndSelect); + connect(this, &KJotsBrowser::anchorClicked, this, [this](const QUrl &url){ + if (!url.toString().startsWith(QLatin1Char('#'))) { + // QTextBrowser tries to automatically handle the url. We only want it for anchor navigation + // (i.e. "#page12" links). This can be overriden by setting the source to an invalid QUrl + setSource(QUrl()); + Q_EMIT linkClicked(url); } - } else { - new KRun(link, this); - } + }); } /* ex: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/kjotslinkdialog.cpp b/src/kjotslinkdialog.cpp --- a/src/kjotslinkdialog.cpp +++ b/src/kjotslinkdialog.cpp @@ -36,6 +36,7 @@ #include "KJotsSettings.h" #include "kjotsbookshelfentryvalidator.h" +#include "kjotsmodel.h" #include #include @@ -124,36 +125,18 @@ void KJotsLinkDialog::setLinkUrl(const QString &linkUrl) { - Akonadi::Item item = Akonadi::Item::fromUrl(QUrl::fromUserInput(linkUrl)); - Akonadi::Collection collection = Akonadi::Collection::fromUrl(QUrl::fromUserInput(linkUrl)); - - if (!item.isValid() && !collection.isValid()) { + const QUrl url(linkUrl); + if (url.scheme() != QStringLiteral("kjots")) { linkUrlLineEdit->setText(linkUrl); linkUrlLineEditRadioButton->setChecked(true); return; } - - QModelIndex idx; - - if (collection.isValid()) { - idx = Akonadi::EntityTreeModel::modelIndexForCollection(m_descendantsProxyModel, collection); - } else if (item.isValid()) { - const QModelIndexList list = Akonadi::EntityTreeModel::modelIndexesForItem(m_descendantsProxyModel, item); - if (list.isEmpty()) { - return; - } - - idx = list.first(); + QModelIndex idx = KJotsModel::modelIndexForUrl(m_descendantsProxyModel, url); + if (idx.isValid()) { + hrefComboRadioButton->setChecked(true); + hrefCombo->view()->setCurrentIndex(idx); + hrefCombo->setCurrentIndex(idx.row()); } - - if (!idx.isValid()) { - return; - } - - hrefComboRadioButton->setChecked(true); - - hrefCombo->view()->setCurrentIndex(idx); - hrefCombo->setCurrentIndex(idx.row()); } QString KJotsLinkDialog::linkText() const @@ -176,14 +159,7 @@ QString KJotsLinkDialog::linkUrl() const { if (hrefComboRadioButton->isChecked()) { - const QModelIndex index = hrefCombo->view()->currentIndex(); - const Akonadi::Collection collection = index.data(Akonadi::EntityTreeModel::CollectionRole).value(); - if (collection.isValid()) { - return QLatin1String("kjots://org.kjots.book/") + QString::number(collection.id()); - } - const Akonadi::Item item = index.data(Akonadi::EntityTreeModel::ItemRole).value(); - Q_ASSERT(item.isValid()); - return QLatin1String("kjots://org.kjots.page/") + QString::number(item.id()); + return hrefCombo->view()->currentIndex().data(KJotsModel::UrlRole).value(); } else { return linkUrlLineEdit->text(); } diff --git a/src/kjotsmodel.h b/src/kjotsmodel.h --- a/src/kjotsmodel.h +++ b/src/kjotsmodel.h @@ -42,6 +42,7 @@ Q_PROPERTY(QString title READ title) Q_PROPERTY(QString content READ content) Q_PROPERTY(QString plainContent READ plainContent) + Q_PROPERTY(QString url READ url) Q_PROPERTY(qint64 entityId READ entityId) Q_PROPERTY(bool isBook READ isBook) Q_PROPERTY(bool isPage READ isPage) @@ -61,6 +62,8 @@ QString plainContent() const; + QString url() const; + qint64 entityId() const; QVariantList entities() const; @@ -81,7 +84,8 @@ enum KJotsRoles { GrantleeObjectRole = EntityTreeModel::UserRole, DocumentRole, - DocumentCursorPositionRole + DocumentCursorPositionRole, + UrlRole }; // We don't reimplement the Collection overload. @@ -92,6 +96,7 @@ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + static QModelIndex modelIndexForUrl(const QAbstractItemModel *model, const QUrl &url); private: QHash m_colors; mutable QHash m_documents; diff --git a/src/kjotsmodel.cpp b/src/kjotsmodel.cpp --- a/src/kjotsmodel.cpp +++ b/src/kjotsmodel.cpp @@ -89,6 +89,11 @@ return result; } +QString KJotsEntity::url() const +{ + return m_index.data(KJotsModel::UrlRole).value(); +} + qint64 KJotsEntity::entityId() const { Item item = m_index.data(EntityTreeModel::ItemRole).value(); @@ -272,6 +277,18 @@ } } + if (role == KJotsModel::UrlRole) { + const auto item = index.data(ItemRole).value(); + if (item.isValid()) { + return QStringLiteral("kjots://org.kjots.page/%1").arg(item.id()); + } + const auto col = index.data(CollectionRole).value(); + if (col.isValid()) { + return QStringLiteral("kjots://org.kjots.book/%1").arg(col.id()); + } + return QString(); + } + return EntityTreeModel::data(index, role); } @@ -284,3 +301,23 @@ return EntityTreeModel::entityData(item, column, role); } +QModelIndex KJotsModel::modelIndexForUrl(const QAbstractItemModel *model, const QUrl &url) +{ + if (url.scheme() != QStringLiteral("kjots")) { + return QModelIndex(); + } + const qint64 targetId = url.path().mid(1).toLongLong(); + + if (url.host() == QStringLiteral("org.kjots.book")) { + return Akonadi::EntityTreeModel::modelIndexForCollection(model, Collection(targetId)); + } else if (url.host() == QStringLiteral("org.kjots.page")) { + const QModelIndexList itemIndexes = Akonadi::EntityTreeModel::modelIndexesForItem(model, Item(targetId)); + if (itemIndexes.isEmpty()) { + return QModelIndex(); + } + return itemIndexes.first(); + } else { + qWarning() << "Could not recognize URL" << url; + return QModelIndex(); + } +} diff --git a/src/kjotswidget.h b/src/kjotswidget.h --- a/src/kjotswidget.h +++ b/src/kjotswidget.h @@ -75,7 +75,6 @@ ~KJotsWidget(); QTextEdit *activeEditor(); - public Q_SLOTS: void prevPage(); void nextPage(); @@ -132,6 +131,7 @@ void deleteBook(); void deleteMultiple(); + void openLink(const QUrl &url); private Q_SLOTS: void delayedInitialization(); void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); diff --git a/src/kjotswidget.cpp b/src/kjotswidget.cpp --- a/src/kjotswidget.cpp +++ b/src/kjotswidget.cpp @@ -85,6 +85,7 @@ #include #include #include +#include // KMime #include @@ -196,6 +197,7 @@ layout->addWidget(m_splitter); browser = new KJotsBrowser(treeview->selectionModel(), stackedWidget); + connect(browser, &KJotsBrowser::linkClicked, this, &KJotsWidget::openLink); stackedWidget->addWidget(browser); stackedWidget->setCurrentWidget(browser); @@ -353,6 +355,7 @@ bookmarkMenu = actionCollection->add(QLatin1String("bookmarks")); bookmarkMenu->setText(i18n("&Bookmarks")); KJotsBookmarks *bookmarks = new KJotsBookmarks(treeview); + connect(bookmarks, &KJotsBookmarks::openLink, this, &KJotsWidget::openLink); KBookmarkMenu *bmm = new KBookmarkMenu( KBookmarkManager::managerForFile( QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).first() + QStringLiteral("/kjots/bookmarks.xml"), @@ -1828,3 +1831,11 @@ } } +void KJotsWidget::openLink(const QUrl &url) +{ + if (url.scheme() == QStringLiteral("kjots")) { + treeview->selectionModel()->select(KJotsModel::modelIndexForUrl(treeview->model(), url), QItemSelectionModel::ClearAndSelect); + } else { + new KRun(url, this); + } +} diff --git a/themes/default/pagetemplate.html b/themes/default/pagetemplate.html --- a/themes/default/pagetemplate.html +++ b/themes/default/pagetemplate.html @@ -1,13 +1,13 @@
-

{{ entity.title }}

+

{{ entity.title }}

{{ entity.content|safe }}
diff --git a/themes/plain_text/template.txt b/themes/plain_text/template.txt --- a/themes/plain_text/template.txt +++ b/themes/plain_text/template.txt @@ -1,3 +1,3 @@ {% for entity in entities %}{% if entity.isBook %}{% include "book_template.txt" %} -{% else %}{% if entity.isPage %} -{% endif %}{% endif %}{% endfor %} \ No newline at end of file +{% else %}{% if entity.isPage %}{% include "page_template.txt" %} +{% endif %}{% endif %}{% endfor %}