From 8877214d2b9d5c375e79c126bd0b1da2d913b989 Mon Sep 17 00:00:00 2001 From: ShaopengLin Date: Fri, 30 Aug 2024 05:22:50 -0400 Subject: [PATCH 1/5] Enhance urlschemehandler archive entry retrieval Retrieval function now includes parsing of path. Prepares future change. --- src/urlschemehandler.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/urlschemehandler.cpp b/src/urlschemehandler.cpp index 52936d7..a5434e3 100644 --- a/src/urlschemehandler.cpp +++ b/src/urlschemehandler.cpp @@ -18,8 +18,12 @@ UrlSchemeHandler::UrlSchemeHandler() { } -zim::Entry getEntryFromPath(const zim::Archive& archive, const std::string& path) +zim::Entry getArchiveEntryFromUrl(const zim::Archive& archive, const QUrl& url) { + std::string path = url.path().toUtf8().constData(); + if (path[0] == '/') + path = path.substr(1); + try { return archive.getEntryByPath(path); } catch (zim::EntryNotFound& e) { @@ -34,9 +38,6 @@ void UrlSchemeHandler::handleContentRequest(QWebEngineUrlRequestJob *request) { auto qurl = request->requestUrl(); - std::string url = qurl.path().toUtf8().constData(); - if (url[0] == '/') - url = url.substr(1); auto library = KiwixApp::instance()->getLibrary(); auto zim_id = qurl.host(); zim_id.resize(zim_id.length()-4); @@ -48,7 +49,7 @@ UrlSchemeHandler::handleContentRequest(QWebEngineUrlRequestJob *request) return; } try { - auto entry = getEntryFromPath(*archive, url); + auto entry = getArchiveEntryFromUrl(*archive, qurl); auto item = entry.getItem(true); if (entry.isRedirect()) { auto path = QString("/") + QString::fromStdString(item.getPath()); From 6ff4dff484311f7e68b71b5a8367b0e5ca4d23ee Mon Sep 17 00:00:00 2001 From: ShaopengLin Date: Fri, 30 Aug 2024 05:25:17 -0400 Subject: [PATCH 2/5] Add support to save page Page saved as either pdf or file based on content --- resources/i18n/en.json | 3 ++- resources/i18n/qqq.json | 3 ++- src/kiwixapp.cpp | 6 +----- src/kprofile.cpp | 22 ++++++++++++++++++---- src/mainmenu.cpp | 3 --- src/webview.cpp | 25 +++++++++++++++++++++++++ src/webview.h | 2 ++ src/zimview.cpp | 5 +++++ 8 files changed, 55 insertions(+), 14 deletions(-) diff --git a/resources/i18n/en.json b/resources/i18n/en.json index bf89c78..1bbee47 100644 --- a/resources/i18n/en.json +++ b/resources/i18n/en.json @@ -181,5 +181,6 @@ "export-reading-list-error": "An error has occured during export of the reading list.", "import-reading-list": "Import reading list", "import-reading-list-error": "An error has occured during import of the reading list.", - "disable-sandbox": "Application was launched from a network drive. This is known to cause compatibility issues due to the sandbox. Do you want to take the risks and disable it?" + "disable-sandbox": "Application was launched from a network drive. This is known to cause compatibility issues due to the sandbox. Do you want to take the risks and disable it?", + "save-page-as": "Save As..." } diff --git a/resources/i18n/qqq.json b/resources/i18n/qqq.json index f79f280..03d4c07 100644 --- a/resources/i18n/qqq.json +++ b/resources/i18n/qqq.json @@ -188,5 +188,6 @@ "export-reading-list": "Represents the action of exporting the reading list to a file.", "export-reading-list-error": "Error description text for when exporting the reading list to a file failed.", "import-reading-list": "Represents the action of importing a reading list from a file.", - "import-reading-list-error": "Error description text for when importing a reading list from a file failed." + "import-reading-list-error": "Error description text for when importing a reading list from a file failed.", + "save-page-as": "Represents the action of saving the current tab content to a file chosen by the user." } diff --git a/src/kiwixapp.cpp b/src/kiwixapp.cpp index b5f31c4..d764a20 100644 --- a/src/kiwixapp.cpp +++ b/src/kiwixapp.cpp @@ -427,11 +427,7 @@ void KiwixApp::createActions() CREATE_ACTION(OpenRecentAction, gt("open-recent")); HIDE_ACTION(OpenRecentAction); - /* TODO See https://github.com/kiwix/kiwix-desktop/issues/77 - CREATE_ACTION(SavePageAsAction, tr("Save page as ...")); - // SET_SHORTCUT(SavePageAsAction, QKeySequence::SaveAs); - HIDE_ACTION(SavePageAsAction); - */ + CREATE_ACTION_SHORTCUT(SavePageAsAction, gt("save-page-as"), QKeySequence::Save); CREATE_ACTION_SHORTCUTS(SearchArticleAction, gt("search-article"), QList({QKeySequence(Qt::Key_F6), QKeySequence(Qt::CTRL | Qt::Key_L), QKeySequence(Qt::ALT | Qt::Key_D)})); diff --git a/src/kprofile.cpp b/src/kprofile.cpp index fa09dc5..a293a63 100644 --- a/src/kprofile.cpp +++ b/src/kprofile.cpp @@ -24,16 +24,30 @@ void KProfile::startDownload(QWebEngineDownloadItem* download) void KProfile::startDownload(QWebEngineDownloadRequest* download) #endif { - QString defaultFileName = download->url().fileName(); - QString fileName = QFileDialog::getSaveFileName(KiwixApp::instance()->getMainWindow(), - gt("save-file-as-window-title"), defaultFileName); + auto app = KiwixApp::instance(); +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + QString defaultFileName = QUrl(download->path()).fileName(); +#else + QString defaultFileName = download->downloadFileName(); +#endif + QString extension = defaultFileName.section('.', -1); + QString filter = extension != '.' ? "(*" + extension + ")" : ""; + + QString fileName = QFileDialog::getSaveFileName( + app->getMainWindow(), gt("save-file-as-window-title"), + defaultFileName, filter); + if (fileName.isEmpty()) { return; } - QString extension = "." + download->url().url().section('.', -1); if (!fileName.endsWith(extension)) { fileName.append(extension); } + + if (download->isSavePageDownload()) { + download->page()->printToPdf(fileName); + return; + } #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) download->setPath(fileName); #else diff --git a/src/mainmenu.cpp b/src/mainmenu.cpp index 53adeb4..0766671 100644 --- a/src/mainmenu.cpp +++ b/src/mainmenu.cpp @@ -26,10 +26,7 @@ MainMenu::MainMenu(QWidget *parent) : m_fileMenu.ADD_ACTION(OpenRecentAction); m_fileMenu.ADD_ACTION(ExportReadingListAction); m_fileMenu.ADD_ACTION(ImportReadingListAction); - - /* TODO See https://github.com/kiwix/kiwix-desktop/issues/77 m_fileMenu.ADD_ACTION(SavePageAsAction); - */ addMenu(&m_fileMenu); diff --git a/src/webview.cpp b/src/webview.cpp index de17f61..6734690 100644 --- a/src/webview.cpp +++ b/src/webview.cpp @@ -11,9 +11,12 @@ class QMenu; #include #include #include +#include #include #include +zim::Entry getArchiveEntryFromUrl(const zim::Archive& archive, const QUrl& url); + void WebViewBackMenu::showEvent(QShowEvent *) { /* In Qt 5.12 CSS options for shifting this menu didn't work. @@ -131,6 +134,28 @@ QMenu* WebView::getHistoryForwardMenu() const return ret; } +void WebView::saveViewContent() +{ + try { + auto app = KiwixApp::instance(); + auto library = app->getLibrary(); + auto archive = library->getArchive(m_currentZimId); + auto entry = getArchiveEntryFromUrl(*archive, this->url()); + if (entry.isRedirect()) + return; + + auto item = entry.getItem(true); + auto mimeType = QByteArray::fromStdString(item.getMimetype()); + mimeType = mimeType.split(';')[0]; + + if (mimeType == "text/html") + page()->save(QString()); + else + page()->download(this->url()); + } + catch (...) { /* Blank */} +} + void WebView::addHistoryItemAction(QMenu *menu, const QWebEngineHistoryItem &item, int n) const { QAction *a = menu->addAction(item.title()); diff --git a/src/webview.h b/src/webview.h index ca1f560..e241994 100644 --- a/src/webview.h +++ b/src/webview.h @@ -45,6 +45,8 @@ public: QMenu* getHistoryBackMenu() const; QMenu* getHistoryForwardMenu() const; + void saveViewContent(); + public slots: void onUrlChanged(const QUrl& url); diff --git a/src/zimview.cpp b/src/zimview.cpp index 53876d3..3e7af77 100644 --- a/src/zimview.cpp +++ b/src/zimview.cpp @@ -49,6 +49,11 @@ ZimView::ZimView(TabBar *tabBar, QWidget *parent) auto key = mp_webView->zimId() + "/zoomFactor"; settingsManager->deleteSettings(key); }); + connect(app->getAction(KiwixApp::SavePageAsAction), &QAction::triggered, + this, [=](){ + if (mp_tabBar->currentZimView() == this) + mp_webView->saveViewContent(); + }); connect(KiwixApp::instance()->getSettingsManager(), &SettingsManager::zoomChanged, this, [=]() { auto key = mp_webView->zimId() + "/zoomFactor"; auto zimZoomFactor = KiwixApp::instance()->getSettingsManager()->getSettings(key); From 3988067dde5eec3b6af6cdbbaf7376ea3a1f0536 Mon Sep 17 00:00:00 2001 From: ShaopengLin Date: Fri, 30 Aug 2024 05:34:11 -0400 Subject: [PATCH 3/5] Save As remember previous save path Document folder is default. --- src/kiwixapp.cpp | 14 ++++++++++++++ src/kiwixapp.h | 2 ++ src/kprofile.cpp | 4 +++- src/webview.cpp | 5 +++-- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/kiwixapp.cpp b/src/kiwixapp.cpp index d764a20..e2e7510 100644 --- a/src/kiwixapp.cpp +++ b/src/kiwixapp.cpp @@ -19,6 +19,8 @@ #include #endif +const QString DEFAULT_SAVE_DIR = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); + //////////////////////////////////////////////////////////////////////////////// // KiwixApp //////////////////////////////////////////////////////////////////////////////// @@ -565,3 +567,15 @@ void KiwixApp::saveCurrentTabIndex() { return mp_session->setValue("currentTabIndex", getTabWidget()->currentIndex()); } + +void KiwixApp::savePrevSaveDir(const QString &prevSaveDir) +{ + mp_session->setValue("prevSaveDir", prevSaveDir); +} + +QString KiwixApp::getPrevSaveDir() const +{ + QString prevSaveDir = mp_session->value("prevSaveDir", DEFAULT_SAVE_DIR).toString(); + QDir dir(prevSaveDir); + return dir.exists() ? prevSaveDir : DEFAULT_SAVE_DIR; +} diff --git a/src/kiwixapp.h b/src/kiwixapp.h index 8c74229..aa5738d 100644 --- a/src/kiwixapp.h +++ b/src/kiwixapp.h @@ -93,6 +93,8 @@ public: void saveWindowState(); void restoreWindowState(); void saveCurrentTabIndex(); + void savePrevSaveDir(const QString& prevSaveDir); + QString getPrevSaveDir() const; public slots: void newTab(); diff --git a/src/kprofile.cpp b/src/kprofile.cpp index a293a63..d1297c2 100644 --- a/src/kprofile.cpp +++ b/src/kprofile.cpp @@ -30,12 +30,13 @@ void KProfile::startDownload(QWebEngineDownloadRequest* download) #else QString defaultFileName = download->downloadFileName(); #endif + QString suggestedPath = app->getPrevSaveDir() + "/" + defaultFileName; QString extension = defaultFileName.section('.', -1); QString filter = extension != '.' ? "(*" + extension + ")" : ""; QString fileName = QFileDialog::getSaveFileName( app->getMainWindow(), gt("save-file-as-window-title"), - defaultFileName, filter); + suggestedPath, filter); if (fileName.isEmpty()) { return; @@ -43,6 +44,7 @@ void KProfile::startDownload(QWebEngineDownloadRequest* download) if (!fileName.endsWith(extension)) { fileName.append(extension); } + app->savePrevSaveDir(QFileInfo(fileName).absolutePath()); if (download->isSavePageDownload()) { download->page()->printToPdf(fileName); diff --git a/src/webview.cpp b/src/webview.cpp index 6734690..8cee5c6 100644 --- a/src/webview.cpp +++ b/src/webview.cpp @@ -148,10 +148,11 @@ void WebView::saveViewContent() auto mimeType = QByteArray::fromStdString(item.getMimetype()); mimeType = mimeType.split(';')[0]; + QString suggestedFileName = item.getTitle().c_str(); if (mimeType == "text/html") - page()->save(QString()); + page()->save(suggestedFileName + ".pdf"); else - page()->download(this->url()); + page()->download(this->url(), suggestedFileName); } catch (...) { /* Blank */} } From fc029c7fe3dedbbaa92e0b01afbbd90290330726 Mon Sep 17 00:00:00 2001 From: ShaopengLin Date: Fri, 30 Aug 2024 05:35:00 -0400 Subject: [PATCH 4/5] Sanitizes file name suggestion Convert reserved chars to '_' before parsing --- src/webview.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/webview.cpp b/src/webview.cpp index 8cee5c6..6ddb043 100644 --- a/src/webview.cpp +++ b/src/webview.cpp @@ -14,6 +14,7 @@ class QMenu; #include #include #include +#include zim::Entry getArchiveEntryFromUrl(const zim::Archive& archive, const QUrl& url); @@ -148,7 +149,10 @@ void WebView::saveViewContent() auto mimeType = QByteArray::fromStdString(item.getMimetype()); mimeType = mimeType.split(';')[0]; - QString suggestedFileName = item.getTitle().c_str(); + /* We have to sanitize here, as parsing will start once we pass the file + name to either save or download method. + */ + QString suggestedFileName = QString::fromStdString(kiwix::getSlugifiedFileName(item.getTitle())); if (mimeType == "text/html") page()->save(suggestedFileName + ".pdf"); else From 7fcd6b52561261d59b59d0396e25a0ed990244e9 Mon Sep 17 00:00:00 2001 From: ShaopengLin Date: Fri, 30 Aug 2024 05:35:26 -0400 Subject: [PATCH 5/5] Added Save Page to context menu --- src/webview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/webview.cpp b/src/webview.cpp index 6ddb043..28b979b 100644 --- a/src/webview.cpp +++ b/src/webview.cpp @@ -271,6 +271,7 @@ QMenu* WebView::createStandardContextMenu() { KiwixApp::instance()->getTabWidget()->triggerWebPageAction(QWebEnginePage::Forward); }); + menu->addAction(app->getAction(KiwixApp::SavePageAsAction)); return menu; }