diff --git a/CMakeLists.txt b/CMakeLists.txt index ca08990e..6ca820ba 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,14 @@ set(CMAKE_BUILD_RPATH ${CMAKE_INSTALL_RPATH}) if (${CMAKE_BUILD_TYPE} STREQUAL "Debug") add_compile_definitions(BLOOM_DEBUG_BUILD) + # BLOOM_COMPILED_RESOURCES_PATH_OVERRIDE can be used to override the file path used for compiled resources. + # We override this path in debug builds to avoid using compiled resources. This makes debugging and small tweaks + # a lot easier, as it removes the need to recompile for each tweak. + # CAUTION: Although convenient, this does add a limitation; the debug build can only be run on the same machine + # that compiled it. Or a machine that has the Bloom source located in the same place. + # See Paths::compiledResourcesPath() for more. + add_compile_definitions(BLOOM_COMPILED_RESOURCES_PATH_OVERRIDE="${CMAKE_CURRENT_SOURCE_DIR}") + # CMAKE_SKIP_BUILD_RPATH needs to be set to true to use Gammaray during development. # This is because the distributed Qt binaries may not be compatible with the local installation of Gammaray set(CMAKE_SKIP_BUILD_RPATH true) diff --git a/src/Application.cpp b/src/Application.cpp index 14677e5c..82653344 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -9,6 +9,7 @@ #include "Application.hpp" #include "src/Logger/Logger.hpp" +#include "src/Helpers/Paths.hpp" #include "SignalHandler/SignalHandler.hpp" #include "Exceptions/InvalidConfig.hpp" @@ -149,7 +150,11 @@ int Application::presentHelpText() { Logger::silence(); // The file help.txt is included in the binary image as a resource. See src/resource.qrc - auto helpFile = QFile(":/compiled/resources/help.txt"); + auto helpFile = QFile(QString::fromStdString( + Paths::compiledResourcesPath() + + "/resources/help.txt" + ) + ); if (!helpFile.open(QIODevice::ReadOnly)) { // This should never happen - if it does, something has gone very wrong @@ -188,7 +193,11 @@ int Application::initProject() { * * We simply copy the template file into the user's working directory. */ - auto templateConfigFile = QFile(":/compiled/resources/bloom.template.json"); + auto templateConfigFile = QFile(QString::fromStdString( + Paths::compiledResourcesPath() + + "/resources/bloom.template.json" + ) + ); if (!templateConfigFile.open(QIODevice::ReadOnly)) { throw Exception("Failed to open template configuration file - please report this issue at https://bloom.oscillate.io/report-issue"); @@ -333,20 +342,6 @@ void Application::onDebugServerThreadStateChanged(EventPointer(); - - if (readlink("/proc/self/exe", pathCharArray.data(), PATH_MAX) < 0) { - throw Exception("Failed to obtain application directory path."); - } - - return std::filesystem::path(std::string(pathCharArray.begin(), pathCharArray.end())).parent_path(); -} - -std::string Application::getResourcesDirPath() { - return Application::getApplicationDirPath() + "/../resources/"; -} - bool Application::isRunningAsRoot() { return geteuid() == 0; } diff --git a/src/Application.hpp b/src/Application.hpp index 61bcaf72..a0da893a 100644 --- a/src/Application.hpp +++ b/src/Application.hpp @@ -248,20 +248,6 @@ namespace Bloom */ void onShutdownApplicationRequest(Events::EventPointer); - /** - * Returns the path to the directory in which the Bloom binary resides. - * - * @return - */ - static std::string getApplicationDirPath(); - - /** - * Returns the path to the Resources directory, located in the application directory. - * - * @return - */ - static std::string getResourcesDirPath(); - /** * Checks if the current effective user running Bloom has root privileges. * diff --git a/src/Helpers/Paths.cpp b/src/Helpers/Paths.cpp new file mode 100644 index 00000000..3ff70885 --- /dev/null +++ b/src/Helpers/Paths.cpp @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include + +#include "Paths.hpp" + +using namespace Bloom; + +std::string Paths::applicationDirPath() { + auto pathCharArray = std::array(); + + if (readlink("/proc/self/exe", pathCharArray.data(), PATH_MAX) < 0) { + throw Exceptions::Exception("Failed to obtain application directory path."); + } + + return std::filesystem::path(std::string(pathCharArray.begin(), pathCharArray.end())).parent_path(); +} diff --git a/src/Helpers/Paths.hpp b/src/Helpers/Paths.hpp new file mode 100644 index 00000000..6e6f9ce0 --- /dev/null +++ b/src/Helpers/Paths.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +namespace Bloom +{ + class Paths + { + public: + /** + * Returns the path to the directory in which the Bloom binary resides. + * + * @return + */ + static std::string applicationDirPath(); + + /** + * Returns the path to the Resources directory, located in the application directory. + * + * @return + */ + static inline std::string resourcesDirPath() { + return Paths::applicationDirPath() + "/../resources/"; + } + + /** + * Returns the path to Bloom's compiled resources. + * + * If the debug configuration is enabled, this function will return the absolute path to Bloom's source code, + * meaning we won't use compiled resources for debug builds. This is useful for debugging and tweaking QT UI + * files such as QT stylesheets and UI templates. + * @return + */ + static inline const std::string compiledResourcesPath() { +#ifdef BLOOM_COMPILED_RESOURCES_PATH_OVERRIDE + return std::string(BLOOM_COMPILED_RESOURCES_PATH_OVERRIDE); +#else + return std::string(":/compiled"); +#endif + } + + }; +} diff --git a/src/Insight/Insight.cpp b/src/Insight/Insight.cpp index 6657de01..8b0c8652 100644 --- a/src/Insight/Insight.cpp +++ b/src/Insight/Insight.cpp @@ -3,7 +3,7 @@ #include "Insight.hpp" #include "InsightWorker.hpp" -#include "src/Application.hpp" +#include "src/Helpers/Paths.hpp" #include "src/Logger/Logger.hpp" #include "src/Exceptions/InvalidConfig.hpp" #include "src/Targets/TargetState.hpp" @@ -49,7 +49,7 @@ void Insight::startup() { auto targetDescriptor = this->targetControllerConsole.getTargetDescriptor(); #ifndef BLOOM_DEBUG_BUILD - QCoreApplication::addLibraryPath(QString::fromStdString(Application::getApplicationDirPath() + "/plugins")); + QCoreApplication::addLibraryPath(QString::fromStdString(Paths::applicationDirPath() + "/plugins")); #endif QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true); diff --git a/src/Insight/UserInterfaces/InsightWindow/AboutWindow.cpp b/src/Insight/UserInterfaces/InsightWindow/AboutWindow.cpp index 4983764c..f10ca686 100644 --- a/src/Insight/UserInterfaces/InsightWindow/AboutWindow.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/AboutWindow.cpp @@ -5,14 +5,23 @@ #include "src/Logger/Logger.hpp" #include "src/Exceptions/Exception.hpp" #include "src/Application.hpp" +#include "src/Helpers/Paths.hpp" using namespace Bloom; using namespace InsightTargetWidgets; using namespace Exceptions; AboutWindow::AboutWindow(QWidget* parent): QObject(parent) { - auto aboutWindowUiFile = QFile(":/compiled/Insight/UserInterfaces/InsightWindow/UiFiles/AboutWindow.ui"); - auto aboutWindowStylesheet = QFile(":/compiled/Insight/UserInterfaces/InsightWindow/Stylesheets/AboutWindow.qss"); + auto aboutWindowUiFile = QFile(QString::fromStdString( + Paths::compiledResourcesPath() + + "/src/Insight/UserInterfaces/InsightWindow/UiFiles/AboutWindow.ui" + ) + ); + auto aboutWindowStylesheet = QFile(QString::fromStdString( + Paths::compiledResourcesPath() + + "/src/Insight/UserInterfaces/InsightWindow/Stylesheets/AboutWindow.qss" + ) + ); if (!aboutWindowUiFile.open(QFile::ReadOnly)) { throw Exception("Failed to open AboutWindow UI file"); diff --git a/src/Insight/UserInterfaces/InsightWindow/InsightWindow.cpp b/src/Insight/UserInterfaces/InsightWindow/InsightWindow.cpp index 32fc59bd..afafc7cf 100644 --- a/src/Insight/UserInterfaces/InsightWindow/InsightWindow.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/InsightWindow.cpp @@ -8,6 +8,7 @@ #include "src/Logger/Logger.hpp" #include "src/Exceptions/Exception.hpp" #include "src/Targets/TargetDescriptor.hpp" +#include "src/Helpers/Paths.hpp" using namespace Bloom; using namespace Bloom::Exceptions; @@ -25,8 +26,16 @@ void InsightWindow::init( ) { this->targetDescriptor = targetDescriptor; - auto mainWindowUiFile = QFile(":/compiled/Insight/UserInterfaces/InsightWindow/UiFiles/InsightWindow.ui"); - auto mainWindowStylesheet = QFile(":/compiled/Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss"); + auto mainWindowUiFile = QFile( + QString::fromStdString(Paths::compiledResourcesPath() + + "/src/Insight/UserInterfaces/InsightWindow/UiFiles/InsightWindow.ui" + ) + ); + auto mainWindowStylesheet = QFile( + QString::fromStdString(Paths::compiledResourcesPath() + + "/src/Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss" + ) + ); if (!mainWindowUiFile.open(QFile::ReadOnly)) { throw Exception("Failed to open InsightWindow UI file"); @@ -40,7 +49,11 @@ void InsightWindow::init( this->mainWindowWidget = uiLoader.load(&mainWindowUiFile); this->mainWindowWidget->setStyleSheet(mainWindowStylesheet.readAll()); - application.setWindowIcon(QIcon(":/compiled/Insight/UserInterfaces/InsightWindow/Images/BloomIcon.svg")); + application.setWindowIcon(QIcon( + QString::fromStdString(Paths::compiledResourcesPath() + + "/src/Insight/UserInterfaces/InsightWindow/Images/BloomIcon.svg" + ) + )); this->ioContainerWidget = this->mainWindowWidget->findChild("io-container"); this->ioUnavailableWidget = this->mainWindowWidget->findChild("io-inspection-unavailable"); this->mainMenuBar = this->mainWindowWidget->findChild("menu-bar"); diff --git a/src/Insight/UserInterfaces/InsightWindow/Stylesheets/AboutWindow.qss b/src/Insight/UserInterfaces/InsightWindow/Stylesheets/AboutWindow.qss index 784ce2ca..96f2455d 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Stylesheets/AboutWindow.qss +++ b/src/Insight/UserInterfaces/InsightWindow/Stylesheets/AboutWindow.qss @@ -13,7 +13,7 @@ QMainWindow { min-width: 150px; max-height: 150px; max-width: 150px; - image: url(":/compiled/Insight/UserInterfaces/InsightWindow/Images/BloomIcon.svg"); + image: url(":/compiled/src/Insight/UserInterfaces/InsightWindow/Images/BloomIcon.svg"); image-position: center; } @@ -21,4 +21,4 @@ QMainWindow { font-size: 14px; color: #adadb1; -} \ No newline at end of file +} diff --git a/src/Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss b/src/Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss index d9579076..d932c069 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss +++ b/src/Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss @@ -88,7 +88,7 @@ QMenu#help-menu::separator { height: 25px; color: #000; border: none; - qproperty-icon: url(":/compiled/Insight/UserInterfaces/InsightWindow/Images/RAM.svg"); + qproperty-icon: url(":/compiled/src/Insight/UserInterfaces/InsightWindow/Images/RAM.svg"); icon-size: 25px; } diff --git a/src/Insight/UserInterfaces/InsightWindow/TargetWidgets/DIP/DualInlinePackageWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/TargetWidgets/DIP/DualInlinePackageWidget.cpp index fa61f098..d31cdd25 100644 --- a/src/Insight/UserInterfaces/InsightWindow/TargetWidgets/DIP/DualInlinePackageWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/TargetWidgets/DIP/DualInlinePackageWidget.cpp @@ -9,6 +9,7 @@ #include "DualInlinePackageWidget.hpp" #include "src/Logger/Logger.hpp" #include "src/Exceptions/Exception.hpp" +#include "src/Helpers/Paths.hpp" #include "PinWidget.hpp" #include "BodyWidget.hpp" @@ -22,7 +23,11 @@ DualInlinePackageWidget::DualInlinePackageWidget( QObject* insightWindowObj, QWidget* parent ): TargetPackageWidget(targetVariant, insightWindowObj, parent) { - auto stylesheetFile = QFile(":/compiled/Insight/UserInterfaces/InsightWindow/TargetWidgets/DIP/Stylesheets/DualInlinePackage.qss"); + auto stylesheetFile = QFile(QString::fromStdString( + Paths::compiledResourcesPath() + + "/src/Insight/UserInterfaces/InsightWindow/TargetWidgets/DIP/Stylesheets/DualInlinePackage.qss" + ) + ); stylesheetFile.open(QFile::ReadOnly); this->setStyleSheet(stylesheetFile.readAll()); @@ -121,4 +126,3 @@ void DualInlinePackageWidget::drawWidget(QPainter& painter) { height ); } - diff --git a/src/Insight/UserInterfaces/InsightWindow/TargetWidgets/QFP/QuadFlatPackageWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/TargetWidgets/QFP/QuadFlatPackageWidget.cpp index 8755f6f4..73a9c8f9 100644 --- a/src/Insight/UserInterfaces/InsightWindow/TargetWidgets/QFP/QuadFlatPackageWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/TargetWidgets/QFP/QuadFlatPackageWidget.cpp @@ -7,6 +7,7 @@ #include "../../InsightWindow.hpp" #include "QuadFlatPackageWidget.hpp" +#include "src/Helpers/Paths.hpp" #include "PinWidget.hpp" #include "BodyWidget.hpp" @@ -20,7 +21,11 @@ QuadFlatPackageWidget::QuadFlatPackageWidget( ): TargetPackageWidget(targetVariant, insightWindowObj, parent) { assert((targetVariant.pinDescriptorsByNumber.size() % 4) == 0); - auto stylesheetFile = QFile(":/compiled/Insight/UserInterfaces/InsightWindow/TargetWidgets/QFP/Stylesheets/QuadFlatPackage.qss"); + auto stylesheetFile = QFile(QString::fromStdString( + Paths::compiledResourcesPath() + + "/src/Insight/UserInterfaces/InsightWindow/TargetWidgets//QFP/Stylesheets/QuadFlatPackage.qss" + ) + ); stylesheetFile.open(QFile::ReadOnly); this->setStyleSheet(stylesheetFile.readAll()); diff --git a/src/Insight/UserInterfaces/InsightWindow/UiFiles/InsightWindow.ui b/src/Insight/UserInterfaces/InsightWindow/UiFiles/InsightWindow.ui index d77af5d8..317bd9ef 100644 --- a/src/Insight/UserInterfaces/InsightWindow/UiFiles/InsightWindow.ui +++ b/src/Insight/UserInterfaces/InsightWindow/UiFiles/InsightWindow.ui @@ -62,8 +62,8 @@ - :/compiled/Insight/UserInterfaces/InsightWindow/Images/refresh-disabled.svg - :/compiled/Insight/UserInterfaces/InsightWindow/Images/refresh.svg + :/compiled/src/Insight/UserInterfaces/InsightWindow/Images/refresh-disabled.svg + :/compiled/src/Insight/UserInterfaces/InsightWindow/Images/refresh.svg diff --git a/src/TargetController/TargetController.cpp b/src/TargetController/TargetController.cpp index 9aa634db..8349e792 100644 --- a/src/TargetController/TargetController.cpp +++ b/src/TargetController/TargetController.cpp @@ -7,6 +7,7 @@ #include "src/Exceptions/TargetControllerStartupFailure.hpp" #include "src/Exceptions/DeviceCommunicationFailure.hpp" #include "src/Application.hpp" +#include "src/Helpers/Paths.hpp" using namespace Bloom; using namespace Bloom::Targets; @@ -87,7 +88,7 @@ void TargetController::startup() { void TargetController::checkUdevRules() { auto bloomRulesPath = std::string("/etc/udev/rules.d/99-bloom.rules"); - auto latestBloomRulesPath = Application::getResourcesDirPath() + "/UDevRules/99-bloom.rules"; + auto latestBloomRulesPath = Paths::resourcesDirPath() + "/UDevRules/99-bloom.rules"; if (!std::filesystem::exists(bloomRulesPath)) { Logger::warning("Bloom udev rules missing - attempting installation"); diff --git a/src/Targets/Microchip/AVR/AVR8/PartDescription/PartDescriptionFile.cpp b/src/Targets/Microchip/AVR/AVR8/PartDescription/PartDescriptionFile.cpp index 14fbdb5c..c538c1b3 100644 --- a/src/Targets/Microchip/AVR/AVR8/PartDescription/PartDescriptionFile.cpp +++ b/src/Targets/Microchip/AVR/AVR8/PartDescription/PartDescriptionFile.cpp @@ -1,7 +1,10 @@ +#include +#include + #include "PartDescriptionFile.hpp" #include "src/Targets/Microchip/AVR/Exceptions/PartDescriptionParsingFailureException.hpp" #include "src/Logger/Logger.hpp" -#include "src/Application.hpp" +#include "src/Helpers/Paths.hpp" using namespace Bloom::Targets::Microchip::Avr::Avr8Bit::PartDescription; using namespace Bloom::Targets::Microchip::Avr::Avr8Bit; @@ -35,7 +38,7 @@ PartDescriptionFile::PartDescriptionFile(const std::string& targetSignatureHex, if (matchingDescriptionFiles.size() == 1) { // Attempt to load the XML part description file - auto descriptionFilePath = QString::fromStdString(Application::getApplicationDirPath()) + "/" + auto descriptionFilePath = QString::fromStdString(Paths::applicationDirPath()) + "/" + matchingDescriptionFiles.front().toObject().find("targetDescriptionFilePath")->toString(); Logger::debug("Loading AVR8 part description file: " + descriptionFilePath.toStdString()); @@ -102,7 +105,7 @@ void PartDescriptionFile::init(const QDomDocument& xml) { QJsonObject PartDescriptionFile::getPartDescriptionMapping() { auto mappingFile = QFile( - QString::fromStdString(Application::getResourcesDirPath() + "/TargetPartDescriptions/AVR/Mapping.json") + QString::fromStdString(Paths::resourcesDirPath() + "/TargetPartDescriptions/AVR/Mapping.json") ); if (!mappingFile.exists()) { diff --git a/src/resources.qrc b/src/resources.qrc index b2ba1e0a..fe150c9d 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -1,6 +1,15 @@ + + ../resources/help.txt @@ -8,19 +17,19 @@ ../resources/bloom.template.json - ./Insight/UserInterfaces/InsightWindow/UiFiles/InsightWindow.ui - ./Insight/UserInterfaces/InsightWindow/UiFiles/AboutWindow.ui + ./Insight/UserInterfaces/InsightWindow/UiFiles/InsightWindow.ui + ./Insight/UserInterfaces/InsightWindow/UiFiles/AboutWindow.ui - ./Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss - ./Insight/UserInterfaces/InsightWindow/Stylesheets/AboutWindow.qss - ./Insight/UserInterfaces/InsightWindow/TargetWidgets/DIP/Stylesheets/DualInlinePackage.qss - ./Insight/UserInterfaces/InsightWindow/TargetWidgets/QFP/Stylesheets/QuadFlatPackage.qss + ./Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss + ./Insight/UserInterfaces/InsightWindow/Stylesheets/AboutWindow.qss + ./Insight/UserInterfaces/InsightWindow/TargetWidgets/DIP/Stylesheets/DualInlinePackage.qss + ./Insight/UserInterfaces/InsightWindow/TargetWidgets/QFP/Stylesheets/QuadFlatPackage.qss - ./Insight/UserInterfaces/InsightWindow/Images/BloomIcon.svg - ./Insight/UserInterfaces/InsightWindow/Images/RAM.svg - ./Insight/UserInterfaces/InsightWindow/Images/refresh.svg - ./Insight/UserInterfaces/InsightWindow/Images/refresh-disabled.svg + ./Insight/UserInterfaces/InsightWindow/Images/BloomIcon.svg + ./Insight/UserInterfaces/InsightWindow/Images/RAM.svg + ./Insight/UserInterfaces/InsightWindow/Images/refresh.svg + ./Insight/UserInterfaces/InsightWindow/Images/refresh-disabled.svg - \ No newline at end of file +