From bf2f3d57c7356a3f67958928bdc75f74dfaa9f81 Mon Sep 17 00:00:00 2001 From: Uyanide Date: Sun, 1 Mar 2026 05:08:58 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20defer=20preview=20command?= =?UTF-8?q?=20until=20states=20are=20captured?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WallReel/Core/CMakeLists.txt | 2 +- WallReel/Core/Config/data.hpp | 1 + WallReel/Core/Config/manager.cpp | 10 ++ WallReel/Core/Config/manager.hpp | 3 + WallReel/Core/Image/data.cpp | 1 + WallReel/Core/Image/data.hpp | 4 +- WallReel/Core/Provider/carousel.hpp | 12 +- WallReel/Core/Service/manager.cpp | 164 ++++++++++++++++++++++++++++ WallReel/Core/Service/manager.hpp | 100 +++-------------- WallReel/Core/Service/wallpaper.cpp | 96 +++------------- WallReel/Core/Service/wallpaper.hpp | 26 ++--- 11 files changed, 232 insertions(+), 187 deletions(-) create mode 100644 WallReel/Core/Service/manager.cpp diff --git a/WallReel/Core/CMakeLists.txt b/WallReel/Core/CMakeLists.txt index 4f307fb..3ccf0a0 100644 --- a/WallReel/Core/CMakeLists.txt +++ b/WallReel/Core/CMakeLists.txt @@ -15,7 +15,7 @@ qt_add_qml_module(${CORELIB_NAME} Config/data.hpp Config/manager.hpp Config/manager.cpp logger.hpp logger.cpp - Service/manager.hpp + Service/manager.hpp Service/manager.cpp Service/wallpaper.hpp Service/wallpaper.cpp appoptions.hpp appoptions.cpp ) diff --git a/WallReel/Core/Config/data.hpp b/WallReel/Core/Config/data.hpp index c44d683..08838a7 100644 --- a/WallReel/Core/Config/data.hpp +++ b/WallReel/Core/Config/data.hpp @@ -141,6 +141,7 @@ struct StyleConfigItems { struct CacheConfigItems { bool saveSortMethod = true; bool savePalette = true; + int maxImageEntries = 1000; static const QString defaultSortType; static const QString defaultSortDescending; diff --git a/WallReel/Core/Config/manager.cpp b/WallReel/Core/Config/manager.cpp index 33fb14a..5087643 100644 --- a/WallReel/Core/Config/manager.cpp +++ b/WallReel/Core/Config/manager.cpp @@ -28,6 +28,11 @@ Manager::Manager( const QString& configPath, QObject* parent) : QObject(parent), m_configDir(configDir) { + connect(this, &Manager::stateCaptured, this, [this]() { + m_stateCaptured = true; + WR_INFO("State capture completed"); + }); + // Load configPath if not empty, otherwise load from default location (configDir + s_DefaultConfigFileName) if (configPath.isEmpty()) { WR_INFO(QString("Configuration directory: %1").arg(m_configDir.absolutePath())); @@ -384,6 +389,11 @@ void Manager::_loadWallpapers() { } void Manager::captureState() { + if (m_stateCaptured) { + WR_DEBUG("State already captured, skipping capture"); + emit stateCaptured(); + } + if (m_pendingCaptures > 0) { WR_WARN("State capture already in progress, ignoring new capture request"); return; diff --git a/WallReel/Core/Config/manager.hpp b/WallReel/Core/Config/manager.hpp index df410c0..8bc7ad6 100644 --- a/WallReel/Core/Config/manager.hpp +++ b/WallReel/Core/Config/manager.hpp @@ -59,6 +59,8 @@ class Manager : public QObject { const CacheConfigItems& getCacheConfig() const { return m_cacheConfig; } + bool isStateCaptured() const { return m_stateCaptured; } + QSize getFocusImageSize() const { return QSize{m_styleConfig.imageWidth, m_styleConfig.imageHeight} * m_styleConfig.imageFocusScale; } @@ -95,6 +97,7 @@ class Manager : public QObject { QStringList m_wallpapers; int m_pendingCaptures = 0; + bool m_stateCaptured = false; // changed and accessed in main thread, no lock needed }; } // namespace WallReel::Core::Config diff --git a/WallReel/Core/Image/data.cpp b/WallReel/Core/Image/data.cpp index 75ae7ec..3600cd4 100644 --- a/WallReel/Core/Image/data.cpp +++ b/WallReel/Core/Image/data.cpp @@ -25,6 +25,7 @@ WallReel::Core::Image::Data::Data(const QString& path, const QSize& targetSize, m_id = cacheMgr.cacheKey(m_file, m_targetSize); m_cachedFile = cacheMgr.getImage(m_id, [this]() { return computeImage(); }); m_dominantColor = cacheMgr.getColor(m_id, [this]() { return computeDominantColor(loadImage()); }); + m_isValid = m_cachedFile.isFile() && m_dominantColor.isValid(); } QImage WallReel::Core::Image::Data::loadImage() const { diff --git a/WallReel/Core/Image/data.hpp b/WallReel/Core/Image/data.hpp index b1ab0f6..d45a3d2 100644 --- a/WallReel/Core/Image/data.hpp +++ b/WallReel/Core/Image/data.hpp @@ -54,6 +54,8 @@ class Data { QColor m_dominantColor; ///< Dominant color of the image, used for palette matching QHash m_colorCache; ///< Cache for palette color matching results, key is palette name, value is matched color name + bool m_isValid = false; + QImage computeImage() const; QColor computeDominantColor(const QImage& image) const; @@ -75,7 +77,7 @@ class Data { QUrl getUrl() const { return QUrl::fromLocalFile(m_cachedFile.absoluteFilePath()); } - bool isValid() const { return m_cachedFile.exists(); } + bool isValid() const { return m_isValid; } QString getFullPath() const { return m_file.absoluteFilePath(); } diff --git a/WallReel/Core/Provider/carousel.hpp b/WallReel/Core/Provider/carousel.hpp index 12c925c..47aff48 100644 --- a/WallReel/Core/Provider/carousel.hpp +++ b/WallReel/Core/Provider/carousel.hpp @@ -251,6 +251,12 @@ class Carousel : public QObject { } }); + // Defer preview until state captured + connect(m_configMgr, + &Config::Manager::stateCaptured, + m_serviceMgr, + &Service::Manager::onStateCaptured); + // Quit on selected if (m_configMgr->getActionConfig().quitOnSelected) { QObject::connect( @@ -286,12 +292,12 @@ class Carousel : public QObject { setSortDescending(m_cacheMgr->getSetting( Cache::SettingsType::LastSortDescending, []() { return Config::CacheConfigItems::defaultSortDescending; }) == "true"); - connect(this, &Carousel::sortTypeChanged, this, [this]() { + connect(app, &QApplication::aboutToQuit, this, [this]() { m_cacheMgr->storeSetting( Cache::SettingsType::LastSortType, Config::sortTypeToString(m_imageMgr->sortType())); }); - connect(this, &Carousel::sortDescendingChanged, this, [this]() { + connect(app, &QApplication::aboutToQuit, this, [this]() { m_cacheMgr->storeSetting( Cache::SettingsType::LastSortDescending, m_imageMgr->sortDescending() ? "true" : "false"); @@ -301,7 +307,7 @@ class Carousel : public QObject { requestSelectPalette(m_cacheMgr->getSetting( Cache::SettingsType::LastSelectedPalette, []() { return Config::CacheConfigItems::defaultSelectedPalette; })); - connect(this, &Carousel::selectedPaletteChanged, this, [this]() { + connect(app, &QApplication::aboutToQuit, this, [this]() { m_cacheMgr->storeSetting( Cache::SettingsType::LastSelectedPalette, m_paletteMgr->getSelectedPaletteName()); diff --git a/WallReel/Core/Service/manager.cpp b/WallReel/Core/Service/manager.cpp new file mode 100644 index 0000000..0da5c59 --- /dev/null +++ b/WallReel/Core/Service/manager.cpp @@ -0,0 +1,164 @@ +#include "manager.hpp" + +#include "Utils/texttemplate.hpp" +#include "logger.hpp" + +WALLREEL_DECLARE_SENDER("ServiceManager") + +namespace WallReel::Core::Service { + +Manager::Manager( + const Config::ActionConfigItems& actionConfig, + Image::Manager& imageManager, + Palette::Manager& paletteManager, + QObject* parent) : m_actionConfig(actionConfig), m_imageManager(imageManager), m_paletteManager(paletteManager) { + m_wallpaperService = new WallpaperService(m_actionConfig.previewDebounceTime, this); + + // Forward signals + // Direct signal 2 signal connection + connect(m_wallpaperService, &WallpaperService::previewCompleted, this, &Manager::previewCompleted); + // Signal 2 slot connection to handle processing state + connect(m_wallpaperService, &WallpaperService::selectCompleted, this, &Manager::_onSelectCompleted); + connect(m_wallpaperService, &WallpaperService::restoreCompleted, this, &Manager::_onRestoreCompleted); +} + +void Manager::onStateCaptured() { + m_stateCaptured = true; + + if (!m_pendingPreviewId.isEmpty()) { + WR_DEBUG("State captured, executing pending preview for id " + m_pendingPreviewId); + const QString pending = m_pendingPreviewId; + m_pendingPreviewId.clear(); + previewWallpaper(pending); + } +} + +void Manager::selectWallpaper(const QString& id) { + WR_DEBUG("Select action triggered for id " + id); + if (m_isProcessing) { + WR_DEBUG("Already processing an select action, ignoring new request"); + return; + } + m_isProcessing = true; + emit isProcessingChanged(); + const auto* data = m_imageManager.imageAt(id); + + if (!data || !data->isValid()) { + WR_WARN(QString("No valid image data at id %1. Skipping select action.").arg(id)); + m_isProcessing = false; + emit isProcessingChanged(); + emit selectCompleted(); + } + + const auto command = _renderCommand(m_actionConfig.onSelected, _generateVariables(*data)); + m_wallpaperService->select(command); +} + +void Manager::restore() { + WR_DEBUG("Restore action triggered"); + if (m_isProcessing) { + WR_DEBUG("Already processing an restore action, ignoring new request"); + return; + } + if (!m_stateCaptured) { + WR_DEBUG("State not captured yet, skipping restore action"); + emit restoreCompleted(); + return; + } + m_isProcessing = true; + emit isProcessingChanged(); + + m_wallpaperService->restore(_renderCommand(m_actionConfig.onRestore, m_actionConfig.savedState)); +} + +void Manager::cancel() { + WR_DEBUG("Cancel action triggered"); + m_wallpaperService->stopAll(); + emit cancelCompleted(); +} + +void Manager::previewWallpaper(const QString& id) { + if (!m_stateCaptured) { + WR_DEBUG("State not captured yet, deferring preview for id " + id); + m_pendingPreviewId = id; + emit previewCompleted(); + return; + } + + WR_DEBUG("Preview action triggered for id " + id); + + const auto* data = m_imageManager.imageAt(id); + + if (!data || !data->isValid()) { + WR_WARN(QString("No valid image data at id %1. Skipping preview action.").arg(id)); + emit previewCompleted(); + return; + } + + m_wallpaperService->preview(_renderCommand(m_actionConfig.onPreview, _generateVariables(*data))); +} + +void Manager::restoreOnQuit() { + if (m_hasSelected) { + Logger::debug("ServiceManager", "Quit with selected wallpaper, no need to restore"); + return; + } + Logger::debug("ServiceManager", "Restore on quit"); + m_wallpaperService->stopAll(); + QEventLoop loop; + connect(m_wallpaperService, &WallpaperService::restoreCompleted, &loop, &QEventLoop::quit); + // Call restore after the event loop starts + QTimer::singleShot(0, this, &Manager::restore); + loop.exec(); +} + +void Manager::_onSelectCompleted() { + Logger::debug("ServiceManager", "Select completed"); + _onProcessCompleted(); + m_hasSelected = true; + emit selectCompleted(); +} + +void Manager::_onRestoreCompleted() { + Logger::debug("ServiceManager", "Restore completed"); + _onProcessCompleted(); + emit restoreCompleted(); +} + +void Manager::_onProcessCompleted() { + m_isProcessing = false; + emit isProcessingChanged(); +} + +QString Manager::_renderCommand(const QString& templateStr, const QHash& variables) const { + return Utils::renderTemplate(templateStr, variables); +} + +QHash Manager::_generateVariables(const Image::Data& imageData) const { + auto palette = m_paletteManager.getSelectedPaletteName(); + if (palette.isEmpty()) { + palette = "null"; + } + auto color = m_paletteManager.getCurrentColorName(); + if (color.isEmpty()) { + color = "null"; + } + auto hex = m_paletteManager.getCurrentColorHex(); + if (hex.isEmpty()) { + hex = "null"; + } + QHash ret{ + {"path", imageData.getFullPath()}, + {"name", imageData.getFileName()}, + {"size", QString::number(imageData.getSize())}, + {"palette", palette}, + {"colorName", color}, + {"colorHex", hex}, + {"domColorHex", imageData.getDominantColor().name()}, + }; + + ret.insert(m_actionConfig.savedState); + return ret; +} + +} // namespace WallReel::Core::Service diff --git a/WallReel/Core/Service/manager.hpp b/WallReel/Core/Service/manager.hpp index 7ce1b7b..cfd25a3 100644 --- a/WallReel/Core/Service/manager.hpp +++ b/WallReel/Core/Service/manager.hpp @@ -8,7 +8,6 @@ #include "Image/manager.hpp" #include "Palette/manager.hpp" #include "Service/wallpaper.hpp" -#include "logger.hpp" namespace WallReel::Core::Service { @@ -22,16 +21,7 @@ class Manager : public QObject { const Config::ActionConfigItems& actionConfig, Image::Manager& imageManager, Palette::Manager& paletteManager, - QObject* parent = nullptr) : m_actionConfig(actionConfig), m_imageManager(imageManager), m_paletteManager(paletteManager) { - m_wallpaperService = new WallpaperService(m_actionConfig, m_paletteManager, this); - - // Forward signals - // Direct signal 2 signal connection - connect(m_wallpaperService, &WallpaperService::previewCompleted, this, &Manager::previewCompleted); - // Signal 2 slot connection to handle processing state - connect(m_wallpaperService, &WallpaperService::selectCompleted, this, &Manager::_onSelectCompleted); - connect(m_wallpaperService, &WallpaperService::restoreCompleted, this, &Manager::_onRestoreCompleted); - } + QObject* parent = nullptr); bool isProcessing() const { return m_isProcessing; } @@ -39,86 +29,25 @@ class Manager : public QObject { public slots: - void selectWallpaper(const QString& id) { - Logger::debug("ServiceManager", QString("Select wallpaper with id %1").arg(id)); - if (m_isProcessing) { - Logger::debug("ServiceManager", "Already processing an select action, ignoring new request"); - return; - } - m_isProcessing = true; - emit isProcessingChanged(); - const auto* data = m_imageManager.imageAt(id); - if (data) { - m_wallpaperService->select(*data); - } else { - Logger::warn("ServiceManager", QString("No image data at id %1. Skipping select action.").arg(id)); - m_isProcessing = false; - emit isProcessingChanged(); - emit selectCompleted(); - } - } + void onStateCaptured(); - void restore() { - Logger::debug("ServiceManager", "Restore states"); - if (m_isProcessing) { - Logger::debug("ServiceManager", "Already processing an restore action, ignoring new request"); - return; - } - m_isProcessing = true; - emit isProcessingChanged(); - m_wallpaperService->restore(); - } + void selectWallpaper(const QString& id); - void cancel() { - Logger::debug("ServiceManager", "Cancel action"); - m_wallpaperService->stopAll(); - emit cancelCompleted(); - } + void restore(); - void previewWallpaper(const QString& id) { - Logger::debug("ServiceManager", "Preview wallpaper"); - const auto* data = m_imageManager.imageAt(id); - if (data) { - m_wallpaperService->preview(*data); - } else { - Logger::warn("ServiceManager", "No image data at id " + id + ". Skipping preview action."); - emit previewCompleted(); - } - } + void cancel(); - void restoreOnQuit() { - if (m_hasSelected) { - Logger::debug("ServiceManager", "Quit with selected wallpaper, no need to restore"); - return; - } - Logger::debug("ServiceManager", "Restore on quit"); - m_wallpaperService->stopAll(); - QEventLoop loop; - connect(m_wallpaperService, &WallpaperService::restoreCompleted, &loop, &QEventLoop::quit); - // Call restore after the event loop starts - QTimer::singleShot(0, m_wallpaperService, &WallpaperService::restore); - loop.exec(); - } + void previewWallpaper(const QString& id); + + void restoreOnQuit(); private slots: - void _onSelectCompleted() { - Logger::debug("ServiceManager", "Select completed"); - _onProcessCompleted(); - m_hasSelected = true; - emit selectCompleted(); - } + void _onSelectCompleted(); - void _onRestoreCompleted() { - Logger::debug("ServiceManager", "Restore completed"); - _onProcessCompleted(); - emit restoreCompleted(); - } + void _onRestoreCompleted(); - void _onProcessCompleted() { - m_isProcessing = false; - emit isProcessingChanged(); - } + void _onProcessCompleted(); signals: void isProcessingChanged(); @@ -127,6 +56,10 @@ class Manager : public QObject { void restoreCompleted(); void cancelCompleted(); + private: + QString _renderCommand(const QString& templateStr, const QHash& variables) const; + QHash _generateVariables(const Image::Data& imageData) const; + private: WallpaperService* m_wallpaperService; const Config::ActionConfigItems& m_actionConfig; @@ -135,6 +68,9 @@ class Manager : public QObject { bool m_isProcessing = false; bool m_hasSelected = false; + + bool m_stateCaptured = false; + QString m_pendingPreviewId; }; } // namespace WallReel::Core::Service diff --git a/WallReel/Core/Service/wallpaper.cpp b/WallReel/Core/Service/wallpaper.cpp index cbe52b6..bf53fee 100644 --- a/WallReel/Core/Service/wallpaper.cpp +++ b/WallReel/Core/Service/wallpaper.cpp @@ -1,25 +1,20 @@ #include "Service/wallpaper.hpp" #include -#include -#include "Utils/texttemplate.hpp" #include "logger.hpp" WALLREEL_DECLARE_SENDER("WallpaperService") namespace WallReel::Core::Service { -WallpaperService::WallpaperService( - const Config::ActionConfigItems& actionConfig, - const Palette::Manager& paletteManager, - QObject* parent) - : QObject(parent), m_actionConfig(actionConfig), m_paletteManager(paletteManager) { +WallpaperService::WallpaperService(int previewDebounceTime, QObject* parent) + : QObject(parent) { m_previewDebounceTimer = new QTimer(this); m_previewDebounceTimer->setSingleShot(true); - m_previewDebounceTimer->setInterval(m_actionConfig.previewDebounceTime); + m_previewDebounceTimer->setInterval(previewDebounceTime); connect(m_previewDebounceTimer, &QTimer::timeout, this, [this]() { - _doPreview(*m_pendingImageData); + _doPreview(m_pendingPreviewCommand); }); m_previewProcess = new QProcess(this); @@ -67,71 +62,29 @@ void WallpaperService::stopAll() { m_previewDebounceTimer->stop(); } -void WallpaperService::preview(const Image::Data& imageData) { - m_pendingImageData = &imageData; +void WallpaperService::preview(const QString& command) { + m_pendingPreviewCommand = command; m_previewDebounceTimer->start(); } -void WallpaperService::select(const Image::Data& imageData) { +void WallpaperService::select(const QString& command) { if (m_selectProcess->state() != QProcess::NotRunning) { WR_WARN("Previous select command is still running. Ignoring new command."); return; } - WR_DEBUG(QString("Select wallpaper: %1").arg(imageData.getFullPath())); - _doSelect(imageData); + _doSelect(command); } -void WallpaperService::restore() { +void WallpaperService::restore(const QString& command) { if (m_restoreProcess->state() != QProcess::NotRunning) { WR_WARN("Previous restore command is still running. Ignoring new command."); return; } WR_DEBUG("Restore state"); - _doRestore(); + _doRestore(command); } -QHash WallpaperService::_generateVariables(const Image::Data& imageData) { - auto palette = m_paletteManager.getSelectedPaletteName(); - if (palette.isEmpty()) { - palette = "null"; - } - auto color = m_paletteManager.getCurrentColorName(); - if (color.isEmpty()) { - color = "null"; - } - auto hex = m_paletteManager.getCurrentColorHex(); - if (hex.isEmpty()) { - hex = "null"; - } - QHash ret{ - {"path", imageData.getFullPath()}, - {"name", imageData.getFileName()}, - {"size", QString::number(imageData.getSize())}, - {"palette", palette}, - {"colorName", color}, - {"colorHex", hex}, - {"domColorHex", imageData.getDominantColor().name()}, - }; - - ret.insert(m_actionConfig.savedState); - return ret; -} - -void WallpaperService::_doPreview(const Image::Data& imageData) { - QString path = imageData.getFullPath(); - - if (path.isEmpty()) { - WR_WARN("No valid image path for preview. Skipping preview action."); - emit previewCompleted(); - return; - } - - if (m_actionConfig.printPreview) { - std::cout << path.toStdString() << std::endl; - } - - const auto variables = _generateVariables(imageData); - auto command = Utils::renderTemplate(m_actionConfig.onPreview, variables); +void WallpaperService::_doPreview(const QString& command) { if (command.isEmpty()) { WR_DEBUG("No preview command configured. Skipping preview action."); emit previewCompleted(); @@ -146,21 +99,7 @@ void WallpaperService::_doPreview(const Image::Data& imageData) { m_previewProcess->start("sh", QStringList() << "-c" << command); } -void WallpaperService::_doSelect(const Image::Data& imageData) { - QString path = imageData.getFullPath(); - - if (path.isEmpty()) { - WR_WARN("No valid image path for select. Skipping select action."); - emit selectCompleted(); - return; - } - - if (m_actionConfig.printSelected) { - std::cout << path.toStdString() << std::endl; - } - - const auto variables = _generateVariables(imageData); - auto command = Utils::renderTemplate(m_actionConfig.onSelected, variables); +void WallpaperService::_doSelect(const QString& command) { if (command.isEmpty()) { WR_DEBUG("No select command configured. Skipping select action."); emit selectCompleted(); @@ -170,16 +109,9 @@ void WallpaperService::_doSelect(const Image::Data& imageData) { m_selectProcess->start("sh", QStringList() << "-c" << command); } -void WallpaperService::_doRestore() { - if (m_actionConfig.onRestore.isEmpty()) { - WR_DEBUG("No restore command configured. Skipping restore action."); - emit restoreCompleted(); - return; - } - - const QString command = Utils::renderTemplate(m_actionConfig.onRestore, m_actionConfig.savedState); +void WallpaperService::_doRestore(const QString& command) { if (command.isEmpty()) { - WR_DEBUG("Restore command is empty after rendering. Skipping restore action."); + WR_DEBUG("Restore command is empty. Skipping restore action."); emit restoreCompleted(); return; } diff --git a/WallReel/Core/Service/wallpaper.hpp b/WallReel/Core/Service/wallpaper.hpp index e368634..ebd0bbe 100644 --- a/WallReel/Core/Service/wallpaper.hpp +++ b/WallReel/Core/Service/wallpaper.hpp @@ -4,27 +4,20 @@ #include #include -#include "Config/data.hpp" -#include "Image/data.hpp" -#include "Palette/manager.hpp" - namespace WallReel::Core::Service { class WallpaperService : public QObject { Q_OBJECT public: - WallpaperService( - const Config::ActionConfigItems& actionConfig, - const Palette::Manager& paletteManager, - QObject* parent = nullptr); + WallpaperService(int previewDebounceTime, QObject* parent = nullptr); void stopAll(); public slots: - void preview(const Image::Data& imageData); // execute after 500ms of inactivity - void select(const Image::Data& imageData); // execute immediately, ignore if already running - void restore(); // execute immediately, ignore if already running + void preview(const QString& command); // execute after 500ms of inactivity + void select(const QString& command); // execute immediately, ignore if already running + void restore(const QString& command); // execute immediately, ignore if already running signals: void previewCompleted(); @@ -32,15 +25,12 @@ class WallpaperService : public QObject { void restoreCompleted(); private: - void _doPreview(const Image::Data& imageData); - void _doSelect(const Image::Data& imageData); - void _doRestore(); - QHash _generateVariables(const Image::Data& imageData); + void _doPreview(const QString& command); + void _doSelect(const QString& command); + void _doRestore(const QString& command); - const Config::ActionConfigItems& m_actionConfig; - const Palette::Manager& m_paletteManager; QTimer* m_previewDebounceTimer; - const Image::Data* m_pendingImageData; + QString m_pendingPreviewCommand; QProcess* m_previewProcess; QProcess* m_selectProcess; QProcess* m_restoreProcess;