# 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