Badge system wiring
Table of Contents
Summary
ORE Studio renders pill badges in Qt list views via a three-layer
DB-driven system: ores.dq owns the four domain entities
(badge_severity, code_domain, badge_definition,
badge_mapping); ores.sql seeds them at install time; and
ores.qt.api's BadgeCache loads them at login and resolves
(domain, entity_code) pairs to colours at paint time. Adding a new
badge requires no C++ changes to the resolution logic — only a SQL
population entry and a one-line delegate call. Return to Knowledge.
Detail
The four domain entities
All four live in the dq schema and are managed by ores.dq.
| Entity | Table | Purpose |
|---|---|---|
badge_severity |
ores_dq_badge_severities_tbl |
Named severity levels (secondary, info, success, warning, danger, primary). Codes align with Bootstrap 5 classes so Wt needs no translation. |
code_domain |
ores_dq_code_domains_tbl |
Named namespace that disambiguates codes across entity types (e.g. account_type, login_status). |
badge_definition |
ores_dq_badge_definitions_tbl |
One row per visual variant: label, background colour, text colour, severity, CSS class hint. |
badge_mapping |
ores_dq_badge_mappings_tbl |
Junction: maps (code_domain, entity_code) → badge_definition. |
SQL population
All badge metadata lives in one idempotent script:
projects/ores.sql/populate/dq/dq_badge_system_populate.sql
The script uses upsert functions so it is safe to re-run. The structure per new badge domain is always three blocks:
- Code domain — one
ores_dq_code_domains_upsert_fncall naming the domain and itsdisplay_order. - Badge definitions — one
ores_dq_badge_definitions_upsert_fncall per distinct visual variant (label, hex colours, severity code, CSS class, display_order). - Badge mappings — one
ores_dq_badge_mappings_upsert_fncall per value, mapping(domain, entity_code)→badge_definition_code.
The entity code in the mapping must match exactly what the Qt model returns for that column (see §Qt wiring below).
BadgeCache
BadgeCache (projects/ores.qt/api/include/ores.qt/BadgeCache.hpp)
is a session-scoped cache populated at login from the standard
service/protocol/client pipeline. It exposes one method:
const badge_definition* resolve( const std::string& domain, const std::string& entity_code) const;
Returns nullptr on cache miss — callers must fall back to a default
colour. The cache is injected into every ItemDelegate at
construction via the plugin_context received in on_login.
Qt wiring — item delegate
Each entity list view has an ItemDelegate subclass (e.g.
AccountItemDelegate) that overrides paint() and sizeHint().
paint():
if (index.column() == Column::MyField /* || ... */) { QStyle* style = QApplication::style(); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter); static const QColor default_gray(107, 114, 128); static const QColor white(255, 255, 255); QColor bgColor = default_gray; QColor textColor = white; QString text = index.data(Qt::DisplayRole).toString(); QString badgeText = text; // or a translated label if (badgeCache_) { auto* def = badgeCache_->resolve("my_domain", text.toStdString()); if (def) { bgColor = QColor(QString::fromStdString(def->background_colour)); textColor = QColor(QString::fromStdString(def->text_colour)); } } QFont badgeFont = opt.font; badgeFont.setPointSize(qRound(badgeFont.pointSize() * 0.8)); badgeFont.setBold(true); DelegatePaintUtils::draw_centered_badge( painter, opt.rect, badgeText, bgColor, textColor, badgeFont); return; }
sizeHint(): add the same column guard and set a minimum height of 24 and a minimum width appropriate for the longest label (typically 50–90 px).
The entity code passed to resolve() must exactly match the string
the model returns for Qt::DisplayRole on that column. If the model
returns a display name (tr("Online")), the badge mapping key must
use that display name. If the model returns the raw DB code ("user"),
the mapping key must use the raw code.
Worked example — account_type
account_type badge (added in sprint 19):
- Code domain:
account_type, display_order 17. - Four badge definitions:
account_type_user(info/#3b82f6),account_type_service(secondary/#6b7280),account_type_algorithm(warning/#eab308),account_type_llm(primary/#7c3aed). - Four mappings keyed on the raw DB codes:
'user','service','algorithm','llm'(becauseClientAccountModelreturnsaccount.account_typeverbatim). - Delegate:
Column::AccountTypeadded to the badge guard inAccountItemDelegate::paint()andsizeHint()(min width 80 px).
See also
- ores.qt.api —
BadgeCache,DelegatePaintUtils, and theplugin_contextthat injects the cache. - How do I add a badge to a Qt list view? — the four-step checklist.
- Qt plugin architecture — how
plugin_context(includingbadge_cache) is passed to plugins at login. - Entity controller pattern — the delegate sits in the entity UI stack alongside the model and list window.