diff --git a/src/Mod/AddonManager/AddonManagerOptions.ui b/src/Mod/AddonManager/AddonManagerOptions.ui
index b701f63f06..e022702023 100644
--- a/src/Mod/AddonManager/AddonManagerOptions.ui
+++ b/src/Mod/AddonManager/AddonManagerOptions.ui
@@ -77,6 +77,38 @@ installed addons will be checked for available updates
+ -
+
+
+ Hide Addons marked Python 2 Only
+
+
+ true
+
+
+ HidePy2
+
+
+ Addons
+
+
+
+ -
+
+
+ Hide Addons marked Obsolete
+
+
+ true
+
+
+ HideObsolete
+
+
+ Addons
+
+
+
-
@@ -128,9 +160,9 @@ of the line after a space (e.g. https://github.com/FreeCAD/FreeCAD master).
No proxy
-
- true
-
+
+ true
+
NoProxyCheck
diff --git a/src/Mod/AddonManager/AddonManagerRepo.py b/src/Mod/AddonManager/AddonManagerRepo.py
index 2363ee6640..5dfbb3439f 100644
--- a/src/Mod/AddonManager/AddonManagerRepo.py
+++ b/src/Mod/AddonManager/AddonManagerRepo.py
@@ -76,6 +76,9 @@ class AddonManagerRepo:
self.url = url.strip()
self.branch = branch.strip()
self.update_status = status
+ self.python2 = False
+ self.obsolete = False
+ self.rejected = False
self.repo_type = AddonManagerRepo.RepoType.WORKBENCH
self.description = None
from addonmanager_utilities import construct_git_url
@@ -114,19 +117,22 @@ class AddonManagerRepo:
return instance
@classmethod
- def from_cache(self, data: Dict):
+ def from_cache(self, cache_dict: Dict):
"""Load basic data from cached dict data. Does not include Macro or Metadata information, which must be populated separately."""
- mod_dir = os.path.join(FreeCAD.getUserAppDataDir(), "Mod", data["name"])
+ mod_dir = os.path.join(FreeCAD.getUserAppDataDir(), "Mod", cache_dict["name"])
if os.path.isdir(mod_dir):
status = AddonManagerRepo.UpdateStatus.UNCHECKED
else:
status = AddonManagerRepo.UpdateStatus.NOT_INSTALLED
- instance = AddonManagerRepo(data["name"], data["url"], status, data["branch"])
- instance.display_name = data["display_name"]
- instance.repo_type = AddonManagerRepo.RepoType(data["repo_type"])
- instance.description = data["description"]
- instance.cached_icon_filename = data["cached_icon_filename"]
+ instance = AddonManagerRepo(
+ cache_dict["name"], cache_dict["url"], status, cache_dict["branch"]
+ )
+
+ for key, value in cache_dict.items():
+ instance.__dict__[key] = value
+
+ instance.repo_type = AddonManagerRepo.RepoType(cache_dict["repo_type"])
if instance.repo_type == AddonManagerRepo.RepoType.PACKAGE:
# There must be a cached metadata file, too
cached_package_xml_file = os.path.join(
@@ -150,6 +156,9 @@ class AddonManagerRepo:
"repo_type": int(self.repo_type),
"description": self.description,
"cached_icon_filename": self.get_cached_icon_filename(),
+ "python2": self.python2,
+ "obsolete": self.obsolete,
+ "rejected": self.rejected,
}
def load_metadata_file(self, file: str) -> None:
diff --git a/src/Mod/AddonManager/addonmanager_workers.py b/src/Mod/AddonManager/addonmanager_workers.py
index b6adc02a08..1460301b11 100644
--- a/src/Mod/AddonManager/addonmanager_workers.py
+++ b/src/Mod/AddonManager/addonmanager_workers.py
@@ -81,6 +81,7 @@ except ImportError:
# reject_listed addons
macros_reject_list = []
+mod_reject_list = []
# These addons will print an additional message informing the user
obsolete = []
@@ -110,7 +111,7 @@ class UpdateWorker(QtCore.QThread):
self.current_thread = QtCore.QThread.currentThread()
# update info lists
- global obsolete, macros_reject_list, py2only
+ global obsolete, macros_reject_list, mod_reject_list, py2only
u = utils.urlopen(
"https://raw.githubusercontent.com/FreeCAD/FreeCAD-addons/master/addonflags.json"
)
@@ -124,6 +125,9 @@ class UpdateWorker(QtCore.QThread):
if "blacklisted" in j and "Macro" in j["blacklisted"]:
macros_reject_list = j["blacklisted"]["Macro"]
+ if "blacklisted" in j and "Mod" in j["blacklisted"]:
+ mod_reject_list = j["blacklisted"]["Mod"]
+
if "py2only" in j and "Mod" in j["py2only"]:
py2only = j["py2only"]["Mod"]
else:
@@ -223,6 +227,12 @@ class UpdateWorker(QtCore.QThread):
repo.load_metadata_file(md_file)
repo.installed_version = repo.metadata.Version
repo.updated_timestamp = os.path.getmtime(md_file)
+ if name in py2only:
+ repo.python2 = True
+ if name in mod_reject_list:
+ repo.rejected = True
+ if name in obsolete:
+ repo.obsolete = True
self.addon_repo.emit(repo)
self.status_message.emit(
diff --git a/src/Mod/AddonManager/package_details.py b/src/Mod/AddonManager/package_details.py
index 61de6d1786..bfbfbc936e 100644
--- a/src/Mod/AddonManager/package_details.py
+++ b/src/Mod/AddonManager/package_details.py
@@ -206,6 +206,29 @@ class PackageDetails(QWidget):
self.ui.buttonUpdate.hide()
self.ui.buttonCheckForUpdate.hide()
+ warningColorString = "rgb(200,0,0)"
+ if "dark" in QApplication.instance().styleSheet().lower():
+ warningColorString = "rgb(255,50,50)"
+
+ if repo.obsolete:
+ self.ui.labelWarningInfo.show()
+ self.ui.labelWarningInfo.setText(
+ "
"
+ + translate("AddonsInstaller", "WARNING: This addon is obsolete")
+ + "
"
+ )
+ self.ui.labelWarningInfo.setStyleSheet("color:" + warningColorString)
+ elif repo.python2:
+ self.ui.labelWarningInfo.show()
+ self.ui.labelWarningInfo.setText(
+ ""
+ + translate("AddonsInstaller", "WARNING: This addon is Python 2 Only")
+ + "
"
+ )
+ self.ui.labelWarningInfo.setStyleSheet("color:" + warningColorString)
+ else:
+ self.ui.labelWarningInfo.hide()
+
@classmethod
def cache_path(self, repo: AddonManagerRepo) -> str:
cache_path = FreeCAD.getUserCachePath()
@@ -389,6 +412,11 @@ class Ui_PackageDetails(object):
self.verticalLayout_2.addWidget(self.labelPackageDetails)
+ self.labelWarningInfo = QLabel(PackageDetails)
+ self.labelWarningInfo.hide()
+
+ self.verticalLayout_2.addWidget(self.labelWarningInfo)
+
self.textBrowserReadMe = QTextBrowser(PackageDetails)
self.textBrowserReadMe.setObjectName("textBrowserReadMe")
self.textBrowserReadMe.setOpenExternalLinks(True)
diff --git a/src/Mod/AddonManager/package_list.py b/src/Mod/AddonManager/package_list.py
index 06b6c077a3..17a2a78e08 100644
--- a/src/Mod/AddonManager/package_list.py
+++ b/src/Mod/AddonManager/package_list.py
@@ -99,6 +99,9 @@ class PackageList(QWidget):
else:
self.ui.buttonCompactLayout.setChecked(True)
+ self.item_filter.setHidePy2(pref.GetBool("HidePy2", True))
+ self.item_filter.setHideObsolete(pref.GetBool("HideObsolete", True))
+
def on_listPackages_clicked(self, index: QModelIndex):
source_selection = self.item_filter.mapToSource(index)
selected_repo = self.item_model.repos[source_selection.row()]
@@ -452,6 +455,8 @@ class PackageListFilter(QSortFilterProxyModel):
self.package_type = 0 # Default to showing everything
self.status = 0 # Default to showing any
self.setSortCaseSensitivity(Qt.CaseInsensitive)
+ self.hide_obsolete = False
+ self.hide_py2 = False
def setPackageFilter(
self, type: int
@@ -465,6 +470,14 @@ class PackageListFilter(QSortFilterProxyModel):
self.status = status
self.invalidateFilter()
+ def setHidePy2(self, hide_py2: bool) -> None:
+ self.hide_py2 = hide_py2
+ self.invalidateFilter()
+
+ def setHideObsolete(self, hide_obsolete: bool) -> None:
+ self.hide_obsolete = hide_obsolete
+ self.invalidateFilter()
+
def lessThan(self, left, right) -> bool:
l = self.sourceModel().data(left, PackageListItemModel.DataAccessRole)
r = self.sourceModel().data(right, PackageListItemModel.DataAccessRole)
@@ -494,6 +507,22 @@ class PackageListFilter(QSortFilterProxyModel):
if data.update_status != AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE:
return False
+ # If it's not installed, check to see if it's Py2 only
+ if (
+ data.update_status == AddonManagerRepo.UpdateStatus.NOT_INSTALLED
+ and self.hide_py2
+ and data.python2
+ ):
+ return False
+
+ # If it's not installed, check to see if it's marked obsolete
+ if (
+ data.update_status == AddonManagerRepo.UpdateStatus.NOT_INSTALLED
+ and self.hide_obsolete
+ and data.obsolete
+ ):
+ return False
+
name = data.display_name
desc = data.description
if hasattr(self, "filterRegularExpression"): # Added in Qt 5.12