19#include <spdlog/spdlog.h>
26 spdlog::debug(
"[ImageControllerBase::ImageControllerBase]: Constructing ImageControllerBase");
28 m_operation_state_manager = std::make_unique<Managers::OperationStateManager>();
29 spdlog::info(
"[ImageControllerBase::ImageControllerBase]: Initialized OperationStateManager");
31 m_operation_model_manager = std::make_unique<Models::Manager::OperationModelManager>();
32 spdlog::info(
"[ImageControllerBase::ImageControllerBase]: Initialized OperationModelManager");
36 spdlog::critical(
"[ImageControllerBase::ImageControllerBase]: Failed to create basic adjustment models.");
37 throw std::runtime_error(
"[ImageControllerBase::ImageControllerBase]: Critical failure during model creation.");
41 spdlog::info(
"[ImageControllerBase::ImageControllerBase]: Initialized DisplayManager");
43 m_engine = std::make_shared<Core::Engine::PhotoEngine>();
44 spdlog::info(
"[ImageControllerBase::ImageControllerBase]: Initialized PhotoEngine");
47 spdlog::debug(
"[ImageControllerBase::ImageControllerBase]: Completed construction");
52 spdlog::debug(
"[ImageControllerBase::~ImageControllerBase]: Destroying ImageControllerBase");
53 m_worker_thread.quit();
54 m_worker_thread.wait();
55 spdlog::debug(
"[ImageControllerBase::~ImageControllerBase]: Worker thread stopped and destroyed");
61 spdlog::warn(
"[ImageControllerBase::registerModel]: Attempting to register nullptr");
65 if (std::find(m_registered_models.begin(), m_registered_models.end(), model) != m_registered_models.end()) {
66 spdlog::debug(
"[ImageControllerBase::registerModel]: Model already registered");
70 m_registered_models.push_back(model);
71 spdlog::debug(
"[ImageControllerBase::registerModel]: Model registered. Total models: {}", m_registered_models.size());
76 if (file_path.isEmpty()) {
77 spdlog::warn(
"[ImageControllerBase::loadImage]: Empty file path provided");
82 spdlog::info(
"[ImageControllerBase::loadImage]: Calling method-thread doLoadImage() Loading {}", file_path.toStdString());
85 QMetaObject::invokeMethod(
this, [
this, file_path]() {
87 }, Qt::QueuedConnection);
92 if (file_url.isEmpty()) {
93 spdlog::warn(
"[ImageControllerBase::loadImageFromUrl]: Empty file URL received");
98 QString native_path = file_url.toLocalFile();
100 if (native_path.isEmpty()) {
101 spdlog::warn(
"[ImageControllerBase::loadImageFromUrl]: Failed to convert URL to local file path: {}", file_url.toString().toStdString());
103 if (!file_url.isLocalFile()) {
104 spdlog::warn(
"[ImageControllerBase::loadImageFromUrl]: Selected URL is not a local file: {}", file_url.toString().toStdString());
108 spdlog::warn(
"[ImageControllerBase::loadImageFromUrl]: Failed to convert URL to local file path: {}", file_url.toString().toStdString());
114 spdlog::info(
"[ImageControllerBase::loadImageFromUrl]: Converted URL to native path: {}", native_path.toStdString());
123 spdlog::warn(
"[ImageControllerBase::applyOperations]: Engine not available");
128 if (operations.empty())
130 spdlog::warn(
"[ImageControllerBase::applyOperations]: Empty operation list provided");
135 spdlog::info(
"[ImageControllerBase::applyOperations]: Applying {} operation(s)", operations.size());
137 if (m_operation_state_manager)
139 QMetaObject::invokeMethod(
this, [
this, ops = std::move(operations)]()
mutable {
141 }, Qt::QueuedConnection);
143 spdlog::error(
"[ImageControllerBase::applyOperations]: OperationStateManager is null during legacy applyOperations call!");
144 emit
operationFailed(
"Internal error: OperationStateManager not initialized");
150 spdlog::info(
"[ImageControllerBase::doLoadImage]: Starting load on worker thread");
153 auto load_result =
m_engine->loadImage(file_path.toStdString());
156 spdlog::error(
"[ImageControllerBase::doLoadImage]: Load failed for {}", file_path.toStdString());
157 auto err = load_result.error();
158 QString error_msg = QString::fromStdString(
182 if (downsample_size.isEmpty()) {
183 spdlog::error(
"[ImageControllerBase::doLoadImage]: Invalid downsample size");
189 spdlog::debug(
"[ImageControllerBase::doLoadImage]: Requesting downsampled image {}x{}",
190 downsample_size.width(), downsample_size.height());
192 auto display_image_result =
m_engine->getDownsampledDisplayImage(
197 if (!display_image_result) {
198 spdlog::error(
"[ImageControllerBase::doLoadImage]: Failed to get downsampled image: {}",
204 spdlog::debug(
"[ImageControllerBase::doLoadImage]: Got downsampled image successfully");
209 spdlog::info(
"[ImageControllerBase::doLoadImage]: DisplayManager updated");
211 spdlog::error(
"[ImageControllerBase::doLoadImage]: No DisplayManager available!");
219 spdlog::debug(
"[ImageControllerBase::doApplyOperations]: Starting operation processing with {} operations", operations.size());
222 spdlog::error(
"[ImageControllerBase::doApplyOperations]: No engine available");
230 spdlog::debug(
"[ImageControllerBase::doApplyOperations]: Applying operations via PhotoEngine");
231 auto apply_future =
m_engine->applyOperations(std::move(operations));
232 if (!apply_future.valid()) {
236 bool apply_ok = apply_future.get();
245 if (downsample_size.isEmpty()) {
246 spdlog::error(
"[ImageControllerBase::doApplyOperations]: Invalid downsample size");
252 spdlog::debug(
"[ImageControllerBase::doApplyOperations]: Requesting downsampled image {}x{}",
253 downsample_size.width(), downsample_size.height());
255 auto display_image_result =
m_engine->getDownsampledDisplayImage(
260 if (!display_image_result) {
261 spdlog::error(
"[ImageControllerBase::doApplyOperations]: Failed to get downsampled display image: {}",
267 spdlog::debug(
"[ImageControllerBase::doApplyOperations]: Got downsampled image successfully");
272 spdlog::info(
"[ImageControllerBase::doApplyOperations]: Display updated");
274 spdlog::warn(
"[ImageControllerBase::doApplyOperations]: No DisplayManager");
282 spdlog::debug(
"[ImageControllerBase::onImageLoadResult]: success={}", success);
285 spdlog::info(
"[ImageControllerBase::onImageLoadResult]: Image loaded successfully ({}x{})",
290 spdlog::error(
"[ImageControllerBase::onImageLoadResult]: Image load failed - {}", error_msg.toStdString());
297 spdlog::debug(
"[ImageControllerBase::onOperationResult]: success={}", success);
300 spdlog::info(
"[ImageControllerBase::onOperationResult]: Operation completed successfully");
303 spdlog::error(
"[ImageControllerBase::onOperationResult]: Operation failed - {}", error_msg.toStdString());
310 spdlog::debug(
"[ImageControllerBase::connectModelsToStateManager]: Starting model connections");
312 if (!m_operation_model_manager || !m_operation_state_manager) {
313 spdlog::critical(
"[ImageControllerBase::connectModelsToStateManager]: ModelManager or StateManager is null. Cannot proceed.");
314 throw std::runtime_error(
"ImageControllerBase: Critical failure during model-to-state-manager connection setup.");
319 for (
const auto& model : models) {
324 [
this, model ](
float new_value) {
325 spdlog::debug(
"[ImageControllerBase::connectModelsToStateManager]: Value changed signal received for model {}", model->name().toStdString());
330 if (m_operation_state_manager) {
331 auto descriptor = model->getDescriptor();
332 m_operation_state_manager->addOrUpdateOperation(descriptor);
333 spdlog::debug(
"[ImageControllerBase::connectModelsToStateManager]: Operation '{}' updated in StateManager via valueChanged signal.", descriptor.name);
335 spdlog::warn(
"[ImageControllerBase::connectModelsToStateManager]: Received valueChanged signal, but StateManager is null.");
347 spdlog::debug(
"[ImageControllerBase::connectModelsToStateManager]: Connected model {}", model->name().toStdString());
350 spdlog::info(
"[ImageControllerBase::connectModelsToStateManager]: All {} BaseAdjustment models connected to StateManager via valueChanged signal.", models.size());
Generic Qt base class for single-value adjustment operations (e.g., Brightness, Contrast,...
std::unique_ptr< CaptureMoment::UI::Display::DisplayManager > m_display_manager
The unique displaymanager instance for managing display updates.
Q_INVOKABLE void loadImageFromUrl(const QUrl &file_url)
Loads an image from a QUrl (typically from QML FileDialog). Converts the QUrl to a native file path a...
void imageSizeChanged()
Emitted when image size changes.
void doApplyOperations(std::vector< Core::Operations::OperationDescriptor > &&operations)
Perform actual operations (runs on worker thread).
ImageControllerBase(QObject *parent=nullptr)
Constructs ImageController.
void applyOperations(std::vector< Core::Operations::OperationDescriptor > operations)
Apply operation with parameters (non-blocking) Note: This slot is designed to be called from QML or o...
void registerModel(IOperationModel *model)
Register an operation model for notifications.
void connectModelsToStateManager()
Connects the operationRequested signal from all created models to the OperationStateManager....
void onImageLoadResult(bool success, const QString &error_msg)
Internal: Handle load image result.
void onOperationResult(bool success, const QString &error_msg)
Internal: Handle operation result.
~ImageControllerBase()
Destructor - cleans up worker thread.
int m_image_height
Current image height.
std::shared_ptr< Core::Engine::PhotoEngine > m_engine
Core processing engine.
void operationCompleted()
Emitted when operation completes.
void loadImage(const QString &file_path)
Load image from file path (non-blocking)
void operationFailed(QString error)
Emitted when operation fails.
void imageLoadFailed(QString error)
Emitted when image load fails.
void doLoadImage(const QString &file_path)
Perform actual image load (runs on worker thread). This method contains the common logic for loading ...
void imageLoaded(int width, int height)
Emitted when image loaded successfully.
int m_image_width
Current image width.
void createDisplayImage(std::unique_ptr< Core::Common::ImageRegion > source_image)
Creates the display buffer from a downsampled source image.
Q_INVOKABLE void setSourceImageSize(int width, int height)
Sets the source image size metadata.
Pure interface for operation models.
std::vector< Core::Operations::OperationDescriptor > getActiveOperations() const
Gets the current list of active operation descriptors.
bool createBasicAdjustmentModels()
Creates instances of basic adjustment operation models. This method typically creates models like Bri...
const std::vector< std::shared_ptr< UI::Models::Operations::BaseAdjustmentModel > > & getBaseAdjustmentModels() const
Gets a const reference to the vector of created BaseAdjustmentModel instances. Provides access to the...
void valueChanged(float value)
Signal emitted when the adjustment value changes. QML can connect to this signal to react to value up...
Central error handling system for CaptureMoment Core library.
Manages image display with downsampling (with OIIO), zoom, and pan.
Qt bridge between Core (PhotoEngine) and Qt UI.
Common type definitions for all image types in CaptureMoment.
Manages the state of active image operations.
std::size_t ImageDim
Type for image dimensions (width, height).
constexpr std::string_view to_string(CoreError code)
Converts a CoreError code to a human-readable string.