All checks were successful
Build and Test / build (pull_request) Successful in 1h11m28s
Issue #28: Add version.py.in CMake template that injects KINDRED_CREATE_VERSION at build time, making the Kindred Create version available to Python code via 'from version import VERSION'. Issue #29: Add update_checker.py that queries the Gitea releases API on startup (10s deferred) to check for newer versions. Uses stdlib urllib only, 5s timeout, never blocks the UI. Respects user preferences for check interval, enable/disable, and skipped versions. Logs results to Console for now — UI notification will follow in issue #30. Closes #28 Closes #29
172 lines
5.6 KiB
Python
172 lines
5.6 KiB
Python
# Kindred Create - Core Module
|
|
# GUI initialization - loads ztools and Silo workbenches
|
|
|
|
import os
|
|
import sys
|
|
|
|
import FreeCAD
|
|
import FreeCADGui
|
|
|
|
|
|
def setup_kindred_workbenches():
|
|
"""Load Kindred Create addon workbenches."""
|
|
home = FreeCAD.getHomePath()
|
|
mods_dir = os.path.join(home, "mods")
|
|
|
|
addons = [
|
|
("ztools", "ztools/ztools"),
|
|
("silo", "silo/freecad"),
|
|
]
|
|
|
|
for name, subpath in addons:
|
|
addon_path = os.path.join(mods_dir, subpath)
|
|
if os.path.isdir(addon_path):
|
|
# Ensure path is in sys.path
|
|
if addon_path not in sys.path:
|
|
sys.path.insert(0, addon_path)
|
|
|
|
# Execute InitGui.py if it exists
|
|
init_gui_file = os.path.join(addon_path, "InitGui.py")
|
|
if os.path.isfile(init_gui_file):
|
|
try:
|
|
with open(init_gui_file) as f:
|
|
exec_globals = globals().copy()
|
|
exec_globals["__file__"] = init_gui_file
|
|
exec_globals["__name__"] = name
|
|
exec(
|
|
compile(f.read(), init_gui_file, "exec"),
|
|
exec_globals,
|
|
)
|
|
FreeCAD.Console.PrintLog(f"Create: Loaded {name} workbench\n")
|
|
except Exception as e:
|
|
FreeCAD.Console.PrintWarning(
|
|
f"Create: Failed to load {name} GUI: {e}\n"
|
|
)
|
|
|
|
|
|
setup_kindred_workbenches()
|
|
FreeCAD.Console.PrintLog("Create GUI module initialized\n")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Silo integration enhancements
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def _check_silo_first_start():
|
|
"""Show Silo settings dialog on first startup if not yet configured."""
|
|
try:
|
|
param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/KindredSilo")
|
|
if not param.GetBool("FirstStartChecked", False):
|
|
param.SetBool("FirstStartChecked", True)
|
|
if not param.GetString("ApiUrl", ""):
|
|
FreeCADGui.runCommand("Silo_Settings")
|
|
except Exception as e:
|
|
FreeCAD.Console.PrintLog(f"Create: Silo first-start check skipped: {e}\n")
|
|
|
|
|
|
def _register_silo_origin():
|
|
"""Register Silo as a file origin so the origin selector can offer it."""
|
|
try:
|
|
import silo_commands # noqa: F401 - registers Silo commands
|
|
import silo_origin
|
|
|
|
silo_origin.register_silo_origin()
|
|
except Exception as e:
|
|
FreeCAD.Console.PrintLog(f"Create: Silo origin registration skipped: {e}\n")
|
|
|
|
|
|
def _setup_silo_auth_panel():
|
|
"""Dock the Silo authentication panel in the right-hand side panel."""
|
|
try:
|
|
from PySide import QtCore, QtWidgets
|
|
|
|
mw = FreeCADGui.getMainWindow()
|
|
if mw is None:
|
|
return
|
|
|
|
# Don't create duplicate panels
|
|
if mw.findChild(QtWidgets.QDockWidget, "SiloDatabaseAuth"):
|
|
return
|
|
|
|
import silo_commands
|
|
|
|
auth = silo_commands.SiloAuthDockWidget()
|
|
|
|
panel = QtWidgets.QDockWidget("Database Auth", mw)
|
|
panel.setObjectName("SiloDatabaseAuth")
|
|
panel.setWidget(auth.widget)
|
|
# Keep the auth object alive so its QTimer isn't destroyed while running
|
|
panel._auth = auth
|
|
mw.addDockWidget(QtCore.Qt.RightDockWidgetArea, panel)
|
|
except Exception as e:
|
|
FreeCAD.Console.PrintLog(f"Create: Silo auth panel skipped: {e}\n")
|
|
|
|
|
|
def _setup_silo_activity_panel():
|
|
"""Show a dock widget with recent Silo database activity."""
|
|
try:
|
|
from PySide import QtCore, QtWidgets
|
|
|
|
mw = FreeCADGui.getMainWindow()
|
|
if mw is None:
|
|
return
|
|
|
|
# Don't create duplicate panels
|
|
if mw.findChild(QtWidgets.QDockWidget, "SiloDatabaseActivity"):
|
|
return
|
|
|
|
panel = QtWidgets.QDockWidget("Database Activity", mw)
|
|
panel.setObjectName("SiloDatabaseActivity")
|
|
|
|
widget = QtWidgets.QWidget()
|
|
layout = QtWidgets.QVBoxLayout(widget)
|
|
|
|
activity_list = QtWidgets.QListWidget()
|
|
layout.addWidget(activity_list)
|
|
|
|
try:
|
|
import silo_commands
|
|
|
|
items = silo_commands._client.list_items()
|
|
if isinstance(items, list):
|
|
for item in items[:20]:
|
|
pn = item.get("part_number", "")
|
|
desc = item.get("description", "")
|
|
updated = item.get("updated_at", "")
|
|
if updated:
|
|
updated = updated[:10]
|
|
activity_list.addItem(f"{pn} - {desc} - {updated}")
|
|
if activity_list.count() == 0:
|
|
activity_list.addItem("(No items in database)")
|
|
except Exception:
|
|
activity_list.addItem("(Unable to connect to Silo database)")
|
|
|
|
panel.setWidget(widget)
|
|
mw.addDockWidget(QtCore.Qt.RightDockWidgetArea, panel)
|
|
except Exception as e:
|
|
FreeCAD.Console.PrintLog(f"Create: Silo activity panel skipped: {e}\n")
|
|
|
|
|
|
def _check_for_updates():
|
|
"""Check for application updates in the background."""
|
|
try:
|
|
from update_checker import _run_update_check
|
|
|
|
_run_update_check()
|
|
except Exception as e:
|
|
FreeCAD.Console.PrintLog(f"Create: Update check skipped: {e}\n")
|
|
|
|
|
|
# Defer enhancements until the GUI event loop is running
|
|
try:
|
|
from PySide.QtCore import QTimer
|
|
|
|
QTimer.singleShot(1500, _register_silo_origin)
|
|
QTimer.singleShot(2000, _setup_silo_auth_panel)
|
|
QTimer.singleShot(3000, _check_silo_first_start)
|
|
QTimer.singleShot(4000, _setup_silo_activity_panel)
|
|
QTimer.singleShot(10000, _check_for_updates)
|
|
except Exception:
|
|
pass
|