diff --git a/resources/desktop/com.github.rssguard.appdata.xml b/resources/desktop/com.github.rssguard.appdata.xml index 17d7aee89..a5cd758fc 100644 --- a/resources/desktop/com.github.rssguard.appdata.xml +++ b/resources/desktop/com.github.rssguard.appdata.xml @@ -26,7 +26,7 @@ https://github.com/sponsors/martinrotter - + none diff --git a/src/librssguard/core/feedsmodel.cpp b/src/librssguard/core/feedsmodel.cpp index afe96b987..3a76989ee 100644 --- a/src/librssguard/core/feedsmodel.cpp +++ b/src/librssguard/core/feedsmodel.cpp @@ -75,7 +75,10 @@ QStringList FeedsModel::mimeTypes() const { return QStringList() << QSL(MIME_TYPE_ITEM_POINTER); } -bool FeedsModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, +bool FeedsModel::dropMimeData(const QMimeData* data, + Qt::DropAction action, + int row, + int column, const QModelIndex& parent) { Q_UNUSED(row) Q_UNUSED(column) @@ -106,8 +109,8 @@ bool FeedsModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int ServiceRoot* target_item_root = target_item->getParentServiceRoot(); if (dragged_item == target_item || dragged_item->parent() == target_item) { - qDebug( - "Dragged item is equal to target item or its parent is equal to target item. Cancelling drag-drop action."); + qDebug("Dragged item is equal to target item or its parent is equal to target item. Cancelling drag-drop " + "action."); return false; } @@ -154,27 +157,27 @@ QVariant FeedsModel::headerData(int section, Qt::Orientation orientation, int ro } switch (role) { - case Qt::DisplayRole: - if (section == FDS_MODEL_TITLE_INDEX) { - return m_headerData.at(FDS_MODEL_TITLE_INDEX); - } - else { + case Qt::DisplayRole: + if (section == FDS_MODEL_TITLE_INDEX) { + return m_headerData.at(FDS_MODEL_TITLE_INDEX); + } + else { + return QVariant(); + } + + case Qt::ToolTipRole: + return m_tooltipData.at(section); + + case Qt::DecorationRole: + if (section == FDS_MODEL_COUNTS_INDEX) { + return m_countsIcon; + } + else { + return QVariant(); + } + + default: return QVariant(); - } - - case Qt::ToolTipRole: - return m_tooltipData.at(section); - - case Qt::DecorationRole: - if (section == FDS_MODEL_COUNTS_INDEX) { - return m_countsIcon; - } - else { - return QVariant(); - } - - default: - return QVariant(); } } @@ -309,36 +312,36 @@ QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { for (Feed* feed : qAsConst(stf)) { switch (feed->autoUpdateType()) { - case Feed::AutoUpdateType::DontAutoUpdate: + case Feed::AutoUpdateType::DontAutoUpdate: - // Do not auto-update this feed ever. - continue; + // Do not auto-update this feed ever. + continue; - case Feed::AutoUpdateType::DefaultAutoUpdate: + case Feed::AutoUpdateType::DefaultAutoUpdate: - if (auto_update_now) { - feeds_for_update.append(feed); - } + if (auto_update_now) { + feeds_for_update.append(feed); + } - break; + break; - case Feed::AutoUpdateType::SpecificAutoUpdate: - default: - int remaining_interval = feed->autoUpdateRemainingInterval(); + case Feed::AutoUpdateType::SpecificAutoUpdate: + default: + int remaining_interval = feed->autoUpdateRemainingInterval(); - if (--remaining_interval <= 0) { - // Interval of this feed passed, include this feed in the output list - // and reset the interval. - feeds_for_update.append(feed); - feed->setAutoUpdateRemainingInterval(feed->autoUpdateInitialInterval()); - } - else { - // Interval did not pass, set new decremented interval and do NOT - // include this feed in the output list. - feed->setAutoUpdateRemainingInterval(remaining_interval); - } + if (--remaining_interval <= 0) { + // Interval of this feed passed, include this feed in the output list + // and reset the interval. + feeds_for_update.append(feed); + feed->setAutoUpdateRemainingInterval(feed->autoUpdateInitialInterval()); + } + else { + // Interval did not pass, set new decremented interval and do NOT + // include this feed in the output list. + feed->setAutoUpdateRemainingInterval(remaining_interval); + } - break; + break; } } @@ -445,8 +448,9 @@ void FeedsModel::onItemDataChanged(const QList& items) { void FeedsModel::setupFonts() { QFont fon; - fon.fromString( - qApp->settings()->value(GROUP(Feeds), Feeds::ListFont, Application::font("FeedsView").toString()).toString()); + fon.fromString(qApp->settings() + ->value(GROUP(Feeds), Feeds::ListFont, Application::font("FeedsView").toString()) + .toString()); m_normalFont = fon; @@ -473,7 +477,9 @@ bool FeedsModel::addServiceAccount(ServiceRoot* root, bool freshly_activated) { endInsertRows(); // Connect. - connect(root, &ServiceRoot::itemRemovalRequested, this, + connect(root, + &ServiceRoot::itemRemovalRequested, + this, static_cast(&FeedsModel::removeItem)); connect(root, &ServiceRoot::itemReassignmentRequested, this, &FeedsModel::reassignNodeToNewParent); connect(root, &ServiceRoot::dataChanged, this, &FeedsModel::onItemDataChanged); @@ -572,26 +578,26 @@ bool FeedsModel::markItemCleared(RootItem* item, bool clean_read_only) { QVariant FeedsModel::data(const QModelIndex& index, int role) const { switch (role) { - case Qt::ItemDataRole::FontRole: { - RootItem* it = itemForIndex(index); - bool is_bold = it->countOfUnreadMessages() > 0; - bool is_striked = it->kind() == RootItem::Kind::Feed ? qobject_cast(it)->isSwitchedOff() : false; + case Qt::ItemDataRole::FontRole: { + RootItem* it = itemForIndex(index); + bool is_bold = it->countOfUnreadMessages() > 0; + bool is_striked = it->kind() == RootItem::Kind::Feed ? qobject_cast(it)->isSwitchedOff() : false; - if (is_bold) { - return is_striked ? m_boldStrikedFont : m_boldFont; - } - else { - return is_striked ? m_normalStrikedFont : m_normalFont; - } - } - - case Qt::ItemDataRole::ToolTipRole: - if (!qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::EnableTooltipsFeedsMessages)).toBool()) { - return QVariant(); + if (is_bold) { + return is_striked ? m_boldStrikedFont : m_boldFont; + } + else { + return is_striked ? m_normalStrikedFont : m_normalFont; + } } - default: - return itemForIndex(index)->data(index.column(), role); - ; + case Qt::ItemDataRole::ToolTipRole: + if (!qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::EnableTooltipsFeedsMessages)).toBool()) { + return QVariant(); + } + + default: + return itemForIndex(index)->data(index.column(), role); + ; } } diff --git a/src/librssguard/definitions/definitions.h b/src/librssguard/definitions/definitions.h index 0670b7f04..0d5089ae7 100644 --- a/src/librssguard/definitions/definitions.h +++ b/src/librssguard/definitions/definitions.h @@ -215,7 +215,12 @@ #define APP_SKIN_USER_FOLDER "skins" #define APP_SKIN_DEFAULT "nudus-light" #define APP_SKIN_METADATA_FILE "metadata.xml" + +#if defined(Q_OS_WIN) +#define APP_STYLE_DEFAULT "windowsvista" +#else #define APP_STYLE_DEFAULT "Fusion" +#endif #if defined(FORCE_BUNDLE_ICONS) // Forcibly bundle icons. diff --git a/src/librssguard/services/abstract/feed.cpp b/src/librssguard/services/abstract/feed.cpp index a10464931..1c5ef42e2 100644 --- a/src/librssguard/services/abstract/feed.cpp +++ b/src/librssguard/services/abstract/feed.cpp @@ -20,9 +20,10 @@ #include Feed::Feed(RootItem* parent) - : RootItem(parent), m_source(QString()), m_status(Status::Normal), m_statusString(QString()), m_autoUpdateType(AutoUpdateType::DefaultAutoUpdate), - m_autoUpdateInitialInterval(DEFAULT_AUTO_UPDATE_INTERVAL), m_autoUpdateRemainingInterval(DEFAULT_AUTO_UPDATE_INTERVAL), - m_isSwitchedOff(false), m_openArticlesDirectly(false), m_messageFilters(QList>()) { + : RootItem(parent), m_source(QString()), m_status(Status::Normal), m_statusString(QString()), + m_autoUpdateType(AutoUpdateType::DefaultAutoUpdate), m_autoUpdateInitialInterval(DEFAULT_AUTO_UPDATE_INTERVAL), + m_autoUpdateRemainingInterval(DEFAULT_AUTO_UPDATE_INTERVAL), m_isSwitchedOff(false), m_openArticlesDirectly(false), + m_messageFilters(QList>()) { setKind(RootItem::Kind::Feed); } @@ -187,9 +188,8 @@ void Feed::appendMessageFilter(MessageFilter* filter) { void Feed::updateCounts(bool including_total_count) { bool is_main_thread = QThread::currentThread() == qApp->thread(); - QSqlDatabase database = is_main_thread ? - qApp->database()->driver()->connection(metaObject()->className()) : - qApp->database()->driver()->connection(QSL("feed_upd")); + QSqlDatabase database = is_main_thread ? qApp->database()->driver()->connection(metaObject()->className()) + : qApp->database()->driver()->connection(QSL("feed_upd")); int account_id = getParentServiceRoot()->accountId(); if (including_total_count) { @@ -228,17 +228,19 @@ QString Feed::getAutoUpdateStatusDescription() const { //: Describes feed auto-update status. auto_update_string = qApp->feedReader()->autoUpdateEnabled() - ? tr("uses global settings (%n minute(s) to next auto-fetch of articles)", - nullptr, - qApp->feedReader()->autoUpdateRemainingInterval()) - : tr("uses global settings (global auto-fetching of articles is disabled)"); + ? tr("uses global settings (%n minute(s) to next auto-fetch of articles)", + nullptr, + qApp->feedReader()->autoUpdateRemainingInterval()) + : tr("uses global settings (global auto-fetching of articles is disabled)"); break; case AutoUpdateType::SpecificAutoUpdate: default: //: Describes feed auto-update status. - auto_update_string = tr("uses specific settings (%n minute(s) to next auto-fetching of new articles)", nullptr, autoUpdateRemainingInterval()); + auto_update_string = tr("uses specific settings (%n minute(s) to next auto-fetching of new articles)", + nullptr, + autoUpdateRemainingInterval()); break; } @@ -304,7 +306,10 @@ QString Feed::additionalTooltip() const { return tr("Auto-update status: %1\n" "Active message filters: %2\n" - "Status: %3").arg(getAutoUpdateStatusDescription(), - QString::number(m_messageFilters.size()), - stat); + "Status: %3") + .arg(getAutoUpdateStatusDescription(), QString::number(m_messageFilters.size()), stat); +} + +Qt::ItemFlags Feed::additionalFlags() const { + return Qt::ItemFlag::ItemNeverHasChildren; } diff --git a/src/librssguard/services/abstract/feed.h b/src/librssguard/services/abstract/feed.h index 2330d0557..924f3a9a3 100644 --- a/src/librssguard/services/abstract/feed.h +++ b/src/librssguard/services/abstract/feed.h @@ -13,16 +13,11 @@ // Base class for "feed" nodes. class Feed : public RootItem { - Q_OBJECT + Q_OBJECT public: - // Specifies the auto-download strategy for the feed. - enum class AutoUpdateType { - DontAutoUpdate = 0, - DefaultAutoUpdate = 1, - SpecificAutoUpdate = 2 - }; + enum class AutoUpdateType { DontAutoUpdate = 0, DefaultAutoUpdate = 1, SpecificAutoUpdate = 2 }; // Specifies the actual "status" of the feed. // For example if it has new messages, error @@ -44,6 +39,7 @@ class Feed : public RootItem { virtual QList undeletedMessages() const; virtual QString additionalTooltip() const; + virtual Qt::ItemFlags additionalFlags() const; virtual bool markAsReadUnread(ReadStatus status); virtual bool cleanMessages(bool clean_read_only); virtual int countOfAllMessages() const; diff --git a/src/librssguard/services/standard/standardfeed.cpp b/src/librssguard/services/standard/standardfeed.cpp index 5bbaa5e15..a337bb505 100644 --- a/src/librssguard/services/standard/standardfeed.cpp +++ b/src/librssguard/services/standard/standardfeed.cpp @@ -9,7 +9,6 @@ #include "exceptions/applicationexception.h" #include "exceptions/networkexception.h" #include "exceptions/scriptexception.h" -#include "exceptions/scriptexception.h" #include "gui/feedmessageviewer.h" #include "gui/feedsview.h" #include "miscellaneous/iconfactory.h" @@ -38,8 +37,7 @@ #include #include -StandardFeed::StandardFeed(RootItem* parent_item) - : Feed(parent_item) { +StandardFeed::StandardFeed(RootItem* parent_item) : Feed(parent_item) { m_type = Type::Rss0X; m_sourceType = SourceType::Url; m_encoding = m_postProcessScript = QString(); @@ -49,8 +47,7 @@ StandardFeed::StandardFeed(RootItem* parent_item) m_password = QString(); } -StandardFeed::StandardFeed(const StandardFeed& other) - : Feed(other) { +StandardFeed::StandardFeed(const StandardFeed& other) : Feed(other) { m_type = other.type(); m_postProcessScript = other.postProcessScript(); m_sourceType = other.sourceType(); @@ -66,7 +63,8 @@ QList StandardFeed::contextMenuFeedsList() { QString StandardFeed::additionalTooltip() const { return Feed::additionalTooltip() + tr("\nEncoding: %2\n" - "Type: %3").arg(encoding(), StandardFeed::typeToString(type())); + "Type: %3") + .arg(encoding(), StandardFeed::typeToString(type())); } bool StandardFeed::canBeDeleted() const { @@ -202,16 +200,14 @@ void StandardFeed::fetchMetadataForItself() { QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className()); DatabaseQueries::createOverwriteFeed(database, this, getParentServiceRoot()->accountId(), parent()->id()); - serviceRoot()->itemChanged({ this }); + serviceRoot()->itemChanged({this}); } catch (const ApplicationException& ex) { - qCriticalNN << LOGSEC_DB - << "Cannot overwrite feed:" - << QUOTE_W_SPACE_DOT(ex.message()); - qApp->showGuiMessage(Notification::Event::GeneralEvent, { - tr("Cannot save feed data"), - tr("Cannot save data for feed: %1").arg(ex.message()), - QSystemTrayIcon::MessageIcon::Critical }); + qCriticalNN << LOGSEC_DB << "Cannot overwrite feed:" << QUOTE_W_SPACE_DOT(ex.message()); + qApp->showGuiMessage(Notification::Event::GeneralEvent, + {tr("Cannot save feed data"), + tr("Cannot save data for feed: %1").arg(ex.message()), + QSystemTrayIcon::MessageIcon::Critical}); } } @@ -237,23 +233,23 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, const QString& username, const QString& password, const QNetworkProxy& custom_proxy) { - auto timeout = qApp->settings()->value(GROUP(Feeds), - SETTING(Feeds::UpdateTimeout)).toInt(); + auto timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); QByteArray feed_contents; QString content_type; if (source_type == StandardFeed::SourceType::Url) { - QList> headers = { NetworkFactory::generateBasicAuthHeader(username, password) }; - NetworkResult network_result = NetworkFactory::performNetworkOperation(source, - timeout, - QByteArray(), - feed_contents, - QNetworkAccessManager::Operation::GetOperation, - headers, - false, - {}, - {}, - custom_proxy); + QList> headers = {NetworkFactory::generateBasicAuthHeader(username, password)}; + NetworkResult network_result = + NetworkFactory::performNetworkOperation(source, + timeout, + QByteArray(), + feed_contents, + QNetworkAccessManager::Operation::GetOperation, + headers, + false, + {}, + {}, + custom_proxy); content_type = network_result.m_contentType; @@ -262,18 +258,14 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, } } else { - qDebugNN << LOGSEC_CORE - << "Running custom script for guessing" - << QUOTE_W_SPACE(source) - << "to obtain feed data."; + qDebugNN << LOGSEC_CORE << "Running custom script for guessing" << QUOTE_W_SPACE(source) << "to obtain feed data."; // Use script to generate feed file. feed_contents = generateFeedFileWithScript(source, timeout).toUtf8(); } if (!post_process_script.simplified().isEmpty()) { - qDebugNN << LOGSEC_CORE - << "Post-processing obtained feed data with custom script for guessing" + qDebugNN << LOGSEC_CORE << "Post-processing obtained feed data with custom script for guessing" << QUOTE_W_SPACE_DOT(post_process_script); feed_contents = postProcessFeedFileWithScript(post_process_script, feed_contents, timeout).toUtf8(); } @@ -309,7 +301,7 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, auto home_page = json.object()[QSL("home_page_url")].toString(); if (!home_page.isEmpty()) { - icon_possible_locations.prepend({ home_page, false }); + icon_possible_locations.prepend({home_page, false}); } auto icon = json.object()[QSL("favicon")].toString(); @@ -320,7 +312,7 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, if (!icon.isEmpty()) { // Low priority, download directly. - icon_possible_locations.append({ icon, true }); + icon_possible_locations.append({icon, true}); } } else { @@ -328,8 +320,10 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, // its encoding before we can read further data. QString xml_schema_encoding; QString xml_contents_encoded; - QString enc = QRegularExpression(QSL("encoding=\"([A-Z0-9\\-]+)\""), - QRegularExpression::PatternOption::CaseInsensitiveOption).match(feed_contents).captured(1); + QString enc = + QRegularExpression(QSL("encoding=\"([A-Z0-9\\-]+)\""), QRegularExpression::PatternOption::CaseInsensitiveOption) + .match(feed_contents) + .captured(1); if (!enc.isEmpty()) { // Some "encoding" attribute was found get the encoding @@ -357,11 +351,7 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, QString error_msg; int error_line, error_column; - if (!xml_document.setContent(xml_contents_encoded, - true, - &error_msg, - &error_line, - &error_column)) { + if (!xml_document.setContent(xml_contents_encoded, true, &error_msg, &error_line, &error_column)) { throw ApplicationException(tr("XML is not well-formed, %1").arg(error_msg)); } @@ -374,16 +364,20 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, if (root_element.namespaceURI() == rdf.rdfNamespace()) { // We found RDF feed. - QDomElement channel_element = root_element.elementsByTagNameNS(rdf.rssNamespace(), QSL("channel")).at(0).toElement(); + QDomElement channel_element = + root_element.elementsByTagNameNS(rdf.rssNamespace(), QSL("channel")).at(0).toElement(); feed->setType(Type::Rdf); feed->setTitle(channel_element.elementsByTagNameNS(rdf.rssNamespace(), QSL("title")).at(0).toElement().text()); - feed->setDescription(channel_element.elementsByTagNameNS(rdf.rssNamespace(), QSL("description")).at(0).toElement().text()); + feed->setDescription(channel_element.elementsByTagNameNS(rdf.rssNamespace(), QSL("description")) + .at(0) + .toElement() + .text()); QString home_page = channel_element.elementsByTagNameNS(rdf.rssNamespace(), QSL("link")).at(0).toElement().text(); if (!home_page.isEmpty()) { - icon_possible_locations.prepend({ home_page, false }); + icon_possible_locations.prepend({home_page, false}); } } else if (root_element.tagName() == QL1S("rss")) { @@ -405,7 +399,7 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, QString icon_url_link = channel_element.namedItem(QSL("image")).namedItem(QSL("url")).toElement().text(); if (!icon_url_link.isEmpty()) { - icon_possible_locations.append({ icon_url_link, true }); + icon_possible_locations.append({icon_url_link, true}); } auto channel_links = channel_element.elementsByTagName(QSL("link")); @@ -414,7 +408,7 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, QString home_page = channel_links.at(i).toElement().text(); if (!home_page.isEmpty()) { - icon_possible_locations.prepend({ home_page, false }); + icon_possible_locations.prepend({home_page, false}); break; } } @@ -428,13 +422,13 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, QString icon_link = root_element.namedItem(QSL("icon")).toElement().text(); if (!icon_link.isEmpty()) { - icon_possible_locations.append({ icon_link, true }); + icon_possible_locations.append({icon_link, true}); } QString home_page = root_element.namedItem(QSL("link")).toElement().attribute(QSL("href")); if (!home_page.isEmpty()) { - icon_possible_locations.prepend({ home_page, false }); + icon_possible_locations.prepend({home_page, false}); } } else { @@ -447,17 +441,14 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, if (source_type == SourceType::Url && icon_possible_locations.isEmpty()) { // We have no source for feed icon, we use the URL of the feed file itself. - icon_possible_locations.append({ source, false }); + icon_possible_locations.append({source, false}); } // Try to obtain icon. QIcon icon_data; - if (NetworkFactory::downloadIcon(icon_possible_locations, - DOWNLOAD_TIMEOUT, - icon_data, - {}, - custom_proxy) == QNetworkReply::NetworkError::NoError) { + if (NetworkFactory::downloadIcon(icon_possible_locations, DOWNLOAD_TIMEOUT, icon_data, {}, custom_proxy) == + QNetworkReply::NetworkError::NoError) { // Icon for feed was downloaded and is stored now in _icon_data. feed->setIcon(icon_data); } @@ -466,7 +457,7 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, } Qt::ItemFlags StandardFeed::additionalFlags() const { - return Qt::ItemFlag::ItemIsDragEnabled; + return Feed::additionalFlags() | Qt::ItemFlag::ItemIsDragEnabled; } bool StandardFeed::performDragDropChange(RootItem* target_item) { @@ -478,14 +469,12 @@ bool StandardFeed::performDragDropChange(RootItem* target_item) { return true; } catch (const ApplicationException& ex) { - qCriticalNN << LOGSEC_DB - << "Cannot overwrite feed:" - << QUOTE_W_SPACE_DOT(ex.message()); + qCriticalNN << LOGSEC_DB << "Cannot overwrite feed:" << QUOTE_W_SPACE_DOT(ex.message()); - qApp->showGuiMessage(Notification::Event::GeneralEvent, { - tr("Cannot move feed"), - tr("Cannot move feed, detailed information was logged via debug log."), - QSystemTrayIcon::MessageIcon::Critical }); + qApp->showGuiMessage(Notification::Event::GeneralEvent, + {tr("Cannot move feed"), + tr("Cannot move feed, detailed information was logged via debug log."), + QSystemTrayIcon::MessageIcon::Critical}); return false; } } @@ -518,8 +507,11 @@ QStringList StandardFeed::prepareExecutionLine(const QString& execution_line) { return qApp->replaceDataUserDataFolderPlaceholder(args); } -QString StandardFeed::runScriptProcess(const QStringList& cmd_args, const QString& working_directory, - int run_timeout, bool provide_input, const QString& input) { +QString StandardFeed::runScriptProcess(const QStringList& cmd_args, + const QString& working_directory, + int run_timeout, + bool provide_input, + const QString& input) { QProcess process; if (provide_input) { @@ -547,8 +539,7 @@ QString StandardFeed::runScriptProcess(const QStringList& cmd_args, const QStrin process.closeWriteChannel(); } - if (process.waitForFinished(run_timeout) && - process.exitStatus() == QProcess::ExitStatus::NormalExit && + if (process.waitForFinished(run_timeout) && process.exitStatus() == QProcess::ExitStatus::NormalExit && process.exitCode() == EXIT_SUCCESS) { auto raw_output = process.readAllStandardOutput(); auto raw_error = process.readAllStandardError();