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