From c25aa17591903149a0307a4f5c3a1aec479dd30e Mon Sep 17 00:00:00 2001 From: forbes-0023 Date: Tue, 10 Feb 2026 08:18:05 -0600 Subject: [PATCH] docs(c++): OriginSelectorWidget toolbar integration Covers widget lifecycle, signal connections (fastsignals), menu population, origin selection with authentication gate, icon overlays for connection state, StdCmdOrigin/OriginSelectorAction command wrappers, and StdWorkbench toolbar placement. Closes #133 --- docs/src/SUMMARY.md | 1 + .../reference/cpp-origin-selector-widget.md | 224 ++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 docs/src/reference/cpp-origin-selector-widget.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 6e5c126588..770d3f4f86 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -53,4 +53,5 @@ - [LocalFileOrigin](./reference/cpp-local-file-origin.md) - [OriginManager](./reference/cpp-origin-manager.md) - [CommandOrigin](./reference/cpp-command-origin.md) +- [OriginSelectorWidget](./reference/cpp-origin-selector-widget.md) - [FileOriginPython Bridge](./reference/cpp-file-origin-python.md) diff --git a/docs/src/reference/cpp-origin-selector-widget.md b/docs/src/reference/cpp-origin-selector-widget.md new file mode 100644 index 0000000000..376bc253e3 --- /dev/null +++ b/docs/src/reference/cpp-origin-selector-widget.md @@ -0,0 +1,224 @@ +# OriginSelectorWidget + +`OriginSelectorWidget` is a toolbar dropdown that lets users switch between registered file origins (Local Files, Silo, etc.). It appears as the first item in the File toolbar across all workbenches. + +- **Header:** `src/Gui/OriginSelectorWidget.h` +- **Source:** `src/Gui/OriginSelectorWidget.cpp` +- **Base class:** `QToolButton` +- **Command ID:** `Std_Origin` + +## Widget appearance + +The button shows the current origin's nickname and icon. Clicking opens a dropdown menu listing all registered origins with a checkmark on the active one. + +``` +┌────────────────┐ +│ Local ▼ │ ← nickname + icon, InstantPopup mode +└────────────────┘ + +Dropdown: + ✓ Local ← checked = current origin + Kindred Silo ← disconnected origins show status overlay + ────────────────── + Manage Origins... ← opens OriginManagerDialog +``` + +### Size constraints + +| Property | Value | +|----------|-------| +| Popup mode | `QToolButton::InstantPopup` | +| Button style | `Qt::ToolButtonTextBesideIcon` | +| Minimum width | 80 px | +| Maximum width | 160 px | +| Size policy | `Preferred, Fixed` | + +## Lifecycle + +### Construction + +The constructor calls four setup methods in order: + +1. **`setupUi()`** — Configures the button, creates `m_menu` (QMenu) and `m_originActions` (exclusive QActionGroup). Connects the action group's `triggered` signal to `onOriginActionTriggered`. +2. **`connectSignals()`** — Subscribes to three OriginManager fastsignals via `scoped_connection` objects. +3. **`rebuildMenu()`** — Populates the menu from the current OriginManager state. +4. **`updateDisplay()`** — Sets the button text, icon, and tooltip to match the current origin. + +### Destruction + +The destructor calls `disconnectSignals()`, which explicitly disconnects the three `fastsignals::scoped_connection` members. The scoped connections would auto-disconnect on destruction regardless, but explicit disconnection prevents any signal delivery during teardown. + +## Signal connections + +The widget subscribes to three `OriginManager` fastsignals: + +| OriginManager signal | Widget handler | Response | +|----------------------|----------------|----------| +| `signalOriginRegistered` | `onOriginRegistered(id)` | Rebuild menu | +| `signalOriginUnregistered` | `onOriginUnregistered(id)` | Rebuild menu | +| `signalCurrentOriginChanged` | `onCurrentOriginChanged(id)` | Update display + menu checkmarks | + +Connections are stored as `fastsignals::scoped_connection` members for RAII lifetime management: + +```cpp +fastsignals::scoped_connection m_connRegistered; +fastsignals::scoped_connection m_connUnregistered; +fastsignals::scoped_connection m_connChanged; +``` + +## Menu population + +`rebuildMenu()` rebuilds the entire dropdown from scratch each time an origin is registered or unregistered: + +1. Clear `m_menu` and remove all actions from `m_originActions`. +2. Iterate `OriginManager::originIds()` (returns `std::vector` in registration order). +3. For each origin ID, create a `QAction` with: + - Icon from `iconForOrigin(origin)` (with connection-state overlay) + - Text from `origin->nickname()` + - Tooltip from `origin->name()` + - `setCheckable(true)`, checked if this is the current origin + - Data set to the origin ID string +4. Add a separator. +5. Add a "Manage Origins..." action with the `preferences-system` theme icon, connected to `onManageOriginsClicked`. + +Origins appear in the menu in the order returned by `OriginManager::originIds()`. The local origin is always first (registered at startup), followed by Python-registered origins in registration order. + +## Origin selection + +When the user clicks an origin in the dropdown, `onOriginActionTriggered(QAction*)` runs: + +1. Extract the origin ID from `action->data()`. +2. Look up the `FileOrigin` from OriginManager. +3. **Authentication gate:** If `origin->requiresAuthentication()` is true and the connection state is `Disconnected` or `Error`: + - Call `origin->connect()`. + - If connection fails, revert the menu checkmark to the previous origin and return without changing. +4. On success, call `OriginManager::setCurrentOrigin(originId)`. + +This means selecting a disconnected PLM origin triggers an automatic reconnection attempt. The user sees no change if the connection fails. + +## Icon overlays + +`iconForOrigin(FileOrigin*)` generates a display icon with optional connection-state indicators: + +| Connection state | Overlay | Position | +|------------------|---------|----------| +| `Connected` | None | — | +| `Connecting` | None (TODO: animated) | — | +| `Disconnected` | `dagViewFail` (8x8 px, red) | Bottom-right | +| `Error` | `Warning` (8x8 px, yellow) | Bottom-right | + +Overlays are only applied to origins where `requiresAuthentication()` returns `true`. Local origins never get overlays. The merge uses `BitmapFactoryInst::mergePixmap` with `BottomRight` placement. + +## Display updates + +`updateDisplay()` sets the button face to reflect the current origin: + +- **Text:** `origin->nickname()` (e.g. "Local", "Silo") +- **Icon:** Result of `iconForOrigin(origin)` (with possible overlay) +- **Tooltip:** `origin->name()` (e.g. "Local Files", "Kindred Silo") +- **No origin:** Text becomes "No Origin", icon and tooltip are cleared + +This method runs on construction, on `signalCurrentOriginChanged`, and after the Manage Origins dialog closes. + +## Command wrapper + +The widget is exposed to the command/toolbar system through two classes. + +### StdCmdOrigin + +Defined in `src/Gui/CommandStd.cpp` using `DEF_STD_CMD_AC(StdCmdOrigin)`: + +```cpp +StdCmdOrigin::StdCmdOrigin() + : Command("Std_Origin") +{ + sGroup = "File"; + sMenuText = QT_TR_NOOP("&Origin"); + sToolTipText = QT_TR_NOOP("Select file origin (Local Files, Silo, etc.)"); + sWhatsThis = "Std_Origin"; + sStatusTip = sToolTipText; + sPixmap = "folder"; + eType = 0; +} +``` + +| Property | Value | +|----------|-------| +| Command ID | `Std_Origin` | +| Menu group | `File` | +| Icon | `folder` | +| `isActive()` | Always `true` | +| `activated()` | No-op (widget handles interaction) | + +`createAction()` returns an `OriginSelectorAction` instance. + +### OriginSelectorAction + +Defined in `src/Gui/Action.h` / `Action.cpp`. Bridges the command system and the widget: + +```cpp +void OriginSelectorAction::addTo(QWidget* widget) +{ + if (widget->inherits("QToolBar")) { + auto* selector = new OriginSelectorWidget(widget); + static_cast(widget)->addWidget(selector); + } else { + widget->addAction(action()); + } +} +``` + +When added to a `QToolBar`, it instantiates an `OriginSelectorWidget`. When added to a menu or other container, it falls back to adding a plain `QAction`. + +## Toolbar integration + +`StdWorkbench::setupToolBars()` in `src/Gui/Workbench.cpp` places the widget: + +```cpp +auto file = new ToolBarItem(root); +file->setCommand("File"); +*file << "Std_Origin" // ← origin selector (first) + << "Std_New" + << "Std_Open" + << "Std_Save"; +``` + +The widget appears as the **first item** in the File toolbar. Because `StdWorkbench` is the base workbench, this placement is inherited by all workbenches (Part Design, Assembly, Silo, etc.). + +A separate "Origin Tools" toolbar follows with PLM-specific commands: + +```cpp +auto originTools = new ToolBarItem(root); +originTools->setCommand("Origin Tools"); +*originTools << "Origin_Commit" << "Origin_Pull" << "Origin_Push" + << "Separator" + << "Origin_Info" << "Origin_BOM"; +``` + +These commands auto-disable based on the current origin's capability flags (`supportsRevisions`, `supportsBOM`, etc.). + +## Member variables + +```cpp +QMenu* m_menu; // dropdown menu +QActionGroup* m_originActions; // exclusive checkmark group +QAction* m_manageAction; // "Manage Origins..." action + +fastsignals::scoped_connection m_connRegistered; // signalOriginRegistered +fastsignals::scoped_connection m_connUnregistered; // signalOriginUnregistered +fastsignals::scoped_connection m_connChanged; // signalCurrentOriginChanged +``` + +## Behavioural notes + +- **Origin scope is global, not per-document.** Switching origin affects all subsequent New/Open/Save operations. Existing open documents retain their origin association via `OriginManager::_documentOrigins`. +- **Menu rebuilds are full rebuilds.** On any registration/unregistration event, the entire menu is cleared and rebuilt. This is simple and correct — origin counts are small (typically 2-3). +- **No document-switch tracking.** The widget does not respond to active document changes. The current origin is a user preference, not derived from the active document. +- **Thread safety.** All operations assume the Qt main thread. Signal emissions from OriginManager are synchronous. + +## See also + +- [FileOrigin Interface](./cpp-file-origin.md) — abstract base class +- [LocalFileOrigin](./cpp-local-file-origin.md) — built-in default origin +- [OriginManager](./cpp-origin-manager.md) — singleton registry and signal source +- [CommandOrigin](./cpp-command-origin.md) — PLM commands in the Origin Tools toolbar