File indexing completed on 2024-05-12 04:34:10

0001 /*
0002     SPDX-FileCopyrightText: 2012 Marco Martin <mart@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "documentitem.h"
0008 
0009 #include <QMimeDatabase>
0010 #include <QQmlEngine>
0011 
0012 #ifdef Q_OS_ANDROID
0013 #include <QCoreApplication>
0014 #include <QJniObject>
0015 #endif
0016 
0017 #include <core/bookmarkmanager.h>
0018 #include <core/document_p.h>
0019 #include <core/page.h>
0020 
0021 #include "gui/signatureguiutils.h"
0022 
0023 DocumentItem::DocumentItem(QObject *parent)
0024     : QObject(parent)
0025     , m_thumbnailObserver(nullptr)
0026     , m_pageviewObserver(nullptr)
0027     , m_searchInProgress(false)
0028 {
0029     qmlRegisterUncreatableType<TOCModel>("org.kde.okular.private", 1, 0, "TOCModel", QStringLiteral("Do not create objects of this type."));
0030     qmlRegisterUncreatableType<SignatureModel>("org.kde.okular.private", 1, 0, "SignatureModel", QStringLiteral("Do not create objects of this type."));
0031     Okular::Settings::instance(QStringLiteral("okularproviderrc"));
0032     m_document = new Okular::Document(nullptr);
0033     m_tocModel = new TOCModel(m_document, this);
0034     m_signaturesModel = new SignatureModel(m_document, this);
0035 
0036     connect(m_document, &Okular::Document::searchFinished, this, &DocumentItem::searchFinished);
0037     connect(m_document->bookmarkManager(), &Okular::BookmarkManager::bookmarksChanged, this, &DocumentItem::bookmarkedPagesChanged);
0038     connect(m_document->bookmarkManager(), &Okular::BookmarkManager::bookmarksChanged, this, &DocumentItem::bookmarksChanged);
0039     connect(m_document, &Okular::Document::error, this, &DocumentItem::error);
0040     connect(m_document, &Okular::Document::warning, this, &DocumentItem::warning);
0041     connect(m_document, &Okular::Document::notice, this, &DocumentItem::notice);
0042 }
0043 
0044 DocumentItem::~DocumentItem()
0045 {
0046     delete m_signaturesModel;
0047     delete m_document;
0048 }
0049 
0050 void DocumentItem::setUrl(const QUrl &url)
0051 {
0052     openUrl(url, {});
0053 }
0054 
0055 void DocumentItem::openUrl(const QUrl &url, const QString &password)
0056 {
0057     m_document->closeDocument();
0058     // TODO: password
0059     QMimeDatabase db;
0060 
0061     QUrl realUrl = url; // NOLINT(performance-unnecessary-copy-initialization) because of the ifdef below this can't be const &
0062 
0063 #ifdef Q_OS_ANDROID
0064     realUrl =
0065         QUrl(QJniObject(QNativeInterface::QAndroidApplication::context()).callObjectMethod("contentUrlToFd", "(Ljava/lang/String;)Ljava/lang/String;", QJniObject::fromString(url.toString(QUrl::FullyEncoded)).object<jstring>()).toString());
0066 #endif
0067 
0068     const QString path = realUrl.isLocalFile() ? realUrl.toLocalFile() : QStringLiteral("-");
0069 
0070     const Okular::Document::OpenResult res = m_document->openDocument(path, realUrl, db.mimeTypeForUrl(realUrl), password);
0071 
0072     m_tocModel->clear();
0073     m_tocModel->fill(m_document->documentSynopsis());
0074     m_tocModel->setCurrentViewport(m_document->viewport());
0075 
0076     m_matchingPages.clear();
0077     for (uint i = 0; i < m_document->pages(); ++i) {
0078         m_matchingPages << (int)i;
0079     }
0080     m_needsPassword = res == Okular::Document::OpenNeedsPassword;
0081     Q_EMIT matchingPagesChanged();
0082     Q_EMIT urlChanged();
0083     Q_EMIT pageCountChanged();
0084     Q_EMIT openedChanged();
0085     Q_EMIT needsPasswordChanged();
0086     Q_EMIT supportsSearchingChanged();
0087     Q_EMIT windowTitleForDocumentChanged();
0088     Q_EMIT bookmarkedPagesChanged();
0089 
0090     KMessageWidget::MessageType messageType;
0091     QString message;
0092     std::tie(messageType, message) = SignatureGuiUtils::documentSignatureMessageWidgetText(m_document);
0093     if (!message.isEmpty()) {
0094         if (messageType == KMessageWidget::Information) {
0095             Q_EMIT notice(message, -1);
0096         } else if (messageType == KMessageWidget::Warning) {
0097             Q_EMIT warning(message, -1);
0098         } else {
0099             qWarning() << "Unexpected message type" << messageType;
0100         }
0101     }
0102 }
0103 
0104 QString DocumentItem::windowTitleForDocument() const
0105 {
0106     // If 'DocumentTitle' should be used, check if the document has one. If
0107     // either case is false, use the file name.
0108     QString title = Okular::Settings::displayDocumentNameOrPath() == Okular::Settings::EnumDisplayDocumentNameOrPath::Path ? m_document->currentDocument().toDisplayString(QUrl::PreferLocalFile) : m_document->currentDocument().fileName();
0109 
0110     if (Okular::Settings::displayDocumentTitle()) {
0111         const QString docTitle = m_document->metaData(QStringLiteral("DocumentTitle")).toString();
0112 
0113         if (!docTitle.isEmpty() && !docTitle.trimmed().isEmpty()) {
0114             title = docTitle;
0115         }
0116     }
0117 
0118     return title;
0119 }
0120 
0121 QUrl DocumentItem::url() const
0122 {
0123     return m_document->currentDocument();
0124 }
0125 
0126 void DocumentItem::setCurrentPage(int page)
0127 {
0128     m_document->setViewportPage(page);
0129     m_tocModel->setCurrentViewport(m_document->viewport());
0130     Q_EMIT currentPageChanged();
0131 }
0132 
0133 int DocumentItem::currentPage() const
0134 {
0135     return m_document->currentPage();
0136 }
0137 
0138 bool DocumentItem::isOpened() const
0139 {
0140     return m_document->isOpened();
0141 }
0142 
0143 int DocumentItem::pageCount() const
0144 {
0145     return m_document->pages();
0146 }
0147 
0148 QVariantList DocumentItem::matchingPages() const
0149 {
0150     return m_matchingPages;
0151 }
0152 
0153 TOCModel *DocumentItem::tableOfContents() const
0154 {
0155     return m_tocModel;
0156 }
0157 
0158 SignatureModel *DocumentItem::signaturesModel() const
0159 {
0160     return m_signaturesModel;
0161 }
0162 
0163 QVariantList DocumentItem::bookmarkedPages() const
0164 {
0165     QList<int> list;
0166     QSet<int> pages;
0167     const KBookmark::List bMarks = m_document->bookmarkManager()->bookmarks();
0168     for (const KBookmark &bookmark : bMarks) {
0169         Okular::DocumentViewport viewport(bookmark.url().fragment());
0170         pages << viewport.pageNumber;
0171     }
0172     list = pages.values();
0173     std::sort(list.begin(), list.end());
0174 
0175     QVariantList variantList;
0176     for (const int page : std::as_const(list)) {
0177         variantList << page;
0178     }
0179     return variantList;
0180 }
0181 
0182 QStringList DocumentItem::bookmarks() const
0183 {
0184     QStringList list;
0185     const KBookmark::List bMarks = m_document->bookmarkManager()->bookmarks();
0186     for (const KBookmark &bookmark : bMarks) {
0187         list << bookmark.url().toString();
0188     }
0189     return list;
0190 }
0191 
0192 bool DocumentItem::supportsSearching() const
0193 {
0194     return m_document->supportsSearching();
0195 }
0196 
0197 bool DocumentItem::isSearchInProgress() const
0198 {
0199     return m_searchInProgress;
0200 }
0201 
0202 void DocumentItem::searchText(const QString &text)
0203 {
0204     if (text.isEmpty()) {
0205         resetSearch();
0206         return;
0207     }
0208     m_document->cancelSearch();
0209     m_document->resetSearch(PAGEVIEW_SEARCH_ID);
0210     m_document->searchText(PAGEVIEW_SEARCH_ID, text, true, Qt::CaseInsensitive, Okular::Document::AllDocument, true, QColor(100, 100, 200, 40));
0211 
0212     if (!m_searchInProgress) {
0213         m_searchInProgress = true;
0214         Q_EMIT searchInProgressChanged();
0215     }
0216 }
0217 
0218 void DocumentItem::resetSearch()
0219 {
0220     m_document->resetSearch(PAGEVIEW_SEARCH_ID);
0221     m_matchingPages.clear();
0222     for (uint i = 0; i < m_document->pages(); ++i) {
0223         m_matchingPages << (int)i;
0224     }
0225     if (m_searchInProgress) {
0226         m_searchInProgress = false;
0227         Q_EMIT searchInProgressChanged();
0228     }
0229 
0230     Q_EMIT matchingPagesChanged();
0231 }
0232 
0233 void DocumentItem::setPassword(const QString &password)
0234 {
0235     openUrl(m_document->currentDocument(), password);
0236 }
0237 
0238 Okular::Document *DocumentItem::document()
0239 {
0240     return m_document;
0241 }
0242 
0243 Observer *DocumentItem::thumbnailObserver()
0244 {
0245     if (!m_thumbnailObserver) {
0246         m_thumbnailObserver = new Observer(this);
0247     }
0248 
0249     return m_thumbnailObserver;
0250 }
0251 
0252 Observer *DocumentItem::pageviewObserver()
0253 {
0254     if (!m_pageviewObserver) {
0255         m_pageviewObserver = new Observer(this);
0256     }
0257 
0258     return m_pageviewObserver;
0259 }
0260 
0261 void DocumentItem::searchFinished(int id, Okular::Document::SearchStatus endStatus)
0262 {
0263     Q_UNUSED(endStatus)
0264 
0265     if (id != PAGEVIEW_SEARCH_ID) {
0266         return;
0267     }
0268 
0269     m_matchingPages.clear();
0270     for (uint i = 0; i < m_document->pages(); ++i) {
0271         if (m_document->page(i)->hasHighlights(id)) {
0272             m_matchingPages << (int)i;
0273         }
0274     }
0275 
0276     if (m_searchInProgress) {
0277         m_searchInProgress = false;
0278         Q_EMIT searchInProgressChanged();
0279     }
0280     Q_EMIT matchingPagesChanged();
0281 }
0282 
0283 // Observer
0284 
0285 Observer::Observer(DocumentItem *parent)
0286     : QObject(parent)
0287     , m_document(parent)
0288 {
0289     parent->document()->addObserver(this);
0290 }
0291 
0292 Observer::~Observer()
0293 {
0294 }
0295 
0296 void Observer::notifyPageChanged(int page, int flags)
0297 {
0298     Q_EMIT pageChanged(page, flags);
0299 }