Addon Manager: Auto-create toolbar button

When installing a macro, prompt user to install a toolbar button
automatically. Fills in the details of the button using the macro's
metadata, including an icon if the __icon__ metadata variable points to
a file.

Also:
* Support XPM data for macro icon
* Support online icons
* Fix bug in macro uninstall
* Cleaned up macro code
This commit is contained in:
Chris Hennes
2022-02-14 21:57:56 -06:00
parent 3be45f4087
commit 1a7fcd575e
9 changed files with 696 additions and 37 deletions

View File

@@ -41,6 +41,10 @@ import AddonManager_rc
from package_list import PackageList, PackageListItemModel
from package_details import PackageDetails
from AddonManagerRepo import AddonManagerRepo
from install_to_toolbar import (
ask_to_install_toolbar_button,
remove_custom_toolbar_button,
)
from NetworkManager import HAVE_QTNETWORK, InitializeNetworkManager
@@ -839,8 +843,27 @@ class CommandAddonManager:
path += "_workbench_icon.svg"
default_icon = QtGui.QIcon(":/icons/document-package.svg")
elif repo.repo_type == AddonManagerRepo.RepoType.MACRO:
path += "_macro_icon.svg"
default_icon = QtGui.QIcon(":/icons/document-python.svg")
if repo.macro and repo.macro.icon:
if os.path.isabs(repo.macro.icon):
path = repo.macro.icon
default_icon = QtGui.QIcon(":/icons/document-python.svg")
else:
path = os.path.join(
os.path.dirname(repo.macro.src_filename), repo.macro.icon
)
default_icon = QtGui.QIcon(":/icons/document-python.svg")
elif repo.macro and repo.macro.xpm:
cache_path = FreeCAD.getUserCachePath()
am_path = os.path.join(cache_path, "AddonManager", "MacroIcons")
os.makedirs(am_path, exist_ok=True)
path = os.path.join(am_path, repo.name + "_icon.xpm")
if not os.path.exists(path):
with open(path, "w") as f:
f.write(repo.macro.xpm)
default_icon = QtGui.QIcon(repo.macro.xpm)
else:
path += "_macro_icon.svg"
default_icon = QtGui.QIcon(":/icons/document-python.svg")
elif repo.repo_type == AddonManagerRepo.RepoType.PACKAGE:
# The cache might not have been downloaded yet, check to see if it's there...
if os.path.isfile(repo.get_cached_icon_filename()):
@@ -1399,6 +1422,8 @@ class CommandAddonManager:
repo.set_status(AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE)
self.item_model.reload_item(repo)
self.packageDetails.show_repo(repo)
if repo.repo_type == AddonManagerRepo.RepoType.MACRO:
ask_to_install_toolbar_button(repo)
def on_installation_failed(self, _: AddonManagerRepo, message: str) -> None:
self.hide_progress_widgets()
@@ -1526,13 +1551,24 @@ class CommandAddonManager:
elif repo.repo_type == AddonManagerRepo.RepoType.MACRO:
macro = repo.macro
if macro.remove():
remove_custom_toolbar_button(repo)
FreeCAD.Console.PrintMessage(
translate("AddonsInstaller", "Successfully uninstalled {}").format(
repo.name
)
+ "\n"
)
self.item_model.update_item_status(
repo.name, AddonManagerRepo.UpdateStatus.NOT_INSTALLED
)
self.packageDetails.show_repo(repo)
else:
self.dialog.textBrowserReadMe.setText(
translate("AddonsInstaller", "Macro could not be removed.")
FreeCAD.Console.PrintMessage(
translate(
"AddonsInstaller",
"Failed to uninstall {}. Please remove manually.",
).format(repo.name)
+ "\n"
)

View File

@@ -3,27 +3,30 @@ IF (BUILD_GUI)
ENDIF (BUILD_GUI)
SET(AddonManager_SRCS
Init.py
InitGui.py
add_toolbar_button_dialog.ui
AddonManager.py
AddonManagerRepo.py
AddonManager.ui
addonmanager_macro.py
addonmanager_utilities.py
addonmanager_workers.py
AddonManager.ui
AddonManagerOptions.ui
AddonManagerRepo.py
ALLOWED_PYTHON_PACKAGES.txt
change_branch.py
change_branch.ui
first_run.ui
compact_view.py
dependency_resolution_dialog.ui
expanded_view.py
NetworkManager.py
package_list.py
package_details.py
first_run.ui
Init.py
InitGui.py
install_to_toolbar.py
loading.html
NetworkManager.py
package_details.py
package_list.py
TestAddonManagerApp.py
select_toolbar_dialog.ui
)
IF (BUILD_GUI)
LIST(APPEND AddonManager_SRCS TestAddonManagerGui.py)

View File

@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>add_toolbar_button_dialog</class>
<widget class="QDialog" name="add_toolbar_button_dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>257</width>
<height>62</height>
</rect>
</property>
<property name="windowTitle">
<string>Add button?</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Add a toolbar button for this macro?</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="buttonYes">
<property name="text">
<string>Yes</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonNo">
<property name="text">
<string>No</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonNever">
<property name="text">
<string>Never</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonYes</sender>
<signal>clicked()</signal>
<receiver>add_toolbar_button_dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>47</x>
<y>40</y>
</hint>
<hint type="destinationlabel">
<x>128</x>
<y>30</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonNo</sender>
<signal>clicked()</signal>
<receiver>add_toolbar_button_dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>128</x>
<y>40</y>
</hint>
<hint type="destinationlabel">
<x>128</x>
<y>30</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonNever</sender>
<signal>clicked()</signal>
<receiver>add_toolbar_button_dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>209</x>
<y>40</y>
</hint>
<hint type="destinationlabel">
<x>128</x>
<y>30</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -28,11 +28,11 @@ import codecs
import shutil
import time
from urllib.parse import urlparse
import tempfile
from typing import Dict, Tuple, List, Union
import FreeCAD
import NetworkManager
from PySide2 import QtCore
translate = FreeCAD.Qt.translate
@@ -68,6 +68,7 @@ class Macro(object):
self.src_filename = ""
self.author = ""
self.icon = ""
self.xpm = "" # Possible alternate icon data
self.other_files = []
self.parsed = False
@@ -115,9 +116,9 @@ class Macro(object):
# __Files__
# __Author__
# __Date__
# __Icon__
max_lines_to_search = 200
line_counter = 0
ic = re.IGNORECASE # Shorten the line for Black
string_search_mapping = {
"__comment__": "comment",
@@ -127,23 +128,29 @@ class Macro(object):
"__author__": "author",
"__date__": "date",
"__icon__": "icon",
"__xpm__": "xpm",
}
string_search_regex = re.compile(r"\s*(['\"])(.*)\1")
f = io.StringIO(code)
while f and line_counter < max_lines_to_search:
line = f.readline()
if not line:
break
if QtCore.QThread.currentThread().isInterruptionRequested():
return
line_counter += 1
# if not line.startswith("__"):
# # Speed things up a bit... this comparison is very cheap
# continue
if not line.startswith("__"):
# Speed things up a bit... this comparison is very cheap
continue
lowercase_line = line.lower()
for key, value in string_search_mapping.items():
if lowercase_line.startswith(key):
_, _, after_equals = line.partition("=")
match = re.match(string_search_regex, after_equals)
if match:
# We do NOT support triple-quoted strings, except for the icon XPM data
if match and '"""' not in after_equals:
if type(self.__dict__[value]) == str:
self.__dict__[value] = match.group(2)
elif type(self.__dict__[value]) == list:
@@ -177,6 +184,32 @@ class Macro(object):
)
self.version = str(after_equals).strip()
break
elif key == "__icon__" or key == "__xpm__":
# If this is an icon, it's possible that the icon was actually directly specified
# in the file as XPM data. This data **must** be between triple double quotes in
# order for the Addon Manager to recognize it.
if '"""' in after_equals:
_, _, xpm_data = after_equals.partition('"""')
while True:
line = f.readline()
if not line:
FreeCAD.Console.PrintError(
translate(
"AddonsInstaller",
"Syntax error while reading {} from macro {}",
).format(key, self.name)
+ "\n"
)
break
if '"""' in line:
last_line, _, _ = line.partition('"""')
xpm_data += last_line
break
else:
xpm_data += line
self.xpm = xpm_data
break
FreeCAD.Console.PrintError(
translate(
"AddonsInstaller",
@@ -273,6 +306,27 @@ class Macro(object):
self.author = self.parse_desc("Author: ")
if not self.date:
self.date = self.parse_desc("Last modified: ")
if self.icon.startswith("http://") or self.icon.startswith("https://"):
# Technically we don't claim to support this, but some macro authors are
# doing it anyway, so let's give it a shot...
FreeCAD.Console.PrintMessage(
translate(
"AddonsInstaller", "Attempting to fetch macro icon from {}"
).format(self.icon)
+ "\n"
)
p = NetworkManager.AM_NETWORK_MANAGER.blocking_get(self.icon)
if p:
cache_path = FreeCAD.getUserCachePath()
am_path = os.path.join(cache_path, "AddonManager", "MacroIcons")
os.makedirs(am_path, exist_ok=True)
_, _, filename = self.icon.rpartition("/")
base, _, extension = filename.rpartition(".")
constructed_name = os.path.join(am_path, base + "." + extension)
with open(constructed_name, "wb") as f:
f.write(p.data())
self.icon_source = self.icon
self.icon = constructed_name
def parse_desc(self, line_start: str) -> Union[str, None]:
components = self.desc.split(">")
@@ -306,15 +360,43 @@ class Macro(object):
# self.src_filename.
base_dir = os.path.dirname(self.src_filename)
warnings = []
if self.xpm:
xpm_file = os.path.join(base_dir, self.name + "_icon.xpm")
with open(xpm_file, "w") as f:
f.write(self.xpm)
if self.icon:
if os.path.isabs(self.icon):
dst_file = os.path.normpath(
os.path.join(macro_dir, os.path.basename(self.icon))
)
try:
shutil.copy(self.icon, dst_file)
except IOError:
warnings.append(f"Failed to copy icon to {dst_file}")
elif self.icon not in self.other_files:
self.other_files.append(self.icon)
for other_file in self.other_files:
dst_dir = os.path.join(macro_dir, os.path.dirname(other_file))
if not other_file:
continue
if os.path.isabs(other_file):
dst_dir = macro_dir
else:
dst_dir = os.path.join(macro_dir, os.path.dirname(other_file))
if not os.path.isdir(dst_dir):
try:
os.makedirs(dst_dir)
except OSError:
return False, [f"Failed to create {dst_dir}"]
src_file = os.path.normpath(os.path.join(base_dir, other_file))
dst_file = os.path.normpath(os.path.join(macro_dir, other_file))
if os.path.isabs(other_file):
src_file = other_file
dst_file = os.path.normpath(
os.path.join(macro_dir, os.path.basename(other_file))
)
else:
src_file = os.path.normpath(os.path.join(base_dir, other_file))
dst_file = os.path.normpath(os.path.join(macro_dir, other_file))
if not os.path.isfile(src_file):
warnings.append(
translate(
@@ -351,19 +433,35 @@ class Macro(object):
os.remove(macro_path_with_macro_prefix)
# Remove related files, which are supposed to be given relative to
# self.src_filename.
if self.xpm:
xpm_file = os.path.join(macro_dir, self.name + "_icon.xpm")
if os.path.exists(xpm_file):
os.remove(xpm_file)
for other_file in self.other_files:
if not other_file:
continue
FreeCAD.Console.PrintMessage(f"{other_file}...")
dst_file = os.path.join(macro_dir, other_file)
if not dst_file or not os.path.exists(dst_file):
FreeCAD.Console.PrintMessage(f"X\n")
continue
try:
os.remove(dst_file)
remove_directory_if_empty(os.path.dirname(dst_file))
FreeCAD.Console.PrintMessage("\n")
except Exception:
FreeCAD.Console.PrintWarning(
translate(
"AddonsInstaller",
"Failed to remove macro file '{}': it might not exist, or its permissions changed",
).format(dst_file)
+ "\n"
)
FreeCAD.Console.PrintMessage(f"?\n")
if os.path.isabs(self.icon):
dst_file = os.path.normpath(
os.path.join(macro_dir, os.path.basename(self.icon))
)
if os.path.exists(dst_file):
try:
FreeCAD.Console.PrintMessage(f"{os.path.basename(self.icon)}...")
os.remove(dst_file)
FreeCAD.Console.PrintMessage("\n")
except Exception:
FreeCAD.Console.PrintMessage(f"?\n")
return True

View File

@@ -528,7 +528,7 @@ class UpdateChecker:
macro_wrapper.macro.fill_details_from_file(
macro_wrapper.macro.src_filename
)
if not macro_wrapper.macro.parsed and macro_wrapper.macro.on_wiki:
elif not macro_wrapper.macro.parsed and macro_wrapper.macro.on_wiki:
mac = macro_wrapper.macro.name.replace(" ", "_")
mac = mac.replace("&", "%26")
mac = mac.replace("+", "%2B")
@@ -647,7 +647,7 @@ class FillMacroListWorker(QtCore.QThread):
except Exception as e:
FreeCAD.Console.PrintWarning(
translate(
"AddonsInstaller", "An error occurred fetching macros from GitHub"
"AddonsInstaller", "An error occurred updating macros from GitHub"
)
+ f":\n{e}\n"
)

View File

@@ -0,0 +1,278 @@
# ***************************************************************************
# * *
# * Copyright (c) 2022 FreeCAD Project Association *
# * *
# * This program is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Lesser General Public *
# * License as published by the Free Software Foundation; either *
# * version 2.1 of the License, or (at your option) any later version. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
# * Lesser General Public License for more details. *
# * *
# * You should have received a copy of the GNU Lesser General Public *
# * License along with this library; if not, write to the Free Software *
# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
# * 02110-1301 USA *
# * *
# ***************************************************************************
import FreeCAD
import FreeCADGui
from PySide2 import QtCore, QtWidgets
import AddonManagerRepo
import os
translate = FreeCAD.Qt.translate
def ask_to_install_toolbar_button(repo: AddonManagerRepo) -> None:
pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons")
do_not_show_dialog = pref.GetBool("dontShowAddMacroButtonDialog", False)
if not do_not_show_dialog:
add_toolbar_button_dialog = FreeCADGui.PySideUic.loadUi(
os.path.join(os.path.dirname(__file__), "add_toolbar_button_dialog.ui")
)
add_toolbar_button_dialog.buttonYes.clicked.connect(
lambda: install_toolbar_button(repo)
)
add_toolbar_button_dialog.buttonNever.clicked.connect(
lambda: pref.SetBool("dontShowAddMacroButtonDialog", True)
)
add_toolbar_button_dialog.exec()
def ask_for_toolbar(
repo: AddonManagerRepo, custom_toolbars
) -> object: # Returns the pref group for the new toolbar
pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons")
# In this one spot, default True: if this is the first time we got to
# this chunk of code, we are always going to ask.
ask = pref.GetBool("alwaysAskForToolbar", True)
if ask:
select_toolbar_dialog = FreeCADGui.PySideUic.loadUi(
os.path.join(os.path.dirname(__file__), "select_toolbar_dialog.ui")
)
select_toolbar_dialog.comboBox.clear()
for group in custom_toolbars:
ref = FreeCAD.ParamGet(
"User parameter:BaseApp/Workbench/Global/Toolbar/" + group
)
name = ref.GetString("Name", "")
if name:
select_toolbar_dialog.comboBox.addItem(name)
else:
FreeCAD.Console.PrintWarning(
f"Custom toolbar {group} does not have a Name element\n"
)
new_menubar_option_text = translate("AddonsInstaller", "Create new toolbar")
select_toolbar_dialog.comboBox.addItem(new_menubar_option_text)
result = select_toolbar_dialog.exec()
if result == QtWidgets.QDialog.Accepted:
selection = select_toolbar_dialog.comboBox.currentText()
if select_toolbar_dialog.checkBox.checkState() == QtCore.Qt.Unchecked:
pref.SetBool("alwaysAskForToolbar", False)
else:
pref.SetBool("alwaysAskForToolbar", True)
if selection == new_menubar_option_text:
return create_new_custom_toolbar()
else:
return get_toolbar_with_name(selection)
else:
return None
else:
custom_toolbar_name = pref.GetString(
"CustomToolbarName", "Auto-Created Macro Toolbar"
)
toolbar = get_toolbar_with_name(custom_toolbar_name)
if not toolbar:
# They told us not to ask, but then the toolbar got deleted... ask anyway!
ask = pref.RemBool("alwaysAskForToolbar")
return ask_for_toolbar(repo, custom_toolbars)
else:
return toolbar
def get_toolbar_with_name(name: str) -> object:
top_group = FreeCAD.ParamGet("User parameter:BaseApp/Workbench/Global/Toolbar")
custom_toolbars = top_group.GetGroups()
for toolbar in custom_toolbars:
group = FreeCAD.ParamGet(
"User parameter:BaseApp/Workbench/Global/Toolbar/" + toolbar
)
group_name = group.GetString("Name", "")
if group_name == name:
return group
return None
def create_new_custom_toolbar() -> object:
# We need two names: the name of the auto-created toolbar, as it will be displayed to the
# user in various menus, and the underlying name of the toolbar group. Both must be
# unique.
# First, the displayed name
custom_toolbar_name = "Auto-Created Macro Toolbar"
pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons")
top_group = FreeCAD.ParamGet("User parameter:BaseApp/Workbench/Global/Toolbar")
custom_toolbars = top_group.GetGroups()
name_taken = check_for_toolbar(custom_toolbars, custom_toolbar_name)
if name_taken:
i = 2 # Don't use (1), start at (2)
while True:
test_name = custom_toolbar_name + f" ({i})"
if not check_for_toolbar(custom_toolbars, test_name):
custom_toolbar_name = test_name
i = i + 1
# Second, the toolbar preference group name
i = 1
while True:
new_group_name = "Custom_" + str(i)
if new_group_name not in custom_toolbars:
break
i = i + 1
custom_toolbar = FreeCAD.ParamGet(
"User parameter:BaseApp/Workbench/Global/Toolbar/" + new_group_name
)
custom_toolbar.SetString("Name", custom_toolbar_name)
custom_toolbar.SetBool("Active", True)
return custom_toolbar
def check_for_toolbar(custom_toolbars, toolbar_name: str) -> bool:
tb = get_toolbar_with_name(toolbar_name)
if tb:
return True
else:
return False
def install_toolbar_button(repo: AddonManagerRepo) -> None:
pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons")
custom_toolbar_name = pref.GetString(
"CustomToolbarName", "Auto-Created Macro Toolbar"
)
# Default to false here: if the variable hasn't been set, we don't assume
# that we have to ask, because the simplest is to just create a new toolbar
# and never ask at all.
ask = pref.GetBool("alwaysAskForToolbar", False)
# See if there is already a custom toolbar for macros:
top_group = FreeCAD.ParamGet("User parameter:BaseApp/Workbench/Global/Toolbar")
custom_toolbars = top_group.GetGroups()
if custom_toolbars:
# If there are already custom toolbars, see if one of them is the one we used last time
found_toolbar = False
for toolbar_name in custom_toolbars:
test_toolbar = FreeCAD.ParamGet(
"User parameter:BaseApp/Workbench/Global/Toolbar/" + toolbar_name
)
name = test_toolbar.GetString("Name", "")
if name == custom_toolbar_name:
custom_toolbar = test_toolbar
found_toolbar = True
break
if ask or not found_toolbar:
# We have to ask the user what to do...
custom_toolbar = ask_for_toolbar(repo, custom_toolbars)
if custom_toolbar:
custom_toolbar_name = custom_toolbar.GetString("Name")
pref.SetString("CustomToolbarName", custom_toolbar_name)
else:
# Create a custom toolbar
custom_toolbar = FreeCAD.ParamGet(
"User parameter:BaseApp/Workbench/Global/Toolbar/Custom_1"
)
custom_toolbar.SetString("Name", custom_toolbar_name)
custom_toolbar.SetBool("Active", True)
if custom_toolbar:
install_macro_to_toolbar(repo, custom_toolbar)
else:
FreeCAD.Console.PrintMessage(
f"In the end, no custom toolbar was set, bailing out\n"
)
def install_macro_to_toolbar(repo: AddonManagerRepo, toolbar: object) -> None:
menuText = repo.display_name
tooltipText = f"<b>{repo.display_name}</b>"
if repo.macro.comment:
tooltipText += f"<br/><p>{repo.macro.comment}</p>"
whatsThisText = repo.macro.comment
else:
whatsThisText = translate(
"AddonsInstaller", "A macro installed with the FreeCAD Addon Manager"
)
statustipText = (
translate("AddonsInstaller", "Run", "Indicates a macro that can be 'run'")
+ " "
+ repo.display_name
)
if repo.macro.icon:
if os.path.isabs(repo.macro.icon):
pixmapText = os.path.normpath(repo.macro.icon)
else:
macro_repo_dir = FreeCAD.getUserMacroDir(True)
pixmapText = os.path.normpath(os.path.join(macro_repo_dir, repo.macro.icon))
elif repo.macro.xpm:
macro_repo_dir = FreeCAD.getUserMacroDir(True)
icon_file = os.path.normpath(
os.path.join(macro_repo_dir, repo.macro.name + "_icon.xpm")
)
with open(icon_file, "w") as f:
f.write(repo.macro.xpm)
pixmapText = icon_file
else:
pixmapText = None
# Add this command to that toolbar
command_name = FreeCADGui.Command.createCustomCommand(
repo.macro.filename,
menuText,
tooltipText,
whatsThisText,
statustipText,
pixmapText,
)
toolbar.SetString(command_name, "FreeCAD")
# Force the toolbars to be recreated
wb = FreeCADGui.activeWorkbench()
wb.reloadActive()
def remove_custom_toolbar_button(repo: AddonManagerRepo) -> None:
"""If this repo contains a macro, look through the custom commands and
see if one is set up for this macro. If so, remove it, including any
toolbar entries."""
command = FreeCADGui.Command.findCustomCommand(repo.macro.filename)
if not command:
return
custom_toolbars = FreeCAD.ParamGet(
"User parameter:BaseApp/Workbench/Global/Toolbar"
)
toolbar_groups = custom_toolbars.GetGroups()
for group in toolbar_groups:
toolbar = custom_toolbars.GetGroup(group)
if toolbar.GetString(command, "*") != "*":
toolbar.RemString(command)
FreeCADGui.Command.removeCustomCommand(command)
# Force the toolbars to be recreated
wb = FreeCADGui.activeWorkbench()
wb.reloadActive()

View File

@@ -146,14 +146,10 @@ class PackageDetails(QWidget):
self.show_package(repo)
self.ui.buttonExecute.hide()
if self.status_update_thread is not None:
if not self.status_update_thread.isFinished():
self.status_update_thread.requestInterruption()
self.status_update_thread.wait()
if repo.status() == AddonManagerRepo.UpdateStatus.UNCHECKED:
self.status_update_thread = QThread()
self.status_update_worker = CheckSingleUpdateWorker(repo, self)
if not self.status_update_thread:
self.status_update_thread = QThread()
self.status_update_worker = CheckSingleUpdateWorker(repo)
self.status_update_worker.moveToThread(self.status_update_thread)
self.status_update_thread.finished.connect(
self.status_update_worker.deleteLater

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>select_toolbar_dialog</class>
<widget class="QDialog" name="select_toolbar_dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>308</width>
<height>109</height>
</rect>
</property>
<property name="windowTitle">
<string>Select Toolbar</string>
</property>
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Select a toolbar to add this macro to:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox"/>
</item>
<item>
<widget class="QCheckBox" name="checkBox">
<property name="text">
<string>Ask every time</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>select_toolbar_dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>select_toolbar_dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>toolbar_button</class>
<widget class="QDialog" name="toolbar_button">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>257</width>
<height>62</height>
</rect>
</property>
<property name="windowTitle">
<string>Add button?</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Add a toolbar button for this macro?</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>Yes</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_3">
<property name="text">
<string>No</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_4">
<property name="text">
<string>Never</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>