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:

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

Emacs 29.3 (Org mode 9.6.15)