1
- #!/usr/bin/env python3
2
-
3
1
# SPDX-License-Identifier: LGPL-2.1-or-later
4
2
# ***************************************************************************
5
3
# * *
6
- # * Copyright (c) 2022-2023 FreeCAD Project Association *
4
+ # * Copyright (c) 2022-2025 The FreeCAD project association AISBL *
7
5
# * Copyright (c) 2015 Yorik van Havre <yorik@uncreated.net> *
8
6
# * *
9
7
# * This file is part of FreeCAD. *
32
30
from datetime import date
33
31
from typing import Dict
34
32
35
- from PySide import QtGui , QtCore , QtWidgets
36
- from PySide .QtGui import QDesktopServices
37
- from PySide .QtCore import QUrl
38
-
39
- import FreeCAD
40
- import FreeCADGui
33
+ from PySideWrapper import QtGui , QtCore , QtWidgets
41
34
42
35
from addonmanager_workers_startup import (
43
36
CreateAddonListWorker ,
75
68
76
69
from AddonManagerOptions import AddonManagerOptions
77
70
78
- translate = FreeCAD . Qt .translate
71
+ translate = fci .translate
79
72
80
73
81
74
def QT_TRANSLATE_NOOP (_ , txt ):
@@ -129,7 +122,7 @@ def get_icon(repo: Addon, update: bool = False) -> QtGui.QIcon:
129
122
path = os .path .join (os .path .dirname (repo .macro .src_filename ), repo .macro .icon )
130
123
default_icon = QtGui .QIcon (":/icons/document-python.svg" )
131
124
elif repo .macro and repo .macro .xpm :
132
- cache_path = FreeCAD . getUserCachePath ()
125
+ cache_path = fci . DataPaths (). cache_dir
133
126
am_path = os .path .join (cache_path , "AddonManager" , "MacroIcons" )
134
127
os .makedirs (am_path , exist_ok = True )
135
128
path = os .path .join (am_path , repo .name + "_icon.xpm" )
@@ -188,10 +181,11 @@ def __init__(self):
188
181
super ().__init__ ()
189
182
190
183
QT_TRANSLATE_NOOP ("QObject" , "Addon Manager" )
191
- FreeCADGui .addPreferencePage (
192
- AddonManagerOptions ,
193
- "Addon Manager" ,
194
- )
184
+ if fci .GuiUp :
185
+ fci .addPreferencePage (
186
+ AddonManagerOptions ,
187
+ "Addon Manager" ,
188
+ )
195
189
196
190
self .item_model = None
197
191
self .developer_mode = None
@@ -254,28 +248,25 @@ def launch(self) -> None:
254
248
"""Shows the Addon Manager UI"""
255
249
256
250
# create the dialog
257
- self .dialog = FreeCADGui .PySideUic .loadUi (
258
- os .path .join (os .path .dirname (__file__ ), "AddonManager.ui" )
259
- )
251
+ self .dialog = fci .loadUi (os .path .join (os .path .dirname (__file__ ), "AddonManager.ui" ))
260
252
self .dialog .setObjectName ("AddonManager_Main_Window" )
261
253
# self.dialog.setWindowFlag(QtCore.Qt.WindowStaysOnTopHint, True)
262
254
263
255
# cleanup the leftovers from previous runs
264
- self .macro_repo_dir = FreeCAD . getUserMacroDir ( True )
256
+ self .macro_repo_dir = fci . DataPaths (). macro_dir
265
257
self .packages_with_updates = set ()
266
258
self .startup_sequence = []
267
259
self .cleanup_workers ()
268
260
self .update_cache = local_cache_needs_update ()
269
261
270
262
# restore window geometry from stored state
271
- pref = FreeCAD .ParamGet ("User parameter:BaseApp/Preferences/Addons" )
272
- w = pref .GetInt ("WindowWidth" , 800 )
273
- h = pref .GetInt ("WindowHeight" , 600 )
263
+ w = fci .Preferences ().get ("WindowWidth" )
264
+ h = fci .Preferences ().get ("WindowHeight" )
274
265
self .composite_view = CompositeView (self .dialog )
275
266
self .button_bar = WidgetGlobalButtonBar (self .dialog )
276
267
277
268
# If we are checking for updates automatically, hide the Check for updates button:
278
- autocheck = pref . GetBool ( "AutoCheck" , True )
269
+ autocheck = fci . Preferences (). get ( "AutoCheck" )
279
270
if autocheck :
280
271
self .button_bar .check_for_updates .hide ()
281
272
else :
@@ -290,8 +281,7 @@ def launch(self) -> None:
290
281
# set nice icons to everything, by theme with fallback to FreeCAD icons
291
282
self .dialog .setWindowIcon (QtGui .QIcon (":/icons/AddonManager.svg" ))
292
283
293
- pref = FreeCAD .ParamGet ("User parameter:BaseApp/Preferences/Addons" )
294
- dev_mode_active = pref .GetBool ("developerMode" , False )
284
+ dev_mode_active = fci .Preferences ().get ("developerMode" )
295
285
296
286
# enable/disable stuff
297
287
self .button_bar .update_all_addons .setEnabled (False )
@@ -323,12 +313,13 @@ def launch(self) -> None:
323
313
self .composite_view .update .connect (self .update )
324
314
self .composite_view .update_status .connect (self .status_updated )
325
315
326
- # center the dialog over the FreeCAD window
316
+ # center the dialog over the FreeCAD window, if it exists
327
317
self .dialog .resize (w , h )
328
- mw = FreeCADGui .getMainWindow ()
329
- self .dialog .move (
330
- mw .frameGeometry ().topLeft () + mw .rect ().center () - self .dialog .rect ().center ()
331
- )
318
+ if fci .FreeCADGui :
319
+ mw = fci .FreeCADGui .getMainWindow ()
320
+ self .dialog .move (
321
+ mw .frameGeometry ().topLeft () + mw .rect ().center () - self .dialog .rect ().center ()
322
+ )
332
323
333
324
# begin populating the table in a set of sub-threads
334
325
self .startup ()
@@ -353,7 +344,7 @@ def cleanup_workers(self) -> None:
353
344
if not thread .isFinished ():
354
345
finished = thread .wait (500 )
355
346
if not finished :
356
- FreeCAD .Console .PrintWarning (
347
+ fci .Console .PrintWarning (
357
348
translate (
358
349
"AddonsInstaller" ,
359
350
"Worker process {} is taking a long time to stop..." ,
@@ -368,9 +359,8 @@ def reject(self) -> None:
368
359
"""called when the window has been closed"""
369
360
370
361
# save window geometry for next use
371
- pref = FreeCAD .ParamGet ("User parameter:BaseApp/Preferences/Addons" )
372
- pref .SetInt ("WindowWidth" , self .dialog .width ())
373
- pref .SetInt ("WindowHeight" , self .dialog .height ())
362
+ fci .Preferences ().set ("WindowWidth" , self .dialog .width ())
363
+ fci .Preferences ().set ("WindowHeight" , self .dialog .height ())
374
364
375
365
# ensure all threads are finished before closing
376
366
ok_to_close = True
@@ -407,7 +397,7 @@ def reject(self) -> None:
407
397
self .write_macro_cache ()
408
398
else :
409
399
self .write_cache_stopfile ()
410
- FreeCAD .Console .PrintLog (
400
+ fci .Console .PrintLog (
411
401
"Not writing the cache because a process was forcibly terminated and the state is "
412
402
"unknown.\n "
413
403
)
@@ -478,8 +468,7 @@ def startup(self) -> None:
478
468
self .fetch_addon_score ,
479
469
self .select_addon ,
480
470
]
481
- pref = FreeCAD .ParamGet ("User parameter:BaseApp/Preferences/Addons" )
482
- if pref .GetBool ("DownloadMacros" , True ):
471
+ if fci .Preferences ().get ("DownloadMacros" ):
483
472
self .startup_sequence .append (self .load_macro_metadata )
484
473
self .number_of_progress_regions = len (self .startup_sequence )
485
474
self .current_progress_region = 0
@@ -499,8 +488,7 @@ def do_next_startup_phase(self) -> None:
499
488
self .button_bar .refresh_local_cache .setText (
500
489
translate ("AddonsInstaller" , "Refresh local cache" )
501
490
)
502
- pref = FreeCAD .ParamGet ("User parameter:BaseApp/Preferences/Addons" )
503
- pref .SetString ("LastCacheUpdate" , date .today ().isoformat ())
491
+ fci .Preferences ().set ("LastCacheUpdate" , date .today ().isoformat ())
504
492
self .composite_view .package_list .item_filter .invalidateFilter ()
505
493
506
494
def populate_packages_table (self ) -> None :
@@ -595,7 +583,7 @@ def cache_macro(self, repo: Addon):
595
583
if repo .macro is not None :
596
584
self .macro_cache .append (repo .macro .to_cache ())
597
585
else :
598
- FreeCAD .Console .PrintError (
586
+ fci .Console .PrintError (
599
587
f"Addon Manager: Internal error, cache_macro called on non-macro { repo .name } \n "
600
588
)
601
589
@@ -621,7 +609,7 @@ def update_metadata_cache(self) -> None:
621
609
622
610
def on_button_update_cache_clicked (self ) -> None :
623
611
self .update_cache = True
624
- cache_path = FreeCAD . getUserCachePath ()
612
+ cache_path = fci . DataPaths (). cache_dir
625
613
am_path = os .path .join (cache_path , "AddonManager" )
626
614
utils .rmdir (am_path )
627
615
self .button_bar .refresh_local_cache .setEnabled (False )
@@ -663,10 +651,9 @@ def select_addon(self) -> None:
663
651
def check_updates (self ) -> None :
664
652
"""checks every installed addon for available updates"""
665
653
666
- pref = FreeCAD .ParamGet ("User parameter:BaseApp/Preferences/Addons" )
667
- autocheck = pref .GetBool ("AutoCheck" , True )
654
+ autocheck = fci .Preferences ().get ("AutoCheck" )
668
655
if not autocheck :
669
- FreeCAD .Console .PrintLog (
656
+ fci .Console .PrintLog (
670
657
"Addon Manager: Skipping update check because AutoCheck user preference is False\n "
671
658
)
672
659
self .do_next_startup_phase ()
@@ -740,8 +727,7 @@ def show_python_updates_dialog(self) -> None:
740
727
741
728
def fetch_addon_stats (self ) -> None :
742
729
"""Fetch the Addon Stats JSON data from a URL"""
743
- pref = FreeCAD .ParamGet ("User parameter:BaseApp/Preferences/Addons" )
744
- url = pref .GetString ("AddonsStatsURL" , "https://freecad.org/addon_stats.json" )
730
+ url = fci .Preferences ().get ("AddonsStatsURL" )
745
731
if url and url != "NONE" :
746
732
self .get_basic_addon_stats_worker = GetBasicAddonStatsWorker (
747
733
url , self .item_model .repos , self .dialog
@@ -815,7 +801,7 @@ def mark_repo_update_available(self, repo: Addon, available: bool) -> None:
815
801
816
802
def launch_installer_gui (self , addon : Addon ) -> None :
817
803
if self .installer_gui is not None :
818
- FreeCAD .Console .PrintError (
804
+ fci .Console .PrintError (
819
805
translate (
820
806
"AddonsInstaller" ,
821
807
"Cannot launch a new installer until the previous one has finished." ,
@@ -841,7 +827,7 @@ def update_all(self) -> None:
841
827
stop other updates"""
842
828
843
829
if self .installer_gui is not None :
844
- FreeCAD .Console .PrintError (
830
+ fci .Console .PrintError (
845
831
translate (
846
832
"AddonsInstaller" ,
847
833
"Cannot launch a new installer until the previous one has finished." ,
@@ -912,32 +898,36 @@ def on_package_status_changed(self, repo: Addon) -> None:
912
898
def execute_macro (self , repo : Addon ) -> None :
913
899
"""executes a selected macro"""
914
900
901
+ if not fci .FreeCADGui :
902
+ fci .Console .PrintError ("Cannot execute a FreeCAD Macro outside FreeCAD" )
903
+ return
904
+
915
905
macro = repo .macro
916
906
if not macro or not macro .code :
917
907
return
918
908
919
909
if macro .is_installed ():
920
910
macro_path = os .path .join (self .macro_repo_dir , macro .filename )
921
- FreeCADGui .open (str (macro_path ))
911
+ fci . FreeCADGui .open (str (macro_path ))
922
912
self .dialog .hide ()
923
- FreeCADGui .SendMsgToActiveView ("Run" )
913
+ fci . FreeCADGui .SendMsgToActiveView ("Run" )
924
914
else :
925
915
with tempfile .TemporaryDirectory () as temp_dir :
926
916
temp_install_succeeded = macro .install (temp_dir )
927
917
if not temp_install_succeeded :
928
- FreeCAD .Console .PrintError (
918
+ fci .Console .PrintError (
929
919
translate ("AddonsInstaller" , "Temporary installation of macro failed." )
930
920
)
931
921
return
932
922
macro_path = os .path .join (temp_dir , macro .filename )
933
- FreeCADGui .open (str (macro_path ))
923
+ fci . FreeCADGui .open (str (macro_path ))
934
924
self .dialog .hide ()
935
- FreeCADGui .SendMsgToActiveView ("Run" )
925
+ fci . FreeCADGui .SendMsgToActiveView ("Run" )
936
926
937
927
def remove (self , addon : Addon ) -> None :
938
928
"""Remove this addon."""
939
929
if self .installer_gui is not None :
940
- FreeCAD .Console .PrintError (
930
+ fci .Console .PrintError (
941
931
translate (
942
932
"AddonsInstaller" ,
943
933
"Cannot launch a new installer until the previous one has finished." ,
@@ -953,7 +943,7 @@ def remove(self, addon: Addon) -> None:
953
943
954
944
def open_addons_folder (self ):
955
945
addons_folder = fci .DataPaths ().mod_dir
956
- QDesktopServices .openUrl (QUrl .fromLocalFile (addons_folder ))
946
+ QtGui . QDesktopServices .openUrl (QtCore . QUrl .fromLocalFile (addons_folder ))
957
947
return
958
948
959
949
0 commit comments