From 359dbfa25c51a06a558dba9e76ebd9b7303d5e3c Mon Sep 17 00:00:00 2001 From: Matt Firth Date: Fri, 13 Oct 2023 01:53:21 +0100 Subject: [PATCH 01/14] Move update_check files to shared dir --- .../src/reaper_adm/CMakeLists.txt | 5 +- .../reaper_adm => shared}/update_check.cpp | 443 +++++++++--------- .../src/reaper_adm => shared}/update_check.h | 77 ++- 3 files changed, 263 insertions(+), 262 deletions(-) rename {reaper-adm-extension/src/reaper_adm => shared}/update_check.cpp (97%) rename {reaper-adm-extension/src/reaper_adm => shared}/update_check.h (93%) diff --git a/reaper-adm-extension/src/reaper_adm/CMakeLists.txt b/reaper-adm-extension/src/reaper_adm/CMakeLists.txt index f30f167a7..866cec2e9 100644 --- a/reaper-adm-extension/src/reaper_adm/CMakeLists.txt +++ b/reaper-adm-extension/src/reaper_adm/CMakeLists.txt @@ -8,6 +8,7 @@ find_package(JUCE REQUIRED QUIET) set(EXTENSION_SOURCES ${EPS_SHARED_DIR}/helper/common_definition_helper.cpp + ${EPS_SHARED_DIR}/update_check.cpp actionmanager.cpp admchannel.cpp @@ -68,7 +69,6 @@ set(EXTENSION_SOURCES reaperguid.cpp reaperhost.cpp track.cpp - update_check.cpp coordinate_conversion/coord_conv.cpp progress/importdialog.cpp progress/importlistener.cpp @@ -84,6 +84,7 @@ set(EXTENSION_HEADERS ${EPS_SHARED_DIR}/helper/resource_paths.hpp ${EPS_SHARED_DIR}/helper/native_message_box.hpp ${EPS_SHARED_DIR}/daw_channel_count.h + ${EPS_SHARED_DIR}/update_check.h AppConfig.h juce_modules.h @@ -153,7 +154,6 @@ set(EXTENSION_HEADERS reaper_plugin_functions.h resource.h track.h - update_check.h win_mem_debug.h coordinate_conversion/coord_conv.hpp progress/importdialog.h @@ -197,6 +197,7 @@ find_package(WDL REQUIRED QUIET) target_include_directories(reaper_adm_object PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} $ $ $ diff --git a/reaper-adm-extension/src/reaper_adm/update_check.cpp b/shared/update_check.cpp similarity index 97% rename from reaper-adm-extension/src/reaper_adm/update_check.cpp rename to shared/update_check.cpp index 2954c2a6b..cae23fc78 100644 --- a/reaper-adm-extension/src/reaper_adm/update_check.cpp +++ b/shared/update_check.cpp @@ -1,221 +1,222 @@ -#include "update_check.h" -#include -#include -#include -#include -#include - -UpdateChecker::UpdateChecker() -{ - if (eps::versionInfoAvailable()) { - currentVersion = Version( - eps::versionMajor(), - eps::versionMinor(), - eps::versionRevision()); - } - - settingsFile = ResourcePaths::getSettingsDirectory(true).getChildFile("UpdateCheck.settings"); - if (!settingsFileExists()) { - // No settings file - perhaps first run? - if (saveSettings() && settingsFileExists()) { - // Settings file is writable so probably was just first run. - // Set autocheck on initially. - setAutoCheckEnabled(true); - } - } - loadSettings(); -} - -UpdateChecker::~UpdateChecker() -{ -} - -bool UpdateChecker::getAutoCheckEnabled() -{ - return settingAutoCheckEnabled; -} - -bool UpdateChecker::setAutoCheckEnabled(bool enabled, bool displayConfirmation) -{ - settingAutoCheckEnabled = enabled; - auto success = saveSettings(); - if (displayConfirmation) { - if (success) { - if (enabled) { - displayMessageBox(messageBoxTitles, "Update check will now be performed each time REAPER is started.", MB_ICONINFORMATION); - } - else { - displayMessageBox(messageBoxTitles, "Update check will no longer be performed when REAPER is started.", MB_ICONINFORMATION); - } - } - else { - displayMessageBox(messageBoxTitles, "Error: Failed to save preferences.", MB_ICONEXCLAMATION); - } - } - return success; -} - -void UpdateChecker::doUpdateCheck(bool manualCheck, int timeoutMs) -{ - Version remoteVersion; - std::string remoteVersionStr; - auto success = getRemoteVersion(manualCheck, timeoutMs, remoteVersion, remoteVersionStr); - - if (success) { - if (remoteVersion > currentVersion) { - if (manualCheck || remoteVersion != settingLastReportedVersion) { - // Haven't mentioned this version before or told to always show result - settingLastReportedVersion = remoteVersion; - saveSettings(); - displayUpdateAvailable(remoteVersionStr, manualCheck); - } - } - else if (manualCheck) { - displayUpdateUnavailable(); - } - } -} - -bool UpdateChecker::getRemoteVersion(bool reportErrors, int timeoutMs, Version& version, std::string& versionStr) -{ - std::string body; - auto getSuccess = getHTTPResponseBody(versionJsonUrl, body, timeoutMs); - if (!getSuccess) { - if (reportErrors) { - displayError("Failed to connect to server. Do you have a working internet connection?"); - } - return false; - } - - juce::var j; - auto parseResult = juce::JSON::parse(body, j); - if (parseResult.failed()) { - if (reportErrors) { - displayError("Failed to parse data."); - } - return false; - } - - juce::var varVersionMajor = j.getProperty("version_major", juce::var()); - juce::var varVersionMinor = j.getProperty("version_minor", juce::var()); - juce::var varVersionRevision = j.getProperty("version_revision", juce::var()); - - if (!varVersionMajor.isInt() || - !varVersionMinor.isInt() || - !varVersionRevision.isInt()) { - if (reportErrors) { - displayError("Unexpected data."); - } - return false; - } - - version.major = static_cast (varVersionMajor); - version.minor = static_cast (varVersionMinor); - version.revision = static_cast (varVersionRevision); - - versionStr.clear(); - juce::var varVersionText = j.getProperty("version", juce::var()); - if (varVersionText.isString()) { - versionStr = varVersionText.toString().toStdString(); - } - - return true; -} - -bool UpdateChecker::getHTTPResponseBody(const std::string& url, std::string& responseBody, int timeoutMs) -{ - juce::URL jUrl{ url }; - auto isOpt = juce::URL::InputStreamOptions(juce::URL::ParameterHandling::inAddress).withConnectionTimeoutMs(timeoutMs); - auto is = jUrl.createInputStream(isOpt); - if (is != nullptr) - { - juce::MemoryBlock memoryBlock; - is->readIntoMemoryBlock(memoryBlock); - responseBody = memoryBlock.toString().toStdString(); - return true; - } - return false; -} - -void UpdateChecker::displayError(const std::string& errorText) -{ - std::string text{ "An error occurred whilst checking for updates:\n\n" }; - text += errorText; - displayMessageBox(messageBoxTitles, text, MB_ICONEXCLAMATION); -} - -void UpdateChecker::displayUpdateAvailable(const std::string& versionText, bool instigatedManually) -{ - std::string text; - if (versionText.empty()) { - text = "A new version of the EAR Production Suite is now available."; - } - else { - text = "EAR Production Suite " + versionText + " is now available."; - } - text += "\n\nDownload from https://ear-production-suite.ebu.io/"; - if (!instigatedManually) { - text += "\n\nNo further notifications will appear for this version. You can disable all future notifications through the Extensions menu."; - } - displayMessageBox(messageBoxTitles, text, MB_ICONINFORMATION); -} - -void UpdateChecker::displayUpdateUnavailable() -{ - displayMessageBox(messageBoxTitles, "No updates are currently available.", MB_ICONINFORMATION); -} - -void UpdateChecker::displayMessageBox(const std::string& title, const std::string& text, long winIcon) -{ - // Windows version of Reaper locks up if you try show a message box during splash - NativeMessageBox::splashCompatibleMessage(title.c_str(), text.c_str(), nullptr, winIcon); -} - -bool UpdateChecker::loadSettings() -{ - if (!settingsFileExists()) { - return false; - } - - juce::XmlDocument xml(settingsFile); - auto updateCheckElement = xml.getDocumentElementIfTagMatches("UpdateCheck"); - if (!updateCheckElement) { - return false; - } - - auto lastReportedElement = updateCheckElement->getChildByName("LastReportedVersion"); - if (lastReportedElement) { - settingLastReportedVersion.major = lastReportedElement->getIntAttribute("VersionMajor", 0); - settingLastReportedVersion.minor = lastReportedElement->getIntAttribute("VersionMinor", 0); - settingLastReportedVersion.revision = lastReportedElement->getIntAttribute("VersionRevision", 0); - } - - auto autoCheckElement = updateCheckElement->getChildByName("AutoCheck"); - if (autoCheckElement) { - settingAutoCheckEnabled = autoCheckElement->getBoolAttribute("OnStartUp", false); - } - - return true; -} - -bool UpdateChecker::saveSettings() -{ - auto updateCheckElement = juce::XmlElement("UpdateCheck"); - - auto lastReportedElement = new juce::XmlElement("LastReportedVersion"); - lastReportedElement->setAttribute("VersionMajor", settingLastReportedVersion.major); - lastReportedElement->setAttribute("VersionMinor", settingLastReportedVersion.minor); - lastReportedElement->setAttribute("VersionRevision", settingLastReportedVersion.revision); - updateCheckElement.addChildElement(lastReportedElement); - - auto autoCheckElement = new juce::XmlElement("AutoCheck"); - autoCheckElement->setAttribute("OnStartUp", settingAutoCheckEnabled); - updateCheckElement.addChildElement(autoCheckElement); - - return updateCheckElement.writeTo(settingsFile); -} - -bool UpdateChecker::settingsFileExists() -{ - return settingsFile.existsAsFile(); -} +#include "update_check.h" +#include +#include +#include +#include +#include +#include + +UpdateChecker::UpdateChecker() +{ + if (eps::versionInfoAvailable()) { + currentVersion = Version( + eps::versionMajor(), + eps::versionMinor(), + eps::versionRevision()); + } + + settingsFile = ResourcePaths::getSettingsDirectory(true).getChildFile("UpdateCheck.settings"); + if (!settingsFileExists()) { + // No settings file - perhaps first run? + if (saveSettings() && settingsFileExists()) { + // Settings file is writable so probably was just first run. + // Set autocheck on initially. + setAutoCheckEnabled(true); + } + } + loadSettings(); +} + +UpdateChecker::~UpdateChecker() +{ +} + +bool UpdateChecker::getAutoCheckEnabled() +{ + return settingAutoCheckEnabled; +} + +bool UpdateChecker::setAutoCheckEnabled(bool enabled, bool displayConfirmation) +{ + settingAutoCheckEnabled = enabled; + auto success = saveSettings(); + if (displayConfirmation) { + if (success) { + if (enabled) { + displayMessageBox(messageBoxTitles, "Update check will now be performed each time REAPER is started.", MB_ICONINFORMATION); + } + else { + displayMessageBox(messageBoxTitles, "Update check will no longer be performed when REAPER is started.", MB_ICONINFORMATION); + } + } + else { + displayMessageBox(messageBoxTitles, "Error: Failed to save preferences.", MB_ICONEXCLAMATION); + } + } + return success; +} + +void UpdateChecker::doUpdateCheck(bool manualCheck, int timeoutMs) +{ + Version remoteVersion; + std::string remoteVersionStr; + auto success = getRemoteVersion(manualCheck, timeoutMs, remoteVersion, remoteVersionStr); + + if (success) { + if (remoteVersion > currentVersion) { + if (manualCheck || remoteVersion != settingLastReportedVersion) { + // Haven't mentioned this version before or told to always show result + settingLastReportedVersion = remoteVersion; + saveSettings(); + displayUpdateAvailable(remoteVersionStr, manualCheck); + } + } + else if (manualCheck) { + displayUpdateUnavailable(); + } + } +} + +bool UpdateChecker::getRemoteVersion(bool reportErrors, int timeoutMs, Version& version, std::string& versionStr) +{ + std::string body; + auto getSuccess = getHTTPResponseBody(versionJsonUrl, body, timeoutMs); + if (!getSuccess) { + if (reportErrors) { + displayError("Failed to connect to server. Do you have a working internet connection?"); + } + return false; + } + + juce::var j; + auto parseResult = juce::JSON::parse(body, j); + if (parseResult.failed()) { + if (reportErrors) { + displayError("Failed to parse data."); + } + return false; + } + + juce::var varVersionMajor = j.getProperty("version_major", juce::var()); + juce::var varVersionMinor = j.getProperty("version_minor", juce::var()); + juce::var varVersionRevision = j.getProperty("version_revision", juce::var()); + + if (!varVersionMajor.isInt() || + !varVersionMinor.isInt() || + !varVersionRevision.isInt()) { + if (reportErrors) { + displayError("Unexpected data."); + } + return false; + } + + version.major = static_cast (varVersionMajor); + version.minor = static_cast (varVersionMinor); + version.revision = static_cast (varVersionRevision); + + versionStr.clear(); + juce::var varVersionText = j.getProperty("version", juce::var()); + if (varVersionText.isString()) { + versionStr = varVersionText.toString().toStdString(); + } + + return true; +} + +bool UpdateChecker::getHTTPResponseBody(const std::string& url, std::string& responseBody, int timeoutMs) +{ + juce::URL jUrl{ url }; + auto isOpt = juce::URL::InputStreamOptions(juce::URL::ParameterHandling::inAddress).withConnectionTimeoutMs(timeoutMs); + auto is = jUrl.createInputStream(isOpt); + if (is != nullptr) + { + juce::MemoryBlock memoryBlock; + is->readIntoMemoryBlock(memoryBlock); + responseBody = memoryBlock.toString().toStdString(); + return true; + } + return false; +} + +void UpdateChecker::displayError(const std::string& errorText) +{ + std::string text{ "An error occurred whilst checking for updates:\n\n" }; + text += errorText; + displayMessageBox(messageBoxTitles, text, MB_ICONEXCLAMATION); +} + +void UpdateChecker::displayUpdateAvailable(const std::string& versionText, bool instigatedManually) +{ + std::string text; + if (versionText.empty()) { + text = "A new version of the EAR Production Suite is now available."; + } + else { + text = "EAR Production Suite " + versionText + " is now available."; + } + text += "\n\nDownload from https://ear-production-suite.ebu.io/"; + if (!instigatedManually) { + text += "\n\nNo further notifications will appear for this version. You can disable all future notifications through the Extensions menu."; + } + displayMessageBox(messageBoxTitles, text, MB_ICONINFORMATION); +} + +void UpdateChecker::displayUpdateUnavailable() +{ + displayMessageBox(messageBoxTitles, "No updates are currently available.", MB_ICONINFORMATION); +} + +void UpdateChecker::displayMessageBox(const std::string& title, const std::string& text, long winIcon) +{ + // Windows version of Reaper locks up if you try show a message box during splash + NativeMessageBox::splashCompatibleMessage(title.c_str(), text.c_str(), nullptr, winIcon); +} + +bool UpdateChecker::loadSettings() +{ + if (!settingsFileExists()) { + return false; + } + + juce::XmlDocument xml(settingsFile); + auto updateCheckElement = xml.getDocumentElementIfTagMatches("UpdateCheck"); + if (!updateCheckElement) { + return false; + } + + auto lastReportedElement = updateCheckElement->getChildByName("LastReportedVersion"); + if (lastReportedElement) { + settingLastReportedVersion.major = lastReportedElement->getIntAttribute("VersionMajor", 0); + settingLastReportedVersion.minor = lastReportedElement->getIntAttribute("VersionMinor", 0); + settingLastReportedVersion.revision = lastReportedElement->getIntAttribute("VersionRevision", 0); + } + + auto autoCheckElement = updateCheckElement->getChildByName("AutoCheck"); + if (autoCheckElement) { + settingAutoCheckEnabled = autoCheckElement->getBoolAttribute("OnStartUp", false); + } + + return true; +} + +bool UpdateChecker::saveSettings() +{ + auto updateCheckElement = juce::XmlElement("UpdateCheck"); + + auto lastReportedElement = new juce::XmlElement("LastReportedVersion"); + lastReportedElement->setAttribute("VersionMajor", settingLastReportedVersion.major); + lastReportedElement->setAttribute("VersionMinor", settingLastReportedVersion.minor); + lastReportedElement->setAttribute("VersionRevision", settingLastReportedVersion.revision); + updateCheckElement.addChildElement(lastReportedElement); + + auto autoCheckElement = new juce::XmlElement("AutoCheck"); + autoCheckElement->setAttribute("OnStartUp", settingAutoCheckEnabled); + updateCheckElement.addChildElement(autoCheckElement); + + return updateCheckElement.writeTo(settingsFile); +} + +bool UpdateChecker::settingsFileExists() +{ + return settingsFile.existsAsFile(); +} diff --git a/reaper-adm-extension/src/reaper_adm/update_check.h b/shared/update_check.h similarity index 93% rename from reaper-adm-extension/src/reaper_adm/update_check.h rename to shared/update_check.h index 1dc5246bf..fa6c03243 100644 --- a/reaper-adm-extension/src/reaper_adm/update_check.h +++ b/shared/update_check.h @@ -1,39 +1,38 @@ -#pragma once -#include -#include "reaperhost.h" -#include "juce_modules.h" -#include - -class UpdateChecker { -public: - UpdateChecker(); - ~UpdateChecker(); - - bool getAutoCheckEnabled(); - bool setAutoCheckEnabled(bool enabled, bool displayConfirmation=false); - - void doUpdateCheck(bool manualCheck=false, int timeoutMs=3000); - -private: - const std::string versionJsonUrl{ "https://ear-production-suite.ebu.io/version_info.json" }; - const std::string messageBoxTitles{ "EAR Production Suite Update" }; - - bool getRemoteVersion(bool reportErrors, int timeoutMs, Version& version, std::string& versionStr); - bool getHTTPResponseBody(const std::string& url, std::string& responseBody, int timeoutMs); - - void displayError(const std::string& errorText); - void displayUpdateAvailable(const std::string& versionText, bool instigatedManually); - void displayUpdateUnavailable(); - void displayMessageBox(const std::string& title, const std::string& text, long winIcon); - - juce::File settingsFile; - bool loadSettings(); - bool saveSettings(); - bool settingsFileExists(); - - bool settingAutoCheckEnabled{ false }; - Version settingLastReportedVersion; - - Version currentVersion; - -}; +#pragma once +#include +#include +#include + +class UpdateChecker { +public: + UpdateChecker(); + ~UpdateChecker(); + + bool getAutoCheckEnabled(); + bool setAutoCheckEnabled(bool enabled, bool displayConfirmation=false); + + void doUpdateCheck(bool manualCheck=false, int timeoutMs=3000); + +private: + const std::string versionJsonUrl{ "https://ear-production-suite.ebu.io/version_info.json" }; + const std::string messageBoxTitles{ "EAR Production Suite Update" }; + + bool getRemoteVersion(bool reportErrors, int timeoutMs, Version& version, std::string& versionStr); + bool getHTTPResponseBody(const std::string& url, std::string& responseBody, int timeoutMs); + + void displayError(const std::string& errorText); + void displayUpdateAvailable(const std::string& versionText, bool instigatedManually); + void displayUpdateUnavailable(); + void displayMessageBox(const std::string& title, const std::string& text, long winIcon); + + juce::File settingsFile; + bool loadSettings(); + bool saveSettings(); + bool settingsFileExists(); + + bool settingAutoCheckEnabled{ false }; + Version settingLastReportedVersion; + + Version currentVersion; + +}; From 5682e4afb40a9d21ed53a4b747e2e62e38b98ed3 Mon Sep 17 00:00:00 2001 From: Matt Firth Date: Fri, 13 Oct 2023 13:23:42 +0100 Subject: [PATCH 02/14] Simplify JUCE includes in update_check --- .../src/reaper_adm/CMakeLists.txt | 1 - .../src/reaper_adm/juce_modules.h | 16 ---------------- shared/update_check.cpp | 1 - shared/update_check.h | 3 ++- 4 files changed, 2 insertions(+), 19 deletions(-) delete mode 100644 reaper-adm-extension/src/reaper_adm/juce_modules.h diff --git a/reaper-adm-extension/src/reaper_adm/CMakeLists.txt b/reaper-adm-extension/src/reaper_adm/CMakeLists.txt index 866cec2e9..2430bfc0d 100644 --- a/reaper-adm-extension/src/reaper_adm/CMakeLists.txt +++ b/reaper-adm-extension/src/reaper_adm/CMakeLists.txt @@ -87,7 +87,6 @@ set(EXTENSION_HEADERS ${EPS_SHARED_DIR}/update_check.h AppConfig.h - juce_modules.h actionmanager.h admchannel.h diff --git a/reaper-adm-extension/src/reaper_adm/juce_modules.h b/reaper-adm-extension/src/reaper_adm/juce_modules.h deleted file mode 100644 index 92238132d..000000000 --- a/reaper-adm-extension/src/reaper_adm/juce_modules.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "AppConfig.h" -#include -#include -// Will leave these here in case we want to use any other modules at a later date -// Don't forget to change the associated macro in AppConfig.h -//include -//include -//include -//include -//include -//include -//include -//include -//include -//include diff --git a/shared/update_check.cpp b/shared/update_check.cpp index cae23fc78..617f62f8e 100644 --- a/shared/update_check.cpp +++ b/shared/update_check.cpp @@ -4,7 +4,6 @@ #include #include #include -#include UpdateChecker::UpdateChecker() { diff --git a/shared/update_check.h b/shared/update_check.h index fa6c03243..3ec084be5 100644 --- a/shared/update_check.h +++ b/shared/update_check.h @@ -1,6 +1,7 @@ #pragma once #include -#include +#include +#include #include class UpdateChecker { From 8f9ca6c521dfdfe47ce7c9c840ac1afa70481abc Mon Sep 17 00:00:00 2001 From: Matt Firth Date: Fri, 13 Oct 2023 17:58:10 +0100 Subject: [PATCH 03/14] AutoUpdateCheckButton component in final setup screen --- .../install_phases/component_complete.cpp | 80 ++++++++++++++++++- .../setup/install_phases/component_complete.h | 30 +++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/tools/setup/install_phases/component_complete.cpp b/tools/setup/install_phases/component_complete.cpp index 756268dd2..af5c89150 100644 --- a/tools/setup/install_phases/component_complete.cpp +++ b/tools/setup/install_phases/component_complete.cpp @@ -39,7 +39,15 @@ void ComponentComplete::resized() auto sectionHeight = area.getHeight() / 4; titleLabel.setBounds(area.removeFromTop(sectionHeight)); - descriptionLabel.setBounds(area.removeFromTop(sectionHeight)); + descriptionLabel.setBounds(area.removeFromTop(sectionHeight / 2)); + + if (autoUpdateCheck) { + const int autoUpdateCheckHeight{ 35 }; + auto autoUpdateCheckWidth = autoUpdateCheck->getMinReqWidth(autoUpdateCheckHeight); + auto autoUpdateCheckArea = area.removeFromTop(sectionHeight / 2).withSizeKeepingCentre(autoUpdateCheckWidth, autoUpdateCheckHeight); + if (autoUpdateCheckArea.getX() < 0) autoUpdateCheckArea.setX(0); + autoUpdateCheck->setBounds(autoUpdateCheckArea); + } auto buttonSectionWidth = area.getWidth(); auto buttonHeight = std::min(area.getHeight(), 40); @@ -51,6 +59,10 @@ void ComponentComplete::resized() void ComponentComplete::configureForUninstallPhase() { + if (autoUpdateCheck) { + removeChildComponent(autoUpdateCheck.get()); + autoUpdateCheck.reset(); + } titleLabel.setText("Uninstall Complete", juce::NotificationType::dontSendNotification); descriptionLabel.setText("Uninstallation is complete.", @@ -59,6 +71,10 @@ void ComponentComplete::configureForUninstallPhase() void ComponentComplete::configureForUninstallUnnecessaryPhase() { + if (autoUpdateCheck) { + removeChildComponent(autoUpdateCheck.get()); + autoUpdateCheck.reset(); + } titleLabel.setText("Uninstall", juce::NotificationType::dontSendNotification); descriptionLabel.setText("Setup did not find any files relating to a previous installation.", @@ -67,8 +83,70 @@ void ComponentComplete::configureForUninstallUnnecessaryPhase() void ComponentComplete::configureForInstallPhase() { + if (!autoUpdateCheck) { + autoUpdateCheck = std::make_unique(); + addAndMakeVisible(autoUpdateCheck.get()); + } titleLabel.setText("Installation Complete", juce::NotificationType::dontSendNotification); descriptionLabel.setText("The EAR Production Suite has been installed.\nUse the software via the REAPER digital audio workstation.", juce::NotificationType::dontSendNotification); } + +AutoUpdateCheckButton::AutoUpdateCheckButton() +{ + text1.setFont(EarFontsSingleton::instance().Label); + text1.setColour(Label::textColourId, EarColours::Label.withAlpha(Emphasis::high)); + text1.setJustificationType(Justification::centredLeft); + text1.setText(text1Str, dontSendNotification); + addAndMakeVisible(text1); + + text2.setFont(EarFontsSingleton::instance().Label); + text2.setColour(Label::textColourId, EarColours::Label.withAlpha(Emphasis::medium)); + text2.setJustificationType(Justification::centredLeft); + text2.setText(text2Str, dontSendNotification); + addAndMakeVisible(text2); + + this->setMouseCursor(MouseCursor::PointingHandCursor); + text1.setMouseCursor(MouseCursor::PointingHandCursor); + text2.setMouseCursor(MouseCursor::PointingHandCursor); + text1.setInterceptsMouseClicks(false, false); + text2.setInterceptsMouseClicks(false, false); +} + +AutoUpdateCheckButton::~AutoUpdateCheckButton() +{ +} + +void AutoUpdateCheckButton::paint(Graphics& g) +{ + auto area = getLocalBounds(); + getLookAndFeel().drawTickBox(g, text1, 1, 1, area.getHeight() - 2, area.getHeight() - 2, enabled, true, true, false); +} + +void AutoUpdateCheckButton::resized() +{ + auto area = getLocalBounds(); + area.removeFromLeft(area.getHeight() + 10); + text1.setBounds(area.removeFromTop(area.getHeight() / 2)); + text2.setBounds(area); +} + +int AutoUpdateCheckButton::getMinReqWidth(int forComponentHeight) +{ + auto text1Width = EarFontsSingleton::instance().Label.getStringWidthFloat(text1Str); + auto text2Width = EarFontsSingleton::instance().Label.getStringWidthFloat(text2Str); + auto textWidth = std::max(text1Width, text2Width) * 1.05f; // 5% excess + return forComponentHeight + marginBoxText + textWidth; +} + +void AutoUpdateCheckButton::setState(bool checked) +{ + enabled = checked; + repaint(); +} + +void AutoUpdateCheckButton::mouseDown(const MouseEvent& event) +{ + setState(!enabled); +} diff --git a/tools/setup/install_phases/component_complete.h b/tools/setup/install_phases/component_complete.h index 96a6eea4c..1bb93ad1a 100644 --- a/tools/setup/install_phases/component_complete.h +++ b/tools/setup/install_phases/component_complete.h @@ -1,6 +1,35 @@ #pragma once #include "JuceHeader.h" +#include + +class AutoUpdateCheckButton : public Component +{ +public: + AutoUpdateCheckButton(); + ~AutoUpdateCheckButton(); + + void paint(Graphics&) override; + void resized() override; + + int getMinReqWidth(int forComponentHeight); + + void setState(bool checked); + + void mouseDown(const MouseEvent& event) override; + +private: + Label text1; + Label text2; + + const String text1Str{ "Automatically check for updates on start-up (requires internet connection.)" }; + const String text2Str{ "You can change your preference at any time from the REAPER Extensions menu." }; + const int marginBoxText{ 10 }; + + bool enabled{ false }; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AutoUpdateCheckButton) +}; class ComponentComplete : public Component { @@ -19,6 +48,7 @@ class ComponentComplete : public Component Label titleLabel; Label descriptionLabel; TextButton exitButton; + std::unique_ptr autoUpdateCheck; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentComplete) }; \ No newline at end of file From d8aad8aafe5b782dae66a28fd7f8fad328677f78 Mon Sep 17 00:00:00 2001 From: Matt Firth Date: Fri, 13 Oct 2023 19:08:33 +0100 Subject: [PATCH 04/14] UpdateChecker instance in AutoUpdateCheckButton --- reaper-adm-extension/src/reaper_adm/pluginmain.cpp | 2 +- tools/setup/CMakeLists.txt | 2 ++ tools/setup/install_phases/component_complete.cpp | 1 + tools/setup/install_phases/component_complete.h | 3 +++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/reaper-adm-extension/src/reaper_adm/pluginmain.cpp b/reaper-adm-extension/src/reaper_adm/pluginmain.cpp index aa00b5015..5a19edb5d 100644 --- a/reaper-adm-extension/src/reaper_adm/pluginmain.cpp +++ b/reaper-adm-extension/src/reaper_adm/pluginmain.cpp @@ -12,7 +12,7 @@ #include "pluginsuite.h" #include "pluginregistry.h" #include "pluginsuite_ear.h" -#include "update_check.h" +#include #include #include #include diff --git a/tools/setup/CMakeLists.txt b/tools/setup/CMakeLists.txt index 723f2dbe0..6c8630c39 100644 --- a/tools/setup/CMakeLists.txt +++ b/tools/setup/CMakeLists.txt @@ -24,6 +24,7 @@ set(HEADERS_SETUP install_phases/component_complete.h helpers/manifests.h ${EPS_SHARED_DIR}/helper/resource_paths_juce-file.hpp + ${EPS_SHARED_DIR}/update_check.cpp ) set(SOURCES_SETUP @@ -41,6 +42,7 @@ set(SOURCES_SETUP install_phases/component_complete.cpp helpers/manifests.cpp ${EPS_SHARED_DIR}/binary_data.cpp + ${EPS_SHARED_DIR}/update_check.h ) source_group("Header Files" FILES ${HEADERS_SETUP}) diff --git a/tools/setup/install_phases/component_complete.cpp b/tools/setup/install_phases/component_complete.cpp index af5c89150..fb17d5001 100644 --- a/tools/setup/install_phases/component_complete.cpp +++ b/tools/setup/install_phases/component_complete.cpp @@ -84,6 +84,7 @@ void ComponentComplete::configureForUninstallUnnecessaryPhase() void ComponentComplete::configureForInstallPhase() { if (!autoUpdateCheck) { + // Only instantiate this on successful install because UpdateCheck will want to write a settings file. autoUpdateCheck = std::make_unique(); addAndMakeVisible(autoUpdateCheck.get()); } diff --git a/tools/setup/install_phases/component_complete.h b/tools/setup/install_phases/component_complete.h index 1bb93ad1a..62f45f156 100644 --- a/tools/setup/install_phases/component_complete.h +++ b/tools/setup/install_phases/component_complete.h @@ -2,6 +2,7 @@ #include "JuceHeader.h" #include +#include class AutoUpdateCheckButton : public Component { @@ -28,6 +29,8 @@ class AutoUpdateCheckButton : public Component bool enabled{ false }; + UpdateChecker updateChecker; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AutoUpdateCheckButton) }; From f3a1e8d79cf688c292103f3bcec7e389a6c4164a Mon Sep 17 00:00:00 2001 From: Matt Firth Date: Fri, 13 Oct 2023 19:28:37 +0100 Subject: [PATCH 05/14] Get and Set update check state from setup UI --- tools/setup/install_phases/component_complete.cpp | 8 +++++--- tools/setup/install_phases/component_complete.h | 2 -- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/setup/install_phases/component_complete.cpp b/tools/setup/install_phases/component_complete.cpp index fb17d5001..9b6a1339c 100644 --- a/tools/setup/install_phases/component_complete.cpp +++ b/tools/setup/install_phases/component_complete.cpp @@ -87,6 +87,7 @@ void ComponentComplete::configureForInstallPhase() // Only instantiate this on successful install because UpdateCheck will want to write a settings file. autoUpdateCheck = std::make_unique(); addAndMakeVisible(autoUpdateCheck.get()); + resized(); } titleLabel.setText("Installation Complete", juce::NotificationType::dontSendNotification); @@ -122,7 +123,8 @@ AutoUpdateCheckButton::~AutoUpdateCheckButton() void AutoUpdateCheckButton::paint(Graphics& g) { auto area = getLocalBounds(); - getLookAndFeel().drawTickBox(g, text1, 1, 1, area.getHeight() - 2, area.getHeight() - 2, enabled, true, true, false); + auto checked = updateChecker.getAutoCheckEnabled(); + getLookAndFeel().drawTickBox(g, text1, 1, 1, area.getHeight() - 2, area.getHeight() - 2, checked, true, true, false); } void AutoUpdateCheckButton::resized() @@ -143,11 +145,11 @@ int AutoUpdateCheckButton::getMinReqWidth(int forComponentHeight) void AutoUpdateCheckButton::setState(bool checked) { - enabled = checked; + updateChecker.setAutoCheckEnabled(checked); repaint(); } void AutoUpdateCheckButton::mouseDown(const MouseEvent& event) { - setState(!enabled); + setState(!updateChecker.getAutoCheckEnabled()); } diff --git a/tools/setup/install_phases/component_complete.h b/tools/setup/install_phases/component_complete.h index 62f45f156..dda26d4cf 100644 --- a/tools/setup/install_phases/component_complete.h +++ b/tools/setup/install_phases/component_complete.h @@ -27,8 +27,6 @@ class AutoUpdateCheckButton : public Component const String text2Str{ "You can change your preference at any time from the REAPER Extensions menu." }; const int marginBoxText{ 10 }; - bool enabled{ false }; - UpdateChecker updateChecker; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AutoUpdateCheckButton) From c182a5995ef84e52892215a2892fc295be5ce52e Mon Sep 17 00:00:00 2001 From: Matt Firth Date: Sat, 14 Oct 2023 01:16:10 +0100 Subject: [PATCH 06/14] Warn if update prefs can't be saved --- shared/update_check.cpp | 10 ++++++++++ shared/update_check.h | 3 +++ tools/setup/install_phases/component_complete.cpp | 10 ++++++---- tools/setup/install_phases/component_complete.h | 2 -- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/shared/update_check.cpp b/shared/update_check.cpp index 617f62f8e..771070f34 100644 --- a/shared/update_check.cpp +++ b/shared/update_check.cpp @@ -76,6 +76,16 @@ void UpdateChecker::doUpdateCheck(bool manualCheck, int timeoutMs) } } +bool UpdateChecker::canReadSettingsFile() +{ + return loadSettings(); +} + +bool UpdateChecker::canWriteSettingsFile() +{ + return saveSettings(); +} + bool UpdateChecker::getRemoteVersion(bool reportErrors, int timeoutMs, Version& version, std::string& versionStr) { std::string body; diff --git a/shared/update_check.h b/shared/update_check.h index 3ec084be5..88cee841d 100644 --- a/shared/update_check.h +++ b/shared/update_check.h @@ -14,6 +14,9 @@ class UpdateChecker { void doUpdateCheck(bool manualCheck=false, int timeoutMs=3000); + bool canReadSettingsFile(); + bool canWriteSettingsFile(); + private: const std::string versionJsonUrl{ "https://ear-production-suite.ebu.io/version_info.json" }; const std::string messageBoxTitles{ "EAR Production Suite Update" }; diff --git a/tools/setup/install_phases/component_complete.cpp b/tools/setup/install_phases/component_complete.cpp index 9b6a1339c..6006d1f5c 100644 --- a/tools/setup/install_phases/component_complete.cpp +++ b/tools/setup/install_phases/component_complete.cpp @@ -97,16 +97,18 @@ void ComponentComplete::configureForInstallPhase() AutoUpdateCheckButton::AutoUpdateCheckButton() { + bool success = updateChecker.canWriteSettingsFile(); + text1.setFont(EarFontsSingleton::instance().Label); text1.setColour(Label::textColourId, EarColours::Label.withAlpha(Emphasis::high)); text1.setJustificationType(Justification::centredLeft); - text1.setText(text1Str, dontSendNotification); + text1.setText(success ? "Automatically check for updates on start-up (requires internet connection.)" : "Automatic update checking disabled - cannot write preferences to settings file.", dontSendNotification); addAndMakeVisible(text1); text2.setFont(EarFontsSingleton::instance().Label); text2.setColour(Label::textColourId, EarColours::Label.withAlpha(Emphasis::medium)); text2.setJustificationType(Justification::centredLeft); - text2.setText(text2Str, dontSendNotification); + text2.setText(success ? "You can change your preference at any time from the REAPER Extensions menu." : "You can still perform a manual update check from the REAPER Extensions menu.", dontSendNotification); addAndMakeVisible(text2); this->setMouseCursor(MouseCursor::PointingHandCursor); @@ -137,8 +139,8 @@ void AutoUpdateCheckButton::resized() int AutoUpdateCheckButton::getMinReqWidth(int forComponentHeight) { - auto text1Width = EarFontsSingleton::instance().Label.getStringWidthFloat(text1Str); - auto text2Width = EarFontsSingleton::instance().Label.getStringWidthFloat(text2Str); + auto text1Width = EarFontsSingleton::instance().Label.getStringWidthFloat(text1.getText()); + auto text2Width = EarFontsSingleton::instance().Label.getStringWidthFloat(text2.getText()); auto textWidth = std::max(text1Width, text2Width) * 1.05f; // 5% excess return forComponentHeight + marginBoxText + textWidth; } diff --git a/tools/setup/install_phases/component_complete.h b/tools/setup/install_phases/component_complete.h index dda26d4cf..b28d7baa9 100644 --- a/tools/setup/install_phases/component_complete.h +++ b/tools/setup/install_phases/component_complete.h @@ -23,8 +23,6 @@ class AutoUpdateCheckButton : public Component Label text1; Label text2; - const String text1Str{ "Automatically check for updates on start-up (requires internet connection.)" }; - const String text2Str{ "You can change your preference at any time from the REAPER Extensions menu." }; const int marginBoxText{ 10 }; UpdateChecker updateChecker; From e846111bf3457af522775e0d478bb0f847782f9c Mon Sep 17 00:00:00 2001 From: Matt Firth Date: Thu, 19 Oct 2023 21:26:15 +0100 Subject: [PATCH 07/14] Use correct swell header previous didn't load swell-types --- shared/helper/native_message_box.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/helper/native_message_box.hpp b/shared/helper/native_message_box.hpp index fd81f0c24..8d9902187 100644 --- a/shared/helper/native_message_box.hpp +++ b/shared/helper/native_message_box.hpp @@ -5,7 +5,7 @@ #define WIN32_LEAN_AND_MEAN #include #else -#include +#include #endif #include From f6ca8212da012dfdc1dabf2284e7ebe3b6b6fb88 Mon Sep 17 00:00:00 2001 From: Matt Firth Date: Fri, 20 Oct 2023 10:31:18 +0100 Subject: [PATCH 08/14] Split UpdateChecker file access into separate class Means we avoid pulling in the UpdateChecker dialog code into setup. We don't use any of the actual update checking code or user feedback in setup anyway, and so this change means we don't need to link swell at all --- .../src/reaper_adm/CMakeLists.txt | 2 + shared/update_check.cpp | 82 +------------- shared/update_check.h | 13 +-- shared/update_check_settings_file.cpp | 103 ++++++++++++++++++ shared/update_check_settings_file.h | 29 +++++ tools/setup/CMakeLists.txt | 6 +- .../install_phases/component_complete.cpp | 8 +- .../setup/install_phases/component_complete.h | 4 +- 8 files changed, 150 insertions(+), 97 deletions(-) create mode 100644 shared/update_check_settings_file.cpp create mode 100644 shared/update_check_settings_file.h diff --git a/reaper-adm-extension/src/reaper_adm/CMakeLists.txt b/reaper-adm-extension/src/reaper_adm/CMakeLists.txt index 2430bfc0d..f49f362ed 100644 --- a/reaper-adm-extension/src/reaper_adm/CMakeLists.txt +++ b/reaper-adm-extension/src/reaper_adm/CMakeLists.txt @@ -9,6 +9,7 @@ find_package(JUCE REQUIRED QUIET) set(EXTENSION_SOURCES ${EPS_SHARED_DIR}/helper/common_definition_helper.cpp ${EPS_SHARED_DIR}/update_check.cpp + ${EPS_SHARED_DIR}/update_check_settings_file.cpp actionmanager.cpp admchannel.cpp @@ -85,6 +86,7 @@ set(EXTENSION_HEADERS ${EPS_SHARED_DIR}/helper/native_message_box.hpp ${EPS_SHARED_DIR}/daw_channel_count.h ${EPS_SHARED_DIR}/update_check.h + ${EPS_SHARED_DIR}/update_check_settings_file.h AppConfig.h diff --git a/shared/update_check.cpp b/shared/update_check.cpp index 771070f34..f6d4fe75b 100644 --- a/shared/update_check.cpp +++ b/shared/update_check.cpp @@ -13,17 +13,6 @@ UpdateChecker::UpdateChecker() eps::versionMinor(), eps::versionRevision()); } - - settingsFile = ResourcePaths::getSettingsDirectory(true).getChildFile("UpdateCheck.settings"); - if (!settingsFileExists()) { - // No settings file - perhaps first run? - if (saveSettings() && settingsFileExists()) { - // Settings file is writable so probably was just first run. - // Set autocheck on initially. - setAutoCheckEnabled(true); - } - } - loadSettings(); } UpdateChecker::~UpdateChecker() @@ -32,13 +21,12 @@ UpdateChecker::~UpdateChecker() bool UpdateChecker::getAutoCheckEnabled() { - return settingAutoCheckEnabled; + return settingsFile.getAutoCheckEnabled(); } bool UpdateChecker::setAutoCheckEnabled(bool enabled, bool displayConfirmation) { - settingAutoCheckEnabled = enabled; - auto success = saveSettings(); + auto success = settingsFile.setAutoCheckEnabled(enabled); if (displayConfirmation) { if (success) { if (enabled) { @@ -63,10 +51,9 @@ void UpdateChecker::doUpdateCheck(bool manualCheck, int timeoutMs) if (success) { if (remoteVersion > currentVersion) { - if (manualCheck || remoteVersion != settingLastReportedVersion) { + if (manualCheck || remoteVersion != settingsFile.getLastReportedVersion()) { // Haven't mentioned this version before or told to always show result - settingLastReportedVersion = remoteVersion; - saveSettings(); + settingsFile.setLastReportedVersion(remoteVersion); displayUpdateAvailable(remoteVersionStr, manualCheck); } } @@ -76,16 +63,6 @@ void UpdateChecker::doUpdateCheck(bool manualCheck, int timeoutMs) } } -bool UpdateChecker::canReadSettingsFile() -{ - return loadSettings(); -} - -bool UpdateChecker::canWriteSettingsFile() -{ - return saveSettings(); -} - bool UpdateChecker::getRemoteVersion(bool reportErrors, int timeoutMs, Version& version, std::string& versionStr) { std::string body; @@ -179,53 +156,4 @@ void UpdateChecker::displayMessageBox(const std::string& title, const std::strin { // Windows version of Reaper locks up if you try show a message box during splash NativeMessageBox::splashCompatibleMessage(title.c_str(), text.c_str(), nullptr, winIcon); -} - -bool UpdateChecker::loadSettings() -{ - if (!settingsFileExists()) { - return false; - } - - juce::XmlDocument xml(settingsFile); - auto updateCheckElement = xml.getDocumentElementIfTagMatches("UpdateCheck"); - if (!updateCheckElement) { - return false; - } - - auto lastReportedElement = updateCheckElement->getChildByName("LastReportedVersion"); - if (lastReportedElement) { - settingLastReportedVersion.major = lastReportedElement->getIntAttribute("VersionMajor", 0); - settingLastReportedVersion.minor = lastReportedElement->getIntAttribute("VersionMinor", 0); - settingLastReportedVersion.revision = lastReportedElement->getIntAttribute("VersionRevision", 0); - } - - auto autoCheckElement = updateCheckElement->getChildByName("AutoCheck"); - if (autoCheckElement) { - settingAutoCheckEnabled = autoCheckElement->getBoolAttribute("OnStartUp", false); - } - - return true; -} - -bool UpdateChecker::saveSettings() -{ - auto updateCheckElement = juce::XmlElement("UpdateCheck"); - - auto lastReportedElement = new juce::XmlElement("LastReportedVersion"); - lastReportedElement->setAttribute("VersionMajor", settingLastReportedVersion.major); - lastReportedElement->setAttribute("VersionMinor", settingLastReportedVersion.minor); - lastReportedElement->setAttribute("VersionRevision", settingLastReportedVersion.revision); - updateCheckElement.addChildElement(lastReportedElement); - - auto autoCheckElement = new juce::XmlElement("AutoCheck"); - autoCheckElement->setAttribute("OnStartUp", settingAutoCheckEnabled); - updateCheckElement.addChildElement(autoCheckElement); - - return updateCheckElement.writeTo(settingsFile); -} - -bool UpdateChecker::settingsFileExists() -{ - return settingsFile.existsAsFile(); -} +} \ No newline at end of file diff --git a/shared/update_check.h b/shared/update_check.h index 88cee841d..c332ca488 100644 --- a/shared/update_check.h +++ b/shared/update_check.h @@ -3,6 +3,7 @@ #include #include #include +#include class UpdateChecker { public: @@ -14,9 +15,6 @@ class UpdateChecker { void doUpdateCheck(bool manualCheck=false, int timeoutMs=3000); - bool canReadSettingsFile(); - bool canWriteSettingsFile(); - private: const std::string versionJsonUrl{ "https://ear-production-suite.ebu.io/version_info.json" }; const std::string messageBoxTitles{ "EAR Production Suite Update" }; @@ -29,14 +27,7 @@ class UpdateChecker { void displayUpdateUnavailable(); void displayMessageBox(const std::string& title, const std::string& text, long winIcon); - juce::File settingsFile; - bool loadSettings(); - bool saveSettings(); - bool settingsFileExists(); - - bool settingAutoCheckEnabled{ false }; - Version settingLastReportedVersion; - + UpdateCheckerSettingsFile settingsFile; Version currentVersion; }; diff --git a/shared/update_check_settings_file.cpp b/shared/update_check_settings_file.cpp new file mode 100644 index 000000000..5cd82bb64 --- /dev/null +++ b/shared/update_check_settings_file.cpp @@ -0,0 +1,103 @@ +#include "update_check_settings_file.h" +#include +#include + +UpdateCheckerSettingsFile::UpdateCheckerSettingsFile() +{ + settingsFile = ResourcePaths::getSettingsDirectory(true).getChildFile("UpdateCheck.settings"); + if (!settingsFileExists()) { + // No settings file - perhaps first run? + if (saveSettings() && settingsFileExists()) { + // Settings file is writable so probably was just first run. + // Set autocheck on initially. + setAutoCheckEnabled(true); + } + } + loadSettings(); +} + +UpdateCheckerSettingsFile::~UpdateCheckerSettingsFile() +{ +} + +bool UpdateCheckerSettingsFile::getAutoCheckEnabled() +{ + return settingAutoCheckEnabled; +} + +bool UpdateCheckerSettingsFile::setAutoCheckEnabled(bool enabled) +{ + settingAutoCheckEnabled = enabled; + return saveSettings(); +} + +Version UpdateCheckerSettingsFile::getLastReportedVersion() +{ + return settingLastReportedVersion; +} + +bool UpdateCheckerSettingsFile::setLastReportedVersion(Version version) +{ + settingLastReportedVersion = version; + return saveSettings(); +} + + +bool UpdateCheckerSettingsFile::canReadSettingsFile() +{ + return loadSettings(); +} + +bool UpdateCheckerSettingsFile::canWriteSettingsFile() +{ + return saveSettings(); +} + +bool UpdateCheckerSettingsFile::loadSettings() +{ + if (!settingsFileExists()) { + return false; + } + + juce::XmlDocument xml(settingsFile); + auto updateCheckElement = xml.getDocumentElementIfTagMatches("UpdateCheck"); + if (!updateCheckElement) { + return false; + } + + auto lastReportedElement = updateCheckElement->getChildByName("LastReportedVersion"); + if (lastReportedElement) { + settingLastReportedVersion.major = lastReportedElement->getIntAttribute("VersionMajor", 0); + settingLastReportedVersion.minor = lastReportedElement->getIntAttribute("VersionMinor", 0); + settingLastReportedVersion.revision = lastReportedElement->getIntAttribute("VersionRevision", 0); + } + + auto autoCheckElement = updateCheckElement->getChildByName("AutoCheck"); + if (autoCheckElement) { + settingAutoCheckEnabled = autoCheckElement->getBoolAttribute("OnStartUp", false); + } + + return true; +} + +bool UpdateCheckerSettingsFile::saveSettings() +{ + auto updateCheckElement = juce::XmlElement("UpdateCheck"); + + auto lastReportedElement = new juce::XmlElement("LastReportedVersion"); + lastReportedElement->setAttribute("VersionMajor", settingLastReportedVersion.major); + lastReportedElement->setAttribute("VersionMinor", settingLastReportedVersion.minor); + lastReportedElement->setAttribute("VersionRevision", settingLastReportedVersion.revision); + updateCheckElement.addChildElement(lastReportedElement); + + auto autoCheckElement = new juce::XmlElement("AutoCheck"); + autoCheckElement->setAttribute("OnStartUp", settingAutoCheckEnabled); + updateCheckElement.addChildElement(autoCheckElement); + + return updateCheckElement.writeTo(settingsFile); +} + +bool UpdateCheckerSettingsFile::settingsFileExists() +{ + return settingsFile.existsAsFile(); +} diff --git a/shared/update_check_settings_file.h b/shared/update_check_settings_file.h new file mode 100644 index 000000000..d80814425 --- /dev/null +++ b/shared/update_check_settings_file.h @@ -0,0 +1,29 @@ +#pragma once +#include +#include +#include + +class UpdateCheckerSettingsFile { +public: + UpdateCheckerSettingsFile(); + ~UpdateCheckerSettingsFile(); + + bool getAutoCheckEnabled(); + bool setAutoCheckEnabled(bool enabled); + + Version getLastReportedVersion(); + bool setLastReportedVersion(Version version); + + bool canReadSettingsFile(); + bool canWriteSettingsFile(); + +private: + + juce::File settingsFile; + bool loadSettings(); + bool saveSettings(); + bool settingsFileExists(); + + bool settingAutoCheckEnabled{ false }; + Version settingLastReportedVersion; +}; diff --git a/tools/setup/CMakeLists.txt b/tools/setup/CMakeLists.txt index 6c8630c39..715f142ad 100644 --- a/tools/setup/CMakeLists.txt +++ b/tools/setup/CMakeLists.txt @@ -24,7 +24,7 @@ set(HEADERS_SETUP install_phases/component_complete.h helpers/manifests.h ${EPS_SHARED_DIR}/helper/resource_paths_juce-file.hpp - ${EPS_SHARED_DIR}/update_check.cpp + ${EPS_SHARED_DIR}/update_check_settings_file.h ) set(SOURCES_SETUP @@ -42,7 +42,7 @@ set(SOURCES_SETUP install_phases/component_complete.cpp helpers/manifests.cpp ${EPS_SHARED_DIR}/binary_data.cpp - ${EPS_SHARED_DIR}/update_check.h + ${EPS_SHARED_DIR}/update_check_settings_file.cpp ) source_group("Header Files" FILES ${HEADERS_SETUP}) @@ -83,6 +83,6 @@ add_custom_command(TARGET setup PRE_BUILD COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/helpers/gen_license_header.cmake ) -set_target_properties(setup PROPERTIES FOLDER tools) +set_target_properties(setup PROPERTIES FOLDER tools) target_link_libraries(setup PRIVATE Juce::core ear-version) target_include_directories(setup PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${EPS_SHARED_DIR}) diff --git a/tools/setup/install_phases/component_complete.cpp b/tools/setup/install_phases/component_complete.cpp index 6006d1f5c..962a96ac0 100644 --- a/tools/setup/install_phases/component_complete.cpp +++ b/tools/setup/install_phases/component_complete.cpp @@ -97,7 +97,7 @@ void ComponentComplete::configureForInstallPhase() AutoUpdateCheckButton::AutoUpdateCheckButton() { - bool success = updateChecker.canWriteSettingsFile(); + bool success = updateCheckerSettingsFile.canWriteSettingsFile(); text1.setFont(EarFontsSingleton::instance().Label); text1.setColour(Label::textColourId, EarColours::Label.withAlpha(Emphasis::high)); @@ -125,7 +125,7 @@ AutoUpdateCheckButton::~AutoUpdateCheckButton() void AutoUpdateCheckButton::paint(Graphics& g) { auto area = getLocalBounds(); - auto checked = updateChecker.getAutoCheckEnabled(); + auto checked = updateCheckerSettingsFile.getAutoCheckEnabled(); getLookAndFeel().drawTickBox(g, text1, 1, 1, area.getHeight() - 2, area.getHeight() - 2, checked, true, true, false); } @@ -147,11 +147,11 @@ int AutoUpdateCheckButton::getMinReqWidth(int forComponentHeight) void AutoUpdateCheckButton::setState(bool checked) { - updateChecker.setAutoCheckEnabled(checked); + updateCheckerSettingsFile.setAutoCheckEnabled(checked); repaint(); } void AutoUpdateCheckButton::mouseDown(const MouseEvent& event) { - setState(!updateChecker.getAutoCheckEnabled()); + setState(!updateCheckerSettingsFile.getAutoCheckEnabled()); } diff --git a/tools/setup/install_phases/component_complete.h b/tools/setup/install_phases/component_complete.h index b28d7baa9..cf01ef63f 100644 --- a/tools/setup/install_phases/component_complete.h +++ b/tools/setup/install_phases/component_complete.h @@ -2,7 +2,7 @@ #include "JuceHeader.h" #include -#include +#include class AutoUpdateCheckButton : public Component { @@ -25,7 +25,7 @@ class AutoUpdateCheckButton : public Component const int marginBoxText{ 10 }; - UpdateChecker updateChecker; + UpdateCheckerSettingsFile updateCheckerSettingsFile; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AutoUpdateCheckButton) }; From ba3bc28e5fc05f0c5565816945bf1dae20749906 Mon Sep 17 00:00:00 2001 From: Matt Firth Date: Mon, 11 Dec 2023 16:04:14 +0000 Subject: [PATCH 09/14] No need for explicit destructor --- shared/update_check_settings_file.cpp | 4 ---- shared/update_check_settings_file.h | 1 - 2 files changed, 5 deletions(-) diff --git a/shared/update_check_settings_file.cpp b/shared/update_check_settings_file.cpp index 5cd82bb64..11b79d1ce 100644 --- a/shared/update_check_settings_file.cpp +++ b/shared/update_check_settings_file.cpp @@ -16,10 +16,6 @@ UpdateCheckerSettingsFile::UpdateCheckerSettingsFile() loadSettings(); } -UpdateCheckerSettingsFile::~UpdateCheckerSettingsFile() -{ -} - bool UpdateCheckerSettingsFile::getAutoCheckEnabled() { return settingAutoCheckEnabled; diff --git a/shared/update_check_settings_file.h b/shared/update_check_settings_file.h index d80814425..2f21ba675 100644 --- a/shared/update_check_settings_file.h +++ b/shared/update_check_settings_file.h @@ -6,7 +6,6 @@ class UpdateCheckerSettingsFile { public: UpdateCheckerSettingsFile(); - ~UpdateCheckerSettingsFile(); bool getAutoCheckEnabled(); bool setAutoCheckEnabled(bool enabled); From 6a97ce7aff09b43749e976da1f3c2ca10bad9ac6 Mon Sep 17 00:00:00 2001 From: Matt Firth Date: Mon, 11 Dec 2023 16:04:34 +0000 Subject: [PATCH 10/14] ensureSettingsFileExists func for readability --- shared/update_check_settings_file.cpp | 11 ++++++++++- shared/update_check_settings_file.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/shared/update_check_settings_file.cpp b/shared/update_check_settings_file.cpp index 11b79d1ce..aac4d1737 100644 --- a/shared/update_check_settings_file.cpp +++ b/shared/update_check_settings_file.cpp @@ -7,7 +7,7 @@ UpdateCheckerSettingsFile::UpdateCheckerSettingsFile() settingsFile = ResourcePaths::getSettingsDirectory(true).getChildFile("UpdateCheck.settings"); if (!settingsFileExists()) { // No settings file - perhaps first run? - if (saveSettings() && settingsFileExists()) { + if (ensureSettingsFileExists()) { // Settings file is writable so probably was just first run. // Set autocheck on initially. setAutoCheckEnabled(true); @@ -97,3 +97,12 @@ bool UpdateCheckerSettingsFile::settingsFileExists() { return settingsFile.existsAsFile(); } + +bool UpdateCheckerSettingsFile::ensureSettingsFileExists() +{ + bool success = settingsFileExists(); + if (!success) { + success = saveSettings() && settingsFileExists(); + } + return success; +} diff --git a/shared/update_check_settings_file.h b/shared/update_check_settings_file.h index 2f21ba675..44c83ec77 100644 --- a/shared/update_check_settings_file.h +++ b/shared/update_check_settings_file.h @@ -22,6 +22,7 @@ class UpdateCheckerSettingsFile { bool loadSettings(); bool saveSettings(); bool settingsFileExists(); + bool ensureSettingsFileExists(); bool settingAutoCheckEnabled{ false }; Version settingLastReportedVersion; From d29a2aa6624393d1ec4a1d92a84e404de95dcfbb Mon Sep 17 00:00:00 2001 From: Matt Firth Date: Mon, 11 Dec 2023 16:06:56 +0000 Subject: [PATCH 11/14] rename canRead/WriteSettingsFile --- shared/update_check_settings_file.cpp | 4 ++-- shared/update_check_settings_file.h | 4 ++-- tools/setup/install_phases/component_complete.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/shared/update_check_settings_file.cpp b/shared/update_check_settings_file.cpp index aac4d1737..061296189 100644 --- a/shared/update_check_settings_file.cpp +++ b/shared/update_check_settings_file.cpp @@ -39,12 +39,12 @@ bool UpdateCheckerSettingsFile::setLastReportedVersion(Version version) } -bool UpdateCheckerSettingsFile::canReadSettingsFile() +bool UpdateCheckerSettingsFile::canRead() { return loadSettings(); } -bool UpdateCheckerSettingsFile::canWriteSettingsFile() +bool UpdateCheckerSettingsFile::canWrite() { return saveSettings(); } diff --git a/shared/update_check_settings_file.h b/shared/update_check_settings_file.h index 44c83ec77..374223e68 100644 --- a/shared/update_check_settings_file.h +++ b/shared/update_check_settings_file.h @@ -13,8 +13,8 @@ class UpdateCheckerSettingsFile { Version getLastReportedVersion(); bool setLastReportedVersion(Version version); - bool canReadSettingsFile(); - bool canWriteSettingsFile(); + bool canRead(); + bool canWrite(); private: diff --git a/tools/setup/install_phases/component_complete.cpp b/tools/setup/install_phases/component_complete.cpp index 962a96ac0..e30fd7c93 100644 --- a/tools/setup/install_phases/component_complete.cpp +++ b/tools/setup/install_phases/component_complete.cpp @@ -97,7 +97,7 @@ void ComponentComplete::configureForInstallPhase() AutoUpdateCheckButton::AutoUpdateCheckButton() { - bool success = updateCheckerSettingsFile.canWriteSettingsFile(); + bool success = updateCheckerSettingsFile.canWrite(); text1.setFont(EarFontsSingleton::instance().Label); text1.setColour(Label::textColourId, EarColours::Label.withAlpha(Emphasis::high)); From b3ba4c882ffe49f32839821f8d5712d33d9e957c Mon Sep 17 00:00:00 2001 From: Matt Firth Date: Mon, 11 Dec 2023 16:07:57 +0000 Subject: [PATCH 12/14] Make canRead/Write const --- shared/update_check_settings_file.cpp | 4 ++-- shared/update_check_settings_file.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shared/update_check_settings_file.cpp b/shared/update_check_settings_file.cpp index 061296189..ac0e2d8dc 100644 --- a/shared/update_check_settings_file.cpp +++ b/shared/update_check_settings_file.cpp @@ -39,12 +39,12 @@ bool UpdateCheckerSettingsFile::setLastReportedVersion(Version version) } -bool UpdateCheckerSettingsFile::canRead() +const bool UpdateCheckerSettingsFile::canRead() { return loadSettings(); } -bool UpdateCheckerSettingsFile::canWrite() +const bool UpdateCheckerSettingsFile::canWrite() { return saveSettings(); } diff --git a/shared/update_check_settings_file.h b/shared/update_check_settings_file.h index 374223e68..bd47aea62 100644 --- a/shared/update_check_settings_file.h +++ b/shared/update_check_settings_file.h @@ -13,8 +13,8 @@ class UpdateCheckerSettingsFile { Version getLastReportedVersion(); bool setLastReportedVersion(Version version); - bool canRead(); - bool canWrite(); + const bool canRead(); + const bool canWrite(); private: From 7cad1a22014ee923d3a95640ce9641231c1f5467 Mon Sep 17 00:00:00 2001 From: Matt Firth Date: Mon, 11 Dec 2023 16:34:22 +0000 Subject: [PATCH 13/14] Constness on getters and setters --- shared/update_check_settings_file.cpp | 8 ++++---- shared/update_check_settings_file.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/shared/update_check_settings_file.cpp b/shared/update_check_settings_file.cpp index ac0e2d8dc..bdc7dad0b 100644 --- a/shared/update_check_settings_file.cpp +++ b/shared/update_check_settings_file.cpp @@ -16,23 +16,23 @@ UpdateCheckerSettingsFile::UpdateCheckerSettingsFile() loadSettings(); } -bool UpdateCheckerSettingsFile::getAutoCheckEnabled() +const bool UpdateCheckerSettingsFile::getAutoCheckEnabled() { return settingAutoCheckEnabled; } -bool UpdateCheckerSettingsFile::setAutoCheckEnabled(bool enabled) +const bool UpdateCheckerSettingsFile::setAutoCheckEnabled(bool enabled) { settingAutoCheckEnabled = enabled; return saveSettings(); } -Version UpdateCheckerSettingsFile::getLastReportedVersion() +const Version UpdateCheckerSettingsFile::getLastReportedVersion() { return settingLastReportedVersion; } -bool UpdateCheckerSettingsFile::setLastReportedVersion(Version version) +const bool UpdateCheckerSettingsFile::setLastReportedVersion(const Version& version) { settingLastReportedVersion = version; return saveSettings(); diff --git a/shared/update_check_settings_file.h b/shared/update_check_settings_file.h index bd47aea62..fd945483b 100644 --- a/shared/update_check_settings_file.h +++ b/shared/update_check_settings_file.h @@ -7,11 +7,11 @@ class UpdateCheckerSettingsFile { public: UpdateCheckerSettingsFile(); - bool getAutoCheckEnabled(); - bool setAutoCheckEnabled(bool enabled); + const bool getAutoCheckEnabled(); + const bool setAutoCheckEnabled(bool enabled); - Version getLastReportedVersion(); - bool setLastReportedVersion(Version version); + const Version getLastReportedVersion(); + const bool setLastReportedVersion(const Version& version); const bool canRead(); const bool canWrite(); From b438b8aa9a2c65e17cb98a18238890a00ed84be0 Mon Sep 17 00:00:00 2001 From: Matt Firth Date: Tue, 12 Dec 2023 00:23:38 +0000 Subject: [PATCH 14/14] update_check needn't be shared Its function is specific to the extension --- reaper-adm-extension/src/reaper_adm/CMakeLists.txt | 12 ++++++------ .../src/reaper_adm}/update_check.cpp | 0 .../src/reaper_adm}/update_check.h | 0 3 files changed, 6 insertions(+), 6 deletions(-) rename {shared => reaper-adm-extension/src/reaper_adm}/update_check.cpp (100%) rename {shared => reaper-adm-extension/src/reaper_adm}/update_check.h (100%) diff --git a/reaper-adm-extension/src/reaper_adm/CMakeLists.txt b/reaper-adm-extension/src/reaper_adm/CMakeLists.txt index f49f362ed..23078fbb6 100644 --- a/reaper-adm-extension/src/reaper_adm/CMakeLists.txt +++ b/reaper-adm-extension/src/reaper_adm/CMakeLists.txt @@ -8,7 +8,6 @@ find_package(JUCE REQUIRED QUIET) set(EXTENSION_SOURCES ${EPS_SHARED_DIR}/helper/common_definition_helper.cpp - ${EPS_SHARED_DIR}/update_check.cpp ${EPS_SHARED_DIR}/update_check_settings_file.cpp actionmanager.cpp @@ -70,6 +69,7 @@ set(EXTENSION_SOURCES reaperguid.cpp reaperhost.cpp track.cpp + update_check.cpp coordinate_conversion/coord_conv.cpp progress/importdialog.cpp progress/importlistener.cpp @@ -85,7 +85,6 @@ set(EXTENSION_HEADERS ${EPS_SHARED_DIR}/helper/resource_paths.hpp ${EPS_SHARED_DIR}/helper/native_message_box.hpp ${EPS_SHARED_DIR}/daw_channel_count.h - ${EPS_SHARED_DIR}/update_check.h ${EPS_SHARED_DIR}/update_check_settings_file.h AppConfig.h @@ -155,6 +154,7 @@ set(EXTENSION_HEADERS reaper_plugin_functions.h resource.h track.h + update_check.h win_mem_debug.h coordinate_conversion/coord_conv.hpp progress/importdialog.h @@ -198,13 +198,13 @@ find_package(WDL REQUIRED QUIET) target_include_directories(reaper_adm_object PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} $ $ $ $ $ - ${EPS_SHARED_DIR} + ${EPS_SHARED_DIR} ) target_link_libraries(reaper_adm_dependencies @@ -216,9 +216,9 @@ target_link_libraries(reaper_adm_dependencies Boost::filesystem nng::nng ear-version - Juce::core + Juce::core ) - + add_dependencies(reaper_adm_dependencies reaper_adm_object) set_target_properties(reaper_adm diff --git a/shared/update_check.cpp b/reaper-adm-extension/src/reaper_adm/update_check.cpp similarity index 100% rename from shared/update_check.cpp rename to reaper-adm-extension/src/reaper_adm/update_check.cpp diff --git a/shared/update_check.h b/reaper-adm-extension/src/reaper_adm/update_check.h similarity index 100% rename from shared/update_check.h rename to reaper-adm-extension/src/reaper_adm/update_check.h