FreeCAD
293 строки · 12.4 Кб
1# SPDX-License-Identifier: LGPL-2.1-or-later
2# ***************************************************************************
3# * *
4# * Copyright (c) 2022-2024 The FreeCAD Project Association AISBL *
5# * *
6# * This file is part of FreeCAD. *
7# * *
8# * FreeCAD is free software: you can redistribute it and/or modify it *
9# * under the terms of the GNU Lesser General Public License as *
10# * published by the Free Software Foundation, either version 2.1 of the *
11# * License, or (at your option) any later version. *
12# * *
13# * FreeCAD is distributed in the hope that it will be useful, but *
14# * WITHOUT ANY WARRANTY; without even the implied warranty of *
15# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16# * Lesser General Public License for more details. *
17# * *
18# * You should have received a copy of the GNU Lesser General Public *
19# * License along with FreeCAD. If not, see *
20# * <https://www.gnu.org/licenses/>. *
21# * *
22# ***************************************************************************
23
24""" A collection of functions to handle installing a macro icon to the toolbar. """
25
26import os
27
28import FreeCAD
29import FreeCADGui
30from PySide import QtCore, QtWidgets
31import Addon
32
33translate = FreeCAD.Qt.translate
34
35
36def ask_to_install_toolbar_button(repo: Addon) -> None:
37"""Presents a dialog to the user asking if they want to install a toolbar button for
38a particular macro, and walks through that process if they agree to do so."""
39pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons")
40do_not_show_dialog = pref.GetBool("dontShowAddMacroButtonDialog", False)
41button_exists = check_for_button(repo)
42if not do_not_show_dialog and not button_exists:
43add_toolbar_button_dialog = FreeCADGui.PySideUic.loadUi(
44os.path.join(os.path.dirname(__file__), "add_toolbar_button_dialog.ui")
45)
46add_toolbar_button_dialog.buttonYes.clicked.connect(lambda: install_toolbar_button(repo))
47add_toolbar_button_dialog.buttonNever.clicked.connect(
48lambda: pref.SetBool("dontShowAddMacroButtonDialog", True)
49)
50add_toolbar_button_dialog.exec()
51
52
53def check_for_button(repo: Addon) -> bool:
54"""Returns True if a button already exists for this macro, or False if not."""
55command = FreeCADGui.Command.findCustomCommand(repo.macro.filename)
56if not command:
57return False
58custom_toolbars = FreeCAD.ParamGet("User parameter:BaseApp/Workbench/Global/Toolbar")
59toolbar_groups = custom_toolbars.GetGroups()
60for group in toolbar_groups:
61toolbar = custom_toolbars.GetGroup(group)
62if toolbar.GetString(command, "*") != "*":
63return True
64return False
65
66
67def ask_for_toolbar(repo: Addon, custom_toolbars) -> object:
68"""Determine what toolbar to add the icon to. The first time it is called it prompts the
69user to select or create a toolbar. After that, the prompt is optional and can be configured
70via a preference. Returns the pref group for the new toolbar."""
71pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons")
72
73# In this one spot, default True: if this is the first time we got to
74# this chunk of code, we are always going to ask.
75ask = pref.GetBool("alwaysAskForToolbar", True)
76
77if ask:
78select_toolbar_dialog = FreeCADGui.PySideUic.loadUi(
79os.path.join(os.path.dirname(__file__), "select_toolbar_dialog.ui")
80)
81
82select_toolbar_dialog.comboBox.clear()
83
84for group in custom_toolbars:
85ref = FreeCAD.ParamGet("User parameter:BaseApp/Workbench/Global/Toolbar/" + group)
86name = ref.GetString("Name", "")
87if name:
88select_toolbar_dialog.comboBox.addItem(name)
89else:
90FreeCAD.Console.PrintWarning(
91f"Custom toolbar {group} does not have a Name element\n"
92)
93new_menubar_option_text = translate("AddonsInstaller", "Create new toolbar")
94select_toolbar_dialog.comboBox.addItem(new_menubar_option_text)
95
96result = select_toolbar_dialog.exec()
97if result == QtWidgets.QDialog.Accepted:
98selection = select_toolbar_dialog.comboBox.currentText()
99if select_toolbar_dialog.checkBox.checkState() == QtCore.Qt.Unchecked:
100pref.SetBool("alwaysAskForToolbar", False)
101else:
102pref.SetBool("alwaysAskForToolbar", True)
103if selection == new_menubar_option_text:
104return create_new_custom_toolbar()
105return get_toolbar_with_name(selection)
106return None
107
108# If none of the above code returned...
109custom_toolbar_name = pref.GetString("CustomToolbarName", "Auto-Created Macro Toolbar")
110toolbar = get_toolbar_with_name(custom_toolbar_name)
111if not toolbar:
112# They told us not to ask, but then the toolbar got deleted... ask anyway!
113ask = pref.RemBool("alwaysAskForToolbar")
114return ask_for_toolbar(repo, custom_toolbars)
115return toolbar
116
117
118def get_toolbar_with_name(name: str) -> object:
119"""Try to find a toolbar with a given name. Returns the preference group for the toolbar
120if found, or None if it does not exist."""
121top_group = FreeCAD.ParamGet("User parameter:BaseApp/Workbench/Global/Toolbar")
122custom_toolbars = top_group.GetGroups()
123for toolbar in custom_toolbars:
124group = FreeCAD.ParamGet("User parameter:BaseApp/Workbench/Global/Toolbar/" + toolbar)
125group_name = group.GetString("Name", "")
126if group_name == name:
127return group
128return None
129
130
131def create_new_custom_toolbar() -> object:
132"""Create a new custom toolbar and returns its preference group."""
133
134# We need two names: the name of the auto-created toolbar, as it will be displayed to the
135# user in various menus, and the underlying name of the toolbar group. Both must be
136# unique.
137
138# First, the displayed name
139custom_toolbar_name = "Auto-Created Macro Toolbar"
140top_group = FreeCAD.ParamGet("User parameter:BaseApp/Workbench/Global/Toolbar")
141custom_toolbars = top_group.GetGroups()
142name_taken = check_for_toolbar(custom_toolbar_name)
143if name_taken:
144i = 2 # Don't use (1), start at (2)
145while True:
146test_name = custom_toolbar_name + f" ({i})"
147if not check_for_toolbar(test_name):
148custom_toolbar_name = test_name
149i = i + 1
150
151# Second, the toolbar preference group name
152i = 1
153while True:
154new_group_name = "Custom_" + str(i)
155if new_group_name not in custom_toolbars:
156break
157i = i + 1
158
159custom_toolbar = FreeCAD.ParamGet(
160"User parameter:BaseApp/Workbench/Global/Toolbar/" + new_group_name
161)
162custom_toolbar.SetString("Name", custom_toolbar_name)
163custom_toolbar.SetBool("Active", True)
164return custom_toolbar
165
166
167def check_for_toolbar(toolbar_name: str) -> bool:
168"""Returns True if the toolbar exists, otherwise False"""
169return get_toolbar_with_name(toolbar_name) is not None
170
171
172def install_toolbar_button(repo: Addon) -> None:
173"""If the user has requested a toolbar button be installed, this function is called
174to continue the process and request any additional required information."""
175pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons")
176custom_toolbar_name = pref.GetString("CustomToolbarName", "Auto-Created Macro Toolbar")
177
178# Default to false here: if the variable hasn't been set, we don't assume
179# that we have to ask, because the simplest is to just create a new toolbar
180# and never ask at all.
181ask = pref.GetBool("alwaysAskForToolbar", False)
182
183# See if there is already a custom toolbar for macros:
184top_group = FreeCAD.ParamGet("User parameter:BaseApp/Workbench/Global/Toolbar")
185custom_toolbars = top_group.GetGroups()
186if custom_toolbars:
187# If there are already custom toolbars, see if one of them is the one we used last time
188found_toolbar = False
189for toolbar_name in custom_toolbars:
190test_toolbar = FreeCAD.ParamGet(
191"User parameter:BaseApp/Workbench/Global/Toolbar/" + toolbar_name
192)
193name = test_toolbar.GetString("Name", "")
194if name == custom_toolbar_name:
195custom_toolbar = test_toolbar
196found_toolbar = True
197break
198if ask or not found_toolbar:
199# We have to ask the user what to do...
200custom_toolbar = ask_for_toolbar(repo, custom_toolbars)
201if custom_toolbar:
202custom_toolbar_name = custom_toolbar.GetString("Name")
203pref.SetString("CustomToolbarName", custom_toolbar_name)
204else:
205# Create a custom toolbar
206custom_toolbar = FreeCAD.ParamGet(
207"User parameter:BaseApp/Workbench/Global/Toolbar/Custom_1"
208)
209custom_toolbar.SetString("Name", custom_toolbar_name)
210custom_toolbar.SetBool("Active", True)
211
212if custom_toolbar:
213install_macro_to_toolbar(repo, custom_toolbar)
214else:
215FreeCAD.Console.PrintMessage("In the end, no custom toolbar was set, bailing out\n")
216
217
218def find_installed_icon(repo: Addon) -> str:
219"""The icon the macro specifies is usually not the actual installed icon, but rather a cached
220copy. This function looks for a file with the same name located in the macro installation
221path."""
222macro_repo_dir = FreeCAD.getUserMacroDir(True)
223if repo.macro.icon:
224basename = os.path.basename(repo.macro.icon)
225# Simple case first: the file is just in the macro directory...
226if os.path.isfile(os.path.join(macro_repo_dir, basename)):
227return os.path.join(macro_repo_dir, basename)
228# More complex: search for it
229for root, dirs, files in os.walk(macro_repo_dir):
230for name in files:
231if name == basename:
232return os.path.join(root, name)
233return ""
234elif repo.macro.xpm:
235return os.path.normpath(os.path.join(macro_repo_dir, repo.macro.name + "_icon.xpm"))
236else:
237return ""
238
239
240def install_macro_to_toolbar(repo: Addon, toolbar: object) -> None:
241"""Adds an icon for the given macro to the given toolbar."""
242menuText = repo.display_name
243tooltipText = f"<b>{repo.display_name}</b>"
244if repo.macro.comment:
245tooltipText += f"<br/><p>{repo.macro.comment}</p>"
246whatsThisText = repo.macro.comment
247else:
248whatsThisText = translate(
249"AddonsInstaller", "A macro installed with the FreeCAD Addon Manager"
250)
251statustipText = (
252translate("AddonsInstaller", "Run", "Indicates a macro that can be 'run'")
253+ " "
254+ repo.display_name
255)
256pixmapText = find_installed_icon(repo)
257
258# Add this command to that toolbar
259command_name = FreeCADGui.Command.createCustomCommand(
260repo.macro.filename,
261menuText,
262tooltipText,
263whatsThisText,
264statustipText,
265pixmapText,
266)
267toolbar.SetString(command_name, "FreeCAD")
268
269# Force the toolbars to be recreated
270wb = FreeCADGui.activeWorkbench()
271wb.reloadActive()
272
273
274def remove_custom_toolbar_button(repo: Addon) -> None:
275"""If this repo contains a macro, look through the custom commands and
276see if one is set up for this macro. If so, remove it, including any
277toolbar entries."""
278
279command = FreeCADGui.Command.findCustomCommand(repo.macro.filename)
280if not command:
281return
282custom_toolbars = FreeCAD.ParamGet("User parameter:BaseApp/Workbench/Global/Toolbar")
283toolbar_groups = custom_toolbars.GetGroups()
284for group in toolbar_groups:
285toolbar = custom_toolbars.GetGroup(group)
286if toolbar.GetString(command, "*") != "*":
287toolbar.RemString(command)
288
289FreeCADGui.Command.removeCustomCommand(command)
290
291# Force the toolbars to be recreated
292wb = FreeCADGui.activeWorkbench()
293wb.reloadActive()
294