ores.cpp.qt.controller_header
Table of Contents
Controller declarations. Qt UI component: model/view class or dialog wired to the service layer via request/response messages.
See the Template variable reference for the complete list of available variables and their semantics.
Extension points
<<paste:UUID>> markers in this template are paste-block injection
points — see paste blocks: injecting custom code into generated files
for the full mechanism. This template defines one:
66E078FB-D6A6-4DF6-814B-65995D948090— insignals:, after the generated signals. Extra entity-specific signals, e.g. a cross-navigation request relayed from the list window (see the matching seam in ores.cpp.qt.mdi_window_impl), or a signal relayed from the detail dialog (seeDF72DFCF-FD65-4FE5-98BA-CB8168CE0FDFin ores.cpp.qt.controller_impl and the paired dialog-side seam in ores.cpp.qt.detail_dialog_header).
Not a paste-block, but a related extension point: qt.explorer_interface
(a model property, not a paste-block UUID) names an abstract interface
the generated Controller additionally implements — for a cross-component
explorer window (e.g. ores.qt.trading's OrgExplorerMdiWindow) that
needs to drive openEdit=/=openHistory (from has_explorer_api) without
linking against this entity's concrete Controller header. The interface
itself is hand-authored elsewhere (e.g. ores.qt.api/IBusinessUnitBrowser.hpp)
and must declare exactly the openEdit=/=openHistory signatures
has_explorer_api generates.
Template
The full template source. Edit here and re-tangle with
compass build --direct tangle_codegen_templates to regenerate
library/templates/cpp_qt_controller.hpp.mustache.
{{! GENERATED FILE — tangled from projects/ores.codegen/library/templates/cpp_qt.org. Edit the org source. }}
{{! Template to generate Qt controller header for domain entities }}
{{{cpp_license}}}
#ifndef ORES_QT_{{domain_entity.entity_upper}}_CONTROLLER_HPP
#define ORES_QT_{{domain_entity.entity_upper}}_CONTROLLER_HPP
#include <QMdiArea>
#include <QMainWindow>
#include "ores.qt/EntityController.hpp"
#include "ores.qt/ClientManager.hpp"
#include "ores.logging/make_logger.hpp"
#include "{{domain_entity.qt.domain_include}}"
#include "ores.qt/EntityListMdiWindow.hpp"
{{#domain_entity.qt.has_export_macro}}
#include "ores.qt/{{domain_entity.qt.export_header}}"
{{/domain_entity.qt.has_export_macro}}
{{#domain_entity.qt.has_explorer_interface}}
#include "ores.qt/{{domain_entity.qt.explorer_interface}}.hpp"
{{/domain_entity.qt.has_explorer_interface}}
#include <expected>
#include <functional>
#include <vector>
namespace ores::qt {
class {{domain_entity.entity_pascal}}MdiWindow;
{{^domain_entity.qt.has_readonly_paginated_list}}
class {{domain_entity.entity_pascal}}DetailDialog;
{{/domain_entity.qt.has_readonly_paginated_list}}
class DetachableMdiSubWindow;
{{#domain_entity.qt.has_badge_columns}}
class BadgeCache;
{{/domain_entity.qt.has_badge_columns}}
{{#domain_entity.qt.has_change_reason_cache}}
class ChangeReasonCache;
{{/domain_entity.qt.has_change_reason_cache}}
{{#domain_entity.qt.needs_image_cache}}
class ImageCache;
{{/domain_entity.qt.needs_image_cache}}
/**
* @brief Controller for managing {{domain_entity.entity_singular_words}} windows and operations.
*
* Manages the lifecycle of {{domain_entity.entity_singular_words}} list, detail, and history windows.
* Handles event subscriptions and coordinates between windows.
*/
class {{#domain_entity.qt.has_export_macro}}{{domain_entity.qt.export_macro}} {{/domain_entity.qt.has_export_macro}}{{domain_entity.entity_pascal}}Controller final : public EntityController{{#domain_entity.qt.has_explorer_interface}}, public {{domain_entity.qt.explorer_interface}}{{/domain_entity.qt.has_explorer_interface}} {
Q_OBJECT
private:
inline static std::string_view logger_name =
"ores.qt.{{domain_entity.entity_snake}}_controller";
[[nodiscard]] static auto& lg() {
using namespace ores::logging;
static auto instance = make_logger(logger_name);
return instance;
}
public:
{{domain_entity.entity_pascal}}Controller(
QMainWindow* mainWindow,
QMdiArea* mdiArea,
ClientManager* clientManager,
{{#domain_entity.qt.needs_image_cache}}
ImageCache* imageCache,
{{/domain_entity.qt.needs_image_cache}}
{{#domain_entity.qt.has_change_reason_cache}}
ChangeReasonCache* changeReasonCache,
{{/domain_entity.qt.has_change_reason_cache}}
const QString& username,
{{#domain_entity.qt.has_badge_columns}}
BadgeCache* badgeCache,
{{/domain_entity.qt.has_badge_columns}}
QObject* parent = nullptr);
void showListWindow() override;
void closeAllWindows() override;
void reloadListWindow() override;
{{#domain_entity.qt.has_parent_scoped_list}}
/**
* @brief Opens the list window scoped to @p {{domain_entity.qt.parent_key_param}},
* sending it on every paginated fetch. showListWindow() alone (the
* EntityController override above) opens with an empty/unset key.
*/
void openForParent(const QString& {{domain_entity.qt.parent_key_param}});
{{/domain_entity.qt.has_parent_scoped_list}}
{{#domain_entity.qt.has_explorer_api}}
{{^domain_entity.qt.has_readonly_paginated_list}}
void openAdd();
{{#domain_entity.qt.has_parent_relationship}}
void openAddWithParent(boost::uuids::uuid {{domain_entity.qt.parent_id_field_camel}});
{{/domain_entity.qt.has_parent_relationship}}
void openEdit(const {{domain_entity.qt.domain_class}}& {{domain_entity.qt.item_var}}){{#domain_entity.qt.has_explorer_interface}} override{{/domain_entity.qt.has_explorer_interface}};
void openHistory(const {{domain_entity.qt.domain_class}}& {{domain_entity.qt.item_var}}){{#domain_entity.qt.has_explorer_interface}} override{{/domain_entity.qt.has_explorer_interface}};
{{/domain_entity.qt.has_readonly_paginated_list}}
{{/domain_entity.qt.has_explorer_api}}
signals:
void statusMessage(const QString& message);
void errorMessage(const QString& error);
{{#domain_entity.qt.has_related_entity_shortcuts}}
/**
* @brief Relayed from {{domain_entity.entity_pascal}}MdiWindow; wired to
* the target's own controller in the plugin's composition root.
*/
{{#domain_entity.qt.related_entity_shortcuts}}
void show{{signal}}Requested();
{{/domain_entity.qt.related_entity_shortcuts}}
{{/domain_entity.qt.has_related_entity_shortcuts}}
{{! see * Extension points above }}
<<paste:66E078FB-D6A6-4DF6-814B-65995D948090>>
protected:
EntityListMdiWindow* listWindow() const override;
{{#domain_entity.qt.changed_event_class}}
void notifyOpenDialogs(const QStringList& entityIds) override;
{{/domain_entity.qt.changed_event_class}}
{{^domain_entity.qt.has_readonly_paginated_list}}
private slots:
void onShowDetails(const {{domain_entity.qt.domain_class}}& {{domain_entity.qt.item_var}});
void onAddNewRequested();
void onShowHistory(const {{domain_entity.qt.domain_class}}& {{domain_entity.qt.item_var}});
void onRevertVersion(const {{domain_entity.qt.domain_class}}& {{domain_entity.qt.item_var}});
{{#domain_entity.qt.has_version_navigation}}
void onOpenVersion(const {{domain_entity.qt.domain_class}}& {{domain_entity.qt.item_var}},
int versionNumber,
const std::vector<{{domain_entity.qt.domain_class}}>& fullHistory = {});
{{/domain_entity.qt.has_version_navigation}}
{{^domain_entity.qt.has_version_navigation}}
void onOpenVersion(const {{domain_entity.qt.domain_class}}& {{domain_entity.qt.item_var}},
int versionNumber);
{{/domain_entity.qt.has_version_navigation}}
void onOpenHistoryVersion(const QString& entityId, int versionNumber);
void onRevertHistoryVersion(const QString& entityId, int versionNumber);
private:
{{#domain_entity.qt.has_parent_relationship}}
void showAddWindow(boost::uuids::uuid {{domain_entity.qt.parent_id_field_camel}} = {});
{{/domain_entity.qt.has_parent_relationship}}
{{^domain_entity.qt.has_parent_relationship}}
void showAddWindow();
{{/domain_entity.qt.has_parent_relationship}}
void showDetailWindow(const {{domain_entity.qt.domain_class}}& {{domain_entity.qt.item_var}});
/**
* @brief Wires the caches/status/error plumbing every
* {{domain_entity.entity_pascal}}DetailDialog needs regardless of which
* window opened it (add/edit/history-version/revert) -- kept in one
* place so those four call sites can't drift from each other.
*/
void wireDetailDialogCommon({{domain_entity.entity_pascal}}DetailDialog* detailDialog);
{{#domain_entity.qt.has_uuid_primary_key}}
void showHistoryWindow(const {{domain_entity.qt.domain_class}}& {{domain_entity.qt.item_var}});
{{/domain_entity.qt.has_uuid_primary_key}}
{{^domain_entity.qt.has_uuid_primary_key}}
void showHistoryWindow(const QString& code);
{{/domain_entity.qt.has_uuid_primary_key}}
/**
* @brief Fetches the full typed {{domain_entity.entity_singular_words}} history (the
* existing per-entity {{domain_entity.qt.history_request_class}}/
* {{domain_entity.qt.history_response_class}}, unrelated to the generic
* history.v1.get subject) and hands it to @p callback on the UI
* thread. Used to resolve HistoryDialog's generic (entity_id,
* version) signals back to a typed {{domain_entity.entity_singular_words}}, since the
* generic dialog holds no typed domain data.
*/
void fetch{{domain_entity.entity_pascal}}History(
const QString& entityId,
std::function<void(std::expected<std::vector<{{domain_entity.qt.domain_class}}>, QString>)>
callback);
{{/domain_entity.qt.has_readonly_paginated_list}}
{{#domain_entity.qt.has_readonly_paginated_list}}
private:
{{/domain_entity.qt.has_readonly_paginated_list}}
{{#domain_entity.qt.has_parent_scoped_list}}
void showListWindow(const QString& {{domain_entity.qt.parent_key_param}});
{{/domain_entity.qt.has_parent_scoped_list}}
{{#domain_entity.qt.has_change_reason_cache}}
ChangeReasonCache* changeReasonCache_;
{{/domain_entity.qt.has_change_reason_cache}}
{{#domain_entity.qt.has_badge_columns}}
BadgeCache* badgeCache_;
{{/domain_entity.qt.has_badge_columns}}
{{#domain_entity.qt.has_parent_scoped_list}}
QString {{domain_entity.qt.parent_key_param}}_;
{{/domain_entity.qt.has_parent_scoped_list}}
{{domain_entity.entity_pascal}}MdiWindow* listWindow_;
DetachableMdiSubWindow* listMdiSubWindow_;
};
}
#endif
See also
- Parent facet: ores.cpp.qt
- Template variable reference