diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 0b2940044f..f8fc081d5c 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -714,10 +714,8 @@ class CuraApplication(QtApplication): self._print_information = PrintInformation.PrintInformation(self) self._cura_actions = CuraActions.CuraActions(self) - # Initialize setting visibility presets model - self._setting_visibility_presets_model = SettingVisibilityPresetsModel(self) - default_visibility_profile = self._setting_visibility_presets_model.getItem(0) - self.getPreferences().setDefault("general/visible_settings", ";".join(default_visibility_profile["settings"])) + # Initialize setting visibility presets model. + self._setting_visibility_presets_model = SettingVisibilityPresetsModel(self.getPreferences(), parent = self) # Initialize Cura API self._cura_API.initialize() diff --git a/cura/Machines/Models/SettingVisibilityPresetsModel.py b/cura/Machines/Models/SettingVisibilityPresetsModel.py index 7e098197a9..2702001d8a 100644 --- a/cura/Machines/Models/SettingVisibilityPresetsModel.py +++ b/cura/Machines/Models/SettingVisibilityPresetsModel.py @@ -1,135 +1,109 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import Optional, List, Dict, Union -import os -import urllib.parse -from configparser import ConfigParser +from typing import Optional, List -from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal, pyqtSlot +from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject -from UM.Application import Application from UM.Logger import Logger -from UM.Qt.ListModel import ListModel from UM.Resources import Resources -from UM.MimeTypeDatabase import MimeTypeDatabase, MimeTypeNotFoundError from UM.i18n import i18nCatalog +from cura.Settings.SettingVisibilityPreset import SettingVisibilityPreset + catalog = i18nCatalog("cura") -class SettingVisibilityPresetsModel(ListModel): - IdRole = Qt.UserRole + 1 - NameRole = Qt.UserRole + 2 - SettingsRole = Qt.UserRole + 3 +class SettingVisibilityPresetsModel(QObject): + onItemsChanged = pyqtSignal() + activePresetChanged = pyqtSignal() - def __init__(self, parent = None): + def __init__(self, preferences, parent = None): super().__init__(parent) - self.addRoleName(self.IdRole, "id") - self.addRoleName(self.NameRole, "name") - self.addRoleName(self.SettingsRole, "settings") + self._items = [] # type: List[SettingVisibilityPreset] self._populate() - basic_item = self.items[1] - basic_visibile_settings = ";".join(basic_item["settings"]) - self._preferences = Application.getInstance().getPreferences() + basic_item = self.getVisibilityPresetById("basic") + basic_visibile_settings = ";".join(basic_item.settings) + + self._preferences = preferences + # Preference to store which preset is currently selected self._preferences.addPreference("cura/active_setting_visibility_preset", "basic") + # Preference that stores the "custom" set so it can always be restored (even after a restart) self._preferences.addPreference("cura/custom_visible_settings", basic_visibile_settings) self._preferences.preferenceChanged.connect(self._onPreferencesChanged) - self._active_preset_item = self._getItem(self._preferences.getValue("cura/active_setting_visibility_preset")) + self._active_preset_item = self.getVisibilityPresetById(self._preferences.getValue("cura/active_setting_visibility_preset")) + # Initialize visible settings if it is not done yet visible_settings = self._preferences.getValue("general/visible_settings") + if not visible_settings: - self._preferences.setValue("general/visible_settings", ";".join(self._active_preset_item["settings"])) + self._preferences.setValue("general/visible_settings", ";".join(self._active_preset_item.settings)) else: self._onPreferencesChanged("general/visible_settings") self.activePresetChanged.emit() - def _getItem(self, item_id: str) -> Optional[dict]: + def getVisibilityPresetById(self, item_id: str) -> Optional[SettingVisibilityPreset]: result = None - for item in self.items: - if item["id"] == item_id: + for item in self._items: + if item.presetId == item_id: result = item break return result def _populate(self) -> None: from cura.CuraApplication import CuraApplication - items = [] # type: List[Dict[str, Union[str, int, List[str]]]] + items = [] # type: List[SettingVisibilityPreset] + + custom_preset = SettingVisibilityPreset(preset_id="custom", name ="Custom selection", weight = -100) + items.append(custom_preset) for file_path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.SettingVisibilityPreset): + setting_visibility_preset = SettingVisibilityPreset() try: - mime_type = MimeTypeDatabase.getMimeTypeForFile(file_path) - except MimeTypeNotFoundError: - Logger.log("e", "Could not determine mime type of file %s", file_path) - continue - - item_id = urllib.parse.unquote_plus(mime_type.stripExtension(os.path.basename(file_path))) - if not os.path.isfile(file_path): - Logger.log("e", "[%s] is not a file", file_path) - continue - - parser = ConfigParser(allow_no_value = True) # accept options without any value, - try: - parser.read([file_path]) - if not parser.has_option("general", "name") or not parser.has_option("general", "weight"): - continue - - settings = [] # type: List[str] - for section in parser.sections(): - if section == 'general': - continue - - settings.append(section) - for option in parser[section].keys(): - settings.append(option) - - items.append({ - "id": item_id, - "name": catalog.i18nc("@action:inmenu", parser["general"]["name"]), - "weight": parser["general"]["weight"], - "settings": settings, - }) - + setting_visibility_preset.loadFromFile(file_path) except Exception: Logger.logException("e", "Failed to load setting preset %s", file_path) - items.sort(key = lambda k: (int(k["weight"]), k["id"])) # type: ignore - # Put "custom" at the top - items.insert(0, {"id": "custom", - "name": "Custom selection", - "weight": -100, - "settings": []}) + items.append(setting_visibility_preset) + + # Sort them on weight (and if that fails, use ID) + items.sort(key = lambda k: (int(k.weight), k.presetId)) self.setItems(items) + @pyqtProperty("QVariantList", notify = onItemsChanged) + def items(self): + return self._items + + def setItems(self, items: List[SettingVisibilityPreset]) -> None: + if self._items != items: + self._items = items + self.onItemsChanged.emit() + @pyqtSlot(str) - def setActivePreset(self, preset_id: str): - if preset_id == self._active_preset_item["id"]: + def setActivePreset(self, preset_id: str) -> None: + if preset_id == self._active_preset_item.presetId: Logger.log("d", "Same setting visibility preset [%s] selected, do nothing.", preset_id) return - preset_item = None - for item in self.items: - if item["id"] == preset_id: - preset_item = item - break + preset_item = self.getVisibilityPresetById(preset_id) if preset_item is None: Logger.log("w", "Tried to set active preset to unknown id [%s]", preset_id) return - need_to_save_to_custom = self._active_preset_item["id"] == "custom" and preset_id != "custom" + need_to_save_to_custom = self._active_preset_item.presetId == "custom" and preset_id != "custom" if need_to_save_to_custom: # Save the current visibility settings to custom current_visibility_string = self._preferences.getValue("general/visible_settings") if current_visibility_string: self._preferences.setValue("cura/custom_visible_settings", current_visibility_string) - new_visibility_string = ";".join(preset_item["settings"]) + new_visibility_string = ";".join(preset_item.settings) if preset_id == "custom": # Get settings from the stored custom data new_visibility_string = self._preferences.getValue("cura/custom_visible_settings") @@ -141,11 +115,9 @@ class SettingVisibilityPresetsModel(ListModel): self._active_preset_item = preset_item self.activePresetChanged.emit() - activePresetChanged = pyqtSignal() - @pyqtProperty(str, notify = activePresetChanged) def activePreset(self) -> str: - return self._active_preset_item["id"] + return self._active_preset_item.presetId def _onPreferencesChanged(self, name: str) -> None: if name != "general/visible_settings": @@ -158,25 +130,26 @@ class SettingVisibilityPresetsModel(ListModel): visibility_set = set(visibility_string.split(";")) matching_preset_item = None - for item in self.items: - if item["id"] == "custom": + for item in self._items: + if item.presetId == "custom": continue - if set(item["settings"]) == visibility_set: + if set(item.settings) == visibility_set: matching_preset_item = item break item_to_set = self._active_preset_item if matching_preset_item is None: # The new visibility setup is "custom" should be custom - if self._active_preset_item["id"] == "custom": + if self._active_preset_item.presetId == "custom": # We are already in custom, just save the settings self._preferences.setValue("cura/custom_visible_settings", visibility_string) else: - item_to_set = self.items[0] # 0 is custom + # We need to move to custom preset. + item_to_set = self.getVisibilityPresetById("custom") else: item_to_set = matching_preset_item - if self._active_preset_item is None or self._active_preset_item["id"] != item_to_set["id"]: + if self._active_preset_item is None or self._active_preset_item.presetId != item_to_set.presetId: self._active_preset_item = item_to_set - self._preferences.setValue("cura/active_setting_visibility_preset", self._active_preset_item["id"]) + self._preferences.setValue("cura/active_setting_visibility_preset", self._active_preset_item.presetId) self.activePresetChanged.emit() diff --git a/cura/Settings/SettingVisibilityPreset.py b/cura/Settings/SettingVisibilityPreset.py new file mode 100644 index 0000000000..e8a4211d69 --- /dev/null +++ b/cura/Settings/SettingVisibilityPreset.py @@ -0,0 +1,90 @@ +import os +import urllib.parse +from configparser import ConfigParser +from typing import List + +from PyQt5.QtCore import pyqtProperty, QObject, pyqtSignal + +from UM.Logger import Logger +from UM.MimeTypeDatabase import MimeTypeDatabase + + +class SettingVisibilityPreset(QObject): + onSettingsChanged = pyqtSignal() + onNameChanged = pyqtSignal() + onWeightChanged = pyqtSignal() + onIdChanged = pyqtSignal() + + def __init__(self, preset_id: str = "", name: str = "", weight: int = 0, parent = None) -> None: + super().__init__(parent) + self._settings = [] # type: List[str] + self._id = preset_id + self._weight = weight + self._name = name + + @pyqtProperty("QStringList", notify = onSettingsChanged) + def settings(self) -> List[str]: + return self._settings + + @pyqtProperty(str, notify = onIdChanged) + def presetId(self) -> str: + return self._id + + @pyqtProperty(int, notify = onWeightChanged) + def weight(self) -> int: + return self._weight + + @pyqtProperty(str, notify = onNameChanged) + def name(self) -> str: + return self._name + + def setName(self, name: str) -> None: + if name != self._name: + self._name = name + self.onNameChanged.emit() + + def setId(self, id: str) -> None: + if id != self._id: + self._id = id + self.onIdChanged.emit() + + def setWeight(self, weight: int) -> None: + if weight != self._weight: + self._weight = weight + self.onWeightChanged.emit() + + def setSettings(self, settings: List[str]) -> None: + if set(settings) != set(self._settings): + self._settings = list(set(settings)) # filter out non unique + self.onSettingsChanged.emit() + + # Load a preset from file. We expect a file that can be parsed by means of the config parser. + # The sections indicate the categories and the parameters placed in it (which don't need values) are the settings + # that should be considered visible. + def loadFromFile(self, file_path: str) -> None: + mime_type = MimeTypeDatabase.getMimeTypeForFile(file_path) + + item_id = urllib.parse.unquote_plus(mime_type.stripExtension(os.path.basename(file_path))) + if not os.path.isfile(file_path): + Logger.log("e", "[%s] is not a file", file_path) + return None + + parser = ConfigParser(interpolation = None, allow_no_value = True) # Accept options without any value, + + parser.read([file_path]) + if not parser.has_option("general", "name") or not parser.has_option("general", "weight"): + return None + + settings = [] # type: List[str] + for section in parser.sections(): + if section == "general": + continue + + settings.append(section) + for option in parser[section].keys(): + settings.append(option) + self.setSettings(settings) + self.setId(item_id) + self.setName(parser["general"]["name"]) + self.setWeight(int(parser["general"]["weight"])) + diff --git a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml index c34dc2a484..8116b6def1 100644 --- a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml +++ b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml @@ -18,17 +18,17 @@ Menu Instantiator { - model: settingVisibilityPresetsModel + model: settingVisibilityPresetsModel.items MenuItem { - text: model.name + text: modelData.name checkable: true - checked: model.id == settingVisibilityPresetsModel.activePreset + checked: modelData.presetId == settingVisibilityPresetsModel.activePreset exclusiveGroup: group onTriggered: { - settingVisibilityPresetsModel.setActivePreset(model.id); + settingVisibilityPresetsModel.setActivePreset(modelData.presetId); } } diff --git a/resources/qml/Preferences/SettingVisibilityPage.qml b/resources/qml/Preferences/SettingVisibilityPage.qml index 0f39a3c047..8896d0611e 100644 --- a/resources/qml/Preferences/SettingVisibilityPage.qml +++ b/resources/qml/Preferences/SettingVisibilityPage.qml @@ -110,24 +110,25 @@ UM.PreferencesPage right: parent.right } - model: settingVisibilityPresetsModel + model: settingVisibilityPresetsModel.items textRole: "name" currentIndex: { - // Load previously selected preset. - var index = settingVisibilityPresetsModel.find("id", settingVisibilityPresetsModel.activePreset) - if (index == -1) + for(var i = 0; i < settingVisibilityPresetsModel.items.length; ++i) { - return 0 + if(settingVisibilityPresetsModel.items[i].id == settingVisibilityPresetsModel.activePreset) + { + currentIndex = i; + return; + } } - - return index + return -1 } onActivated: { - var preset_id = settingVisibilityPresetsModel.getItem(index).id; + var preset_id = settingVisibilityPresetsModel.items[index].id; settingVisibilityPresetsModel.setActivePreset(preset_id); } } diff --git a/scripts/check_setting_visibility.py b/scripts/check_setting_visibility.py deleted file mode 100755 index 8fb5d5b293..0000000000 --- a/scripts/check_setting_visibility.py +++ /dev/null @@ -1,239 +0,0 @@ -#!/usr/bin/env python3 -# -# This script checks the correctness of the list of visibility settings -# -import collections -import configparser -import json -import os -import sys -from typing import Any, Dict, List - -# Directory where this python file resides -SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) - - -# -# This class -# -class SettingVisibilityInspection: - - def __init__(self) -> None: - # The order of settings type. If the setting is in basic list then it also should be in expert - self._setting_visibility_order = ["basic", "advanced", "expert"] - - # This is dictionary with categories as keys and all setting keys as values. - self.all_settings_keys = {} # type: Dict[str, List[str]] - - # Load all Cura setting keys from the given fdmprinter.json file - def loadAllCuraSettingKeys(self, fdmprinter_json_path: str) -> None: - with open(fdmprinter_json_path, "r", encoding = "utf-8") as f: - json_data = json.load(f) - - # Get all settings keys in each category - for key, data in json_data["settings"].items(): # top level settings are categories - if "type" in data and data["type"] == "category": - self.all_settings_keys[key] = [] - self._flattenSettings(data["children"], key) # actual settings are children of top level category-settings - - def _flattenSettings(self, settings: Dict[str, str], category: str) -> None: - for key, setting in settings.items(): - if "type" in setting and setting["type"] != "category": - self.all_settings_keys[category].append(key) - - if "children" in setting: - self._flattenSettings(setting["children"], category) - - # Loads the given setting visibility file and returns a dict with categories as keys and a list of setting keys as - # values. - def _loadSettingVisibilityConfigFile(self, file_name: str) -> Dict[str, List[str]]: - with open(file_name, "r", encoding = "utf-8") as f: - parser = configparser.ConfigParser(allow_no_value = True) - parser.read_file(f) - - data_dict = {} - for category, option_dict in parser.items(): - if category in (parser.default_section, "general"): - continue - - data_dict[category] = [] - for key in option_dict: - data_dict[category].append(key) - - return data_dict - - def validateSettingsVisibility(self, setting_visibility_files: Dict[str, str]) -> Dict[str, Dict[str, Any]]: - # First load all setting visibility files into the dict "setting_visibility_dict" in the following structure: - # -> -> - # "basic" -> "info" - setting_visibility_dict = {} # type: Dict[str, Dict[str, List[str]]] - for visibility_name, file_path in setting_visibility_files.items(): - setting_visibility_dict[visibility_name] = self._loadSettingVisibilityConfigFile(file_path) - - # The result is in the format: - # -> dict - # "basic" -> "file_name": "basic.cfg" - # "is_valid": True / False - # "invalid_categories": List[str] - # "invalid_settings": Dict[category -> List[str]] - # "missing_categories_from_previous": List[str] - # "missing_settings_from_previous": Dict[category -> List[str]] - all_result_dict = dict() # type: Dict[str, Dict[str, Any]] - - previous_result = None - previous_visibility_dict = None - is_all_valid = True - for visibility_name in self._setting_visibility_order: - invalid_categories = [] - invalid_settings = collections.defaultdict(list) - - this_visibility_dict = setting_visibility_dict[visibility_name] - # Check if categories and keys exist at all - for category, key_list in this_visibility_dict.items(): - if category not in self.all_settings_keys: - invalid_categories.append(category) - continue # If this category doesn't exist at all, not need to check for details - - for key in key_list: - if key not in self.all_settings_keys[category]: - invalid_settings[category].append(key) - - is_settings_valid = len(invalid_categories) == 0 and len(invalid_settings) == 0 - file_path = setting_visibility_files[visibility_name] - result_dict = {"file_name": os.path.basename(file_path), - "is_valid": is_settings_valid, - "invalid_categories": invalid_categories, - "invalid_settings": invalid_settings, - "missing_categories_from_previous": list(), - "missing_settings_from_previous": dict(), - } - - # If this is not the first item in the list, check if the settings are defined in the previous - # visibility file. - # A visibility with more details SHOULD add more settings. It SHOULD NOT remove any settings defined - # in the less detailed visibility. - if previous_visibility_dict is not None: - missing_categories_from_previous = [] - missing_settings_from_previous = collections.defaultdict(list) - - for prev_category, prev_key_list in previous_visibility_dict.items(): - # Skip the categories that are invalid - if prev_category in previous_result["invalid_categories"]: - continue - if prev_category not in this_visibility_dict: - missing_categories_from_previous.append(prev_category) - continue - - this_key_list = this_visibility_dict[prev_category] - for key in prev_key_list: - # Skip the settings that are invalid - if key in previous_result["invalid_settings"][prev_category]: - continue - - if key not in this_key_list: - missing_settings_from_previous[prev_category].append(key) - - result_dict["missing_categories_from_previous"] = missing_categories_from_previous - result_dict["missing_settings_from_previous"] = missing_settings_from_previous - is_settings_valid = len(missing_categories_from_previous) == 0 and len(missing_settings_from_previous) == 0 - result_dict["is_valid"] = result_dict["is_valid"] and is_settings_valid - - # Update the complete result dict - all_result_dict[visibility_name] = result_dict - previous_result = result_dict - previous_visibility_dict = this_visibility_dict - - is_all_valid = is_all_valid and result_dict["is_valid"] - - all_result_dict["all_results"] = {"is_valid": is_all_valid} - - return all_result_dict - - def printResults(self, all_result_dict: Dict[str, Dict[str, Any]]) -> None: - print("") - print("Setting Visibility Check Results:") - - prev_visibility_name = None - for visibility_name in self._setting_visibility_order: - if visibility_name not in all_result_dict: - continue - - result_dict = all_result_dict[visibility_name] - print("=============================") - result_str = "OK" if result_dict["is_valid"] else "INVALID" - print("[%s] : [%s] : %s" % (visibility_name, result_dict["file_name"], result_str)) - - if result_dict["is_valid"]: - continue - - # Print details of invalid settings - if result_dict["invalid_categories"]: - print("It has the following non-existing CATEGORIES:") - for category in result_dict["invalid_categories"]: - print(" - [%s]" % category) - - if result_dict["invalid_settings"]: - print("") - print("It has the following non-existing SETTINGS:") - for category, key_list in result_dict["invalid_settings"].items(): - for key in key_list: - print(" - [%s / %s]" % (category, key)) - - if prev_visibility_name is not None: - if result_dict["missing_categories_from_previous"]: - print("") - print("The following CATEGORIES are defined in the previous visibility [%s] but not here:" % prev_visibility_name) - for category in result_dict["missing_categories_from_previous"]: - print(" - [%s]" % category) - - if result_dict["missing_settings_from_previous"]: - print("") - print("The following SETTINGS are defined in the previous visibility [%s] but not here:" % prev_visibility_name) - for category, key_list in result_dict["missing_settings_from_previous"].items(): - for key in key_list: - print(" - [%s / %s]" % (category, key)) - - print("") - prev_visibility_name = visibility_name - - -# -# Returns a dictionary of setting visibility .CFG files in the given search directory. -# The dict has the name of the visibility type as the key (such as "basic", "advanced", "expert"), and -# the actual file path (absolute path). -# -def getAllSettingVisiblityFiles(search_dir: str) -> Dict[str, str]: - visibility_file_dict = dict() - extension = ".cfg" - for file_name in os.listdir(search_dir): - file_path = os.path.join(search_dir, file_name) - - # Only check files that has the .cfg extension - if not os.path.isfile(file_path): - continue - if not file_path.endswith(extension): - continue - - base_filename = os.path.basename(file_name)[:-len(extension)] - visibility_file_dict[base_filename] = file_path - return visibility_file_dict - - -def main() -> None: - setting_visibility_files_dir = os.path.abspath(os.path.join(SCRIPT_DIR, "..", "resources", "setting_visibility")) - fdmprinter_def_path = os.path.abspath(os.path.join(SCRIPT_DIR, "..", "resources", "definitions", "fdmprinter.def.json")) - - setting_visibility_files_dict = getAllSettingVisiblityFiles(setting_visibility_files_dir) - - inspector = SettingVisibilityInspection() - inspector.loadAllCuraSettingKeys(fdmprinter_def_path) - - check_result = inspector.validateSettingsVisibility(setting_visibility_files_dict) - is_result_valid = check_result["all_results"]["is_valid"] - inspector.printResults(check_result) - - sys.exit(0 if is_result_valid else 1) - - -if __name__ == "__main__": - main() diff --git a/tests/Settings/TestSettingVisibilityPresets.py b/tests/Settings/TestSettingVisibilityPresets.py new file mode 100644 index 0000000000..b82aa62ea7 --- /dev/null +++ b/tests/Settings/TestSettingVisibilityPresets.py @@ -0,0 +1,89 @@ +from unittest.mock import MagicMock + +import os.path + +from UM.Preferences import Preferences +from UM.Resources import Resources +from cura.CuraApplication import CuraApplication +from cura.Machines.Models.SettingVisibilityPresetsModel import SettingVisibilityPresetsModel +from cura.Settings.SettingVisibilityPreset import SettingVisibilityPreset + +setting_visibility_preset_test_settings = {"test", "zomg", "derp", "yay", "whoo"} + +Resources.addSearchPath(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "resources"))) +Resources.addStorageType(CuraApplication.ResourceTypes.SettingVisibilityPreset, "setting_visibility") + + +def test_createVisibilityPresetFromLocalFile(): + # Simple creation test. This is seperated from the visibilityFromPrevious, since we can't check for the contents + # of the other profiles, since they might change over time. + visibility_preset = SettingVisibilityPreset() + + visibility_preset.loadFromFile(os.path.join(os.path.dirname(os.path.abspath(__file__)), "setting_visiblity_preset_test.cfg")) + assert setting_visibility_preset_test_settings == set(visibility_preset.settings) + + assert visibility_preset.name == "test" + assert visibility_preset.weight == 1 + assert visibility_preset.settings.count("yay") == 1 # It's in the file twice but we should load it once. + +def test_visibilityFromPrevious(): + # This test checks that all settings in basic are in advanced and all settings in advanced are in expert. + + visibility_model = SettingVisibilityPresetsModel(Preferences()) + + basic_visibility = visibility_model.getVisibilityPresetById("basic") + advanced_visibility = visibility_model.getVisibilityPresetById("advanced") + expert_visibility = visibility_model.getVisibilityPresetById("expert") + + # Check if there are settings that are in basic, but not in advanced. + settings_not_in_advanced = set(basic_visibility.settings) - set(advanced_visibility.settings) + assert len(settings_not_in_advanced) == 0 # All settings in basic should be in advanced + + # Check if there are settings that are in advanced, but not in expert. + settings_not_in_expert = set(advanced_visibility.settings) - set(expert_visibility.settings) + assert len(settings_not_in_expert) == 0 # All settings in advanced should be in expert. + + +def test_setActivePreset(): + preferences = Preferences() + visibility_model = SettingVisibilityPresetsModel(preferences) + visibility_model.activePresetChanged = MagicMock() + # Ensure that we start off with basic (since we didn't change anyting just yet!) + assert visibility_model.activePreset == "basic" + + # Everything should be the same. + visibility_model.setActivePreset("basic") + assert visibility_model.activePreset == "basic" + assert visibility_model.activePresetChanged.emit.call_count == 0 # No events should be sent. + + # Change it to existing type (should work...) + visibility_model.setActivePreset("advanced") + assert visibility_model.activePreset == "advanced" + assert visibility_model.activePresetChanged.emit.call_count == 1 + + # Change to unknown preset. Shouldn't do anything. + visibility_model.setActivePreset("OMGZOMGNOPE") + assert visibility_model.activePreset == "advanced" + assert visibility_model.activePresetChanged.emit.call_count == 1 + + +def test_preferenceChanged(): + preferences = Preferences() + # Set the visible_settings to something silly + preferences.addPreference("general/visible_settings", "omgzomg") + visibility_model = SettingVisibilityPresetsModel(preferences) + visibility_model.activePresetChanged = MagicMock() + + assert visibility_model.activePreset == "custom" # This should make the model start at "custom + assert visibility_model.activePresetChanged.emit.call_count == 0 + + + basic_visibility = visibility_model.getVisibilityPresetById("basic") + new_visibility_string = ";".join(basic_visibility.settings) + preferences.setValue("general/visible_settings", new_visibility_string) + + # Fake a signal emit (since we didn't create the application, our own signals are not fired) + visibility_model._onPreferencesChanged("general/visible_settings") + # Set the visibility settings to basic + assert visibility_model.activePreset == "basic" + assert visibility_model.activePresetChanged.emit.call_count == 1 diff --git a/tests/Settings/setting_visiblity_preset_test.cfg b/tests/Settings/setting_visiblity_preset_test.cfg new file mode 100644 index 0000000000..0a89bf6b14 --- /dev/null +++ b/tests/Settings/setting_visiblity_preset_test.cfg @@ -0,0 +1,11 @@ +[general] +name = test +weight = 1 + +[test] +zomg +derp +yay + +[whoo] +yay \ No newline at end of file