From fcab295ab806fea7332624156e90ab2fdbb91d57 Mon Sep 17 00:00:00 2001 From: martinrotter Date: Fri, 21 Apr 2017 08:04:23 +0200 Subject: [PATCH 01/10] Improved logging (now with time), preparation for #71. --- rssguard.pro | 6 +- src/miscellaneous/application.cpp | 2 +- src/miscellaneous/debugging.cpp | 13 ++++- src/miscellaneous/feedreader.cpp | 58 ++++++++++++++++++- src/miscellaneous/feedreader.h | 12 +++- src/miscellaneous/serviceoperator.cpp | 25 ++++++++ src/miscellaneous/serviceoperator.h | 36 ++++++++++++ src/services/abstract/serviceroot.cpp | 3 + src/services/abstract/serviceroot.h | 5 ++ src/services/owncloud/owncloudserviceroot.cpp | 6 ++ src/services/owncloud/owncloudserviceroot.h | 2 + 11 files changed, 159 insertions(+), 9 deletions(-) create mode 100755 src/miscellaneous/serviceoperator.cpp create mode 100755 src/miscellaneous/serviceoperator.h diff --git a/rssguard.pro b/rssguard.pro index 512df2e2c..411f216fb 100755 --- a/rssguard.pro +++ b/rssguard.pro @@ -326,7 +326,8 @@ HEADERS += src/core/feeddownloader.h \ src/services/standard/atomparser.h \ src/services/standard/feedparser.h \ src/services/standard/rdfparser.h \ - src/services/standard/rssparser.h + src/services/standard/rssparser.h \ + src/miscellaneous/serviceoperator.h SOURCES += src/core/feeddownloader.cpp \ src/core/feedsmodel.cpp \ @@ -444,7 +445,8 @@ SOURCES += src/core/feeddownloader.cpp \ src/services/standard/atomparser.cpp \ src/services/standard/feedparser.cpp \ src/services/standard/rdfparser.cpp \ - src/services/standard/rssparser.cpp + src/services/standard/rssparser.cpp \ + src/miscellaneous/serviceoperator.cpp FORMS += src/gui/toolbareditor.ui \ src/network-web/downloaditem.ui \ diff --git a/src/miscellaneous/application.cpp b/src/miscellaneous/application.cpp index d17b33215..8d1a23bc0 100755 --- a/src/miscellaneous/application.cpp +++ b/src/miscellaneous/application.cpp @@ -373,7 +373,7 @@ void Application::onAboutToQuit() { system()->removeTrolltechJunkRegistryKeys(); #endif - qApp->feedReader()->stop(); + qApp->feedReader()->quit(); database()->saveDatabase(); if (mainForm() != nullptr) { diff --git a/src/miscellaneous/debugging.cpp b/src/miscellaneous/debugging.cpp index 34099ddaf..e433edb1b 100755 --- a/src/miscellaneous/debugging.cpp +++ b/src/miscellaneous/debugging.cpp @@ -23,6 +23,8 @@ #include #include +#include +#include Debugging::Debugging() { @@ -31,13 +33,18 @@ Debugging::Debugging() { void Debugging::performLog(const char *message, QtMsgType type, const char *file, const char *function, int line) { const char *type_string = typeToString(type); + std::time_t t = std::time(nullptr); + char mbstr[32]; + + std::strftime(mbstr, sizeof(mbstr), "%y/%d/%m %H:%M:%S", std::localtime(&t)); + // Write to console. if (file == 0 || function == 0 || line < 0) { - fprintf(stderr, "[%s] %s: %s\n", APP_LOW_NAME, type_string, message); + fprintf(stderr, "[%s] %s: %s (%s)\n", APP_LOW_NAME, type_string, message, mbstr); } else { - fprintf(stderr, "[%s] %s\n Type: %s\n File: %s (line %d)\n Function: %s\n\n", - APP_LOW_NAME, message, type_string, file, line, function); + fprintf(stderr, "[%s] %s (%s)\n Type: %s\n File: %s (line %d)\n Function: %s\n\n", + APP_LOW_NAME, message, mbstr, type_string, file, line, function); } if (type == QtFatalMsg) { diff --git a/src/miscellaneous/feedreader.cpp b/src/miscellaneous/feedreader.cpp index 73a779a6c..aeae24e79 100755 --- a/src/miscellaneous/feedreader.cpp +++ b/src/miscellaneous/feedreader.cpp @@ -20,6 +20,7 @@ #include "services/standard/standardserviceentrypoint.h" #include "services/owncloud/owncloudserviceentrypoint.h" #include "services/tt-rss/ttrssserviceentrypoint.h" +#include "services/abstract/serviceroot.h" #include "core/feedsmodel.h" #include "core/feedsproxymodel.h" @@ -32,10 +33,12 @@ #include #include +#include FeedReader::FeedReader(QObject *parent) - : QObject(parent), m_feedServices(QList()), m_autoUpdateTimer(new QTimer(this)), + : QObject(parent), m_feedServices(QList()), + m_cacheSaveFutureWatcher(QFutureWatcher()), m_autoUpdateTimer(new QTimer(this)), m_feedDownloaderThread(nullptr), m_feedDownloader(nullptr), m_dbCleanerThread(nullptr), m_dbCleaner(nullptr) { m_feedsModel = new FeedsModel(this); @@ -43,8 +46,10 @@ FeedReader::FeedReader(QObject *parent) m_messagesModel = new MessagesModel(this); m_messagesProxyModel = new MessagesProxyModel(m_messagesModel, this); + connect(&m_cacheSaveFutureWatcher, &QFutureWatcher::finished, this, &FeedReader::asyncCacheSaveFinished); connect(m_autoUpdateTimer, &QTimer::timeout, this, &FeedReader::executeNextAutoUpdate); updateAutoUpdateStatus(); + asyncCacheSaveFinished(); if (qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::FeedsUpdateOnStartup)).toBool()) { qDebug("Requesting update for all feeds on application startup."); @@ -209,11 +214,60 @@ void FeedReader::executeNextAutoUpdate() { } } -void FeedReader::stop() { +void FeedReader::checkServicesForAsyncOperations() { + checkServicesForAsyncOperations(false); +} + +void FeedReader::checkServicesForAsyncOperations(bool wait_for_future) { + if (m_cacheSaveFutureWatcher.future().isStarted() || m_cacheSaveFutureWatcher.future().isRunning()) { + qDebug("Previous future is still running or was already started."); + + + // If we want to wait for future synchronously, we want to make sure that + // we save all cached data (app exit). + if (wait_for_future) { + qWarning("Waiting for previously started saving of cached service data."); + m_cacheSaveFutureWatcher.future().waitForFinished(); + } + else { + qWarning("Some cached service data are being saved now, so aborting this saving cycle."); + // Some cache saving is now running. + return; + } + } + + QFuture future = QtConcurrent::run([&] { + foreach (ServiceRoot *service, m_feedsModel->serviceRoots()) { + // Store any cached data. + service->saveAllCachedData(); + } + }); + + if (wait_for_future) { + qDebug("Waiting for saving of cached service data to finish."); + future.waitForFinished(); + } + else { + m_cacheSaveFutureWatcher.setFuture(future); + } +} + +void FeedReader::asyncCacheSaveFinished() { + qDebug("I will start next check for cached service data in 30 seconds."); + + QTimer::singleShot(30000, [&] { + qDebug("Starting next check for cached service data in NOW."); + checkServicesForAsyncOperations(false); + }); +} + +void FeedReader::quit() { if (m_autoUpdateTimer->isActive()) { m_autoUpdateTimer->stop(); } + checkServicesForAsyncOperations(true); + // Close worker threads. if (m_feedDownloaderThread != nullptr && m_feedDownloaderThread->isRunning()) { m_feedDownloader->stopRunningUpdate(); diff --git a/src/miscellaneous/feedreader.h b/src/miscellaneous/feedreader.h index d3715d8c1..6e45bce66 100755 --- a/src/miscellaneous/feedreader.h +++ b/src/miscellaneous/feedreader.h @@ -23,12 +23,15 @@ #include "services/abstract/feed.h" #include "core/feeddownloader.h" +#include + class FeedsModel; class MessagesModel; class MessagesProxyModel; class FeedsProxyModel; class ServiceEntryPoint; +class ServiceOperator; class DatabaseCleaner; class QTimer; @@ -69,11 +72,14 @@ class FeedReader : public QObject { // Schedules all feeds from all accounts for update. void updateAllFeeds(); void stopRunningFeedUpdate(); - void stop(); + void quit(); private slots: // Is executed when next auto-update round could be done. void executeNextAutoUpdate(); + void checkServicesForAsyncOperations(); + void checkServicesForAsyncOperations(bool wait_for_future); + void asyncCacheSaveFinished(); signals: void feedUpdatesStarted(); @@ -88,12 +94,16 @@ class FeedReader : public QObject { MessagesModel *m_messagesModel; MessagesProxyModel *m_messagesProxyModel; + QFutureWatcher m_cacheSaveFutureWatcher; + // Auto-update stuff. QTimer *m_autoUpdateTimer; bool m_globalAutoUpdateEnabled; int m_globalAutoUpdateInitialInterval; int m_globalAutoUpdateRemainingInterval; + ServiceOperator *m_serviceOperator; + QThread *m_feedDownloaderThread; FeedDownloader *m_feedDownloader; diff --git a/src/miscellaneous/serviceoperator.cpp b/src/miscellaneous/serviceoperator.cpp new file mode 100755 index 000000000..cbb07c04f --- /dev/null +++ b/src/miscellaneous/serviceoperator.cpp @@ -0,0 +1,25 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2017 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "miscellaneous/serviceoperator.h" + + +ServiceOperator::ServiceOperator(QObject *parent) : QObject(parent) { +} + +ServiceOperator::~ServiceOperator() { +} diff --git a/src/miscellaneous/serviceoperator.h b/src/miscellaneous/serviceoperator.h new file mode 100755 index 000000000..352ae29df --- /dev/null +++ b/src/miscellaneous/serviceoperator.h @@ -0,0 +1,36 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2017 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef SERVICEOPERATOR_H +#define SERVICEOPERATOR_H + +#include + + +class ServiceOperator : public QObject { + Q_OBJECT + + public: + explicit ServiceOperator(QObject *parent = 0); + virtual ~ServiceOperator(); + + signals: + + public slots: +}; + +#endif // SERVICEOPERATOR_H diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 6c5c46feb..59494d234 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -192,6 +192,9 @@ QList ServiceRoot::undeletedMessages() const { return DatabaseQueries::getUndeletedMessagesForAccount(database, accountId()); } +void ServiceRoot::saveAllCachedData() { +} + void ServiceRoot::itemChanged(const QList &items) { emit dataChanged(items); } diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 39f5268e7..e17fe9ae6 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -59,6 +59,7 @@ class ServiceRoot : public RootItem { // NOTE: Caller does NOT take ownership of created menu! virtual QList addItemMenu(); + // Returns actions to display as context menu. QList contextMenu(); // Returns list of specific actions to be shown in main window menu @@ -83,6 +84,10 @@ class ServiceRoot : public RootItem { virtual void start(bool freshly_activated) = 0; virtual void stop() = 0; + // Is called in short intervals in worker thread. + // Service can save its cached data (if any) here. + virtual void saveAllCachedData(); + // Account ID corresponds with DB attribute Accounts (id). int accountId() const; void setAccountId(int account_id); diff --git a/src/services/owncloud/owncloudserviceroot.cpp b/src/services/owncloud/owncloudserviceroot.cpp index 928252c7e..c895309e0 100755 --- a/src/services/owncloud/owncloudserviceroot.cpp +++ b/src/services/owncloud/owncloudserviceroot.cpp @@ -31,6 +31,8 @@ #include "services/owncloud/gui/formeditowncloudaccount.h" #include "services/owncloud/gui/formowncloudfeeddetails.h" +#include + OwnCloudServiceRoot::OwnCloudServiceRoot(RootItem *parent) : ServiceRoot(parent), m_recycleBin(new OwnCloudRecycleBin(this)), @@ -195,6 +197,10 @@ void OwnCloudServiceRoot::saveAccountDataToDatabase() { } } +void OwnCloudServiceRoot::saveAllCachedData() { + QThread::msleep(2000); +} + void OwnCloudServiceRoot::addNewFeed(const QString &url) { if (!qApp->feedUpdateLock()->tryLock()) { // Lock was not obtained because diff --git a/src/services/owncloud/owncloudserviceroot.h b/src/services/owncloud/owncloudserviceroot.h index 3c2ddef6b..43ff2a91f 100755 --- a/src/services/owncloud/owncloudserviceroot.h +++ b/src/services/owncloud/owncloudserviceroot.h @@ -51,6 +51,8 @@ class OwnCloudServiceRoot : public ServiceRoot { void updateTitle(); void saveAccountDataToDatabase(); + void saveAllCachedData(); + public slots: void addNewFeed(const QString &url); void addNewCategory(); From fbf1cd2124161c0af051ff5853c623465705a455 Mon Sep 17 00:00:00 2001 From: martinrotter Date: Fri, 21 Apr 2017 08:05:17 +0200 Subject: [PATCH 02/10] Format da shit. --- rssguard.pro | 4 ++-- src/services/owncloud/owncloudserviceroot.cpp | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/rssguard.pro b/rssguard.pro index 411f216fb..672a69c89 100755 --- a/rssguard.pro +++ b/rssguard.pro @@ -327,7 +327,7 @@ HEADERS += src/core/feeddownloader.h \ src/services/standard/feedparser.h \ src/services/standard/rdfparser.h \ src/services/standard/rssparser.h \ - src/miscellaneous/serviceoperator.h + src/miscellaneous/serviceoperator.h SOURCES += src/core/feeddownloader.cpp \ src/core/feedsmodel.cpp \ @@ -446,7 +446,7 @@ SOURCES += src/core/feeddownloader.cpp \ src/services/standard/feedparser.cpp \ src/services/standard/rdfparser.cpp \ src/services/standard/rssparser.cpp \ - src/miscellaneous/serviceoperator.cpp + src/miscellaneous/serviceoperator.cpp FORMS += src/gui/toolbareditor.ui \ src/network-web/downloaditem.ui \ diff --git a/src/services/owncloud/owncloudserviceroot.cpp b/src/services/owncloud/owncloudserviceroot.cpp index c895309e0..f4895e101 100755 --- a/src/services/owncloud/owncloudserviceroot.cpp +++ b/src/services/owncloud/owncloudserviceroot.cpp @@ -198,7 +198,6 @@ void OwnCloudServiceRoot::saveAccountDataToDatabase() { } void OwnCloudServiceRoot::saveAllCachedData() { - QThread::msleep(2000); } void OwnCloudServiceRoot::addNewFeed(const QString &url) { From c228aa9518e8e44850a25aad5ded291db28106c5 Mon Sep 17 00:00:00 2001 From: martinrotter Date: Fri, 21 Apr 2017 08:08:19 +0200 Subject: [PATCH 03/10] Fix typo. --- src/gui/messagepreviewer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/messagepreviewer.cpp b/src/gui/messagepreviewer.cpp index 8e6df343f..aa2a1ffb3 100755 --- a/src/gui/messagepreviewer.cpp +++ b/src/gui/messagepreviewer.cpp @@ -50,7 +50,7 @@ void MessagePreviewer::createConnections() { QAbstractButton *btn_cancel = box.addButton(QMessageBox::Cancel); bool always; - MessageBox::setCheckBox(&box, tr("Alway open links in external browser."), &always); + MessageBox::setCheckBox(&box, tr("Always open links in external browser."), &always); box.setDefaultButton(QMessageBox::Cancel); box.exec(); From 5edac574e9b13fc82d98c5520a60d719061115c4 Mon Sep 17 00:00:00 2001 From: martinrotter Date: Fri, 21 Apr 2017 08:17:29 +0200 Subject: [PATCH 04/10] Owncloud rename and lang sync. --- localization/rssguard_cs.ts | 31 ++++++++------- localization/rssguard_da.ts | 6 +-- localization/rssguard_de.ts | 10 +++-- localization/rssguard_en.ts | 2 +- localization/rssguard_en_GB.ts | 2 +- localization/rssguard_fr.ts | 6 +-- localization/rssguard_he.ts | 2 +- localization/rssguard_id.ts | 10 +++-- localization/rssguard_it.ts | 10 +++-- localization/rssguard_ja.ts | 4 +- localization/rssguard_lt.ts | 37 ++++++++++-------- localization/rssguard_nl.ts | 37 ++++++++++-------- localization/rssguard_pl.ts | 10 +++-- localization/rssguard_pt.ts | 37 ++++++++++-------- localization/rssguard_sv.ts | 37 ++++++++++-------- resources/graphics/misc/nextcloud.png | Bin 0 -> 7408 bytes resources/graphics/misc/owncloud.png | Bin 2749 -> 0 bytes .../owncloud/owncloudserviceentrypoint.cpp | 7 ++-- 18 files changed, 135 insertions(+), 113 deletions(-) create mode 100755 resources/graphics/misc/nextcloud.png delete mode 100755 resources/graphics/misc/owncloud.png diff --git a/localization/rssguard_cs.ts b/localization/rssguard_cs.ts index f2b7146bd..efa7fe19f 100644 --- a/localization/rssguard_cs.ts +++ b/localization/rssguard_cs.ts @@ -283,12 +283,14 @@ Klikněte sem pro otevření nadřazeného adresáře. Auto-update status: %3 Tooltip for feed. - + %1%2 + +Status auto-aktualizace: %3 does not use auto-update Describes feed auto-update status. - + nepoužívá auto-aktualizace uses global settings (%n minute(s) to next auto-update) @@ -1666,7 +1668,7 @@ or this functionality is not implemented yet. &Mark all items as read - + &Označit všechny zprávy jako přečtené @@ -2194,32 +2196,33 @@ Musíte ho nainstalovat manuálně. Changelog - + Historie verzí Available files - + Dostupné soubory Download selected update - + Stáhnout vybranou aktualizaci Go to application website to get update packages manually. - + Přejděte na web aplikace pro získání balíčku aktualizace manuálně. (size - + (velikost Available update files - + Dostupné soubory aktualizace Package was downloaded successfully. You can install it now. - + Balíček byl úspěšně stažen. +Nyní ho můžete nainstalovat. @@ -2244,7 +2247,7 @@ You can install it now. MessageBox Do not show this dialog again. - + Znovu toto upozornění nezobrazovat. @@ -2294,7 +2297,7 @@ You can install it now. obrázek - Alway open links in external browser. + Always open links in external browser. @@ -2884,7 +2887,7 @@ File filter for external e-mail selection dialog. Always open links from simple internal text browser in external web browser - + Odkazy z jednoduchého interního prohlížeče vždy otevírat v externím webovém prohlížeči. @@ -3498,7 +3501,7 @@ ID účtu: %1 bytes - + bajtů diff --git a/localization/rssguard_da.ts b/localization/rssguard_da.ts index b426f6fa0..847b6e48e 100644 --- a/localization/rssguard_da.ts +++ b/localization/rssguard_da.ts @@ -284,7 +284,7 @@ Auto-update status: %3 does not use auto-update Describes feed auto-update status. - + bruger ikke automatisk ajourføring uses global settings (%n minute(s) to next auto-update) @@ -2184,7 +2184,7 @@ You must install it manually. Changelog - + Ændringslog Available files @@ -2284,7 +2284,7 @@ You can install it now. - Alway open links in external browser. + Always open links in external browser. diff --git a/localization/rssguard_de.ts b/localization/rssguard_de.ts index 28f68b44b..c8eb6cbab 100644 --- a/localization/rssguard_de.ts +++ b/localization/rssguard_de.ts @@ -281,12 +281,14 @@ Click here to open parent directory. Auto-update status: %3 Tooltip for feed. - + %1%2 + +Status der automatische Aktualisierung: %3 does not use auto-update Describes feed auto-update status. - + keine automatische Aktualisierung uses global settings (%n minute(s) to next auto-update) @@ -2191,7 +2193,7 @@ You must install it manually. Changelog - + Changelog Available files @@ -2291,7 +2293,7 @@ You can install it now. Graphik - Alway open links in external browser. + Always open links in external browser. diff --git a/localization/rssguard_en.ts b/localization/rssguard_en.ts index 948da3849..5bf7fa171 100644 --- a/localization/rssguard_en.ts +++ b/localization/rssguard_en.ts @@ -2320,7 +2320,7 @@ You can install it now. - Alway open links in external browser. + Always open links in external browser. diff --git a/localization/rssguard_en_GB.ts b/localization/rssguard_en_GB.ts index b047c1566..4cb65ac06 100644 --- a/localization/rssguard_en_GB.ts +++ b/localization/rssguard_en_GB.ts @@ -2284,7 +2284,7 @@ You can install it now. - Alway open links in external browser. + Always open links in external browser. diff --git a/localization/rssguard_fr.ts b/localization/rssguard_fr.ts index b76f3d909..b03c306ed 100644 --- a/localization/rssguard_fr.ts +++ b/localization/rssguard_fr.ts @@ -285,7 +285,7 @@ Auto-update status: %3 does not use auto-update Describes feed auto-update status. - + Ne pas utiliser la mise à jour automatique uses global settings (%n minute(s) to next auto-update) @@ -2189,7 +2189,7 @@ You must install it manually. Changelog - + Changelog Available files @@ -2289,7 +2289,7 @@ You can install it now. - Alway open links in external browser. + Always open links in external browser. diff --git a/localization/rssguard_he.ts b/localization/rssguard_he.ts index 08f56aa35..5d19e1d73 100644 --- a/localization/rssguard_he.ts +++ b/localization/rssguard_he.ts @@ -2284,7 +2284,7 @@ You can install it now. - Alway open links in external browser. + Always open links in external browser. diff --git a/localization/rssguard_id.ts b/localization/rssguard_id.ts index ec177f4e2..04e965755 100644 --- a/localization/rssguard_id.ts +++ b/localization/rssguard_id.ts @@ -281,12 +281,14 @@ Klik disini untuk membuka direktori induk. Auto-update status: %3 Tooltip for feed. - + %1%2 + +Status pembaruan otomatis: %3 does not use auto-update Describes feed auto-update status. - + tidak menggunakan pembaruan otomatis uses global settings (%n minute(s) to next auto-update) @@ -2195,7 +2197,7 @@ Anda harus instal secara manual. Changelog - + Daftar perubahan Available files @@ -2295,7 +2297,7 @@ You can install it now. gambar - Alway open links in external browser. + Always open links in external browser. diff --git a/localization/rssguard_it.ts b/localization/rssguard_it.ts index e7d662b66..74d9cf26b 100644 --- a/localization/rssguard_it.ts +++ b/localization/rssguard_it.ts @@ -282,12 +282,14 @@ Fai clic qui per aprire la cartella genitrice. Auto-update status: %3 Tooltip for feed. - + %1%2 + +Stato aggiornamento automatico: %3 does not use auto-update Describes feed auto-update status. - + non utilizza l'auto-aggiornamento uses global settings (%n minute(s) to next auto-update) @@ -2195,7 +2197,7 @@ Devi installarlo manualmente. Changelog - + Changelog Available files @@ -2295,7 +2297,7 @@ You can install it now. immagine - Alway open links in external browser. + Always open links in external browser. diff --git a/localization/rssguard_ja.ts b/localization/rssguard_ja.ts index dc050eb98..708d00a07 100644 --- a/localization/rssguard_ja.ts +++ b/localization/rssguard_ja.ts @@ -2184,7 +2184,7 @@ You must install it manually. Changelog - + 変更履歴 Available files @@ -2284,7 +2284,7 @@ You can install it now. - Alway open links in external browser. + Always open links in external browser. diff --git a/localization/rssguard_lt.ts b/localization/rssguard_lt.ts index 69ec94cb8..003ea0e3f 100644 --- a/localization/rssguard_lt.ts +++ b/localization/rssguard_lt.ts @@ -283,22 +283,24 @@ Spustelėkite čia, kad atvertumėte virškatalogį. Auto-update status: %3 Tooltip for feed. - + %1%2 + +Automatinio atnaujinimo būsena: %3 does not use auto-update Describes feed auto-update status. - + nenaudoja automatinio atnaujinimo uses global settings (%n minute(s) to next auto-update) Describes feed auto-update status. - + naudoja visuotinius nustatymus (%n minutė iki kito automatinio atnaujinimo)naudoja visuotinius nustatymus (%n minutės iki kito automatinio atnaujinimo)naudoja visuotinius nustatymus (%n minučių iki kito automatinio atnaujinimo) uses specific settings (%n minute(s) to next auto-update) Describes feed auto-update status. - + naudoja specifinius nustatymus (%n minutė iki kito automatinio atnaujinimo)naudoja specifinius nustatymus (%n minutės iki kito automatinio atnaujinimo)naudoja specifinius nustatymus (%n minučių iki kito automatinio atnaujinimo) @@ -532,7 +534,7 @@ arba šis funkcionalumas dar nėra įgyvendintas. NOT portable - + NEPERKELIAMI @@ -1667,7 +1669,7 @@ arba šis funkcionalumas dar nėra įgyvendintas. &Mark all items as read - + Žymėti visus elementus kaip &skaitytus @@ -2197,32 +2199,33 @@ Jūs privalote jį įdiegti rankiniu būdu. Changelog - + Keitimų žurnalas Available files - + Prieinami failai Download selected update - + Atsisiųsti pasirinktą atnaujinimą Go to application website to get update packages manually. - + Pereikite į programos svetainę, kad rankiniu būdu gautumėte atnaujinimo paketus. (size - + (dydis Available update files - + Prieinami atnaujinimo failai Package was downloaded successfully. You can install it now. - + Paketas buvo sėkmingai atsisiųstas. +Jūs dabar galite jį įdiegti. @@ -2247,7 +2250,7 @@ You can install it now. MessageBox Do not show this dialog again. - + Daugiau neberodyti šio dialogo. @@ -2297,7 +2300,7 @@ You can install it now. paveikslas - Alway open links in external browser. + Always open links in external browser. @@ -2887,7 +2890,7 @@ File filter for external e-mail selection dialog. Always open links from simple internal text browser in external web browser - + Visada atverti nuorodas iš paprastos vidinės tekstų naršyklės į išorinę saityno naršyklę @@ -3501,7 +3504,7 @@ Paskyros ID: %1 bytes - + baitų diff --git a/localization/rssguard_nl.ts b/localization/rssguard_nl.ts index 7962d8e2e..900283a95 100644 --- a/localization/rssguard_nl.ts +++ b/localization/rssguard_nl.ts @@ -283,22 +283,24 @@ Klik hier om map te openen. Auto-update status: %3 Tooltip for feed. - + %1%2 + +Auto update status: %3 does not use auto-update Describes feed auto-update status. - + automatisch bijwerken niet gebruiken uses global settings (%n minute(s) to next auto-update) Describes feed auto-update status. - + gebruik algemene instellingen (%n minuut(en) tot volgende auto-update)gebruik globale instellingen (%n minut(en) voor volgende automatische update) uses specific settings (%n minute(s) to next auto-update) Describes feed auto-update status. - + gebruik specifieke instellingen (%n minuut(en) tot volgende auto-update)gebruik specifieke instellingen (%n minut(en) tot volgende auto-update) @@ -532,7 +534,7 @@ of deze functie bestaat nog niet. NOT portable - + NIET portable @@ -1667,7 +1669,7 @@ of deze functie bestaat nog niet. &Mark all items as read - + &Markeer alle items als gelezen @@ -2197,32 +2199,33 @@ Je moet het handmatig installeren. Changelog - + Changelog Available files - + Beschikbare bestanden Download selected update - + Download geselecteerde update Go to application website to get update packages manually. - + Ga naar Rssguard website om update handmatig te verkrijgen (size - + (grootte Available update files - + Beschikbare update bestanden Package was downloaded successfully. You can install it now. - + Pakket was succesvol gedownload. +Installeer het nu. @@ -2247,7 +2250,7 @@ You can install it now. MessageBox Do not show this dialog again. - + Laat deze dialoog niet meer zien @@ -2297,7 +2300,7 @@ You can install it now. Beeld - Alway open links in external browser. + Always open links in external browser. @@ -2885,7 +2888,7 @@ File filter for external e-mail selection dialog. Always open links from simple internal text browser in external web browser - + Open links altijd van een simpele interne tekstbrowser in de externe browser. @@ -3500,7 +3503,7 @@ Account ID: %1 bytes - + bytes diff --git a/localization/rssguard_pl.ts b/localization/rssguard_pl.ts index e3307bab0..8ab88c159 100644 --- a/localization/rssguard_pl.ts +++ b/localization/rssguard_pl.ts @@ -284,12 +284,14 @@ Kliknij tutaj, aby otworzyć katalog nadrzędny. Auto-update status: %3 Tooltip for feed. - + %1%2 + +Stan auto-aktualizacji: %3 does not use auto-update Describes feed auto-update status. - + nie używa auto-aktualizacji uses global settings (%n minute(s) to next auto-update) @@ -2198,7 +2200,7 @@ Musisz go zainstalować ręcznie. Changelog - + Lista zmian Available files @@ -2298,7 +2300,7 @@ You can install it now. Obraz - Alway open links in external browser. + Always open links in external browser. diff --git a/localization/rssguard_pt.ts b/localization/rssguard_pt.ts index deb89bec3..17905ece5 100644 --- a/localization/rssguard_pt.ts +++ b/localization/rssguard_pt.ts @@ -282,22 +282,24 @@ Clique para abrir a pasta de destino. Auto-update status: %3 Tooltip for feed. - + %1%2 + +Status da atualização automática: %3 does not use auto-update Describes feed auto-update status. - + não usa a atualização automática uses global settings (%n minute(s) to next auto-update) Describes feed auto-update status. - + usa configurações globais (%n minuto(s) para a próxima atualização automática)usa configurações globais (%n minuto(s) para a próxima atualização automática) uses specific settings (%n minute(s) to next auto-update) Describes feed auto-update status. - + usa configurações específicas (%n minuto(s) para a próxima atualização automática)usa configurações específicas (%n minuto(s) para a próxima atualização automática) @@ -531,7 +533,7 @@ ou esta função ainda não foi implementada. NOT portable - + NÃO portátil @@ -1666,7 +1668,7 @@ ou esta função ainda não foi implementada. &Mark all items as read - + &Marcar todos os itens como lidos @@ -2196,32 +2198,33 @@ Você precisa instalá-lo manualmente. Changelog - + Log de alterações Available files - + Arquivos disponíveis Download selected update - + Baixar atualização selecionada Go to application website to get update packages manually. - + Acesse o site do aplicativo para obter os pacotes de atualização manualmente. (size - + (tamanho Available update files - + Arquivos de atualização disponíveis Package was downloaded successfully. You can install it now. - + O pacote foi baixado com sucesso. +Você pode instalá-lo agora. @@ -2246,7 +2249,7 @@ You can install it now. MessageBox Do not show this dialog again. - + Não exibir novamente. @@ -2296,7 +2299,7 @@ You can install it now. imagem - Alway open links in external browser. + Always open links in external browser. @@ -2884,7 +2887,7 @@ File filter for external e-mail selection dialog. Always open links from simple internal text browser in external web browser - + Sempre abrir links do navegador de texto interno simples no navegador externo. @@ -3498,7 +3501,7 @@ ID da Conta: %1 bytes - + bytes diff --git a/localization/rssguard_sv.ts b/localization/rssguard_sv.ts index 67aaa40a2..7f3be804a 100644 --- a/localization/rssguard_sv.ts +++ b/localization/rssguard_sv.ts @@ -282,22 +282,24 @@ Klicka här för att öppna målmappen. Auto-update status: %3 Tooltip for feed. - + %1%2 + +Autouppdateringsstatus: %3 does not use auto-update Describes feed auto-update status. - + uppdateras inte automatiskt uses global settings (%n minute(s) to next auto-update) Describes feed auto-update status. - + använder global inställning (%n minut till nästa automatiska uppdatering)använder globala inställningar (%n minuter till nästa automatiska uppdatering) uses specific settings (%n minute(s) to next auto-update) Describes feed auto-update status. - + använder specifik inställning (%n minut till nästa automatiska uppdatering)använder specifika inställningar (%n minuter till nästa automatiska uppdatering) @@ -531,7 +533,7 @@ att funktionen inte är implementerad än. NOT portable - + INTE portabel @@ -1666,7 +1668,7 @@ att funktionen inte är implementerad än. &Mark all items as read - + &Märk alla objekt som lästa @@ -2195,32 +2197,33 @@ Du måste installera det manuellt. Changelog - + Ändringslogg Available files - + Tillgängliga filer Download selected update - + Ladda ner vald uppdatering Go to application website to get update packages manually. - + Gå till programmets webbsida för att hämta uppdateringspaketet manuellt. (size - + (storlek Available update files - + Tillgängliga uppdateringsfiler Package was downloaded successfully. You can install it now. - + Paketet har laddats ner. +Du kan installera det nu. @@ -2245,7 +2248,7 @@ You can install it now. MessageBox Do not show this dialog again. - + Visa inte denna dialog igen. @@ -2295,7 +2298,7 @@ You can install it now. bild - Alway open links in external browser. + Always open links in external browser. @@ -2881,7 +2884,7 @@ File filter for external e-mail selection dialog. Always open links from simple internal text browser in external web browser - + Öppna alltid länkar från intern textläsare, i extern webbläsare. @@ -3496,7 +3499,7 @@ Konto-ID: %1 bytes - + byte diff --git a/resources/graphics/misc/nextcloud.png b/resources/graphics/misc/nextcloud.png new file mode 100755 index 0000000000000000000000000000000000000000..65fafbc63ee9528a0949bf208f6ba502c68b2675 GIT binary patch literal 7408 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 z zIE&B$eRVqgcFTWw^0Dz)Slqi(LkBA>rcHi?UmJhbdh!5WeLVSa=>noh4d=xL?^1QW zS})%kV}O76t|V;zl$V~Jsy=yu;*v6)oOG}74*hhRsK_wA4sHlhk)g!zJ)+Z25iyuA z*Dlt(1DXZE*T;iRpTCcnmL;d9g#|*io?5EPDyph$bQVC2p@*L@`2|IKrT4&ofxI$% zhF*Tv0gxn#e=UDaV+nd2xvLWeg(a;zD=IES?(C@7fsMi0(VpUxGQDhPOqr-xN2mkv z@Q84N0(!J)=-<67N$1j9byiVXg?$SFycamw+fh=c-xAou!kkIb3Y~W90E~M$vQ@)L z(F(Th+S{s4r;gT?w_%mHyh7DthH7JY_yCXAa%YHjdAFLZI{e7cAnKSNZgDuob2Y}^(vBBGxXo8x{EdDjX>QAwE?{>XH3B{yHEFGI<= zlr0{4`~`#dsZdplVPl_E|1T*k7c*wRA#R_ucc4P3FM+CR-ScK}AAhFBMDzIHUm^nEu_WCkY3SGcq#NpnVF9N^xm2C_CEQ@yV(; z3GUM*+iyqW^qCaBBfB~72jLSmQk+Z4(AcKTxhjT@eNxodHyG4gtx;23E5b)lGdQ!h z?o1G`FNxJ?-+%a|W(FkucwFzuj#do8*V{wutkJED7r}x4e6x9%LA}))pMU+mx>{ri z@q3S;7_ON$1N-$+|5gWJMw{Sk~?n_sRXH(e} zw}&~;PBm!1l=O>S{pA`%2WzQAG+j$I9T4WewnDGex?Wu)LPt$$)#li#vm$)-G?8^V z*Pyg*O6H{;5jtv$NKVZ(Xus;3S}|twbK>C9Q(Cw0KXgL#5&+n`Gl7+B*XvyJcC_w* zua76ke?HfuP4Aw5R90PQ+}~c{@UcXLdJk?^gvL*Mk?QJNoqC#5TUW>I`AZoxs2{__ zAJo|1&~SrQAAhC(uTc>?nV8Ili&=yO_0o8ndz;Ft>l`_r$k&^9F=pgYI@>gVkGj6T zfjJA8k$T}0b#?V@-@TtqWe&Z2`srNATvT3W{y#rp)kj}ZU*AAYZ5=!Qdk}lu&II&& z0GZVCLzA?OEN0Dli{n3^qo%fwuz|tNj#pG%%IpP8IdM8!-PU43#M07&$RPuX2pfQh zyDQcmtjNtP;8fCib|)NG-)=fN*zxT2$qWtckGZ*w^Jy3Pxys%jPmp@yQi~_p-LDIi#*QE&{HCT(*47jhm2fuY0`Un)*mK}$ zvzsL|nT$aLg6QJqPJTf#Cr&3*TUXayQ(HbB|2^=he?{hg08A~w)Z7n%sRfvt`vCy- zy8-xPqLKl5rdDAp1mwv8!x!p*5M+qcGKAP+Y9XdWwo~S6RsKDoG_@2Hkkz@-eur6p zetx69Th~009yPV1_CyG2rZRO`su@5TmxF zlDIc7-u#x4c>hW-hlT(Ddk0>96q6*075wqOB~%I_&C5;MyS-_n*78a~K#XOjtbDvc zOc2mdy7~G1@9pENDgn7NNJJ8GE*9lG5)%^}?lk%z2xZZe-0~yT00000NkvXXu0mjf DrddDC diff --git a/src/services/owncloud/owncloudserviceentrypoint.cpp b/src/services/owncloud/owncloudserviceentrypoint.cpp index 33089089f..45244f19d 100755 --- a/src/services/owncloud/owncloudserviceentrypoint.cpp +++ b/src/services/owncloud/owncloudserviceentrypoint.cpp @@ -38,7 +38,6 @@ ServiceRoot *OwnCloudServiceEntryPoint::createNewRoot() const { } QList OwnCloudServiceEntryPoint::initializeSubtree() const { - // Check DB if standard account is enabled. QSqlDatabase database = qApp->database()->connection(QSL("OwnCloudServiceEntryPoint"), DatabaseFactory::FromSettings); return DatabaseQueries::getOwnCloudAccounts(database); @@ -49,7 +48,7 @@ bool OwnCloudServiceEntryPoint::isSingleInstanceService() const { } QString OwnCloudServiceEntryPoint::name() const { - return QSL("ownCloud News"); + return QSL("NextCloud News"); } QString OwnCloudServiceEntryPoint::code() const { @@ -57,7 +56,7 @@ QString OwnCloudServiceEntryPoint::code() const { } QString OwnCloudServiceEntryPoint::description() const { - return QObject::tr("The News app is an RSS/Atom feed aggregator. It is part of ownCloud suite. This plugin implements %1 API.").arg(API_VERSION); + return QObject::tr("The News app is an RSS/Atom feed aggregator. It is part of Nextcloud suite. This plugin implements %1 API.").arg(API_VERSION); } QString OwnCloudServiceEntryPoint::version() const { @@ -69,6 +68,6 @@ QString OwnCloudServiceEntryPoint::author() const { } QIcon OwnCloudServiceEntryPoint::icon() const { - return qApp->icons()->miscIcon(QSL("owncloud")); + return qApp->icons()->miscIcon(QSL("nextcloud")); } From a3849dd64bd5d8bbddbfcc1b98acd2682268fb47 Mon Sep 17 00:00:00 2001 From: martinrotter Date: Fri, 21 Apr 2017 08:26:20 +0200 Subject: [PATCH 05/10] Fix compilation. --- src/miscellaneous/feedreader.cpp | 10 +++++----- src/miscellaneous/feedreader.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/miscellaneous/feedreader.cpp b/src/miscellaneous/feedreader.cpp index aeae24e79..9863c9823 100755 --- a/src/miscellaneous/feedreader.cpp +++ b/src/miscellaneous/feedreader.cpp @@ -38,7 +38,7 @@ FeedReader::FeedReader(QObject *parent) : QObject(parent), m_feedServices(QList()), - m_cacheSaveFutureWatcher(QFutureWatcher()), m_autoUpdateTimer(new QTimer(this)), + m_cacheSaveFutureWatcher(new QFutureWatcher(this)), m_autoUpdateTimer(new QTimer(this)), m_feedDownloaderThread(nullptr), m_feedDownloader(nullptr), m_dbCleanerThread(nullptr), m_dbCleaner(nullptr) { m_feedsModel = new FeedsModel(this); @@ -46,7 +46,7 @@ FeedReader::FeedReader(QObject *parent) m_messagesModel = new MessagesModel(this); m_messagesProxyModel = new MessagesProxyModel(m_messagesModel, this); - connect(&m_cacheSaveFutureWatcher, &QFutureWatcher::finished, this, &FeedReader::asyncCacheSaveFinished); + connect(m_cacheSaveFutureWatcher, &QFutureWatcher::finished, this, &FeedReader::asyncCacheSaveFinished); connect(m_autoUpdateTimer, &QTimer::timeout, this, &FeedReader::executeNextAutoUpdate); updateAutoUpdateStatus(); asyncCacheSaveFinished(); @@ -219,7 +219,7 @@ void FeedReader::checkServicesForAsyncOperations() { } void FeedReader::checkServicesForAsyncOperations(bool wait_for_future) { - if (m_cacheSaveFutureWatcher.future().isStarted() || m_cacheSaveFutureWatcher.future().isRunning()) { + if (m_cacheSaveFutureWatcher->future().isStarted() || m_cacheSaveFutureWatcher->future().isRunning()) { qDebug("Previous future is still running or was already started."); @@ -227,7 +227,7 @@ void FeedReader::checkServicesForAsyncOperations(bool wait_for_future) { // we save all cached data (app exit). if (wait_for_future) { qWarning("Waiting for previously started saving of cached service data."); - m_cacheSaveFutureWatcher.future().waitForFinished(); + m_cacheSaveFutureWatcher->future().waitForFinished(); } else { qWarning("Some cached service data are being saved now, so aborting this saving cycle."); @@ -248,7 +248,7 @@ void FeedReader::checkServicesForAsyncOperations(bool wait_for_future) { future.waitForFinished(); } else { - m_cacheSaveFutureWatcher.setFuture(future); + m_cacheSaveFutureWatcher->setFuture(future); } } diff --git a/src/miscellaneous/feedreader.h b/src/miscellaneous/feedreader.h index 6e45bce66..46c0b8413 100755 --- a/src/miscellaneous/feedreader.h +++ b/src/miscellaneous/feedreader.h @@ -94,7 +94,7 @@ class FeedReader : public QObject { MessagesModel *m_messagesModel; MessagesProxyModel *m_messagesProxyModel; - QFutureWatcher m_cacheSaveFutureWatcher; + QFutureWatcher *m_cacheSaveFutureWatcher; // Auto-update stuff. QTimer *m_autoUpdateTimer; From 34902d33ad6d12519193c21a42b4286d67e78b2a Mon Sep 17 00:00:00 2001 From: martinrotter Date: Fri, 21 Apr 2017 08:29:17 +0200 Subject: [PATCH 06/10] Remove superfluous includes. --- src/gui/statusbar.cpp | 1 - src/miscellaneous/application.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/gui/statusbar.cpp b/src/gui/statusbar.cpp index 98164999c..f3672bb5d 100755 --- a/src/gui/statusbar.cpp +++ b/src/gui/statusbar.cpp @@ -26,7 +26,6 @@ #include #include #include -#include StatusBar::StatusBar(QWidget *parent) : QStatusBar(parent), m_mutex(new Mutex(QMutex::NonRecursive, this)) { diff --git a/src/miscellaneous/application.cpp b/src/miscellaneous/application.cpp index 8d1a23bc0..4b7a21dd1 100755 --- a/src/miscellaneous/application.cpp +++ b/src/miscellaneous/application.cpp @@ -35,7 +35,6 @@ #include "services/owncloud/owncloudserviceentrypoint.h" #include -#include #include #if defined(USE_WEBENGINE) From 3eaef9e9f61d7de78b9e6cafb715700b8580b3b2 Mon Sep 17 00:00:00 2001 From: martinrotter Date: Fri, 21 Apr 2017 08:30:43 +0200 Subject: [PATCH 07/10] Remove superfluous includes. --- src/services/owncloud/owncloudserviceroot.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/services/owncloud/owncloudserviceroot.cpp b/src/services/owncloud/owncloudserviceroot.cpp index f4895e101..65836513e 100755 --- a/src/services/owncloud/owncloudserviceroot.cpp +++ b/src/services/owncloud/owncloudserviceroot.cpp @@ -31,8 +31,6 @@ #include "services/owncloud/gui/formeditowncloudaccount.h" #include "services/owncloud/gui/formowncloudfeeddetails.h" -#include - OwnCloudServiceRoot::OwnCloudServiceRoot(RootItem *parent) : ServiceRoot(parent), m_recycleBin(new OwnCloudRecycleBin(this)), From 935ef8c76946bd7e90c4adfa9760d712ac309f92 Mon Sep 17 00:00:00 2001 From: martinrotter Date: Fri, 21 Apr 2017 08:48:01 +0200 Subject: [PATCH 08/10] Lang sync. --- localization/rssguard_cs.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/localization/rssguard_cs.ts b/localization/rssguard_cs.ts index efa7fe19f..fffa9c179 100644 --- a/localization/rssguard_cs.ts +++ b/localization/rssguard_cs.ts @@ -295,12 +295,12 @@ Status auto-aktualizace: %3 uses global settings (%n minute(s) to next auto-update) Describes feed auto-update status. - + používá globální nastavení (%n minuta do další aktualizace)používá globální nastavení (%n minuty do další aktualizace)používá globální nastavení (%n minut do další aktualizace) uses specific settings (%n minute(s) to next auto-update) Describes feed auto-update status. - + používá specifické nastavení (%n minuta do další aktualizace)používá specifické nastavení (%n minuty do další aktualizace)používá specifické nastavení (%n minut do další aktualizace) @@ -533,7 +533,7 @@ or this functionality is not implemented yet. NOT portable - + NEportable @@ -2298,7 +2298,7 @@ Nyní ho můžete nainstalovat. Always open links in external browser. - + Vždy otevírat odkazy v ext. prohlížeči. From 09630f1e81ebc8ad71f127cf2edacdc36955c762 Mon Sep 17 00:00:00 2001 From: martinrotter Date: Fri, 21 Apr 2017 09:59:04 +0200 Subject: [PATCH 09/10] Very initial implementation of #71. --- src/miscellaneous/feedreader.cpp | 4 +- src/services/abstract/serviceroot.h | 2 - src/services/owncloud/owncloudserviceroot.cpp | 63 ++++++++++++++++--- src/services/owncloud/owncloudserviceroot.h | 7 +++ 4 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/miscellaneous/feedreader.cpp b/src/miscellaneous/feedreader.cpp index 9863c9823..9dca3071b 100755 --- a/src/miscellaneous/feedreader.cpp +++ b/src/miscellaneous/feedreader.cpp @@ -219,8 +219,8 @@ void FeedReader::checkServicesForAsyncOperations() { } void FeedReader::checkServicesForAsyncOperations(bool wait_for_future) { - if (m_cacheSaveFutureWatcher->future().isStarted() || m_cacheSaveFutureWatcher->future().isRunning()) { - qDebug("Previous future is still running or was already started."); + if (m_cacheSaveFutureWatcher->future().isRunning()) { + qDebug("Previous future is still running."); // If we want to wait for future synchronously, we want to make sure that diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index e17fe9ae6..7850d83f4 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -84,8 +84,6 @@ class ServiceRoot : public RootItem { virtual void start(bool freshly_activated) = 0; virtual void stop() = 0; - // Is called in short intervals in worker thread. - // Service can save its cached data (if any) here. virtual void saveAllCachedData(); // Account ID corresponds with DB attribute Accounts (id). diff --git a/src/services/owncloud/owncloudserviceroot.cpp b/src/services/owncloud/owncloudserviceroot.cpp index 65836513e..3c1867618 100755 --- a/src/services/owncloud/owncloudserviceroot.cpp +++ b/src/services/owncloud/owncloudserviceroot.cpp @@ -33,7 +33,8 @@ OwnCloudServiceRoot::OwnCloudServiceRoot(RootItem *parent) - : ServiceRoot(parent), m_recycleBin(new OwnCloudRecycleBin(this)), + : ServiceRoot(parent), m_cacheSaveMutex(new Mutex(QMutex::NonRecursive, this)), m_cachedStatesRead(QMap()), + m_cachedStatesImportant(QMap()), m_recycleBin(new OwnCloudRecycleBin(this)), m_actionSyncIn(nullptr), m_serviceMenu(QList()), m_network(new OwnCloudNetworkFactory()) { setIcon(OwnCloudServiceEntryPoint().icon()); } @@ -112,12 +113,61 @@ OwnCloudNetworkFactory *OwnCloudServiceRoot::network() const { return m_network; } +void OwnCloudServiceRoot::saveAllCachedData() { + if (m_cachedStatesRead.isEmpty() && m_cachedStatesImportant.isEmpty()) { + // No cached changes. + return; + } + + m_cacheSaveMutex->lock(); + + // Make copy of changes. + QMap cached_data_read = m_cachedStatesRead; + cached_data_read.detach(); + + QMap cached_data_imp = m_cachedStatesImportant; + cached_data_imp.detach(); + + m_cachedStatesRead.clear(); + m_cachedStatesImportant.clear(); + + m_cacheSaveMutex->unlock(); + + // Save the actual data. + for (int i = 0; i < cached_data_read.size(); i++) { + auto key = cached_data_read.keys().at(i); + QStringList ids = cached_data_read[key]; + + if (!ids.isEmpty()) { + network()->markMessagesRead(key, ids); + } + } +} + bool OwnCloudServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, const QList &messages, RootItem::ReadStatus read) { Q_UNUSED(selected_item) - QNetworkReply::NetworkError reply = network()->markMessagesRead(read, customIDsOfMessages(messages)); - return reply == QNetworkReply::NoError; + m_cacheSaveMutex->lock(); + + QStringList &list_act = m_cachedStatesRead[read]; + QStringList &list_other = m_cachedStatesRead[read == RootItem::Read ? RootItem::Unread : RootItem::Read]; + + // Store changes, they will be sent to server later. + list_act.append(customIDsOfMessages(messages)); + + QSet set_act = list_act.toSet(); + QSet set_other = list_other.toSet(); + + // Now, we want to remove all IDS from list_other, which are contained in list. + set_other -= set_act; + + list_act.clear(); list_act.append(set_act.toList()); + list_other.clear(); list_other.append(set_other.toList()); + + m_cacheSaveMutex->unlock(); + + return true; } bool OwnCloudServiceRoot::onBeforeSwitchMessageImportance(RootItem *selected_item, @@ -185,8 +235,8 @@ void OwnCloudServiceRoot::saveAccountDataToDatabase() { if (saved) { if (DatabaseQueries::createOwnCloudAccount(database, id_to_assign, m_network->authUsername(), - m_network->authPassword(), m_network->url(), - m_network->forceServerSideUpdate())) { + m_network->authPassword(), m_network->url(), + m_network->forceServerSideUpdate())) { setId(id_to_assign); setAccountId(id_to_assign); updateTitle(); @@ -195,9 +245,6 @@ void OwnCloudServiceRoot::saveAccountDataToDatabase() { } } -void OwnCloudServiceRoot::saveAllCachedData() { -} - void OwnCloudServiceRoot::addNewFeed(const QString &url) { if (!qApp->feedUpdateLock()->tryLock()) { // Lock was not obtained because diff --git a/src/services/owncloud/owncloudserviceroot.h b/src/services/owncloud/owncloudserviceroot.h index 43ff2a91f..56cbed572 100755 --- a/src/services/owncloud/owncloudserviceroot.h +++ b/src/services/owncloud/owncloudserviceroot.h @@ -20,9 +20,12 @@ #include "services/abstract/serviceroot.h" +#include + class OwnCloudNetworkFactory; class OwnCloudRecycleBin; +class Mutex; class OwnCloudServiceRoot : public ServiceRoot { Q_OBJECT @@ -58,6 +61,10 @@ class OwnCloudServiceRoot : public ServiceRoot { void addNewCategory(); private: + Mutex *m_cacheSaveMutex; + QMap m_cachedStatesRead; + QMap m_cachedStatesImportant; + QMap storeCustomFeedsData(); void restoreCustomFeedsData(const QMap &data, const QHash &feeds); RootItem *obtainNewTreeForSyncIn() const; From 013a2ff0e625a4a4fbad054853b091c2b93de957 Mon Sep 17 00:00:00 2001 From: martinrotter Date: Fri, 21 Apr 2017 13:41:51 +0200 Subject: [PATCH 10/10] New async msg changes now work when marking whole feed/recycle bin read/unread. ONLY owncloud so far. --- src/services/owncloud/owncloudfeed.cpp | 11 +---- src/services/owncloud/owncloudrecyclebin.cpp | 11 +---- src/services/owncloud/owncloudserviceroot.cpp | 41 ++++++++++--------- src/services/owncloud/owncloudserviceroot.h | 2 + 4 files changed, 28 insertions(+), 37 deletions(-) diff --git a/src/services/owncloud/owncloudfeed.cpp b/src/services/owncloud/owncloudfeed.cpp index 9c742d8f6..fe4471a66 100755 --- a/src/services/owncloud/owncloudfeed.cpp +++ b/src/services/owncloud/owncloudfeed.cpp @@ -89,15 +89,8 @@ bool OwnCloudFeed::removeItself() { } bool OwnCloudFeed::markAsReadUnread(RootItem::ReadStatus status) { - QStringList ids = getParentServiceRoot()->customIDSOfMessagesForItem(this); - QNetworkReply::NetworkError response = serviceRoot()->network()->markMessagesRead(status, ids); - - if (response != QNetworkReply::NoError) { - return false; - } - else { - return getParentServiceRoot()->markFeedsReadUnread(QList() << this, status); - } + serviceRoot()->addMessageStatesToCache(getParentServiceRoot()->customIDSOfMessagesForItem(this), status); + return getParentServiceRoot()->markFeedsReadUnread(QList() << this, status); } bool OwnCloudFeed::cleanMessages(bool clear_only_read) { diff --git a/src/services/owncloud/owncloudrecyclebin.cpp b/src/services/owncloud/owncloudrecyclebin.cpp index 128ceb559..5e9cb715d 100755 --- a/src/services/owncloud/owncloudrecyclebin.cpp +++ b/src/services/owncloud/owncloudrecyclebin.cpp @@ -34,13 +34,6 @@ OwnCloudServiceRoot *OwnCloudRecycleBin::serviceRoot() { } bool OwnCloudRecycleBin::markAsReadUnread(RootItem::ReadStatus status) { - QStringList ids = getParentServiceRoot()->customIDSOfMessagesForItem(this); - QNetworkReply::NetworkError response = serviceRoot()->network()->markMessagesRead(status, ids); - - if (response != QNetworkReply::NoError) { - return false; - } - else { - return RecycleBin::markAsReadUnread(status); - } + serviceRoot()->addMessageStatesToCache(getParentServiceRoot()->customIDSOfMessagesForItem(this), status); + return RecycleBin::markAsReadUnread(status); } diff --git a/src/services/owncloud/owncloudserviceroot.cpp b/src/services/owncloud/owncloudserviceroot.cpp index 3c1867618..182e1496b 100755 --- a/src/services/owncloud/owncloudserviceroot.cpp +++ b/src/services/owncloud/owncloudserviceroot.cpp @@ -113,6 +113,27 @@ OwnCloudNetworkFactory *OwnCloudServiceRoot::network() const { return m_network; } +void OwnCloudServiceRoot::addMessageStatesToCache(const QStringList &ids_of_messages, RootItem::ReadStatus read) { + m_cacheSaveMutex->lock(); + + QStringList &list_act = m_cachedStatesRead[read]; + QStringList &list_other = m_cachedStatesRead[read == RootItem::Read ? RootItem::Unread : RootItem::Read]; + + // Store changes, they will be sent to server later. + list_act.append(ids_of_messages); + + QSet set_act = list_act.toSet(); + QSet set_other = list_other.toSet(); + + // Now, we want to remove all IDS from list_other, which are contained in list. + set_other -= set_act; + + list_act.clear(); list_act.append(set_act.toList()); + list_other.clear(); list_other.append(set_other.toList()); + + m_cacheSaveMutex->unlock(); +} + void OwnCloudServiceRoot::saveAllCachedData() { if (m_cachedStatesRead.isEmpty() && m_cachedStatesImportant.isEmpty()) { // No cached changes. @@ -148,25 +169,7 @@ bool OwnCloudServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, const RootItem::ReadStatus read) { Q_UNUSED(selected_item) - m_cacheSaveMutex->lock(); - - QStringList &list_act = m_cachedStatesRead[read]; - QStringList &list_other = m_cachedStatesRead[read == RootItem::Read ? RootItem::Unread : RootItem::Read]; - - // Store changes, they will be sent to server later. - list_act.append(customIDsOfMessages(messages)); - - QSet set_act = list_act.toSet(); - QSet set_other = list_other.toSet(); - - // Now, we want to remove all IDS from list_other, which are contained in list. - set_other -= set_act; - - list_act.clear(); list_act.append(set_act.toList()); - list_other.clear(); list_other.append(set_other.toList()); - - m_cacheSaveMutex->unlock(); - + addMessageStatesToCache(customIDsOfMessages(messages), read); return true; } diff --git a/src/services/owncloud/owncloudserviceroot.h b/src/services/owncloud/owncloudserviceroot.h index 56cbed572..a99fb4049 100755 --- a/src/services/owncloud/owncloudserviceroot.h +++ b/src/services/owncloud/owncloudserviceroot.h @@ -48,6 +48,8 @@ class OwnCloudServiceRoot : public ServiceRoot { OwnCloudNetworkFactory *network() const; + void addMessageStatesToCache(const QStringList &ids_of_messages, ReadStatus read); + bool onBeforeSetMessagesRead(RootItem *selected_item, const QList &messages, ReadStatus read); bool onBeforeSwitchMessageImportance(RootItem *selected_item, const QList &changes);