From 8e86655beb09ab0af93c6df0415bb9118a27fecc Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 5 Jan 2016 08:12:15 +0100 Subject: [PATCH 1/8] Work on better parsing of input import data. --- src/gui/widgetwithstatus.cpp | 5 ++ src/gui/widgetwithstatus.h | 4 +- .../standard/gui/formstandardimportexport.cpp | 59 ++++++++++++------ .../standard/gui/formstandardimportexport.h | 4 ++ .../standard/gui/formstandardimportexport.ui | 10 +++ src/services/standard/standardfeed.cpp | 4 +- src/services/standard/standardfeed.h | 4 +- .../standardfeedsimportexportmodel.cpp | 62 +++++++++++++------ .../standard/standardfeedsimportexportmodel.h | 13 +++- 9 files changed, 122 insertions(+), 43 deletions(-) mode change 100644 => 100755 src/gui/widgetwithstatus.h diff --git a/src/gui/widgetwithstatus.cpp b/src/gui/widgetwithstatus.cpp index 4b71fdf42..257f2c9a3 100755 --- a/src/gui/widgetwithstatus.cpp +++ b/src/gui/widgetwithstatus.cpp @@ -29,6 +29,7 @@ WidgetWithStatus::WidgetWithStatus(QWidget *parent) m_btnStatus = new PlainToolButton(this); m_btnStatus->setFocusPolicy(Qt::NoFocus); + m_iconProgress = qApp->icons()->fromTheme(QSL("item-sync")); m_iconInformation = qApp->icons()->fromTheme(QSL("dialog-information")); m_iconWarning = qApp->icons()->fromTheme(QSL("dialog-warning")); m_iconError = qApp->icons()->fromTheme(QSL("dialog-error")); @@ -52,6 +53,10 @@ void WidgetWithStatus::setStatus(WidgetWithStatus::StatusType status, const QStr m_btnStatus->setIcon(m_iconInformation); break; + case Progress: + m_btnStatus->setIcon(m_iconProgress); + break; + case Warning: m_btnStatus->setIcon(m_iconWarning); break; diff --git a/src/gui/widgetwithstatus.h b/src/gui/widgetwithstatus.h old mode 100644 new mode 100755 index 5bf6b0e66..4afd3b487 --- a/src/gui/widgetwithstatus.h +++ b/src/gui/widgetwithstatus.h @@ -33,7 +33,8 @@ class WidgetWithStatus : public QWidget { Information, Warning, Error, - Ok + Ok, + Progress }; // Constructors and destructors. @@ -53,6 +54,7 @@ class WidgetWithStatus : public QWidget { PlainToolButton *m_btnStatus; QHBoxLayout *m_layout; + QIcon m_iconProgress; QIcon m_iconInformation; QIcon m_iconWarning; QIcon m_iconError; diff --git a/src/services/standard/gui/formstandardimportexport.cpp b/src/services/standard/gui/formstandardimportexport.cpp index 0caa17475..9b508303f 100755 --- a/src/services/standard/gui/formstandardimportexport.cpp +++ b/src/services/standard/gui/formstandardimportexport.cpp @@ -36,6 +36,10 @@ FormStandardImportExport::FormStandardImportExport(StandardServiceRoot *service_ m_ui->setupUi(this); m_model = new FeedsImportExportModel(m_ui->m_treeFeeds); + connect(m_model, SIGNAL(parsingStarted()), this, SLOT(onParsingStarted())); + connect(m_model, SIGNAL(parsingFinished(int,int,bool)), this, SLOT(onParsingFinished(int,int,bool))); + connect(m_model, SIGNAL(parsingProgress(int,int)), this, SLOT(onParsingProgress(int,int))); + setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint); m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Error, tr("No file is selected."), tr("No file is selected.")); @@ -100,6 +104,41 @@ void FormStandardImportExport::selectFile() { } } +void FormStandardImportExport::onParsingStarted() { + m_ui->m_lblResult->setStatus(WidgetWithStatus::Progress, tr("Parsing data..."), tr("Parsing data...")); + m_ui->m_btnSelectFile->setEnabled(false); + m_ui->m_progressBar->setEnabled(true); + m_ui->m_progressBar->setValue(0); +} + +void FormStandardImportExport::onParsingFinished(int count_failed, int count_succeeded, bool parsing_error) { + Q_UNUSED(count_failed) + Q_UNUSED(count_succeeded) + + m_ui->m_progressBar->setValue(0); + m_ui->m_progressBar->setEnabled(false); + m_model->checkAllItems(); + + if (!parsing_error) { + m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, tr("Feeds were loaded."), tr("Feeds were loaded.")); + m_ui->m_groupFeeds->setEnabled(true); + m_ui->m_btnSelectFile->setEnabled(true); + m_ui->m_treeFeeds->setModel(m_model); + m_ui->m_treeFeeds->expandAll(); + } + else { + m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, tr("Error, file is not well-formed. Select another file."), + tr("Error occurred. File is not well-formed. Select another file.")); + } + + m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!parsing_error); +} + +void FormStandardImportExport::onParsingProgress(int completed, int total) { + m_ui->m_progressBar->setMaximum(total); + m_ui->m_progressBar->setValue(completed); +} + void FormStandardImportExport::selectExportFile() { QString filter_opml20 = tr("OPML 2.0 files (*.opml)"); QString filter_txt_url_per_line = tr("TXT files (one URL per line) (*.txt)"); @@ -162,7 +201,6 @@ void FormStandardImportExport::selectImportFile() { m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(selected_file), tr("File is selected.")); parseImportFile(selected_file); - m_model->checkAllItems(); } } @@ -179,15 +217,13 @@ void FormStandardImportExport::parseImportFile(const QString &file_name) { return; } - bool parsing_result; - switch (m_conversionType) { case OPML20: - parsing_result = m_model->importAsOPML20(input_data); + m_model->importAsOPML20(input_data); break; case TXTUrlPerLine: - parsing_result = m_model->importAsTxtURLPerLine(input_data); + m_model->importAsTxtURLPerLine(input_data); break; // TODO: V celém kódu nově zavést pořádně všude const, i v lokálních metodových proměnných @@ -198,19 +234,6 @@ void FormStandardImportExport::parseImportFile(const QString &file_name) { default: return; } - - if (parsing_result) { - m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, tr("Feeds were loaded."), tr("Feeds were loaded.")); - m_ui->m_groupFeeds->setEnabled(true); - m_ui->m_treeFeeds->setModel(m_model); - m_ui->m_treeFeeds->expandAll(); - } - else { - m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, tr("Error, file is not well-formed. Select another file."), - tr("Error occurred. File is not well-formed. Select another file.")); - } - - m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(parsing_result); } void FormStandardImportExport::performAction() { diff --git a/src/services/standard/gui/formstandardimportexport.h b/src/services/standard/gui/formstandardimportexport.h index 237ff08e1..209c20800 100755 --- a/src/services/standard/gui/formstandardimportexport.h +++ b/src/services/standard/gui/formstandardimportexport.h @@ -48,6 +48,10 @@ class FormStandardImportExport : public QDialog { void performAction(); void selectFile(); + void onParsingStarted(); + void onParsingFinished(int count_failed, int count_succeeded, bool parsing_error); + void onParsingProgress(int completed, int total); + private: void selectExportFile(); void selectImportFile(); diff --git a/src/services/standard/gui/formstandardimportexport.ui b/src/services/standard/gui/formstandardimportexport.ui index 53b635d74..671a9dd2d 100755 --- a/src/services/standard/gui/formstandardimportexport.ui +++ b/src/services/standard/gui/formstandardimportexport.ui @@ -114,6 +114,16 @@ + + + + false + + + 0 + + + diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index f7a200997..297ce3480 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -282,7 +282,9 @@ void StandardFeed::fetchMetadataForItself() { } } -QPair StandardFeed::guessFeed(const QString &url, const QString &username, const QString &password) { +QPair StandardFeed::guessFeed(const QString &url, + const QString &username, + const QString &password) { QPair result; result.first = NULL; QByteArray feed_contents; diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index f11b6afd6..303c66916 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -145,7 +145,9 @@ class StandardFeed : public Feed { // Returns pointer to guessed feed (if at least partially // guessed) and retrieved error/status code from network layer // or NULL feed. - static QPair guessFeed(const QString &url, const QString &username, const QString &password); + static QPair guessFeed(const QString &url, + const QString &username = QString(), + const QString &password = QString()); // Converts particular feed type to string. static QString typeToString(Type type); diff --git a/src/services/standard/standardfeedsimportexportmodel.cpp b/src/services/standard/standardfeedsimportexportmodel.cpp index 5702c2616..fb57a9d90 100755 --- a/src/services/standard/standardfeedsimportexportmodel.cpp +++ b/src/services/standard/standardfeedsimportexportmodel.cpp @@ -154,19 +154,22 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray &result) { return true; } -bool FeedsImportExportModel::importAsOPML20(const QByteArray &data) { +void FeedsImportExportModel::importAsOPML20(const QByteArray &data) { + emit parsingStarted(); + QDomDocument opml_document; if (!opml_document.setContent(data)) { - return false; + emit parsingFinished(0, 0, true); } 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. - return false; + emit parsingFinished(0, 0, true); } + int completed = 0, total = 0; StandardServiceRoot *root_item = new StandardServiceRoot(); QStack model_items; model_items.push(root_item); QStack elements_to_process; elements_to_process.push(opml_document.documentElement().elementsByTagName(QSL("body")).at(0).toElement()); @@ -175,7 +178,10 @@ bool FeedsImportExportModel::importAsOPML20(const QByteArray &data) { RootItem *active_model_item = model_items.pop(); QDomElement active_element = elements_to_process.pop(); - for (int i = 0; i < active_element.childNodes().size(); i++) { + int current_count = active_element.childNodes().size(); + total += current_count; + + for (int i = 0; i < current_count; i++) { QDomNode child = active_element.childNodes().at(i); if (child.isElement()) { @@ -242,6 +248,8 @@ bool FeedsImportExportModel::importAsOPML20(const QByteArray &data) { elements_to_process.push(child_element); model_items.push(new_category); } + + emit parsingProgress(++completed, total); } } } @@ -250,8 +258,7 @@ bool FeedsImportExportModel::importAsOPML20(const QByteArray &data) { emit layoutAboutToBeChanged(); setRootItem(root_item); emit layoutChanged(); - - return true; + emit parsingFinished(0, completed, false); } bool FeedsImportExportModel::exportToTxtURLPerLine(QByteArray &result) { @@ -262,32 +269,49 @@ bool FeedsImportExportModel::exportToTxtURLPerLine(QByteArray &result) { return true; } -bool FeedsImportExportModel::importAsTxtURLPerLine(const QByteArray &data) { +void FeedsImportExportModel::importAsTxtURLPerLine(const QByteArray &data) { + emit parsingStarted(); + + int completed = 0, succeded = 0, failed = 0; StandardServiceRoot *root_item = new StandardServiceRoot(); + QList urls = data.split('\n'); - foreach (const QByteArray &url, data.split('\n')) { + foreach (const QByteArray &url, urls) { if (!url.isEmpty()) { + QPair guessed = StandardFeed::guessFeed(url); - StandardFeed *feed = new StandardFeed(); + if (guessed.second == QNetworkReply::NoError) { + guessed.first->setUrl(url); + root_item->appendChild(guessed.first); + succeded++; + } + else { + StandardFeed *feed = new StandardFeed(); - // TODO: co guessovat ten feed? + feed->setUrl(url); + feed->setTitle(url); + feed->setCreationDate(QDateTime::currentDateTime()); + feed->setIcon(qApp->icons()->fromTheme(QSL("folder-feed"))); + feed->setEncoding(DEFAULT_FEED_ENCODING); + root_item->appendChild(feed); + failed++; + } - feed->setUrl(url); - feed->setTitle(url); - feed->setCreationDate(QDateTime::currentDateTime()); - feed->setIcon(qApp->icons()->fromTheme(QSL("folder-feed"))); - feed->setEncoding(DEFAULT_FEED_ENCODING); - - root_item->appendChild(feed); + qApp->processEvents(); } + else { + qWarning("Detected empty URL when parsing input TXT (one URL per line) data."); + failed++; + } + + emit parsingProgress(++completed, urls.size()); } // Now, XML is processed and we have result in form of pointer item structure. emit layoutAboutToBeChanged(); setRootItem(root_item); emit layoutChanged(); - - return true; + emit parsingFinished(failed, succeded, false); } FeedsImportExportModel::Mode FeedsImportExportModel::mode() const { diff --git a/src/services/standard/standardfeedsimportexportmodel.h b/src/services/standard/standardfeedsimportexportmodel.h index 18b1ed01f..5341c8aa2 100755 --- a/src/services/standard/standardfeedsimportexportmodel.h +++ b/src/services/standard/standardfeedsimportexportmodel.h @@ -60,12 +60,12 @@ class FeedsImportExportModel : public QAbstractItemModel { // Exports to OPML 2.0 // NOTE: http://dev.opml.org/spec2.html bool exportToOMPL20(QByteArray &result); - bool importAsOPML20(const QByteArray &data); + void importAsOPML20(const QByteArray &data); // Exports to plain text format // where there is one feed URL per line. bool exportToTxtURLPerLine(QByteArray &result); - bool importAsTxtURLPerLine(const QByteArray &data); + void importAsTxtURLPerLine(const QByteArray &data); Mode mode() const; void setMode(const Mode &mode); @@ -74,8 +74,15 @@ class FeedsImportExportModel : public QAbstractItemModel { void checkAllItems(); void uncheckAllItems(); + signals: + // These signals are emitted when user selects some data + // to be imported/parsed into the model. + void parsingStarted(); + void parsingProgress(int completed, int total); + void parsingFinished(int count_failed, int count_succeeded, bool parsing_error); + private: - QHash m_checkStates; + QHash m_checkStates; RootItem *m_rootItem; bool m_recursiveChange; From cad7219ea2ac8fd8e1f86c72295cc55620d41455 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 5 Jan 2016 09:23:16 +0100 Subject: [PATCH 2/8] New README. --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 24a91f16d..bc6df4d21 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,10 @@ You can [support RSS Guard with tiny amounts of money via PayPal](https://www.pa People who donated: -* Zdenek S. (Sweden). +* Zdenek S. (Sweden) +* Eloi Garibaldi B. + +I say "thank you" for all your support, donators. - - - Feeds & Videos From f64d6d16947e6f353d7270b3d8b1a3dd6a15bb53 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 5 Jan 2016 10:26:10 +0100 Subject: [PATCH 3/8] Fixed #142. --- resources/text/CHANGELOG | 1 + src/services/standard/gui/formstandardimportexport.cpp | 5 +++-- src/services/standard/gui/formstandardimportexport.ui | 3 --- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 701e85fc8..31e809ef2 100755 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -3,6 +3,7 @@ Added: ▪ Added generic "Add new feed" action, which can be accessed via "Feeds & messages" menu. (issue #146) +▪ Added support for import/export to/from plain TXT file (one feed URL per line). (issue #142) Changed: ▪ Some GUI refinements and fixes. diff --git a/src/services/standard/gui/formstandardimportexport.cpp b/src/services/standard/gui/formstandardimportexport.cpp index 9b508303f..275e3fe48 100755 --- a/src/services/standard/gui/formstandardimportexport.cpp +++ b/src/services/standard/gui/formstandardimportexport.cpp @@ -58,6 +58,7 @@ FormStandardImportExport::~FormStandardImportExport() { void FormStandardImportExport::setMode(const FeedsImportExportModel::Mode &mode) { m_model->setMode(mode); + m_ui->m_progressBar->setVisible(false); switch (mode) { case FeedsImportExportModel::Export: { @@ -107,16 +108,16 @@ void FormStandardImportExport::selectFile() { void FormStandardImportExport::onParsingStarted() { m_ui->m_lblResult->setStatus(WidgetWithStatus::Progress, tr("Parsing data..."), tr("Parsing data...")); m_ui->m_btnSelectFile->setEnabled(false); - m_ui->m_progressBar->setEnabled(true); m_ui->m_progressBar->setValue(0); + m_ui->m_progressBar->setVisible(true); } void FormStandardImportExport::onParsingFinished(int count_failed, int count_succeeded, bool parsing_error) { Q_UNUSED(count_failed) Q_UNUSED(count_succeeded) + m_ui->m_progressBar->setVisible(false); m_ui->m_progressBar->setValue(0); - m_ui->m_progressBar->setEnabled(false); m_model->checkAllItems(); if (!parsing_error) { diff --git a/src/services/standard/gui/formstandardimportexport.ui b/src/services/standard/gui/formstandardimportexport.ui index 671a9dd2d..b1107d194 100755 --- a/src/services/standard/gui/formstandardimportexport.ui +++ b/src/services/standard/gui/formstandardimportexport.ui @@ -116,9 +116,6 @@ - - false - 0 From 1489365d327d81e5391c0ab46538ca6f15d7412c Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 5 Jan 2016 12:11:03 +0100 Subject: [PATCH 4/8] Some const/pointers. --- src/core/feedsmodel.cpp | 2 +- src/gui/dialogs/formabout.cpp | 3 +-- src/gui/dialogs/formabout.h | 2 +- src/services/abstract/serviceentrypoint.h | 2 +- src/services/standard/standardserviceentrypoint.cpp | 2 +- src/services/standard/standardserviceentrypoint.h | 2 +- src/services/tt-rss/ttrssserviceentrypoint.cpp | 2 +- src/services/tt-rss/ttrssserviceentrypoint.h | 2 +- 8 files changed, 8 insertions(+), 9 deletions(-) mode change 100644 => 100755 src/gui/dialogs/formabout.h diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index e495f63d2..e888831ce 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -726,7 +726,7 @@ bool FeedsModel::emptyAllBins() { void FeedsModel::loadActivatedServiceAccounts() { // Iterate all globally available feed "service plugins". - foreach (ServiceEntryPoint *entry_point, qApp->feedServices()) { + foreach (const ServiceEntryPoint *entry_point, qApp->feedServices()) { // Load all stored root nodes from the entry point and add those to the model. QList roots = entry_point->initializeSubtree(); diff --git a/src/gui/dialogs/formabout.cpp b/src/gui/dialogs/formabout.cpp index a9fcd4b31..a075c3e08 100755 --- a/src/gui/dialogs/formabout.cpp +++ b/src/gui/dialogs/formabout.cpp @@ -29,7 +29,7 @@ #include -FormAbout::FormAbout(QWidget *parent) : QDialog(parent), m_ui(new Ui::FormAbout) { +FormAbout::FormAbout(QWidget *parent) : QDialog(parent), m_ui(new Ui::FormAbout()) { m_ui->setupUi(this); // Set flags and attributes. @@ -54,7 +54,6 @@ FormAbout::FormAbout(QWidget *parent) : QDialog(parent), m_ui(new Ui::FormAbout) FormAbout::~FormAbout() { qDebug("Destroying FormAbout instance."); - delete m_ui; } void FormAbout::loadSettingsAndPaths() { diff --git a/src/gui/dialogs/formabout.h b/src/gui/dialogs/formabout.h old mode 100644 new mode 100755 index fcd41a1e2..493c47863 --- a/src/gui/dialogs/formabout.h +++ b/src/gui/dialogs/formabout.h @@ -41,7 +41,7 @@ class FormAbout : public QDialog { void loadLicenseAndInformation(); void loadSettingsAndPaths(); - Ui::FormAbout *m_ui; + QScopedPointer m_ui; }; #endif // FORMABOUT_H diff --git a/src/services/abstract/serviceentrypoint.h b/src/services/abstract/serviceentrypoint.h index b5974f446..3502fdb3e 100755 --- a/src/services/abstract/serviceentrypoint.h +++ b/src/services/abstract/serviceentrypoint.h @@ -47,7 +47,7 @@ class ServiceEntryPoint { // point from persistent DB. // Returns list of root nodes which will be afterwards added // to the global feed model. - virtual QList initializeSubtree() = 0; + virtual QList initializeSubtree() const = 0; // Can this service account be added just once? // NOTE: This is true particularly for "standard" service diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index 75deae2d7..7a9485013 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -85,7 +85,7 @@ ServiceRoot *StandardServiceEntryPoint::createNewRoot() { } } -QList StandardServiceEntryPoint::initializeSubtree() { +QList StandardServiceEntryPoint::initializeSubtree() const { // Check DB if standard account is enabled. QSqlDatabase database = qApp->database()->connection(QSL("StandardServiceEntryPoint"), DatabaseFactory::FromSettings); QSqlQuery query(database); diff --git a/src/services/standard/standardserviceentrypoint.h b/src/services/standard/standardserviceentrypoint.h index b99de25a8..665ab21d6 100755 --- a/src/services/standard/standardserviceentrypoint.h +++ b/src/services/standard/standardserviceentrypoint.h @@ -35,7 +35,7 @@ class StandardServiceEntryPoint : public ServiceEntryPoint { QString code(); ServiceRoot *createNewRoot(); - QList initializeSubtree(); + QList initializeSubtree() const; }; #endif // STANDARDSERVICEENTRYPOINT_H diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index 379f87cfd..f36e027a7 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -79,7 +79,7 @@ ServiceRoot *TtRssServiceEntryPoint::createNewRoot() { return new_root; } -QList TtRssServiceEntryPoint::initializeSubtree() { +QList TtRssServiceEntryPoint::initializeSubtree() const { // Check DB if standard account is enabled. QSqlDatabase database = qApp->database()->connection(QSL("TtRssServiceEntryPoint"), DatabaseFactory::FromSettings); QSqlQuery query(database); diff --git a/src/services/tt-rss/ttrssserviceentrypoint.h b/src/services/tt-rss/ttrssserviceentrypoint.h index dcd99616b..fddf9628a 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.h +++ b/src/services/tt-rss/ttrssserviceentrypoint.h @@ -36,7 +36,7 @@ class TtRssServiceEntryPoint : public ServiceEntryPoint { QString code(); ServiceRoot *createNewRoot(); - QList initializeSubtree(); + QList initializeSubtree() const; }; #endif // TTRSSSERVICEENTRYPOINT_H From b4b244d6347366a886eeefc42c4631bc90018097 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 7 Jan 2016 07:39:52 +0100 Subject: [PATCH 5/8] Fixed #148. --- resources/text/CHANGELOG | 1 + src/gui/dialogs/formmain.cpp | 45 ++++++++++++------- src/gui/dialogs/formmain.ui | 9 +++- src/gui/discoverfeedsbutton.cpp | 6 +-- src/gui/feedmessageviewer.cpp | 2 + src/gui/feedsview.cpp | 22 ++++++++- src/gui/feedsview.h | 1 + src/services/abstract/serviceroot.h | 6 ++- src/services/standard/standardserviceroot.cpp | 26 ++++------- src/services/standard/standardserviceroot.h | 6 +-- src/services/tt-rss/ttrssserviceroot.cpp | 24 +++++----- src/services/tt-rss/ttrssserviceroot.h | 7 +-- 12 files changed, 96 insertions(+), 59 deletions(-) diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 31e809ef2..f9e62269e 100755 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -4,6 +4,7 @@ Added: ▪ Added generic "Add new feed" action, which can be accessed via "Feeds & messages" menu. (issue #146) ▪ Added support for import/export to/from plain TXT file (one feed URL per line). (issue #142) +▪ Optimized menu items in "Add new item" submenu. Added two new bindable actions for adding feeds & categories. (issues #146 and #148) Changed: ▪ Some GUI refinements and fixes. diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index ff7b13850..13e1f72de 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -135,6 +135,7 @@ QList FormMain::allActions() { actions << m_ui->m_actionServiceEdit; actions << m_ui->m_actionServiceDelete; actions << m_ui->m_actionAddFeedIntoSelectedAccount; + actions << m_ui->m_actionAddCategoryIntoSelectedAccount; actions << m_ui->m_actionViewSelectedItemsNewspaperMode; actions << m_ui->m_actionSelectNextItem; actions << m_ui->m_actionSelectPreviousItem; @@ -185,28 +186,39 @@ void FormMain::updateAddItemMenu() { root_menu->setIcon(activated_root->icon()); root_menu->setToolTip(activated_root->description()); - QList root_actions = activated_root->addItemMenu(); + QList specific_root_actions = activated_root->addItemMenu(); - if (root_actions.isEmpty()) { - QAction *no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")), - tr("No possible actions"), - m_ui->m_menuAddItem); - no_action->setEnabled(false); - root_menu->addAction(no_action); + if (activated_root->supportsCategoryAdding()) { + QAction *action_new_category = new QAction(qApp->icons()->fromTheme(QSL("folder-category")), + tr("Add new category"), + m_ui->m_menuAddItem); + root_menu->addAction(action_new_category); + connect(action_new_category, SIGNAL(triggered()), activated_root, SLOT(addNewCategory())); } - else { - root_menu->addActions(root_actions); + + if (activated_root->supportsFeedAdding()) { + QAction *action_new_feed = new QAction(qApp->icons()->fromTheme(QSL("folder-feed")), + tr("Add new feed"), + m_ui->m_menuAddItem); + root_menu->addAction(action_new_feed); + connect(action_new_feed, SIGNAL(triggered()), activated_root, SLOT(addNewFeed())); + } + + if (!specific_root_actions.isEmpty()) { + if (!root_menu->isEmpty()) { + root_menu->addSeparator(); + } + + root_menu->addActions(specific_root_actions); } m_ui->m_menuAddItem->addMenu(root_menu); } - if (m_ui->m_menuAddItem->isEmpty()) { - QAction *no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")), - tr("No accounts activated"), - m_ui->m_menuAddItem); - no_action->setEnabled(false); - m_ui->m_menuAddItem->addAction(no_action); + if (!m_ui->m_menuAddItem->isEmpty()) { + m_ui->m_menuAddItem->addSeparator(); + m_ui->m_menuAddItem->addAction(m_ui->m_actionAddCategoryIntoSelectedAccount); + m_ui->m_menuAddItem->addAction(m_ui->m_actionAddFeedIntoSelectedAccount); } } @@ -386,7 +398,8 @@ void FormMain::setupIcons() { m_ui->m_actionServiceAdd->setIcon(icon_theme_factory->fromTheme(QSL("item-new"))); m_ui->m_actionServiceEdit->setIcon(icon_theme_factory->fromTheme(QSL("item-edit"))); m_ui->m_actionServiceDelete->setIcon(icon_theme_factory->fromTheme(QSL("item-remove"))); - m_ui->m_actionAddFeedIntoSelectedAccount->setIcon(icon_theme_factory->fromTheme(QSL("item-new"))); + m_ui->m_actionAddFeedIntoSelectedAccount->setIcon(icon_theme_factory->fromTheme(QSL("folder-feed"))); + m_ui->m_actionAddCategoryIntoSelectedAccount->setIcon(icon_theme_factory->fromTheme(QSL("folder-category"))); // Setup icons for underlying components: opened web browsers... foreach (WebBrowser *browser, WebBrowser::runningWebBrowsers()) { diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index f82153e44..982560d6e 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -137,7 +137,6 @@ - @@ -790,6 +789,14 @@ + + + Add new category into selected account + + + + + diff --git a/src/gui/discoverfeedsbutton.cpp b/src/gui/discoverfeedsbutton.cpp index c95323ffc..f0508f5bc 100755 --- a/src/gui/discoverfeedsbutton.cpp +++ b/src/gui/discoverfeedsbutton.cpp @@ -63,8 +63,8 @@ void DiscoverFeedsButton::linkTriggered(QAction *action) { QString url = action->property("url").toString(); ServiceRoot *root = static_cast(action->property("root").value()); - if (root->supportsFeedAddingByUrl()) { - root->addFeedByUrl(url); + if (root->supportsFeedAdding()) { + root->addNewFeed(url); } else { qApp->showGuiMessage(tr("Not supported"), @@ -81,7 +81,7 @@ void DiscoverFeedsButton::fillMenu() { QMenu *root_menu = menu()->addMenu(root->icon(), root->title()); foreach (const QString &url, m_addresses) { - if (root->supportsFeedAddingByUrl()) { + if (root->supportsFeedAdding()) { QAction *url_action = root_menu->addAction(root->icon(), url); url_action->setProperty("url", url); diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index dc8533d94..88a4b383b 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -257,6 +257,8 @@ void FeedMessageViewer::createConnections() { // Toolbar forwardings. connect(form_main->m_ui->m_actionAddFeedIntoSelectedAccount, SIGNAL(triggered()), m_feedsView, SLOT(addFeedIntoSelectedAccount())); + connect(form_main->m_ui->m_actionAddCategoryIntoSelectedAccount, SIGNAL(triggered()), + m_feedsView, SLOT(addCategoryIntoSelectedAccount())); connect(form_main->m_ui->m_actionCleanupDatabase, SIGNAL(triggered()), this, SLOT(showDbCleanupAssistant())); connect(form_main->m_ui->m_actionSwitchImportanceOfSelectedMessages, diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index a523b6099..7b4af6a2c 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -140,8 +140,8 @@ void FeedsView::addFeedIntoSelectedAccount() { if (selected != NULL) { ServiceRoot *root = selected->getParentServiceRoot(); - if (root->supportsFeedAddingByUrl()) { - root->addFeedByUrl(); + if (root->supportsFeedAdding()) { + root->addNewFeed(); } else { qApp->showGuiMessage(tr("Not supported"), @@ -152,6 +152,24 @@ void FeedsView::addFeedIntoSelectedAccount() { } } +void FeedsView::addCategoryIntoSelectedAccount() { + RootItem *selected = selectedItem(); + + if (selected != NULL) { + ServiceRoot *root = selected->getParentServiceRoot(); + + if (root->supportsCategoryAdding()) { + root->addNewCategory(); + } + else { + qApp->showGuiMessage(tr("Not supported"), + tr("Selected account does not support adding of new categories."), + QSystemTrayIcon::Warning, + qApp->mainForm(), true); + } + } +} + void FeedsView::expandCollapseCurrentItem() { if (selectionModel()->selectedRows().size() == 1) { QModelIndex index = selectionModel()->selectedRows().at(0); diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index f5d68601a..3282ba402 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -63,6 +63,7 @@ class FeedsView : public QTreeView { public slots: void addFeedIntoSelectedAccount(); + void addCategoryIntoSelectedAccount(); void expandCollapseCurrentItem(); // Feed updating. diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 2ef26f714..0ea17a016 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -51,7 +51,8 @@ class ServiceRoot : public RootItem { bool deleteViaGui(); bool markAsReadUnread(ReadStatus status); - virtual bool supportsFeedAddingByUrl() const = 0; + virtual bool supportsFeedAdding() const = 0; + virtual bool supportsCategoryAdding() const = 0; // Returns list of specific actions for "Add new item" main window menu. // So typical list of returned actions could look like: @@ -159,7 +160,8 @@ class ServiceRoot : public RootItem { void setAccountId(int account_id); public slots: - virtual void addFeedByUrl(const QString &url = QString()) = 0; + virtual void addNewFeed(const QString &url = QString()) = 0; + virtual void addNewCategory() = 0; protected: // Takes lists of feeds/categories and assembles them into the tree structure. diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index c10d47fc4..32c29bcfa 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -47,7 +47,7 @@ StandardServiceRoot::StandardServiceRoot(RootItem *parent) : ServiceRoot(parent), m_recycleBin(new StandardRecycleBin(this)), m_actionExportFeeds(NULL), m_actionImportFeeds(NULL), m_serviceMenu(QList()), - m_addItemMenu(QList()), m_feedContextMenu(QList()), m_actionFeedFetchMetadata(NULL) { + m_feedContextMenu(QList()), m_actionFeedFetchMetadata(NULL) { setTitle(qApp->system()->getUsername() + QL1S("@") + QL1S(APP_LOW_NAME)); setIcon(StandardServiceEntryPoint().icon()); @@ -57,7 +57,6 @@ StandardServiceRoot::StandardServiceRoot(RootItem *parent) StandardServiceRoot::~StandardServiceRoot() { qDeleteAll(m_serviceMenu); - qDeleteAll(m_addItemMenu); qDeleteAll(m_feedContextMenu); } @@ -125,11 +124,15 @@ bool StandardServiceRoot::markAsReadUnread(RootItem::ReadStatus status) { return ServiceRoot::markAsReadUnread(status); } -bool StandardServiceRoot::supportsFeedAddingByUrl() const { +bool StandardServiceRoot::supportsFeedAdding() const { return true; } -void StandardServiceRoot::addFeedByUrl(const QString &url) { +bool StandardServiceRoot::supportsCategoryAdding() const { + return true; +} + +void StandardServiceRoot::addNewFeed(const QString &url) { QPointer form_pointer = new FormStandardFeedDetails(this, qApp->mainForm()); form_pointer.data()->exec(NULL, NULL, url); delete form_pointer.data(); @@ -300,7 +303,7 @@ void StandardServiceRoot::checkArgumentsForFeedAdding() { void StandardServiceRoot::checkArgumentForFeedAdding(const QString &argument) { if (argument.startsWith(QL1S("feed:"))) { - addFeedByUrl(argument); + addNewFeed(argument); } } @@ -441,18 +444,7 @@ QStringList StandardServiceRoot::textualFeedIds(const QList &feeds) { } QList StandardServiceRoot::addItemMenu() { - if (m_addItemMenu.isEmpty()) { - QAction *action_new_category = new QAction(qApp->icons()->fromTheme("folder-category"), tr("Add new category"), this); - connect(action_new_category, SIGNAL(triggered()), this, SLOT(addNewCategory())); - - QAction *action_new_feed = new QAction(qApp->icons()->fromTheme("folder-feed"), tr("Add new feed"), this); - connect(action_new_feed, SIGNAL(triggered()), this, SLOT(addFeedByUrl())); - - m_addItemMenu.append(action_new_category); - m_addItemMenu.append(action_new_feed); - } - - return m_addItemMenu; + return QList(); } QList StandardServiceRoot::serviceMenu() { diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 48784611b..a7d2368f0 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -49,7 +49,8 @@ class StandardServiceRoot : public ServiceRoot { bool markAsReadUnread(ReadStatus status); - bool supportsFeedAddingByUrl() const; + bool supportsFeedAdding() const; + bool supportsCategoryAdding() const; QVariant data(int column, int role) const; Qt::ItemFlags additionalFlags() const; @@ -100,7 +101,7 @@ class StandardServiceRoot : public ServiceRoot { void checkArgumentForFeedAdding(const QString &argument); public slots: - void addFeedByUrl(const QString &url = QString()); + void addNewFeed(const QString &url = QString()); void addNewCategory(); void importFeeds(); void exportFeeds(); @@ -119,7 +120,6 @@ class StandardServiceRoot : public ServiceRoot { QAction *m_actionImportFeeds; QList m_serviceMenu; - QList m_addItemMenu; QList m_feedContextMenu; QAction *m_actionFeedFetchMetadata; diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index dce28c353..0524f8cf7 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -41,8 +41,7 @@ TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) : ServiceRoot(parent), m_recycleBin(new TtRssRecycleBin(this)), - m_actionSyncIn(NULL), m_serviceMenu(QList()), m_addItemMenu(QList()), - m_network(new TtRssNetworkFactory) { + m_actionSyncIn(NULL), m_serviceMenu(QList()), m_network(new TtRssNetworkFactory) { setIcon(TtRssServiceEntryPoint().icon()); setCreationDate(QDateTime::currentDateTime()); } @@ -111,17 +110,25 @@ bool TtRssServiceRoot::markAsReadUnread(RootItem::ReadStatus status) { } } -bool TtRssServiceRoot::supportsFeedAddingByUrl() const { +bool TtRssServiceRoot::supportsFeedAdding() const { return true; } -void TtRssServiceRoot::addFeedByUrl(const QString &url) { +bool TtRssServiceRoot::supportsCategoryAdding() const { + return false; +} + +void TtRssServiceRoot::addNewFeed(const QString &url) { QPointer form_pointer = new FormEditFeed(this, qApp->mainForm()); form_pointer.data()->execForAdd(url); delete form_pointer.data(); } +void TtRssServiceRoot::addNewCategory() { + // Do nothing. +} + bool TtRssServiceRoot::canBeEdited() { return true; } @@ -153,14 +160,7 @@ QVariant TtRssServiceRoot::data(int column, int role) const { } QList TtRssServiceRoot::addItemMenu() { - if (m_addItemMenu.isEmpty()) { - QAction *action_new_feed = new QAction(qApp->icons()->fromTheme("folder-feed"), tr("Add new feed"), this); - connect(action_new_feed, SIGNAL(triggered()), this, SLOT(addFeedByUrl())); - - m_addItemMenu.append(action_new_feed); - } - - return m_addItemMenu; + return QList(); } RecycleBin *TtRssServiceRoot::recycleBin() { diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 9f70af5cf..e09c665c5 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -47,7 +47,8 @@ class TtRssServiceRoot : public ServiceRoot { bool markAsReadUnread(ReadStatus status); - bool supportsFeedAddingByUrl() const; + bool supportsFeedAdding() const; + bool supportsCategoryAdding() const; QVariant data(int column, int role) const; @@ -85,7 +86,8 @@ class TtRssServiceRoot : public ServiceRoot { void completelyRemoveAllData(); public slots: - void addFeedByUrl(const QString &url = QString()); + void addNewFeed(const QString &url = QString()); + void addNewCategory(); void syncIn(); private: @@ -105,7 +107,6 @@ class TtRssServiceRoot : public ServiceRoot { QAction *m_actionSyncIn; QList m_serviceMenu; - QList m_addItemMenu; TtRssNetworkFactory *m_network; }; From 4cd04d03db140686d310c2e9f3c7d3641552763e Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 7 Jan 2016 07:45:56 +0100 Subject: [PATCH 6/8] Introduce RootItem class hashCode idea. --- src/gui/feedsview.cpp | 4 ++-- src/services/abstract/rootitem.cpp | 7 +++++++ src/services/abstract/rootitem.h | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 7b4af6a2c..6fd138292 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -108,7 +108,7 @@ void FeedsView::saveExpandedStates() { // Iterate all categories and save their expand statuses. foreach (RootItem *item, expandable_items) { - QString setting_name = QString::number(item->kind()) + QL1S("-") + QString::number(qHash(item->title())) + QL1S("-") + QString::number(item->id()); + QString setting_name = item->hashCode(); settings->setValue(GROUP(Categories), setting_name, @@ -124,7 +124,7 @@ void FeedsView::loadExpandedStates() { // Iterate all categories and save their expand statuses. foreach (RootItem *item, expandable_items) { - QString setting_name = QString::number(item->kind()) + QL1S("-") + QString::number(qHash(item->title())) + QL1S("-") + QString::number(item->id()); + QString setting_name = item->hashCode(); setExpanded(model()->mapFromSource(sourceModel()->indexForItem(item)), settings->value(GROUP(Categories), setting_name, item->childCount() > 0).toBool()); diff --git a/src/services/abstract/rootitem.cpp b/src/services/abstract/rootitem.cpp index f7745907b..4f5e5749f 100755 --- a/src/services/abstract/rootitem.cpp +++ b/src/services/abstract/rootitem.cpp @@ -43,6 +43,13 @@ RootItem::~RootItem() { qDeleteAll(m_childItems); } +QString RootItem::hashCode() const { + return + QString::number(kind()) + QL1S("-") + + QString::number(qHash(title())) + QL1S("-") + + QString::number(id()); +} + QList RootItem::contextMenu() { return QList(); } diff --git a/src/services/abstract/rootitem.h b/src/services/abstract/rootitem.h index 54b9be830..af7e08ebd 100755 --- a/src/services/abstract/rootitem.h +++ b/src/services/abstract/rootitem.h @@ -74,6 +74,8 @@ class RootItem : public QObject { // /* Members to override. ///////////////////////////////////////// + virtual QString hashCode() const; + // Returns list of specific actions which can be done with the item. // Do not include general actions here like actions: Mark as read, Update, ... // NOTE: Ownership of returned actions is not switched to caller, free them when needed. From f73d0eeb8cef0c7be6186661822546e5e652aa93 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 7 Jan 2016 09:10:06 +0100 Subject: [PATCH 7/8] Fixed #149. --- resources/text/CHANGELOG | 1 + src/core/feedsmodel.cpp | 1 + src/core/feedsmodel.h | 4 +++ src/gui/feedmessageviewer.cpp | 2 +- src/gui/feedsview.cpp | 27 ++++++++++++------- src/gui/feedsview.h | 7 +++-- src/main.cpp | 2 +- src/miscellaneous/settings.cpp | 2 +- src/miscellaneous/settings.h | 2 +- src/services/abstract/rootitem.cpp | 5 +--- src/services/abstract/serviceroot.cpp | 6 ++++- src/services/abstract/serviceroot.h | 2 ++ .../standard/standardserviceentrypoint.cpp | 2 ++ src/services/tt-rss/ttrsscategory.cpp | 7 +++++ src/services/tt-rss/ttrsscategory.h | 2 ++ src/services/tt-rss/ttrssfeed.cpp | 7 +++++ src/services/tt-rss/ttrssfeed.h | 2 ++ src/services/tt-rss/ttrssserviceroot.cpp | 13 ++++++++- 18 files changed, 72 insertions(+), 22 deletions(-) diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index f9e62269e..1d16caf2e 100755 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -12,6 +12,7 @@ Changed: Fixed: +▪ Expand status if items in feed list are now persistent when performing sync-in of TT-RSS accounts. (bug #149) ▪ Fixed problem with importing invalid OPML 2.0 files. (bug #145) ▪ Fixed error in SQL initialization script which led to problems with in-memory SQLite DBs. (bug #140) ▪ Fixed problem with saving sort column/order for message list. (bug #141) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index e888831ce..4e383ae22 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -691,6 +691,7 @@ bool FeedsModel::addServiceAccount(ServiceRoot *root, bool freshly_activated) { connect(root, SIGNAL(dataChanged(QList)), this, SLOT(onItemDataChanged(QList))); connect(root, SIGNAL(reloadMessageListRequested(bool)), this, SIGNAL(reloadMessageListRequested(bool))); connect(root, SIGNAL(itemExpandRequested(QList,bool)), this, SIGNAL(itemExpandRequested(QList,bool))); + connect(root, SIGNAL(itemExpandStateSaveRequested(RootItem*)), this, SIGNAL(itemExpandStateSaveRequested(RootItem*))); root->start(freshly_activated); return true; diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 605c92db6..55ef846d9 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -212,6 +212,10 @@ class FeedsModel : public QAbstractItemModel { // Emitted if any item requested that any view should expand it. void itemExpandRequested(QList items, bool expand); + // Emitted if any item requested that its expand states should be explicitly saved. + // NOTE: Normally expand states are saved when application quits. + void itemExpandStateSaveRequested(RootItem *subtree_root); + // Emitted when there is a need of reloading of displayed messages. void reloadMessageListRequested(bool mark_selected_messages_read); diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 88a4b383b..2ca41b107 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -78,7 +78,7 @@ FeedMessageViewer::~FeedMessageViewer() { void FeedMessageViewer::saveSize() { Settings *settings = qApp->settings(); - m_feedsView->saveExpandedStates(); + m_feedsView->saveAllExpandStates(); // Store offsets of splitters. settings->setValue(GROUP(GUI), GUI::SplitterFeeds, QString(m_feedSplitter->saveState().toBase64())); diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 6fd138292..ee99f148d 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -57,6 +57,7 @@ FeedsView::FeedsView(QWidget *parent) // Connections. connect(m_sourceModel, SIGNAL(requireItemValidationAfterDragDrop(QModelIndex)), this, SLOT(validateItemAfterDragDrop(QModelIndex))); connect(m_sourceModel, SIGNAL(itemExpandRequested(QList,bool)), this, SLOT(onItemExpandRequested(QList,bool))); + connect(m_sourceModel, SIGNAL(itemExpandStateSaveRequested(RootItem*)), this, SLOT(onItemExpandStateSaveRequested(RootItem*))); connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder))); setModel(m_proxyModel); @@ -100,23 +101,29 @@ RootItem *FeedsView::selectedItem() const { } } -void FeedsView::saveExpandedStates() { - Settings *settings = qApp->settings(); - QList expandable_items; +void FeedsView::onItemExpandStateSaveRequested(RootItem *item) { + saveExpandStates(item); +} - expandable_items.append(sourceModel()->rootItem()->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot)); +void FeedsView::saveAllExpandStates() { + saveExpandStates(sourceModel()->rootItem()); +} + +void FeedsView::saveExpandStates(RootItem *item) { + Settings *settings = qApp->settings(); + QList items = item->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot); // Iterate all categories and save their expand statuses. - foreach (RootItem *item, expandable_items) { - QString setting_name = item->hashCode(); + foreach (RootItem *item, items) { + const QString setting_name = item->hashCode(); - settings->setValue(GROUP(Categories), + settings->setValue(GROUP(CategoriesExpandStates), setting_name, isExpanded(model()->mapFromSource(sourceModel()->indexForItem(item)))); } } -void FeedsView::loadExpandedStates() { +void FeedsView::loadAllExpandStates() { Settings *settings = qApp->settings(); QList expandable_items; @@ -124,10 +131,10 @@ void FeedsView::loadExpandedStates() { // Iterate all categories and save their expand statuses. foreach (RootItem *item, expandable_items) { - QString setting_name = item->hashCode(); + const QString setting_name = item->hashCode(); setExpanded(model()->mapFromSource(sourceModel()->indexForItem(item)), - settings->value(GROUP(Categories), setting_name, item->childCount() > 0).toBool()); + settings->value(GROUP(CategoriesExpandStates), setting_name, item->childCount() > 0).toBool()); } sortByColumn(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortColumnFeeds)).toInt(), diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 3282ba402..7b93763ea 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -58,8 +58,8 @@ class FeedsView : public QTreeView { RootItem *selectedItem() const; // Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings. - void saveExpandedStates(); - void loadExpandedStates(); + void saveAllExpandStates(); + void loadAllExpandStates(); public slots: void addFeedIntoSelectedAccount(); @@ -107,6 +107,7 @@ class FeedsView : public QTreeView { void saveSortState(int column, Qt::SortOrder order); void validateItemAfterDragDrop(const QModelIndex &source_index); void onItemExpandRequested(const QList &items, bool exp); + void onItemExpandStateSaveRequested(RootItem *item); private: // Initializes context menus. @@ -118,6 +119,8 @@ class FeedsView : public QTreeView { // Sets up appearance of this widget. void setupAppearance(); + void saveExpandStates(RootItem *item); + // Handle selections. void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); diff --git a/src/main.cpp b/src/main.cpp index b1b6a29dc..0651433c0 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -119,7 +119,7 @@ int main(int argc, char *argv[]) { // Load activated accounts. qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->loadActivatedServiceAccounts(); - qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->loadExpandedStates(); + qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->loadAllExpandStates(); // Setup single-instance behavior. QObject::connect(&application, SIGNAL(messageReceived(QString)), &application, SLOT(processExecutionMessage(QString))); diff --git a/src/miscellaneous/settings.cpp b/src/miscellaneous/settings.cpp index 61d21a338..0ecbb3839 100755 --- a/src/miscellaneous/settings.cpp +++ b/src/miscellaneous/settings.cpp @@ -290,7 +290,7 @@ DKEY Browser::QueueTabs = "queue_tabs"; DVALUE(bool) Browser::QueueTabsDef = true; // Categories. -DKEY Categories::ID = "categories_expand_states"; +DKEY CategoriesExpandStates::ID = "categories_expand_states"; Settings::Settings(const QString &file_name, Format format, const SettingsProperties::SettingsType &status, QObject *parent) : QSettings(file_name, format, parent), m_initializationStatus(status) { diff --git a/src/miscellaneous/settings.h b/src/miscellaneous/settings.h index 4a1f89a12..89e8a142b 100755 --- a/src/miscellaneous/settings.h +++ b/src/miscellaneous/settings.h @@ -322,7 +322,7 @@ namespace Browser { } // Categories. -namespace Categories { +namespace CategoriesExpandStates { KEY ID; } diff --git a/src/services/abstract/rootitem.cpp b/src/services/abstract/rootitem.cpp index 4f5e5749f..cc9c20097 100755 --- a/src/services/abstract/rootitem.cpp +++ b/src/services/abstract/rootitem.cpp @@ -44,10 +44,7 @@ RootItem::~RootItem() { } QString RootItem::hashCode() const { - return - QString::number(kind()) + QL1S("-") + - QString::number(qHash(title())) + QL1S("-") + - QString::number(id()); + return QString::number(kind()) + QL1S("-") + QString::number(id()); } QList RootItem::contextMenu() { diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 1f229a9f0..d3f2d1019 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -122,10 +122,14 @@ void ServiceRoot::requestFeedReadFilterReload() { emit readFeedsFilterInvalidationRequested(); } -void ServiceRoot::requestItemExpand(const QList &items, bool expand) { +void ServiceRoot::requestItemExpand(const QList &items, bool expand) { emit itemExpandRequested(items, expand); } +void ServiceRoot::requestItemExpandStateSave(RootItem *subtree_root) { + emit itemExpandStateSaveRequested(subtree_root); +} + void ServiceRoot::requestItemReassignment(RootItem *item, RootItem *new_parent) { emit itemReassignmentRequested(item, new_parent); } diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 0ea17a016..ff6f85c89 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -152,6 +152,7 @@ class ServiceRoot : public RootItem { void requestReloadMessageList(bool mark_selected_messages_read); void requestFeedReadFilterReload(); void requestItemExpand(const QList &items, bool expand); + void requestItemExpandStateSave(RootItem *subtree_root); void requestItemReassignment(RootItem *item, RootItem *new_parent); void requestItemRemoval(RootItem *item); @@ -174,6 +175,7 @@ class ServiceRoot : public RootItem { void readFeedsFilterInvalidationRequested(); void reloadMessageListRequested(bool mark_selected_messages_read); void itemExpandRequested(QList items, bool expand); + void itemExpandStateSaveRequested(RootItem *subtree_root); void itemReassignmentRequested(RootItem *item, RootItem *new_parent); void itemRemovalRequested(RootItem *item); diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index 7a9485013..527186891 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -77,6 +77,7 @@ ServiceRoot *StandardServiceEntryPoint::createNewRoot() { if (query.exec()) { StandardServiceRoot *root = new StandardServiceRoot(); + root->setId(id_to_assign); root->setAccountId(id_to_assign); return root; } @@ -98,6 +99,7 @@ QList StandardServiceEntryPoint::initializeSubtree() const { if (query.exec()) { while (query.next()) { StandardServiceRoot *root = new StandardServiceRoot(); + root->setId(query.value(0).toInt()); root->setAccountId(query.value(0).toInt()); roots.append(root); } diff --git a/src/services/tt-rss/ttrsscategory.cpp b/src/services/tt-rss/ttrsscategory.cpp index 506181f55..4f3ed91b1 100755 --- a/src/services/tt-rss/ttrsscategory.cpp +++ b/src/services/tt-rss/ttrsscategory.cpp @@ -41,6 +41,13 @@ TtRssCategory::TtRssCategory(const QSqlRecord &record) : Category(NULL) { TtRssCategory::~TtRssCategory() { } +QString TtRssCategory::hashCode() const { + return + QString::number(kind()) + QL1S("-") + + QString::number(const_cast(this)->getParentServiceRoot()->accountId()) + QL1S("-") + + QString::number(customId()); +} + TtRssServiceRoot *TtRssCategory::serviceRoot() { return qobject_cast(getParentServiceRoot()); } diff --git a/src/services/tt-rss/ttrsscategory.h b/src/services/tt-rss/ttrsscategory.h index 1fcd9ccf5..7b40cdd04 100755 --- a/src/services/tt-rss/ttrsscategory.h +++ b/src/services/tt-rss/ttrsscategory.h @@ -33,6 +33,8 @@ class TtRssCategory : public Category { explicit TtRssCategory(const QSqlRecord &record); virtual ~TtRssCategory(); + QString hashCode() const; + TtRssServiceRoot *serviceRoot(); bool markAsReadUnread(ReadStatus status); diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index c131320b2..0933f0020 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -50,6 +50,13 @@ TtRssFeed::TtRssFeed(const QSqlRecord &record) : Feed(NULL), m_totalCount(0), m_ TtRssFeed::~TtRssFeed() { } +QString TtRssFeed::hashCode() const { + return + QString::number(kind()) + QL1S("-") + + QString::number(const_cast(this)->getParentServiceRoot()->accountId()) + QL1S("-") + + QString::number(customId()); +} + TtRssServiceRoot *TtRssFeed::serviceRoot() { return qobject_cast(getParentServiceRoot()); } diff --git a/src/services/tt-rss/ttrssfeed.h b/src/services/tt-rss/ttrssfeed.h index 83a16eeb5..53e635d09 100755 --- a/src/services/tt-rss/ttrssfeed.h +++ b/src/services/tt-rss/ttrssfeed.h @@ -33,6 +33,8 @@ class TtRssFeed : public Feed { explicit TtRssFeed(const QSqlRecord &record); virtual ~TtRssFeed(); + QString hashCode() const; + TtRssServiceRoot *serviceRoot(); QVariant data(int column, int role) const; diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 0524f8cf7..17bde213c 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -581,6 +581,7 @@ void TtRssServiceRoot::syncIn() { RootItem *new_tree = feed_cats_response.feedsCategories(true, m_network->url()); // Purge old data from SQL and clean all model items. + requestItemExpandStateSave(this); removeOldFeedTree(false); cleanAllItems(); @@ -602,7 +603,17 @@ void TtRssServiceRoot::syncIn() { itemChanged(all_items); requestReloadMessageList(true); - requestItemExpand(all_items, true); + + // Now we must refresh expand states. + QList items_to_expand; + + foreach (RootItem *item, all_items) { + if (qApp->settings()->value(GROUP(CategoriesExpandStates), item->hashCode(), item->childCount() > 0).toBool()) { + items_to_expand.append(item); + } + } + + requestItemExpand(items_to_expand, true); } setIcon(original_icon); From 3d71264041523f4ab6ba03b1b6714fb449ebec05 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 8 Jan 2016 10:08:00 +0100 Subject: [PATCH 8/8] Some const - no time. --- src/core/feeddownloader.cpp | 17 +++++++++++++++-- src/core/feeddownloader.h | 16 ++++++++-------- src/core/feedsmodel.cpp | 4 ++-- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/core/feeddownloader.cpp b/src/core/feeddownloader.cpp index 22d331a31..fef8b0086 100755 --- a/src/core/feeddownloader.cpp +++ b/src/core/feeddownloader.cpp @@ -45,7 +45,7 @@ void FeedDownloader::updateFeeds(const QList &feeds) { int updated_messages = feeds.at(i)->update(); if (updated_messages > 0) { - results.m_updatedFeeds.append(QPair(feeds.at(i)->title(), updated_messages)); + results.updatedFeeds().append(QPair(feeds.at(i)->title(), updated_messages)); } qDebug("Made progress in feed updates: %d/%d (id of feed is %d).", i + 1, total, feeds.at(i)->id()); @@ -62,7 +62,12 @@ void FeedDownloader::updateFeeds(const QList &feeds) { } -QString FeedDownloadResults::getOverview(int how_many_feeds) { +FeedDownloadResults::FeedDownloadResults() : m_updatedFeeds(QList >()) { +} + + + +QString FeedDownloadResults::overview(int how_many_feeds) { qSort(m_updatedFeeds.begin(), m_updatedFeeds.end(), FeedDownloadResults::lessThan); QStringList result; @@ -79,3 +84,11 @@ QString FeedDownloadResults::getOverview(int how_many_feeds) { return res_str; } + +bool FeedDownloadResults::lessThan(const QPair &lhs, const QPair &rhs) { + return lhs.second > rhs.second; +} + +QList > &FeedDownloadResults::updatedFeeds() { + return m_updatedFeeds; +} diff --git a/src/core/feeddownloader.h b/src/core/feeddownloader.h index 88f8992b7..105103a19 100755 --- a/src/core/feeddownloader.h +++ b/src/core/feeddownloader.h @@ -26,16 +26,16 @@ class Feed; // Represents results of batch feed updates. -struct FeedDownloadResults { - explicit FeedDownloadResults() : m_updatedFeeds(QList >()) { - } +class FeedDownloadResults { + public: + explicit FeedDownloadResults(); - QString getOverview(int how_many_feeds); + QList > &updatedFeeds(); + QString overview(int how_many_feeds); - static bool lessThan(const QPair &lhs, const QPair &rhs) { - return lhs.second > rhs.second; - } + static bool lessThan(const QPair &lhs, const QPair &rhs); + private: // QString represents title if the feed, int represents count of newly downloaded messages. QList > m_updatedFeeds; }; @@ -69,7 +69,7 @@ class FeedDownloader : public QObject { // "Current" number indicates count of processed feeds // and "total" number indicates total number of feeds // which were in the initial queue. - void progress(Feed *feed, int current, int total); + void progress(const Feed *feed, int current, int total); }; #endif // FEEDDOWNLOADER_H diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 4e383ae22..85ad2f5a9 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -172,9 +172,9 @@ void FeedsModel::onFeedUpdatesFinished(FeedDownloadResults results) { qApp->feedUpdateLock()->unlock(); qApp->mainForm()->statusBar()->clearProgressFeeds(); - if (!results.m_updatedFeeds.isEmpty()) { + if (!results.updatedFeeds().isEmpty()) { // Now, inform about results via GUI message/notification. - qApp->showGuiMessage(tr("New messages downloaded"), results.getOverview(10), QSystemTrayIcon::NoIcon, + qApp->showGuiMessage(tr("New messages downloaded"), results.overview(10), QSystemTrayIcon::NoIcon, 0, false, qApp->icons()->fromTheme(QSL("item-update-all"))); }