diff --git a/freecad/InitGui.py b/freecad/InitGui.py index 0a6d1b9..f07896d 100644 --- a/freecad/InitGui.py +++ b/freecad/InitGui.py @@ -35,28 +35,25 @@ class SiloWorkbench(FreeCADGui.Workbench): except Exception as e: FreeCAD.Console.PrintWarning(f"Could not register Silo origin: {e}\n") - self.toolbar_commands = [ - "Silo_ToggleMode", - "Separator", - "Silo_Open", - "Silo_New", - "Silo_Save", - "Silo_Commit", - "Silo_Pull", - "Silo_Push", + # Silo menu provides admin/management commands. + # File operations (New/Open/Save) are handled by the standard File + # toolbar via the origin system -- no separate Silo toolbar needed. + self.menu_commands = [ "Silo_Info", "Silo_BOM", + "Silo_TagProjects", + "Silo_SetStatus", + "Silo_Rollback", + "Separator", "Silo_Settings", "Silo_Auth", ] - self.appendToolbar("Silo", self.toolbar_commands) - self.appendMenu("Silo", self.toolbar_commands) + self.appendMenu("Silo", self.menu_commands) def Activated(self): """Called when workbench is activated.""" FreeCAD.Console.PrintMessage("Kindred Silo workbench activated\n") - self._show_shortcut_recommendations() def Deactivated(self): pass @@ -64,39 +61,6 @@ class SiloWorkbench(FreeCADGui.Workbench): def GetClassName(self): return "Gui::PythonWorkbench" - def _show_shortcut_recommendations(self): - """Show keyboard shortcut recommendations dialog on first activation.""" - try: - param_group = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/KindredSilo") - if param_group.GetBool("ShortcutsShown", False): - return - param_group.SetBool("ShortcutsShown", True) - - from PySide import QtGui - - msg = """
For the best experience, set up these keyboard shortcuts:
-| Ctrl+O | - | Silo_Open (Search & Open) |
| Ctrl+N | - | Silo_New (Register new item) |
| Ctrl+S | - | Silo_Save (Save & upload) |
| Ctrl+Shift+S | - | Silo_Commit (Save with comment) |
To set shortcuts: Tools > Customize > Keyboard
-This message appears once.
""" - - dialog = QtGui.QMessageBox() - dialog.setWindowTitle("Silo Keyboard Shortcuts") - dialog.setTextFormat(QtGui.Qt.RichText) - dialog.setText(msg) - dialog.setIcon(QtGui.QMessageBox.Information) - dialog.addButton("Set Up Now", QtGui.QMessageBox.AcceptRole) - dialog.addButton("Later", QtGui.QMessageBox.RejectRole) - if dialog.exec_() == 0: - FreeCADGui.runCommand("Std_DlgCustomize", 0) - except Exception as e: - FreeCAD.Console.PrintWarning("Silo shortcuts dialog: " + str(e) + "\n") - FreeCADGui.addWorkbench(SiloWorkbench()) FreeCAD.Console.PrintMessage("Silo workbench registered\n") diff --git a/freecad/silo_commands.py b/freecad/silo_commands.py index 9df5c2e..ac89c72 100644 --- a/freecad/silo_commands.py +++ b/freecad/silo_commands.py @@ -106,6 +106,10 @@ def _get_auth_source() -> str: return param.GetString("AuthSource", "") +def _get_auth_token() -> str: + return _fc_settings.get_api_token() + + # Thin wrappers so command classes can call these without refactoring. # They delegate to the settings adapter or the shared client. @@ -881,9 +885,6 @@ class Silo_Save: # Check if document has unsaved changes gui_doc = FreeCADGui.getDocument(doc.Name) is_modified = gui_doc.Modified if gui_doc else True - FreeCAD.Console.PrintMessage( - f"[DEBUG] Modified={is_modified}, FileName={doc.FileName}\n" - ) if gui_doc and not is_modified and doc.FileName: FreeCAD.Console.PrintMessage("No changes to save.\n") @@ -891,17 +892,9 @@ class Silo_Save: # Collect properties BEFORE saving to avoid dirtying the document # (accessing Shape properties can trigger recompute) - FreeCAD.Console.PrintMessage("[DEBUG] Collecting properties...\n") properties = collect_document_properties(doc) - # Check modified state after collecting properties - is_modified_after_props = gui_doc.Modified if gui_doc else True - FreeCAD.Console.PrintMessage( - f"[DEBUG] After collect_properties: Modified={is_modified_after_props}\n" - ) - # Save locally - FreeCAD.Console.PrintMessage("[DEBUG] Saving to canonical path...\n") file_path = _sync.save_to_canonical_path(doc, force_rename=True) if not file_path: # Fallback to regular save if canonical path fails @@ -912,24 +905,12 @@ class Silo_Save: FreeCAD.Console.PrintError("Could not determine save path\n") return - # Check modified state after save - is_modified_after_save = gui_doc.Modified if gui_doc else True - FreeCAD.Console.PrintMessage( - f"[DEBUG] After save: Modified={is_modified_after_save}\n" - ) - # Force clear modified flag if save succeeded (needed for assemblies) - if is_modified_after_save and gui_doc: - FreeCAD.Console.PrintMessage( - "[DEBUG] Attempting to clear Modified flag...\n" - ) + if gui_doc and gui_doc.Modified: try: gui_doc.Modified = False - FreeCAD.Console.PrintMessage( - f"[DEBUG] After force clear: Modified={gui_doc.Modified}\n" - ) - except Exception as e: - FreeCAD.Console.PrintMessage(f"[DEBUG] Could not clear Modified: {e}\n") + except Exception: + pass FreeCAD.Console.PrintMessage(f"Saved: {file_path}\n") @@ -942,12 +923,6 @@ class Silo_Save: new_rev = result["revision_number"] FreeCAD.Console.PrintMessage(f"Uploaded as revision {new_rev}\n") - # Check modified state after upload - is_modified_after_upload = gui_doc.Modified if gui_doc else True - FreeCAD.Console.PrintMessage( - f"[DEBUG] After upload: Modified={is_modified_after_upload}\n" - ) - except Exception as e: FreeCAD.Console.PrintWarning(f"Upload failed: {e}\n") FreeCAD.Console.PrintMessage("File saved locally but not uploaded.\n") @@ -2374,85 +2349,6 @@ class Silo_BOM: return FreeCAD.ActiveDocument is not None -# --------------------------------------------------------------------------- -# Silo Mode toggle - swap Ctrl+O/S/N between standard and Silo commands -# --------------------------------------------------------------------------- - -# Stored original shortcuts so they can be restored on toggle-off -_original_shortcuts: Dict[str, Any] = {} - - -def _swap_shortcuts(mapping, enable_silo): - """Swap keyboard shortcuts between standard and Silo commands. - - mapping: list of (std_cmd, silo_cmd, shortcut) tuples - enable_silo: True to assign shortcuts to Silo commands, False to restore. - """ - from PySide import QtGui - - mw = FreeCADGui.getMainWindow() - if mw is None: - return - - for std_cmd, silo_cmd, shortcut in mapping: - if enable_silo: - # Save and clear the standard command's shortcut - std_action = mw.findChild(QtGui.QAction, std_cmd) - if std_action: - _original_shortcuts[std_cmd] = std_action.shortcut().toString() - std_action.setShortcut("") - # Assign the shortcut to the Silo command - silo_action = mw.findChild(QtGui.QAction, silo_cmd) - if silo_action: - silo_action.setShortcut(shortcut) - else: - # Clear the Silo command's shortcut - silo_action = mw.findChild(QtGui.QAction, silo_cmd) - if silo_action: - silo_action.setShortcut("") - # Restore the standard command's original shortcut - std_action = mw.findChild(QtGui.QAction, std_cmd) - if std_action and std_cmd in _original_shortcuts: - std_action.setShortcut(_original_shortcuts.pop(std_cmd)) - - -_SHORTCUT_MAP = [ - ("Std_Open", "Silo_Open", "Ctrl+O"), - ("Std_Save", "Silo_Save", "Ctrl+S"), - ("Std_New", "Silo_New", "Ctrl+N"), -] - - -class Silo_ToggleMode: - """Toggle between standard file operations and Silo equivalents.""" - - def GetResources(self): - return { - "MenuText": "Silo Mode", - "ToolTip": ( - "Toggle between standard file operations and Silo equivalents.\n" - "When ON: Ctrl+O/S/N use Silo Open/Save/New.\n" - "When OFF: Standard FreeCAD file operations." - ), - "Pixmap": _icon("silo"), - "Checkable": True, - } - - def Activated(self, checked): - param = FreeCAD.ParamGet(_PREF_GROUP) - if checked: - _swap_shortcuts(_SHORTCUT_MAP, enable_silo=True) - param.SetBool("SiloMode", True) - FreeCAD.Console.PrintMessage("Silo mode enabled\n") - else: - _swap_shortcuts(_SHORTCUT_MAP, enable_silo=False) - param.SetBool("SiloMode", False) - FreeCAD.Console.PrintMessage("Silo mode disabled\n") - - def IsActive(self): - return True - - # --------------------------------------------------------------------------- # SSE live-update listener # --------------------------------------------------------------------------- @@ -2722,9 +2618,9 @@ class SiloAuthDockWidget: self._url_label.setText(_get_api_url()) has_token = _client.is_authenticated() - username = _client.auth_username() - role = _client.auth_role() - source = _client.auth_source() + username = _get_auth_username() + role = _get_auth_role() + source = _get_auth_source() # Check server connectivity try: @@ -3057,5 +2953,5 @@ FreeCADGui.addCommand("Silo_TagProjects", Silo_TagProjects()) FreeCADGui.addCommand("Silo_Rollback", Silo_Rollback()) FreeCADGui.addCommand("Silo_SetStatus", Silo_SetStatus()) FreeCADGui.addCommand("Silo_Settings", Silo_Settings()) -FreeCADGui.addCommand("Silo_ToggleMode", Silo_ToggleMode()) + FreeCADGui.addCommand("Silo_Auth", Silo_Auth()) diff --git a/freecad/silo_origin.py b/freecad/silo_origin.py index d78600c..071c772 100644 --- a/freecad/silo_origin.py +++ b/freecad/silo_origin.py @@ -11,14 +11,13 @@ providing the standardized origin interface. import FreeCAD import FreeCADGui - -from .silo_commands import ( +from silo_commands import ( _client, _sync, + collect_document_properties, + find_file_by_part_number, get_tracked_object, set_silo_properties, - find_file_by_part_number, - collect_document_properties, ) @@ -126,19 +125,35 @@ class SiloOrigin: def connect(self) -> bool: """Trigger authentication if needed. - Shows the Silo authentication dialog if not already authenticated. + Shows the Silo login dialog if not already authenticated. Returns: True if authenticated after this call """ if _client.is_authenticated(): - return True + try: + ok, _ = _client.check_connection() + if ok: + return True + except Exception: + pass - # Show auth dialog via existing Silo_Auth command + # Show login dialog directly try: - cmd = FreeCADGui.Command.get("Silo_Auth") - if cmd: - cmd.Activated() + from PySide import QtWidgets + + mw = FreeCADGui.getMainWindow() + if mw is None: + return False + + # Find or create the auth dock widget and trigger its login dialog + panel = mw.findChild(QtWidgets.QDockWidget, "SiloDatabaseAuth") + if panel and hasattr(panel, "_auth"): + panel._auth._show_login_dialog() + else: + # Fallback: run the Settings command so the user can configure + FreeCADGui.runCommand("Silo_Settings") + return _client.is_authenticated() except Exception as e: FreeCAD.Console.PrintError(f"Silo connect failed: {e}\n") @@ -379,7 +394,9 @@ class SiloOrigin: # Upload to Silo properties = collect_document_properties(doc) - _client._upload_file(obj.SiloPartNumber, str(file_path), properties, comment="") + _client._upload_file( + obj.SiloPartNumber, str(file_path), properties, comment="" + ) # Clear modified flag doc.Modified = False