some minor enhancements for OPML import + gmail email viewer uses skin styling, same as classic articles
This commit is contained in:
parent
163f012b71
commit
932222bf58
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include <QDomDocument>
|
||||
#include <QDomElement>
|
||||
#include <QLocale>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlError>
|
||||
#include <QStack>
|
||||
#include <QtConcurrent/QtConcurrentMap>
|
||||
|
||||
@ -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<QIcon>();
|
||||
StandardFeed::SourceType source_type = feed_lookup.custom_data["sourceType"].value<StandardFeed::SourceType>();
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -38,8 +38,7 @@
|
||||
#include <QStack>
|
||||
#include <QTextCodec>
|
||||
|
||||
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<Message> StandardServiceRoot::obtainNewMessages(Feed* feed,
|
||||
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
|
||||
const QHash<ServiceRoot::BagOfMessages, QStringList>&
|
||||
stated_messages,
|
||||
const QHash<QString, QStringList>& tagged_messages) {
|
||||
Q_UNUSED(stated_messages)
|
||||
Q_UNUSED(tagged_messages)
|
||||
@ -154,10 +160,7 @@ QList<Message> 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<QPair<QByteArray, QByteArray>> headers;
|
||||
@ -173,14 +176,12 @@ QList<Message> 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<Message> 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<Message> StandardServiceRoot::obtainNewMessages(Feed* feed,
|
||||
QList<QAction*> 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<StandardFeed*>(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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user