diff --git a/localization/rssguard_cs.ts b/localization/rssguard_cs.ts index f2b7146bd..fffa9c179 100644 --- a/localization/rssguard_cs.ts +++ b/localization/rssguard_cs.ts @@ -283,22 +283,24 @@ 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) 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) @@ -531,7 +533,7 @@ or this functionality is not implemented yet. NOT portable - + NEportable @@ -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,8 +2297,8 @@ You can install it now. obrázek - Alway open links in external browser. - + Always open links in external browser. + Vždy otevírat odkazy v ext. prohlížeči. @@ -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 000000000..65fafbc63 Binary files /dev/null and b/resources/graphics/misc/nextcloud.png differ diff --git a/resources/graphics/misc/owncloud.png b/resources/graphics/misc/owncloud.png deleted file mode 100755 index 75bd1bbf9..000000000 Binary files a/resources/graphics/misc/owncloud.png and /dev/null differ diff --git a/rssguard.pro b/rssguard.pro index 512df2e2c..672a69c89 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/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 d17b33215..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) @@ -373,7 +372,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..9dca3071b 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(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); @@ -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().isRunning()) { + qDebug("Previous future is still running."); + + + // 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..46c0b8413 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..7850d83f4 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,8 @@ class ServiceRoot : public RootItem { virtual void start(bool freshly_activated) = 0; virtual void stop() = 0; + 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/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/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")); } diff --git a/src/services/owncloud/owncloudserviceroot.cpp b/src/services/owncloud/owncloudserviceroot.cpp index 928252c7e..182e1496b 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,64 @@ 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. + 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; + addMessageStatesToCache(customIDsOfMessages(messages), read); + return true; } bool OwnCloudServiceRoot::onBeforeSwitchMessageImportance(RootItem *selected_item, @@ -185,8 +238,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(); diff --git a/src/services/owncloud/owncloudserviceroot.h b/src/services/owncloud/owncloudserviceroot.h index 3c2ddef6b..a99fb4049 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 @@ -45,17 +48,25 @@ 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); void updateTitle(); void saveAccountDataToDatabase(); + void saveAllCachedData(); + public slots: void addNewFeed(const QString &url); 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;