Wholesale copy of all Kindred Create additions that don't conflict with upstream FreeCAD code: - kindred-icons/ (1444 Catppuccin Mocha SVG icon overrides) - src/Mod/Create/ (Kindred Create workbench) - src/Gui/ Kindred source files (FileOrigin, OriginManager, OriginSelectorWidget, CommandOrigin, BreadcrumbToolBar, EditingContext) - src/Gui/Icons/ (Kindred branding and silo icons) - src/Gui/PreferencePacks/KindredCreate/ - src/Gui/Stylesheets/ (KindredCreate.qss, images_dark-light/) - package/ (rattler-build recipe) - docs/ (architecture, guides, specifications) - .gitea/ (CI workflows, issue templates) - mods/silo, mods/ztools submodules - .gitmodules (Kindred submodule URLs) - resources/ (kindred-create.desktop, kindred-create.xml) - banner-logo-light.png, CONTRIBUTING.md
9.1 KiB
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:
setupUi()— Configures the button, createsm_menu(QMenu) andm_originActions(exclusive QActionGroup). Connects the action group'striggeredsignal toonOriginActionTriggered.connectSignals()— Subscribes to three OriginManager fastsignals viascoped_connectionobjects.rebuildMenu()— Populates the menu from the current OriginManager state.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:
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:
- Clear
m_menuand remove all actions fromm_originActions. - Iterate
OriginManager::originIds()(returnsstd::vector<std::string>in registration order). - For each origin ID, create a
QActionwith:- 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
- Icon from
- Add a separator.
- Add a "Manage Origins..." action with the
preferences-systemtheme icon, connected toonManageOriginsClicked.
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:
- Extract the origin ID from
action->data(). - Look up the
FileOriginfrom OriginManager. - Authentication gate: If
origin->requiresAuthentication()is true and the connection state isDisconnectedorError:- Call
origin->connect(). - If connection fails, revert the menu checkmark to the previous origin and return without changing.
- Call
- 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):
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:
void OriginSelectorAction::addTo(QWidget* widget)
{
if (widget->inherits("QToolBar")) {
auto* selector = new OriginSelectorWidget(widget);
static_cast<QToolBar*>(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:
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:
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
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 — abstract base class
- LocalFileOrigin — built-in default origin
- OriginManager — singleton registry and signal source
- CommandOrigin — PLM commands in the Origin Tools toolbar