Archetype: cpp_qt_client_model.hpp.mustache

Table of Contents

Client model 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.

Template

The full template source. Edit here and re-tangle with compass build --direct tangle_codegen_templates to regenerate library/templates/cpp_qt_client_model.hpp.mustache.

{{! GENERATED FILE — tangled from projects/ores.codegen/library/templates/cpp_qt.org. Edit the org source. }}
{{! Template to generate Qt client model header for domain entities }}
{{{cpp_license}}}
#ifndef ORES_QT_CLIENT_{{domain_entity.entity_upper}}_MODEL_HPP
#define ORES_QT_CLIENT_{{domain_entity.entity_upper}}_MODEL_HPP

#include <vector>
#include <QFutureWatcher>
#include "ores.qt/AbstractClientModel.hpp"
#include "ores.qt/ClientManager.hpp"
#include "ores.qt/RecencyPulseManager.hpp"
#include "ores.qt/RecencyTracker.hpp"
#include "ores.logging/make_logger.hpp"
#include "{{domain_entity.qt.domain_include}}"

namespace ores::qt {

/**
 * @brief Model for displaying {{domain_entity.entity_plural_words}} fetched from the server.
 *
 * This model extends AbstractClientModel and fetches {{domain_entity.entity_singular_words}}
 * data asynchronously using the ores.comms client.
 */
class Client{{domain_entity.entity_pascal}}Model final : public AbstractClientModel {
    Q_OBJECT

private:
    inline static std::string_view logger_name =
        "ores.qt.client_{{domain_entity.entity_snake}}_model";

    [[nodiscard]] static auto& lg() {
        using namespace ores::logging;
        static auto instance = make_logger(logger_name);
        return instance;
    }

public:
    /**
     * @brief Enumeration of table columns for type-safe column access.
     */
    enum Column {
{{#domain_entity.qt.columns}}
        {{enum_name}},
{{/domain_entity.qt.columns}}
        ColumnCount
    };

    explicit Client{{domain_entity.entity_pascal}}Model(ClientManager* clientManager,
                                       QObject* parent = nullptr);
    ~Client{{domain_entity.entity_pascal}}Model() override = default;

    // QAbstractTableModel interface
    int rowCount(const QModelIndex& parent = QModelIndex()) const override;
    int columnCount(const QModelIndex& parent = QModelIndex()) const override;
    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
    QVariant headerData(int section, Qt::Orientation orientation,
        int role = Qt::DisplayRole) const override;

    /**
     * @brief Refresh {{domain_entity.entity_singular_words}} data from server asynchronously.
     */
    void refresh();

    /**
     * @brief Get {{domain_entity.entity_singular_words}} at the specified row.
     *
     * @param row The row index.
     * @return The {{domain_entity.entity_singular_words}}, or nullptr if row is invalid.
     */
    const {{domain_entity.qt.domain_class}}* get{{domain_entity.entity_pascal_short}}(int row) const;

    /**
     * @brief Load a specific page of data.
     */
    void load_page(std::uint32_t offset, std::uint32_t limit);

    /**
     * @brief Get the page size used for pagination.
     */
    std::uint32_t page_size() const { return page_size_; }

    /**
     * @brief Set the page size for pagination.
     */
    void set_page_size(std::uint32_t size);

    /**
     * @brief Get the total number of records available on the server.
     */
    std::uint32_t total_available_count() const { return total_available_count_; }

private slots:
    void on{{domain_entity.entity_pascal_short_plural}}Loaded();
    void onPulseStateChanged(bool isOn);
    void onPulsingComplete();

private:
    QVariant recency_foreground_color(const std::string& code) const;

    struct FetchResult {
        bool success;
        std::vector<{{domain_entity.qt.domain_class}}> {{domain_entity.qt.collection_name}};
        std::uint32_t total_available_count;
        QString error_message;
        QString error_details;
    };

    void fetch_{{domain_entity.qt.collection_name}}(std::uint32_t offset, std::uint32_t limit);

    ClientManager* clientManager_;
    std::vector<{{domain_entity.qt.domain_class}}> {{domain_entity.qt.collection_name}}_;
    QFutureWatcher<FetchResult>* watcher_;
    std::uint32_t page_size_{100};
    std::uint32_t total_available_count_{0};
    bool is_fetching_{false};

    using {{domain_entity.entity_pascal}}KeyExtractor = std::string(*)(const {{domain_entity.qt.domain_class}}&);
    RecencyTracker<{{domain_entity.qt.domain_class}}, {{domain_entity.entity_pascal}}KeyExtractor> recencyTracker_;
    RecencyPulseManager* pulseManager_;
};

}

#endif

See also

Emacs 29.1 (Org mode 9.6.6)