diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100755 index 000000000..bb9a6da42 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,46 @@ +version: 666.{build} +skip_tags: true +image: Visual Studio 2013 +clone_depth: 1 +clone_folder: c:\rssguard + +branches: + only: + - master + - dev + except: + - build-artifacts + +environment: + QTDIR: 'C:\Qt\5.7\msvc2013' + QMAKESPEC: win32-msvc2013 + COMPILERBAT: '"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86' + access_token: + secure: XCWdr9wPgK4gm6289WXCg2vtMA02eBSnj6eKHC+ps6Z5lgw0jsK09UQ5y9E9ZFwS + +build_script: + - git submodule update --init --recursive + - set "QT_PLUGIN_PATH=%QTDIR%\plugins" + - set "PATH=%QTDIR%\bin;%PATH%" + - '%COMPILERBAT%' + - dir + - cd .. + - mkdir rssguard-build + - cd rssguard-build + - C:\Qt\5.7\msvc2013\bin\qmake.exe C:\rssguard + - nmake + - nmake windows_all + +on_success: + - dir + - git clone -q --depth=1 --branch=build-artifacts https://github.com/martinrotter/rssguard.git c:\rssguard-artifacts + - git config --global credential.helper store + - ps: Add-Content "$env:USERPROFILE\.git-credentials" "https://$($env:access_token):x-oauth-basic@github.com`n" + - git config --global user.email "rotter.martinos@gmail.com" + - git config --global user.name "martinrotter" + - cd ..\rssguard-build + - for /f "tokens=*" %%F in ('dir /s /b *.7z') do curl --upload-file %%F https://transfer.sh/rssguard-win32.7z --silent >> ..\rssguard-artifacts\windows-builds.txt + - cd ..\rssguard-artifacts + - git add *.* + - git commit -m "New files." + - git push origin build-artifacts \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index e466742a1..eb3c8929c 100755 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,12 @@ -dist: trusty - language: cpp +osx_image: xcode7.3 +sudo: required +dist: trusty os: - linux - + - osx + compiler: - gcc @@ -12,15 +14,10 @@ git: submodules: false depth: 3 -before_install: - - sudo add-apt-repository ppa:beineri/opt-qt57-trusty -y - - sudo apt-get update - - sudo apt-get -y install qt57tools qt57base qt57webengine +before_install: ./resources/scripts/.travis-before-install.sh install: true script: - - source /opt/qt57/bin/qt57-env.sh - - mkdir rssguard-build && cd rssguard-build - - qmake .. - - make \ No newline at end of file + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./resources/scripts/.travis-install-linux.sh ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ./resources/scripts/.travis-install-osx.sh ; fi \ No newline at end of file diff --git a/README.md b/README.md index 88d577a7f..e3ea26ea9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ RSS Guard ========= -[![Build status](https://img.shields.io/travis/martinrotter/rssguard.svg?maxAge=360)](https://travis-ci.org/martinrotter/rssguard) +[![AppVeyor](https://img.shields.io/appveyor/ci/martinrotter/rssguard.svg?maxAge=360)](https://ci.appveyor.com/project/martinrotter/rssguard) +[![Travis CI](https://img.shields.io/travis/martinrotter/rssguard.svg?maxAge=360)](https://travis-ci.org/martinrotter/rssguard) [![Total downloads](https://img.shields.io/github/downloads/martinrotter/rssguard/total.svg?maxAge=360)](#) [![Version](https://img.shields.io/github/release/martinrotter/rssguard.svg?maxAge=360)](#) [![GitHub issues](https://img.shields.io/github/issues/martinrotter/rssguard.svg?maxAge=360)](#) @@ -61,6 +62,7 @@ Downloads * [official downloads](https://github.com/martinrotter/rssguard/releases), * alternative downloads: * [Archlinux AUR package](https://aur.archlinux.org/packages/rssguard/), + * [Automatically generated test builds](https://github.com/martinrotter/rssguard/tree/build-artifacts), * [OBS/development releases](https://build.opensuse.org/package/show/home:skunkos:rssguard/rssguard-git) (click "Download package" in top/right corner of the website). [![Alternative RSS Guard downloads.](http://www.instalki.pl/img/buttons/en/download_dark.png)](http://www.instalki.pl/programy/download/Windows/czytniki_RSS/RSS_Guard.html) @@ -73,7 +75,7 @@ Features -------- RSS Guard is simple (yet powerful) feed reader. It is able to fetch the most known feed formats, including RSS/RDF and ATOM. RSS Guard is developed on top of the [Qt library](http://qt-project.org/) and it supports these operating systems: -* Windows XP and newer, +* Windows Vista and newer, * GNU/Linux, * Mac OS X, * xBSD (possibly), diff --git a/localization/qtbase-cs.ts b/localization/qtbase-cs.ts index d08496a29..4824e1041 100644 --- a/localization/qtbase-cs.ts +++ b/localization/qtbase-cs.ts @@ -2176,10 +2176,6 @@ Přesto chcete soubor smazat? <p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across all major desktop operating systems. It is also available for embedded Linux and other embedded and mobile operating systems.</p><p>Qt is available under three different licensing options designed to accommodate the needs of our various users.</p><p>Qt licensed under our commercial license agreement is appropriate for development of proprietary/commercial software where you do not want to share any source code with third parties or otherwise cannot comply with the terms of the GNU LGPL version 2.1 or GNU GPL version 3.0.</p><p>Qt licensed under the GNU LGPL version 2.1 is appropriate for the development of Qt applications provided you can comply with the terms and conditions of the GNU LGPL version 2.1.</p><p>Qt licensed under the GNU General Public License version 3.0 is appropriate for the development of Qt applications where you wish to use such applications in combination with software subject to the terms of the GNU GPL version 3.0 or where you are otherwise willing to comply with the terms of the GNU GPL version 3.0.</p><p>Please see <a href="http://qt.io/licensing/">qt.io/licensing</a> for an overview of Qt licensing.</p><p>Copyright (C) 2015 The Qt Company Ltd and other contributors.</p><p>Qt and the Qt logo are trademarks of Digia Plc and/or its subsidiary(-ies).</p><p>Qt is developed as an open source project on <a href="http://qt-project.org/">qt-project.org</a>.</p><p>Qt is a Digia product. See <a href="http://qt.io/">qt.io</a> for more information.</p> <p>Qt je sadou softwarových nástrojů C++ určených pro víceplatformní vývoj aplikací.</p><p>Qt poskytuje snadnou přenositelnost a jednotný zdrojový kód pro MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux a všechny hlavní prodejní varianty systému Unix. Qt je rovněž dostupné pro vestavěná zařízení jako Qt pro Embedded Linux a Qt pro Windows CE.</p><p>Qt je dostupné s třemi rozdílnými licencemi, aby vyhovělo širokým řadám našich uživatelů.</p>Qt s naší obchodní licenční smlouvou je vhodné pro vývoj soukromého/obchodního software, u kterého si nepřejete sdílet jakýkoli zdrojový kód se třetími stranami anebo z jiného důvodu nemůžete vyhovět podmínkám GNU LGPL ve verzi 2.1 nebo GNU GPL ve verzi 3.0.</p><p>Qt s licencí GNU LGPL ve verzi 2.1 je vhodné pro vývoj Qt aplikací (soukromých nebo s otevřeným zdrojovým kódem) za předpokladu, že můžete souhlasit s požadavky a podmínkami GNU LGPL verze 2.1.</p><p>Qt s licencí GNU General Public License ve verzi 3.0 je vhodné pro vývoj aplikací Qt, u nichž si přejete použít takovou aplikaci ve spojení se software, který podléhá požadavkům GNU GPL ve verzi 3.0, nebo kde jste jinak ochotni souhlasit s podmínkami GNU GPL ve verzi 3.0.</p><p>Více informací najdete na <a href="http://qt.io/licensing/">qt.nokia.com/products/licensing</a>.</p><p>Autorské právo (C) 2015 The Qt Company Ltd a/nebo její dceřinná(é) společnost(i) a další přispěvatelé.</p><p>Qt a logo Qt jsou obchodní značky Digia Plc a/nebo její dceřinná(é) společnost(i).</p><p>Qt je vyvíjeno jako projekt s otevřeným zdrojovým kódem na <a href="http://qt-project.org/">qt-project.org</a>.</p><p>Qt je výrobkem společnosti Digia. Další informace najdete na <a href="http://qt.io/">qt.io</a>. href="http://qt.io/">qt.nokia.com</a>.</p> - - <p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across all major desktop operating systems. It is also available for embedded Linux and other embedded and mobile operating systems.</p><p>Qt is available under three different licensing options designed to accommodate the needs of our various users.</p><p>Qt licensed under our commercial license agreement is appropriate for development of proprietary/commercial software where you do not want to share any source code with third parties or otherwise cannot comply with the terms of the GNU LGPL version 2.1 or GNU GPL version 3.0.</p><p>Qt licensed under the GNU LGPL version 2.1 is appropriate for the development of Qt applications provided you can comply with the terms and conditions of the GNU LGPL version 2.1.</p><p>Qt licensed under the GNU General Public License version 3.0 is appropriate for the development of Qt applications where you wish to use such applications in combination with software subject to the terms of the GNU GPL version 3.0 or where you are otherwise willing to comply with the terms of the GNU GPL version 3.0.</p><p>Please see <a href="http://qt.io/licensing/">qt.io/licensing</a> for an overview of Qt licensing.</p><p>Copyright (C) 2015 The Qt Company Ltd and other contributors.</p><p>Qt and the Qt logo are trademarks of Digia Plc and/or its subsidiary(-ies).</p><p>Qt is developed as an open source project on <a href="http://qt-project.org/">qt-project.org</a>.</p><p>Qt is a Digia product. See <a href="http://qt.io/">qt.io</a> for more information.</p> - <p>Qt je sadou softwarových nástrojů C++ určených pro víceplatformní vývoj aplikací.</p><p>Qt poskytuje snadnou přenositelnost a jednotný zdrojový kód pro MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux a všechny hlavní prodejní varianty systému Unix. Qt je rovněž dostupné pro vestavěná zařízení jako Qt pro Embedded Linux a Qt pro Windows CE.</p><p>Qt je dostupné s třemi rozdílnými licencemi, aby vyhovělo širokým řadám našich uživatelů.</p>Qt s naší obchodní licenční smlouvou je vhodné pro vývoj soukromého/obchodního software, u kterého si nepřejete sdílet jakýkoli zdrojový kód se třetími stranami anebo z jiného důvodu nemůžete vyhovět podmínkám GNU LGPL ve verzi 2.1 nebo GNU GPL ve verzi 3.0.</p><p>Qt s licencí GNU LGPL ve verzi 2.1 je vhodné pro vývoj Qt aplikací (soukromých nebo s otevřeným zdrojovým kódem) za předpokladu, že můžete souhlasit s požadavky a podmínkami GNU LGPL verze 2.1.</p><p>Qt s licencí GNU General Public License ve verzi 3.0 je vhodné pro vývoj aplikací Qt, u nichž si přejete použít takovou aplikaci ve spojení se software, který podléhá požadavkům GNU GPL ve verzi 3.0, nebo kde jste jinak ochotni souhlasit s podmínkami GNU GPL ve verzi 3.0.</p><p>Více informací najdete na <a href="http://qt.io/licensing/">qt.nokia.com/products/licensing</a>.</p><p>Autorské právo (C) 2015 The Qt Company Ltd a/nebo její dceřinná(é) společnost(i).</p><p>Qt je výrobkem společnosti Nokia. Další informace najdete na <a href="http://qt.io/">qt.nokia.com</a>.</p> - About Qt O Qt diff --git a/resources/macosx/Info.plist.in b/resources/macosx/Info.plist.in index 702d901f4..e6f5bc64f 100755 --- a/resources/macosx/Info.plist.in +++ b/resources/macosx/Info.plist.in @@ -15,7 +15,7 @@ CFBundleIconFile @ICON@ CFBundleIdentifier - org.rssguard.RSSGuard + org.martinrotter.rssguard CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/resources/nsis/NSIS.definitions.nsh.in b/resources/nsis/NSIS.definitions.nsh.in index a698649e6..5d535ab63 100755 --- a/resources/nsis/NSIS.definitions.nsh.in +++ b/resources/nsis/NSIS.definitions.nsh.in @@ -25,5 +25,5 @@ !define MUI_ICON "@PWD@\resources\graphics\@APP_LOW_NAME@.ico" !define MUI_UNICON "@PWD@\resources\graphics\@APP_LOW_NAME@.ico" !define PATCH "0" -!define OUTPUT_FILE "@OUT_PWD@\@APP_LOW_NAME@-@APP_VERSION@-win32.exe" +!define OUTPUT_FILE "@OUT_PWD@\@APP_LOW_NAME@-@APP_VERSION@-@APP_REVISION@-win32.exe" !define BINARY_TREE "@OUT_PWD@\app" \ No newline at end of file diff --git a/resources/scripts/.travis-before-install.sh b/resources/scripts/.travis-before-install.sh new file mode 100755 index 000000000..c7bed69d0 --- /dev/null +++ b/resources/scripts/.travis-before-install.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +if test "$TRAVIS_OS_NAME" = "osx"; then + # Mac OS X. + brew update + brew install qt5 + brew link --force qt5 + brew install curl + brew link --force curl +else + # Linux. + sudo add-apt-repository ppa:beineri/opt-qt57-trusty -y + sudo apt-get update + sudo apt-get -y install qt57tools qt57base qt57webengine +fi \ No newline at end of file diff --git a/resources/scripts/.travis-install-linux.sh b/resources/scripts/.travis-install-linux.sh new file mode 100755 index 000000000..8236fec8f --- /dev/null +++ b/resources/scripts/.travis-install-linux.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +source /opt/qt57/bin/qt57-env.sh +mkdir rssguard-build && cd rssguard-build +qmake .. +make +make install \ No newline at end of file diff --git a/resources/scripts/.travis-install-osx.sh b/resources/scripts/.travis-install-osx.sh new file mode 100755 index 000000000..e2e748014 --- /dev/null +++ b/resources/scripts/.travis-install-osx.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +mkdir rssguard-build && cd rssguard-build +qmake .. +make +make install +macdeployqt rssguard.app -dmg +ls -lha +curl --upload-file ./*.dmg https://transfer.sh/rssguard.dmg \ No newline at end of file diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 29e7b4790..12523e8ab 100755 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -8,7 +8,9 @@ Changed: ▪ Big application core refactoring. Many functions rewritten, some bad code removed. Fixed: +▪ RSS Guard could not stop ongoing feed updates. (bug #52) ▪ RSS Guard was not launchable in Windows XP. (bug #53) +▪ RSS Guard crashed when switching msg status during feed updates. (bug #41) 3.3.3 ————— diff --git a/rssguard.pro b/rssguard.pro index 19099376f..4031b0d75 100755 --- a/rssguard.pro +++ b/rssguard.pro @@ -135,7 +135,7 @@ exists(.git) { } isEmpty(APP_REVISION) { - APP_REVISION = "-" + APP_REVISION = "" } DEFINES += APP_REVISION='"\\\"$$APP_REVISION\\\""' @@ -537,11 +537,11 @@ QMAKE_EXTRA_COMPILERS += lrelease win32 { seven_zip.target = 7zip seven_zip.depends = install - seven_zip.commands = $$shell_path($$shell_quote($$PWD/resources/scripts/7za/7za.exe)) a -t7z $$TARGET-$$APP_VERSION-win32.7z $$shell_path($$PREFIX/*) + seven_zip.commands = $$shell_path($$shell_quote($$PWD/resources/scripts/7za/7za.exe)) a -t7z $$TARGET-$$APP_VERSION-$$APP_REVISION-win32.7z $$shell_path($$PREFIX/*) zip.target = zip zip.depends = install - zip.commands = $$shell_path($$shell_quote($$PWD/resources/scripts/7za/7za.exe)) a -tzip $$TARGET-$$APP_VERSION-win32.zip $$shell_path($$PREFIX/*) + zip.commands = $$shell_path($$shell_quote($$PWD/resources/scripts/7za/7za.exe)) a -tzip $$TARGET-$$APP_VERSION-$$APP_REVISION-win32.zip $$shell_path($$PREFIX/*) QMAKE_EXTRA_TARGETS += seven_zip zip } @@ -551,7 +551,7 @@ win32 { nsis.target = nsis nsis.depends = install nsis.commands = \ - $$shell_path($$shell_quote($$PWD/resources/scripts/sed/sed.exe)) -e \"s|@APP_VERSION@|$$APP_VERSION|g; s|@APP_NAME@|$$APP_NAME|g; s|@APP_LOW_NAME@|$$APP_LOW_NAME|g; s|@EXE_NAME@|$${APP_LOW_NAME}.exe|g; s|@PWD@|$$replace(PWD, /, \\\\)|g; s|@OUT_PWD@|$$replace(OUT_PWD, /, \\\\)|g\" $$shell_path($$shell_quote($$PWD/resources/nsis/NSIS.definitions.nsh.in)) > $$shell_path($$shell_quote($$OUT_PWD/NSIS.definitions.nsh)) && \ + $$shell_path($$shell_quote($$PWD/resources/scripts/sed/sed.exe)) -e \"s|@APP_VERSION@|$$APP_VERSION|g; s|@APP_REVISION@|$$APP_REVISION|g; s|@APP_NAME@|$$APP_NAME|g; s|@APP_LOW_NAME@|$$APP_LOW_NAME|g; s|@EXE_NAME@|$${APP_LOW_NAME}.exe|g; s|@PWD@|$$replace(PWD, /, \\\\)|g; s|@OUT_PWD@|$$replace(OUT_PWD, /, \\\\)|g\" $$shell_path($$shell_quote($$PWD/resources/nsis/NSIS.definitions.nsh.in)) > $$shell_path($$shell_quote($$OUT_PWD/NSIS.definitions.nsh)) && \ xcopy /Y $$shell_path($$shell_quote($$PWD/resources/nsis/NSIS.template.in)) $$shell_path($$shell_quote($$OUT_PWD/)) && \ $$shell_path($$shell_quote($$PWD/resources/scripts/nsis/makensis.exe)) $$shell_path($$shell_quote($$OUT_PWD/NSIS.template.in)) diff --git a/src/core/feeddownloader.cpp b/src/core/feeddownloader.cpp index 91fac96a4..b0ad83307 100755 --- a/src/core/feeddownloader.cpp +++ b/src/core/feeddownloader.cpp @@ -23,99 +23,103 @@ #include #include #include +#include +#include FeedDownloader::FeedDownloader(QObject *parent) - : QObject(parent), m_results(FeedDownloadResults()), m_feedsUpdated(0), m_feedsToUpdate(0), - m_feedsUpdating(0), m_feedsTotalCount(0), m_stopUpdate(false) { + : QObject(parent), m_feeds(QList()), m_mutex(new QMutex()), m_threadPool(new QThreadPool(this)), + m_results(FeedDownloadResults()), m_feedsUpdated(0), + m_feedsUpdating(0), m_feedsOriginalCount(0) { qRegisterMetaType("FeedDownloadResults"); + m_threadPool->setMaxThreadCount(FEED_DOWNLOADER_MAX_THREADS); } FeedDownloader::~FeedDownloader() { + m_mutex->tryLock(); + m_mutex->unlock(); + delete m_mutex; + qDebug("Destroying FeedDownloader instance."); } bool FeedDownloader::isUpdateRunning() const { - return m_feedsToUpdate > 0 || m_feedsUpdating > 0; + return !m_feeds.isEmpty() || m_feedsUpdating > 0; +} + +void FeedDownloader::updateAvailableFeeds() { + while (!m_feeds.isEmpty()) { + connect(m_feeds.first(), &Feed::messagesObtained, this, &FeedDownloader::oneFeedUpdateFinished, + (Qt::ConnectionType) (Qt::UniqueConnection | Qt::AutoConnection)); + if (m_threadPool->tryStart(m_feeds.first())) { + m_feeds.removeFirst(); + m_feedsUpdating++; + } + else { + // We want to start update of some feeds but all working threads are occupied. + break; + } + } } void FeedDownloader::updateFeeds(const QList &feeds) { + QMutexLocker locker(m_mutex); + if (feeds.isEmpty()) { qDebug("No feeds to update in worker thread, aborting update."); finalizeUpdate(); - return; } + else { + qDebug().nospace() << "Starting feed updates from worker in thread: \'" << QThread::currentThreadId() << "\'."; - qDebug().nospace() << "Starting feed updates from worker in thread: \'" << QThread::currentThreadId() << "\'."; + m_feeds = feeds; + m_feedsOriginalCount = m_feeds.size(); + m_results.clear(); + m_feedsUpdated = m_feedsUpdating = 0; - // It may be good to disable "stop" action when batch feed update - // starts. - m_stopUpdate = false; - - m_results.clear(); - - m_feedsUpdated = 0; - m_feedsUpdating = 0; - m_feedsToUpdate = feeds.size(); - m_feedsTotalCount = m_feedsToUpdate; - - // Job starts now. - emit updateStarted(); - - for (int i = 0; i < m_feedsTotalCount; i++) { - if (m_stopUpdate) { - qDebug("Stopping batch feed update now."); - - // We want indicate that no more feeds will be updated in this queue. - m_feedsToUpdate = 0; - - if (m_feedsUpdating <= 0) { - // User forced to stop, no more feeds will start updating. - // If also no feeds are updating right now, finish. - finalizeUpdate(); - } - - break; - } - - connect(feeds.at(i), &Feed::messagesObtained, this, &FeedDownloader::oneFeedUpdateFinished, - (Qt::ConnectionType) (Qt::UniqueConnection | Qt::AutoConnection)); - QThreadPool::globalInstance()->start(feeds.at(i)); - - m_feedsUpdating++; - m_feedsToUpdate--; + // Job starts now. + emit updateStarted(); + updateAvailableFeeds(); } } void FeedDownloader::stopRunningUpdate() { - m_stopUpdate = true; + m_threadPool->clear(); + m_feeds.clear(); } void FeedDownloader::oneFeedUpdateFinished(const QList &messages) { + QMutexLocker locker(m_mutex); + + m_feedsUpdated++; + m_feedsUpdating--; + Feed *feed = qobject_cast(sender()); disconnect(feed, &Feed::messagesObtained, this, &FeedDownloader::oneFeedUpdateFinished); - m_feedsUpdated++; - m_feedsUpdating--; + // Now, we check if there are any feeds we would like to update too. + updateAvailableFeeds(); // Now make sure, that messages are actually stored to SQL in a locked state. qDebug().nospace() << "Saving messages of feed " << feed->id() << " in thread: \'" << QThread::currentThreadId() << "\'."; - if (!m_stopUpdate) { - int updated_messages = messages.isEmpty() ? 0 : feed->updateMessages(messages); + int updated_messages; - if (updated_messages > 0) { - m_results.appendUpdatedFeed(QPair(feed->title(), updated_messages)); - } + QMetaObject::invokeMethod(feed, "updateMessages", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(int, updated_messages), + Q_ARG(QList, messages)); + + if (updated_messages > 0) { + m_results.appendUpdatedFeed(QPair(feed->title(), updated_messages)); } - qDebug("Made progress in feed updates, total feeds count %d/%d (id of feed is %d).", m_feedsUpdated, m_feedsTotalCount, feed->id()); - emit updateProgress(feed, m_feedsUpdated, m_feedsTotalCount); + qDebug("Made progress in feed updates, total feeds count %d/%d (id of feed is %d).", m_feedsUpdated, m_feedsOriginalCount, feed->id()); + emit updateProgress(feed, m_feedsUpdated, m_feedsOriginalCount); - if (m_feedsToUpdate <= 0 && m_feedsUpdating <= 0) { + if (m_feeds.isEmpty() && m_feedsUpdating <= 0) { finalizeUpdate(); } } @@ -125,9 +129,6 @@ void FeedDownloader::finalizeUpdate() { m_results.sort(); - // Make sure that there is not "stop" action pending. - m_stopUpdate = false; - // Update of feeds has finished. // NOTE: This means that now "update lock" can be unlocked // and feeds can be added/edited/deleted and application diff --git a/src/core/feeddownloader.h b/src/core/feeddownloader.h index 00e0f84e0..882a7854a 100755 --- a/src/core/feeddownloader.h +++ b/src/core/feeddownloader.h @@ -26,6 +26,8 @@ class Feed; +class QThreadPool; +class QMutex; // Represents results of batch feed updates. class FeedDownloadResults { @@ -86,16 +88,17 @@ class FeedDownloader : public QObject { void updateProgress(const Feed *feed, int current, int total); private: + void updateAvailableFeeds(); void finalizeUpdate(); + QList m_feeds; + QMutex *m_mutex; + QThreadPool *m_threadPool; FeedDownloadResults m_results; int m_feedsUpdated; - int m_feedsToUpdate; int m_feedsUpdating; - int m_feedsTotalCount; - - bool m_stopUpdate; + int m_feedsOriginalCount; }; #endif // FEEDDOWNLOADER_H diff --git a/src/definitions/definitions.h b/src/definitions/definitions.h index c6293ddd4..d3f6eb460 100755 --- a/src/definitions/definitions.h +++ b/src/definitions/definitions.h @@ -49,6 +49,7 @@ #define DOWNLOAD_TIMEOUT 5000 #define MESSAGES_VIEW_DEFAULT_COL 170 #define FEEDS_VIEW_COLUMN_COUNT 2 +#define FEED_DOWNLOADER_MAX_THREADS 6 #define DEFAULT_DAYS_TO_DELETE_MSG 14 #define ELLIPSIS_LENGTH 3 #define MIN_CATEGORY_NAME_LENGTH 1 diff --git a/src/miscellaneous/feedreader.cpp b/src/miscellaneous/feedreader.cpp index 021a2ed37..fefaf1c33 100755 --- a/src/miscellaneous/feedreader.cpp +++ b/src/miscellaneous/feedreader.cpp @@ -84,9 +84,7 @@ void FeedReader::updateFeeds(const QList &feeds) { qRegisterMetaType >("QList"); m_feedDownloader->moveToThread(m_feedDownloaderThread); - connect(this, &FeedReader::feedsUpdateRequested, m_feedDownloader, &FeedDownloader::updateFeeds); connect(m_feedDownloaderThread, &QThread::finished, m_feedDownloaderThread, &QThread::deleteLater); - connect(m_feedDownloader, &FeedDownloader::updateFinished, this, &FeedReader::feedUpdatesFinished); connect(m_feedDownloader, &FeedDownloader::updateProgress, this, &FeedReader::feedUpdatesProgress); connect(m_feedDownloader, &FeedDownloader::updateStarted, this, &FeedReader::feedUpdatesStarted); @@ -96,7 +94,7 @@ void FeedReader::updateFeeds(const QList &feeds) { m_feedDownloaderThread->start(); } - emit feedsUpdateRequested(feeds); + QMetaObject::invokeMethod(m_feedDownloader, "updateFeeds", Q_ARG(QList, feeds)); } void FeedReader::updateAutoUpdateStatus() { @@ -126,7 +124,7 @@ void FeedReader::updateAllFeeds() { void FeedReader::stopRunningFeedUpdate() { if (m_feedDownloader != nullptr) { - m_feedDownloader->stopRunningUpdate(); + QMetaObject::invokeMethod(m_feedDownloader, "stopRunningUpdate"); } } @@ -209,6 +207,12 @@ void FeedReader::stop() { if (m_feedDownloaderThread != nullptr && m_feedDownloaderThread->isRunning()) { m_feedDownloader->stopRunningUpdate(); + if (m_feedDownloader->isUpdateRunning()) { + QEventLoop loop(this); + connect(m_feedDownloader, &FeedDownloader::updateFinished, &loop, &QEventLoop::quit); + loop.exec(); + } + qDebug("Quitting feed downloader thread."); m_feedDownloaderThread->quit(); diff --git a/src/miscellaneous/feedreader.h b/src/miscellaneous/feedreader.h index a1a994bc4..a31c17e7c 100755 --- a/src/miscellaneous/feedreader.h +++ b/src/miscellaneous/feedreader.h @@ -72,9 +72,6 @@ class FeedReader : public QObject { void executeNextAutoUpdate(); signals: - // Emitted when model requests update of some feeds. - void feedsUpdateRequested(QList feeds); - void feedUpdatesStarted(); void feedUpdatesFinished(FeedDownloadResults updated_feeds); void feedUpdatesProgress(const Feed *feed, int current, int total); diff --git a/src/services/abstract/feed.cpp b/src/services/abstract/feed.cpp index 111f0cf1d..3320712cf 100755 --- a/src/services/abstract/feed.cpp +++ b/src/services/abstract/feed.cpp @@ -144,11 +144,13 @@ void Feed::run() { << QThread::currentThreadId() << "\'."; QList msgs = obtainNewMessages(); - emit messagesObtained(msgs); } int Feed::updateMessages(const QList &messages) { + qDebug().nospace() << "Updating messages in DB. Main thread: " << + (QThread::currentThread() == qApp->thread() ? "true." : "false."); + int custom_id = customId(); int account_id = getParentServiceRoot()->accountId(); bool anything_updated = false; diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index 4919ae687..af3ebf105 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -78,12 +78,13 @@ class Feed : public RootItem, public QRunnable { QString url() const; void setUrl(const QString &url); - int updateMessages(const QList &messages); - void updateCounts(bool including_total_count); - // Runs update in thread (thread pooled). void run(); + public slots: + void updateCounts(bool including_total_count); + int updateMessages(const QList &messages); + private: // Performs synchronous obtaining of new messages for this feed. virtual QList obtainNewMessages() = 0;