From 932222bf58464c9891a432ba7cd68f151bacae06 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 16 Mar 2023 07:37:49 +0100 Subject: [PATCH] some minor enhancements for OPML import + gmail email viewer uses skin styling, same as classic articles --- .../services/gmail/gui/emailpreviewer.cpp | 2 +- .../standard/gui/formstandardimportexport.cpp | 47 ++++++---- .../standardfeedsimportexportmodel.cpp | 39 +++++--- .../standard/standardfeedsimportexportmodel.h | 2 +- .../services/standard/standardserviceroot.cpp | 92 ++++++++----------- 5 files changed, 93 insertions(+), 89 deletions(-) diff --git a/src/librssguard/services/gmail/gui/emailpreviewer.cpp b/src/librssguard/services/gmail/gui/emailpreviewer.cpp index 9191e6605..91dfcd8c8 100644 --- a/src/librssguard/services/gmail/gui/emailpreviewer.cpp +++ b/src/librssguard/services/gmail/gui/emailpreviewer.cpp @@ -52,7 +52,7 @@ void EmailPreviewer::loadMessage(const Message& msg, RootItem* selected_item) { Q_UNUSED(selected_item) m_message = msg; - m_webView->setHtml(msg.m_contents); + m_webView->loadMessages({msg}, selected_item); m_ui.m_tbFrom->setText(msg.m_author); m_ui.m_tbSubject->setText(msg.m_title); diff --git a/src/librssguard/services/standard/gui/formstandardimportexport.cpp b/src/librssguard/services/standard/gui/formstandardimportexport.cpp index 4140afab4..85ecb3295 100644 --- a/src/librssguard/services/standard/gui/formstandardimportexport.cpp +++ b/src/librssguard/services/standard/gui/formstandardimportexport.cpp @@ -130,22 +130,21 @@ void FormStandardImportExport::onParsingFinished(int count_failed, int count_suc m_ui->m_progressBar->setValue(0); m_model->checkAllItems(); - if (count_failed > 0 && count_succeeded == 0) { - m_ui->m_groupFeeds->setEnabled(false); - m_ui->m_groupFetchMetadata->setEnabled(false); - m_ui->m_lblResult->setStatus(WidgetWithStatus::StatusType::Error, - tr("Some feeds were not loaded properly or import file is corrupted."), - tr("Some feeds were not loaded properly or import file is corrupted.")); + if (count_failed > 0) { + m_ui->m_lblResult->setStatus(WidgetWithStatus::StatusType::Warning, + tr("Some feeds were not loaded properly. Check log for more information."), + tr("Some feeds were not loaded properly. Check log for more information.")); } else { m_ui->m_lblResult->setStatus(WidgetWithStatus::StatusType::Ok, tr("Feeds were loaded."), tr("Feeds were loaded.")); - m_ui->m_groupFeeds->setEnabled(true); - m_ui->m_groupFetchMetadata->setEnabled(true); - m_ui->m_btnSelectFile->setEnabled(true); - m_ui->m_treeFeeds->setModel(m_model); - m_ui->m_treeFeeds->expandAll(); } + m_ui->m_groupFeeds->setEnabled(true); + m_ui->m_groupFetchMetadata->setEnabled(true); + m_ui->m_btnSelectFile->setEnabled(true); + m_ui->m_treeFeeds->setModel(m_model); + m_ui->m_treeFeeds->expandAll(); + m_ui->m_buttonBox->button(QDialogButtonBox::StandardButton::Ok)->setEnabled(true); } @@ -215,13 +214,13 @@ void FormStandardImportExport::selectExportFile(bool without_dialog) { void FormStandardImportExport::selectImportFile() { const QString filter_opml20 = tr("OPML 2.0 files (*.opml *.xml)"); const QString filter_txt_url_per_line = tr("TXT files [one URL per line] (*.txt)"); + QString filter; QString selected_filter; // Add more filters here. - filter += filter_opml20; - filter += QSL(";;"); - filter += filter_txt_url_per_line; + filter += filter_opml20 + QSL(";;") + filter_txt_url_per_line; + const QString selected_file = QFileDialog::getOpenFileName(this, tr("Select file for feeds import"), qApp->homeFolder(), @@ -240,13 +239,24 @@ void FormStandardImportExport::selectImportFile() { QDir::toNativeSeparators(selected_file), tr("File is selected.")); - parseImportFile(selected_file, m_ui->m_groupFetchMetadata->isChecked()); + try { + parseImportFile(selected_file, m_ui->m_groupFetchMetadata->isChecked()); + } + catch (const ApplicationException& ex) { + m_ui->m_btnSelectFile->setEnabled(true); + m_ui->m_progressBar->setVisible(false); + m_ui->m_progressBar->setValue(0); + m_ui->m_groupFeeds->setEnabled(false); + m_ui->m_groupFetchMetadata->setEnabled(true); + + m_ui->m_lblResult->setStatus(WidgetWithStatus::StatusType::Error, ex.message(), ex.message()); + } } } void FormStandardImportExport::parseImportFile(const QString& file_name, bool fetch_metadata_online) { - QFile input_file(file_name); QByteArray input_data; + QFile input_file(file_name); if (input_file.open(QIODevice::OpenModeFlag::Text | QIODevice::OpenModeFlag::Unbuffered | QIODevice::OpenModeFlag::ReadOnly)) { @@ -254,10 +264,7 @@ void FormStandardImportExport::parseImportFile(const QString& file_name, bool fe input_file.close(); } else { - m_ui->m_lblResult->setStatus(WidgetWithStatus::StatusType::Error, - tr("Cannot open source file."), - tr("Cannot open source file.")); - return; + throw ApplicationException(tr("cannot open file")); } switch (m_conversionType) { diff --git a/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp b/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp index e6050ba83..a3b0de700 100644 --- a/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp +++ b/src/librssguard/services/standard/standardfeedsimportexportmodel.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -192,7 +194,7 @@ bool FeedsImportExportModel::produceFeed(const FeedLookup& feed_lookup) { else { new_feed = new StandardFeed(); - if (feed_lookup.opml_element.isNull()) { + if (feed_lookup.custom_data.isEmpty()) { new_feed->setSource(feed_lookup.url); new_feed->setTitle(feed_lookup.url); new_feed->setIcon(qApp->icons()->fromTheme(QSL("application-rss+xml"))); @@ -200,15 +202,13 @@ bool FeedsImportExportModel::produceFeed(const FeedLookup& feed_lookup) { new_feed->setPostProcessScript(feed_lookup.post_process_script); } else { - QString feed_title = feed_lookup.opml_element.attribute(QSL("text")); - QString feed_encoding = feed_lookup.opml_element.attribute(QSL("encoding"), QSL(DEFAULT_FEED_ENCODING)); - QString feed_type = feed_lookup.opml_element.attribute(QSL("version"), QSL(DEFAULT_FEED_TYPE)).toUpper(); - QString feed_description = feed_lookup.opml_element.attribute(QSL("description")); - QIcon feed_icon = - qApp->icons()->fromByteArray(feed_lookup.opml_element.attribute(QSL("rssguard:icon")).toLocal8Bit()); - StandardFeed::SourceType source_type = - StandardFeed::SourceType(feed_lookup.opml_element.attribute(QSL("rssguard:xmlUrlType")).toInt()); - QString post_process = feed_lookup.opml_element.attribute(QSL("rssguard:postProcess")); + QString feed_title = feed_lookup.custom_data[QSL("title")].toString(); + QString feed_encoding = feed_lookup.custom_data.value(QSL("encoding"), QSL(DEFAULT_FEED_ENCODING)).toString(); + QString feed_type = feed_lookup.custom_data.value(QSL("feedType"), QSL(DEFAULT_FEED_TYPE)).toString().toUpper(); + QString feed_description = feed_lookup.custom_data[QSL("description")].toString(); + QIcon feed_icon = feed_lookup.custom_data[QSL("icon")].value(); + StandardFeed::SourceType source_type = feed_lookup.custom_data["sourceType"].value(); + QString post_process = feed_lookup.custom_data[QSL("postProcessScript")].toString(); new_feed->setTitle(feed_title); new_feed->setDescription(feed_description); @@ -265,13 +265,12 @@ void FeedsImportExportModel::importAsOPML20(const QByteArray& data, QDomDocument opml_document; if (!opml_document.setContent(data)) { - emit parsingFinished(0, 0); + throw ApplicationException(tr("OPML document contains errors")); } if (opml_document.documentElement().isNull() || opml_document.documentElement().tagName() != QSL("opml") || opml_document.documentElement().elementsByTagName(QSL("body")).size() != 1) { - // This really is not an OPML file. - emit parsingFinished(0, 0); + throw ApplicationException(tr("this is likely not OPML document")); } int completed = 0, total = 0; @@ -311,10 +310,22 @@ void FeedsImportExportModel::importAsOPML20(const QByteArray& data, if (!feed_url.isEmpty()) { FeedLookup f; + QVariantMap feed_data; + + feed_data["title"] = child_element.attribute(QSL("text")); + feed_data["encoding"] = child_element.attribute(QSL("encoding"), QSL(DEFAULT_FEED_ENCODING)); + feed_data["type"] = child_element.attribute(QSL("version"), QSL(DEFAULT_FEED_TYPE)).toUpper(); + feed_data["description"] = child_element.attribute(QSL("description")); + feed_data["icon"] = + qApp->icons()->fromByteArray(child_element.attribute(QSL("rssguard:icon")).toLocal8Bit()); + feed_data["sourceType"] = + QVariant::fromValue(StandardFeed::SourceType(child_element.attribute(QSL("rssguard:xmlUrlType")) + .toInt())); + feed_data["postProcessScript"] = child_element.attribute(QSL("rssguard:postProcess")); f.custom_proxy = custom_proxy; f.fetch_metadata_online = fetch_metadata_online; - f.opml_element = child_element; + f.custom_data = feed_data; f.parent = active_model_item; f.post_process_script = post_process_script; f.url = feed_url; diff --git a/src/librssguard/services/standard/standardfeedsimportexportmodel.h b/src/librssguard/services/standard/standardfeedsimportexportmodel.h index d03e52b6a..1bb818820 100644 --- a/src/librssguard/services/standard/standardfeedsimportexportmodel.h +++ b/src/librssguard/services/standard/standardfeedsimportexportmodel.h @@ -13,7 +13,7 @@ class StandardFeed; struct FeedLookup { RootItem* parent; - QDomElement opml_element; + QVariantMap custom_data; QString url; bool fetch_metadata_online; QNetworkProxy custom_proxy; diff --git a/src/librssguard/services/standard/standardserviceroot.cpp b/src/librssguard/services/standard/standardserviceroot.cpp index f9a2e6698..24763c457 100644 --- a/src/librssguard/services/standard/standardserviceroot.cpp +++ b/src/librssguard/services/standard/standardserviceroot.cpp @@ -38,8 +38,7 @@ #include #include -StandardServiceRoot::StandardServiceRoot(RootItem* parent) - : ServiceRoot(parent) { +StandardServiceRoot::StandardServiceRoot(RootItem* parent) : ServiceRoot(parent) { setTitle(qApp->system()->loggedInUser() + QSL(" (RSS/ATOM/JSON)")); setIcon(StandardServiceEntryPoint().icon()); setDescription(tr("This is obligatory service account for standard RSS/RDF/ATOM feeds.")); @@ -54,10 +53,13 @@ void StandardServiceRoot::start(bool freshly_activated) { if (freshly_activated && getSubTreeFeeds().isEmpty()) { // In other words, if there are no feeds or categories added. - if (MsgBox::show(qApp->mainFormWidget(), QMessageBox::Question, QObject::tr("Load initial set of feeds"), + if (MsgBox::show(qApp->mainFormWidget(), + QMessageBox::Question, + QObject::tr("Load initial set of feeds"), tr("This new account does not include any feeds. You can now add default set of feeds."), tr("Do you want to load initial set of feeds?"), - QString(), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + QString(), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { QString target_opml_file = APP_INITIAL_FEEDS_PATH + QDir::separator() + FEED_INITIAL_OPML_PATTERN; QString current_locale = qApp->localization()->loadedLanguage(); QString file_to_load; @@ -81,11 +83,14 @@ void StandardServiceRoot::start(bool freshly_activated) { } } catch (ApplicationException& ex) { - MsgBox::show(qApp->mainFormWidget(), QMessageBox::Critical, tr("Error when loading initial feeds"), ex.message()); + MsgBox::show(qApp->mainFormWidget(), + QMessageBox::Critical, + tr("Error when loading initial feeds"), + ex.message()); } } else { - requestItemExpand({ this }, true); + requestItemExpand({this}, true); } } } @@ -122,10 +127,10 @@ void StandardServiceRoot::addNewFeed(RootItem* selected_item, const QString& url // Lock was not obtained because // it is used probably by feed updater or application // is quitting. - qApp->showGuiMessage(Notification::Event::GeneralEvent, { - tr("Cannot add item"), - tr("Cannot add feed because another critical operation is ongoing."), - QSystemTrayIcon::MessageIcon::Warning }); + qApp->showGuiMessage(Notification::Event::GeneralEvent, + {tr("Cannot add item"), + tr("Cannot add feed because another critical operation is ongoing."), + QSystemTrayIcon::MessageIcon::Warning}); return; } @@ -144,7 +149,8 @@ Qt::ItemFlags StandardServiceRoot::additionalFlags() const { } QList StandardServiceRoot::obtainNewMessages(Feed* feed, - const QHash& stated_messages, + const QHash& + stated_messages, const QHash& tagged_messages) { Q_UNUSED(stated_messages) Q_UNUSED(tagged_messages) @@ -154,10 +160,7 @@ QList StandardServiceRoot::obtainNewMessages(Feed* feed, int download_timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); if (f->sourceType() == StandardFeed::SourceType::Url) { - qDebugNN << LOGSEC_CORE - << "Downloading URL" - << QUOTE_W_SPACE(feed->source()) - << "to obtain feed data."; + qDebugNN << LOGSEC_CORE << "Downloading URL" << QUOTE_W_SPACE(feed->source()) << "to obtain feed data."; QByteArray feed_contents; QList> headers; @@ -173,14 +176,12 @@ QList StandardServiceRoot::obtainNewMessages(Feed* feed, false, {}, {}, - networkProxy()).m_networkError; + networkProxy()) + .m_networkError; if (network_result != QNetworkReply::NetworkError::NoError) { - qWarningNN << LOGSEC_CORE - << "Error" - << QUOTE_W_SPACE(network_result) - << "during fetching of new messages for feed" - << QUOTE_W_SPACE_DOT(feed->source()); + qWarningNN << LOGSEC_CORE << "Error" << QUOTE_W_SPACE(network_result) + << "during fetching of new messages for feed" << QUOTE_W_SPACE_DOT(feed->source()); throw FeedFetchException(Feed::Status::NetworkError, NetworkFactory::networkErrorText(network_result)); } @@ -197,38 +198,29 @@ QList StandardServiceRoot::obtainNewMessages(Feed* feed, } } else { - qDebugNN << LOGSEC_CORE - << "Running custom script" - << QUOTE_W_SPACE(feed->source()) - << "to obtain feed data."; + qDebugNN << LOGSEC_CORE << "Running custom script" << QUOTE_W_SPACE(feed->source()) << "to obtain feed data."; // Use script to generate feed file. try { formatted_feed_contents = StandardFeed::generateFeedFileWithScript(feed->source(), download_timeout); } catch (const ScriptException& ex) { - qCriticalNN << LOGSEC_CORE - << "Custom script for generating feed file failed:" - << QUOTE_W_SPACE_DOT(ex.message()); + qCriticalNN << LOGSEC_CORE << "Custom script for generating feed file failed:" << QUOTE_W_SPACE_DOT(ex.message()); throw FeedFetchException(Feed::Status::OtherError, ex.message()); } } if (!f->postProcessScript().simplified().isEmpty()) { - qDebugNN << LOGSEC_CORE - << "We will process feed data with post-process script" + qDebugNN << LOGSEC_CORE << "We will process feed data with post-process script" << QUOTE_W_SPACE_DOT(f->postProcessScript()); try { - formatted_feed_contents = StandardFeed::postProcessFeedFileWithScript(f->postProcessScript(), - formatted_feed_contents, - download_timeout); + formatted_feed_contents = + StandardFeed::postProcessFeedFileWithScript(f->postProcessScript(), formatted_feed_contents, download_timeout); } catch (const ScriptException& ex) { - qCriticalNN << LOGSEC_CORE - << "Post-processing script for feed file failed:" - << QUOTE_W_SPACE_DOT(ex.message()); + qCriticalNN << LOGSEC_CORE << "Post-processing script for feed file failed:" << QUOTE_W_SPACE_DOT(ex.message()); throw FeedFetchException(Feed::Status::OtherError, ex.message()); } @@ -270,9 +262,8 @@ QList StandardServiceRoot::obtainNewMessages(Feed* feed, QList StandardServiceRoot::getContextMenuForFeed(StandardFeed* feed) { if (m_feedContextMenu.isEmpty()) { // Initialize. - auto* action_metadata = new QAction(qApp->icons()->fromTheme(QSL("download"), QSL("emblem-downloads")), - tr("Fetch metadata"), - this); + auto* action_metadata = + new QAction(qApp->icons()->fromTheme(QSL("download"), QSL("emblem-downloads")), tr("Fetch metadata"), this); m_feedContextMenu.append(action_metadata); @@ -297,6 +288,8 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model, new_parents.push(model->sourceModel()->rootItem()); bool some_feed_category_error = false; + QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className()); + // Iterate all new items we would like to merge into current model. while (!new_parents.isEmpty()) { RootItem* target_parent = original_parents.pop(); @@ -318,8 +311,6 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model, // Add category to model. new_category->clearChildren(); - QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className()); - try { DatabaseQueries::createOverwriteCategory(database, new_category, @@ -350,9 +341,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model, else { some_feed_category_error = true; - qCriticalNN << LOGSEC_CORE - << "Cannot import category:" - << QUOTE_W_SPACE_DOT(ex.message()); + qCriticalNN << LOGSEC_CORE << "Cannot import category:" << QUOTE_W_SPACE_DOT(ex.message()); } } } @@ -360,7 +349,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model, auto* source_feed = qobject_cast(source_item); const auto* feed_with_same_url = target_root_node->getItemFromSubTree([source_feed](const RootItem* it) { return it->kind() == RootItem::Kind::Feed && - it->toFeed()->source().toLower() == source_feed->source().toLower(); + it->toFeed()->source().toLower() == source_feed->source().toLower(); }); if (feed_with_same_url != nullptr) { @@ -368,7 +357,6 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model, } auto* new_feed = new StandardFeed(*source_feed); - QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className()); try { DatabaseQueries::createOverwriteFeed(database, @@ -378,9 +366,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model, requestItemReassignment(new_feed, target_parent); } catch (const ApplicationException& ex) { - qCriticalNN << LOGSEC_CORE - << "Cannot import feed:" - << QUOTE_W_SPACE_DOT(ex.message()); + qCriticalNN << LOGSEC_CORE << "Cannot import feed:" << QUOTE_W_SPACE_DOT(ex.message()); some_feed_category_error = true; } } @@ -402,10 +388,10 @@ void StandardServiceRoot::addNewCategory(RootItem* selected_item) { // Lock was not obtained because // it is used probably by feed updater or application // is quitting. - qApp->showGuiMessage(Notification::Event::GeneralEvent, { - tr("Cannot add category"), - tr("Cannot add category because another critical operation is ongoing."), - QSystemTrayIcon::MessageIcon::Warning }); + qApp->showGuiMessage(Notification::Event::GeneralEvent, + {tr("Cannot add category"), + tr("Cannot add category because another critical operation is ongoing."), + QSystemTrayIcon::MessageIcon::Warning}); // Thus, cannot delete and quit the method. return;